feat: add news ticker with sentiment analysis and error codes

docs: update site links to retoor repository and documentation
chore: add author lines to header files
build: rebuild binary and object files
This commit is contained in:
2025-12-28 04:30:10 +01:00
parent 7a4f7a82ad
commit 9182d9931e
42 changed files with 262 additions and 76 deletions
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* AI Integration (OpenRouter API) * AI Integration (OpenRouter API)
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Application launcher with .desktop file support * Application launcher with .desktop file support
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* X11 Atoms management (EWMH/ICCCM compliance) * X11 Atoms management (EWMH/ICCCM compliance)
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Client (window) management * Client (window) management
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Configuration system * Configuration system
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Window decorations (title bars, borders, buttons) * Window decorations (title bars, borders, buttons)
*/ */
+12
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Main header with shared types and global state * Main header with shared types and global state
*/ */
@@ -32,6 +33,17 @@
#define DEFAULT_PANEL_HEIGHT 28 #define DEFAULT_PANEL_HEIGHT 28
#define DEFAULT_GAP 4 #define DEFAULT_GAP 4
/* Common error/status codes */
typedef enum {
DWN_OK = 0,
DWN_ERROR = -1,
DWN_ERROR_INVALID_ARG = -2,
DWN_ERROR_NO_MEMORY = -3,
DWN_ERROR_NOT_FOUND = -4,
DWN_ERROR_DISPLAY = -5,
DWN_ERROR_IO = -6
} DwnStatus;
/* Layout types */ /* Layout types */
typedef enum { typedef enum {
LAYOUT_TILING, LAYOUT_TILING,
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Keyboard shortcut handling * Keyboard shortcut handling
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Layout algorithms (tiling, floating, monocle) * Layout algorithms (tiling, floating, monocle)
*/ */
+10
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* News ticker for bottom panel * News ticker for bottom panel
*/ */
@@ -13,12 +14,21 @@
#define MAX_NEWS_ARTICLES 50 #define MAX_NEWS_ARTICLES 50
#define NEWS_API_URL "https://news.app.molodetz.nl/api" #define NEWS_API_URL "https://news.app.molodetz.nl/api"
/* Sentiment classification */
typedef enum {
SENTIMENT_NEUTRAL = 0,
SENTIMENT_POSITIVE,
SENTIMENT_NEGATIVE
} NewsSentiment;
/* News article */ /* News article */
typedef struct { typedef struct {
char title[256]; char title[256];
char content[1024]; char content[1024];
char link[512]; char link[512];
char author[128]; char author[128];
NewsSentiment sentiment;
float sentiment_score;
} NewsArticle; } NewsArticle;
/* News ticker state */ /* News ticker state */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* D-Bus Notification daemon * D-Bus Notification daemon
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Panel system (top and bottom panels with widgets) * Panel system (top and bottom panels with widgets)
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* System tray widgets (WiFi, Audio, etc.) * System tray widgets (WiFi, Audio, etc.)
*/ */
+6
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Utility functions * Utility functions
*/ */
@@ -9,6 +10,11 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdarg.h> #include <stdarg.h>
#include <assert.h>
/* Contract assertion macro - use for programmer errors */
#define DWN_ASSERT(cond) assert(cond)
#define DWN_ASSERT_MSG(cond, msg) assert((cond) && (msg))
/* Logging levels */ /* Logging levels */
typedef enum { typedef enum {
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Workspace (tag/virtual desktop) management * Workspace (tag/virtual desktop) management
*/ */
+7 -7
View File
@@ -28,7 +28,7 @@
<a href="architecture.html">Architecture</a> <a href="architecture.html">Architecture</a>
</div> </div>
</li> </li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
<div class="nav-toggle" onclick="toggleNav()"> <div class="nav-toggle" onclick="toggleNav()">
<span></span> <span></span>
@@ -434,21 +434,21 @@ model = google/gemini-2.0-flash-exp:free</code></pre>
<li><a href="features.html">Features</a></li> <li><a href="features.html">Features</a></li>
<li><a href="installation.html">Installation</a></li> <li><a href="installation.html">Installation</a></li>
<li><a href="ai-features.html">AI Integration</a></li> <li><a href="ai-features.html">AI Integration</a></li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
</div> </div>
<div class="footer-section"> <div class="footer-section">
<h4>Community</h4> <h4>Community</h4>
<ul> <ul>
<li><a href="https://github.com/dwn/dwn/issues">Issue Tracker</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/issues">Issue Tracker</a></li>
<li><a href="https://github.com/dwn/dwn/discussions">Discussions</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/discussions">Discussions</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/LICENSE">License (MIT)</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/LICENSE">License (MIT)</a></li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="footer-bottom"> <div class="footer-bottom">
<p>DWN Window Manager - Open Source under the MIT License</p> <p>DWN Window Manager by retoor &lt;retoor@molodetz.nl&gt; - MIT License</p>
</div> </div>
</div> </div>
</footer> </footer>
+7 -7
View File
@@ -28,7 +28,7 @@
<a href="architecture.html">Architecture</a> <a href="architecture.html">Architecture</a>
</div> </div>
</li> </li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
<div class="nav-toggle" onclick="toggleNav()"> <div class="nav-toggle" onclick="toggleNav()">
<span></span> <span></span>
@@ -541,21 +541,21 @@ extern DWNState *dwn; // Global singleton</code></pre>
<li><a href="features.html">Features</a></li> <li><a href="features.html">Features</a></li>
<li><a href="installation.html">Installation</a></li> <li><a href="installation.html">Installation</a></li>
<li><a href="ai-features.html">AI Integration</a></li> <li><a href="ai-features.html">AI Integration</a></li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
</div> </div>
<div class="footer-section"> <div class="footer-section">
<h4>Community</h4> <h4>Community</h4>
<ul> <ul>
<li><a href="https://github.com/dwn/dwn/issues">Issue Tracker</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/issues">Issue Tracker</a></li>
<li><a href="https://github.com/dwn/dwn/discussions">Discussions</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/discussions">Discussions</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/LICENSE">License (MIT)</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/LICENSE">License (MIT)</a></li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="footer-bottom"> <div class="footer-bottom">
<p>DWN Window Manager - Open Source under the MIT License</p> <p>DWN Window Manager by retoor &lt;retoor@molodetz.nl&gt; - MIT License</p>
</div> </div>
</div> </div>
</footer> </footer>
+7 -7
View File
@@ -28,7 +28,7 @@
<a href="architecture.html">Architecture</a> <a href="architecture.html">Architecture</a>
</div> </div>
</li> </li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
<div class="nav-toggle" onclick="toggleNav()"> <div class="nav-toggle" onclick="toggleNav()">
<span></span> <span></span>
@@ -496,21 +496,21 @@ model = google/gemini-2.0-flash-exp:free
<li><a href="features.html">Features</a></li> <li><a href="features.html">Features</a></li>
<li><a href="installation.html">Installation</a></li> <li><a href="installation.html">Installation</a></li>
<li><a href="ai-features.html">AI Integration</a></li> <li><a href="ai-features.html">AI Integration</a></li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
</div> </div>
<div class="footer-section"> <div class="footer-section">
<h4>Community</h4> <h4>Community</h4>
<ul> <ul>
<li><a href="https://github.com/dwn/dwn/issues">Issue Tracker</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/issues">Issue Tracker</a></li>
<li><a href="https://github.com/dwn/dwn/discussions">Discussions</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/discussions">Discussions</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/LICENSE">License (MIT)</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/LICENSE">License (MIT)</a></li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="footer-bottom"> <div class="footer-bottom">
<p>DWN Window Manager - Open Source under the MIT License</p> <p>DWN Window Manager by retoor &lt;retoor@molodetz.nl&gt; - MIT License</p>
</div> </div>
</div> </div>
</footer> </footer>
+11 -9
View File
@@ -28,7 +28,7 @@
<a href="architecture.html">Architecture</a> <a href="architecture.html">Architecture</a>
</div> </div>
</li> </li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
<div class="nav-toggle" onclick="toggleNav()"> <div class="nav-toggle" onclick="toggleNav()">
<span></span> <span></span>
@@ -360,8 +360,10 @@
<h3>Bottom Panel</h3> <h3>Bottom Panel</h3>
<p> <p>
The bottom panel shows the current time and date. Both panels can be hidden The bottom panel shows the current time and a scrolling news ticker. Navigate
in the configuration if you prefer a minimal setup. news articles with <kbd>Super</kbd> + <kbd>Up</kbd>/<kbd>Down</kbd> and open
the current article with <kbd>Super</kbd> + <kbd>Return</kbd>. Both panels can
be hidden in the configuration if you prefer a minimal setup.
</p> </p>
<h2>Next Steps</h2> <h2>Next Steps</h2>
@@ -399,21 +401,21 @@
<li><a href="features.html">Features</a></li> <li><a href="features.html">Features</a></li>
<li><a href="installation.html">Installation</a></li> <li><a href="installation.html">Installation</a></li>
<li><a href="ai-features.html">AI Integration</a></li> <li><a href="ai-features.html">AI Integration</a></li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
</div> </div>
<div class="footer-section"> <div class="footer-section">
<h4>Community</h4> <h4>Community</h4>
<ul> <ul>
<li><a href="https://github.com/dwn/dwn/issues">Issue Tracker</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/issues">Issue Tracker</a></li>
<li><a href="https://github.com/dwn/dwn/discussions">Discussions</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/discussions">Discussions</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/LICENSE">License (MIT)</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/LICENSE">License (MIT)</a></li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="footer-bottom"> <div class="footer-bottom">
<p>DWN Window Manager - Open Source under the MIT License</p> <p>DWN Window Manager by retoor &lt;retoor@molodetz.nl&gt; - MIT License</p>
</div> </div>
</div> </div>
</footer> </footer>
+23 -8
View File
@@ -28,7 +28,7 @@
<a href="architecture.html">Architecture</a> <a href="architecture.html">Architecture</a>
</div> </div>
</li> </li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
<div class="nav-toggle" onclick="toggleNav()"> <div class="nav-toggle" onclick="toggleNav()">
<span></span> <span></span>
@@ -160,12 +160,27 @@
<p>Optional bottom panel for additional information:</p> <p>Optional bottom panel for additional information:</p>
<ul style="margin-top: 1rem; padding-left: 1.25rem; color: var(--text-muted);"> <ul style="margin-top: 1rem; padding-left: 1.25rem; color: var(--text-muted);">
<li><strong>Clock Display</strong> - Time and date</li> <li><strong>Clock Display</strong> - Time and date</li>
<li><strong>Status Messages</strong> - System notifications</li> <li><strong>News Ticker</strong> - Scrolling news feed with navigation</li>
<li><strong>Customizable</strong> - Can be hidden in config</li> <li><strong>Customizable</strong> - Can be hidden in config</li>
</ul> </ul>
</div> </div>
</div> </div>
<h3 style="margin-top: 3rem; margin-bottom: 1.5rem;">News Ticker</h3>
<div class="card">
<p>The bottom panel includes a scrolling news ticker that displays headlines from a news feed.
Navigate through articles using keyboard shortcuts:</p>
<ul style="margin-top: 1rem; padding-left: 1.25rem; color: var(--text-muted);">
<li><kbd>Super</kbd> + <kbd>Down</kbd> - Next article</li>
<li><kbd>Super</kbd> + <kbd>Up</kbd> - Previous article</li>
<li><kbd>Super</kbd> + <kbd>Return</kbd> - Open in browser</li>
</ul>
<p style="margin-top: 1rem; color: var(--text-muted);">
The ticker updates automatically and caches up to 50 articles. Smooth scrolling animation
at 80 pixels per second keeps you informed without distraction.
</p>
</div>
<h3 style="margin-top: 3rem; margin-bottom: 1.5rem;">System Tray Features</h3> <h3 style="margin-top: 3rem; margin-bottom: 1.5rem;">System Tray Features</h3>
<div class="features-grid"> <div class="features-grid">
<div class="card"> <div class="card">
@@ -387,21 +402,21 @@
<li><a href="features.html">Features</a></li> <li><a href="features.html">Features</a></li>
<li><a href="installation.html">Installation</a></li> <li><a href="installation.html">Installation</a></li>
<li><a href="ai-features.html">AI Integration</a></li> <li><a href="ai-features.html">AI Integration</a></li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
</div> </div>
<div class="footer-section"> <div class="footer-section">
<h4>Community</h4> <h4>Community</h4>
<ul> <ul>
<li><a href="https://github.com/dwn/dwn/issues">Issue Tracker</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/issues">Issue Tracker</a></li>
<li><a href="https://github.com/dwn/dwn/discussions">Discussions</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/discussions">Discussions</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/LICENSE">License (MIT)</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/LICENSE">License (MIT)</a></li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="footer-bottom"> <div class="footer-bottom">
<p>DWN Window Manager - Open Source under the MIT License</p> <p>DWN Window Manager by retoor &lt;retoor@molodetz.nl&gt; - MIT License</p>
</div> </div>
</div> </div>
</footer> </footer>
+10 -10
View File
@@ -29,7 +29,7 @@
<a href="architecture.html">Architecture</a> <a href="architecture.html">Architecture</a>
</div> </div>
</li> </li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
<div class="nav-toggle" onclick="toggleNav()"> <div class="nav-toggle" onclick="toggleNav()">
<span></span> <span></span>
@@ -109,7 +109,7 @@
<div class="container"> <div class="container">
<div class="stats"> <div class="stats">
<div class="stat-item"> <div class="stat-item">
<h3>~10K</h3> <h3>~15K</h3>
<p>Lines of Pure C</p> <p>Lines of Pure C</p>
</div> </div>
<div class="stat-item"> <div class="stat-item">
@@ -121,7 +121,7 @@
<p>Memory Footprint</p> <p>Memory Footprint</p>
</div> </div>
<div class="stat-item"> <div class="stat-item">
<h3>64+</h3> <h3>43+</h3>
<p>Keyboard Shortcuts</p> <p>Keyboard Shortcuts</p>
</div> </div>
</div> </div>
@@ -143,7 +143,7 @@
<button class="copy-btn" onclick="copyCode(this)">Copy</button> <button class="copy-btn" onclick="copyCode(this)">Copy</button>
</div> </div>
<pre><code># Clone the repository <pre><code># Clone the repository
git clone https://github.com/dwn/dwn.git git clone https://retoor.molodetz.nl/retoor/dwn.git
cd dwn cd dwn
# Install dependencies (auto-detects your distro) # Install dependencies (auto-detects your distro)
@@ -328,21 +328,21 @@ echo "exec dwn" >> ~/.xinitrc</code></pre>
<li><a href="features.html">Features</a></li> <li><a href="features.html">Features</a></li>
<li><a href="installation.html">Installation</a></li> <li><a href="installation.html">Installation</a></li>
<li><a href="ai-features.html">AI Integration</a></li> <li><a href="ai-features.html">AI Integration</a></li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
</div> </div>
<div class="footer-section"> <div class="footer-section">
<h4>Community</h4> <h4>Community</h4>
<ul> <ul>
<li><a href="https://github.com/dwn/dwn/issues">Issue Tracker</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/issues">Issue Tracker</a></li>
<li><a href="https://github.com/dwn/dwn/discussions">Discussions</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/discussions">Discussions</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/LICENSE">License (MIT)</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/LICENSE">License (MIT)</a></li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="footer-bottom"> <div class="footer-bottom">
<p>DWN Window Manager - Open Source under the MIT License</p> <p>DWN Window Manager by retoor &lt;retoor@molodetz.nl&gt; - MIT License</p>
</div> </div>
</div> </div>
</footer> </footer>
+12 -12
View File
@@ -28,7 +28,7 @@
<a href="architecture.html">Architecture</a> <a href="architecture.html">Architecture</a>
</div> </div>
</li> </li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
<div class="nav-toggle" onclick="toggleNav()"> <div class="nav-toggle" onclick="toggleNav()">
<span></span> <span></span>
@@ -133,7 +133,7 @@
<span>Terminal</span> <span>Terminal</span>
<button class="copy-btn" onclick="copyCode(this)">Copy</button> <button class="copy-btn" onclick="copyCode(this)">Copy</button>
</div> </div>
<pre><code>git clone https://github.com/dwn/dwn.git <pre><code>git clone https://retoor.molodetz.nl/retoor/dwn.git
cd dwn</code></pre> cd dwn</code></pre>
</div> </div>
</div> </div>
@@ -232,7 +232,7 @@ sudo apt install -y \
pkg-config pkg-config
# Build and install # Build and install
git clone https://github.com/dwn/dwn.git git clone https://retoor.molodetz.nl/retoor/dwn.git
cd dwn cd dwn
make make
sudo make install</code></pre> sudo make install</code></pre>
@@ -259,7 +259,7 @@ sudo dnf install -y \
pkg-config pkg-config
# Build and install # Build and install
git clone https://github.com/dwn/dwn.git git clone https://retoor.molodetz.nl/retoor/dwn.git
cd dwn cd dwn
make make
sudo make install</code></pre> sudo make install</code></pre>
@@ -285,7 +285,7 @@ sudo pacman -S --needed \
pkg-config pkg-config
# Build and install # Build and install
git clone https://github.com/dwn/dwn.git git clone https://retoor.molodetz.nl/retoor/dwn.git
cd dwn cd dwn
make make
sudo make install</code></pre> sudo make install</code></pre>
@@ -316,7 +316,7 @@ sudo xbps-install -S \
pkg-config pkg-config
# Build and install # Build and install
git clone https://github.com/dwn/dwn.git git clone https://retoor.molodetz.nl/retoor/dwn.git
cd dwn cd dwn
make make
sudo make install</code></pre> sudo make install</code></pre>
@@ -586,21 +586,21 @@ sudo dnf install dejavu-fonts-all liberation-fonts # Fedora</code></pre>
<li><a href="features.html">Features</a></li> <li><a href="features.html">Features</a></li>
<li><a href="installation.html">Installation</a></li> <li><a href="installation.html">Installation</a></li>
<li><a href="ai-features.html">AI Integration</a></li> <li><a href="ai-features.html">AI Integration</a></li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
</div> </div>
<div class="footer-section"> <div class="footer-section">
<h4>Community</h4> <h4>Community</h4>
<ul> <ul>
<li><a href="https://github.com/dwn/dwn/issues">Issue Tracker</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/issues">Issue Tracker</a></li>
<li><a href="https://github.com/dwn/dwn/discussions">Discussions</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/discussions">Discussions</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/LICENSE">License (MIT)</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/LICENSE">License (MIT)</a></li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="footer-bottom"> <div class="footer-bottom">
<p>DWN Window Manager - Open Source under the MIT License</p> <p>DWN Window Manager by retoor &lt;retoor@molodetz.nl&gt; - MIT License</p>
</div> </div>
</div> </div>
</footer> </footer>
+42 -8
View File
@@ -28,7 +28,7 @@
<a href="architecture.html">Architecture</a> <a href="architecture.html">Architecture</a>
</div> </div>
</li> </li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
<div class="nav-toggle" onclick="toggleNav()"> <div class="nav-toggle" onclick="toggleNav()">
<span></span> <span></span>
@@ -71,7 +71,7 @@
<td>Open terminal (configurable)</td> <td>Open terminal (configurable)</td>
</tr> </tr>
<tr> <tr>
<td><kbd>Alt</kbd> + <kbd>F2</kbd></td> <td><kbd>Super</kbd> / <kbd>Alt</kbd> + <kbd>F2</kbd></td>
<td>Open application launcher (dmenu/rofi)</td> <td>Open application launcher (dmenu/rofi)</td>
</tr> </tr>
<tr> <tr>
@@ -82,6 +82,10 @@
<td><kbd>Super</kbd> + <kbd>B</kbd></td> <td><kbd>Super</kbd> + <kbd>B</kbd></td>
<td>Open web browser</td> <td>Open web browser</td>
</tr> </tr>
<tr>
<td><kbd>Print</kbd></td>
<td>Take screenshot (xfce4-screenshooter)</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@@ -285,6 +289,36 @@
</table> </table>
</div> </div>
<!-- News Ticker -->
<h2 id="news">News Ticker</h2>
<p style="color: var(--text-muted); margin-bottom: 1rem;">
Navigate the scrolling news ticker displayed in the bottom panel.
</p>
<div class="table-wrapper">
<table class="shortcuts-table">
<thead>
<tr>
<th style="width: 40%;">Shortcut</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><kbd>Super</kbd> + <kbd>Down</kbd></td>
<td>Next news article</td>
</tr>
<tr>
<td><kbd>Super</kbd> + <kbd>Up</kbd></td>
<td>Previous news article</td>
</tr>
<tr>
<td><kbd>Super</kbd> + <kbd>Return</kbd></td>
<td>Open current article in browser</td>
</tr>
</tbody>
</table>
</div>
<!-- Help & System --> <!-- Help & System -->
<h2 id="system">Help & System</h2> <h2 id="system">Help & System</h2>
<div class="table-wrapper"> <div class="table-wrapper">
@@ -389,21 +423,21 @@
<li><a href="features.html">Features</a></li> <li><a href="features.html">Features</a></li>
<li><a href="installation.html">Installation</a></li> <li><a href="installation.html">Installation</a></li>
<li><a href="ai-features.html">AI Integration</a></li> <li><a href="ai-features.html">AI Integration</a></li>
<li><a href="https://github.com/dwn/dwn">GitHub</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
</ul> </ul>
</div> </div>
<div class="footer-section"> <div class="footer-section">
<h4>Community</h4> <h4>Community</h4>
<ul> <ul>
<li><a href="https://github.com/dwn/dwn/issues">Issue Tracker</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/issues">Issue Tracker</a></li>
<li><a href="https://github.com/dwn/dwn/discussions">Discussions</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/discussions">Discussions</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/CONTRIBUTING.md">Contributing</a></li>
<li><a href="https://github.com/dwn/dwn/blob/main/LICENSE">License (MIT)</a></li> <li><a href="https://retoor.molodetz.nl/retoor/dwn/blob/main/LICENSE">License (MIT)</a></li>
</ul> </ul>
</div> </div>
</div> </div>
<div class="footer-bottom"> <div class="footer-bottom">
<p>DWN Window Manager - Open Source under the MIT License</p> <p>DWN Window Manager by retoor &lt;retoor@molodetz.nl&gt; - MIT License</p>
</div> </div>
</div> </div>
</footer> </footer>
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* AI Integration implementation * AI Integration implementation
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Application launcher with .desktop file support * Application launcher with .desktop file support
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* X11 Atoms management implementation * X11 Atoms management implementation
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Client (window) management implementation * Client (window) management implementation
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Configuration system implementation * Configuration system implementation
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Window decorations implementation * Window decorations implementation
*/ */
+41 -3
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Keyboard shortcut handling implementation * Keyboard shortcut handling implementation
*/ */
@@ -15,6 +16,11 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdbool.h>
#include <X11/XKBlib.h>
static bool super_pressed = false;
static bool super_used_in_combo = false;
/* Forward declarations for key callbacks */ /* Forward declarations for key callbacks */
void key_spawn_terminal(void); void key_spawn_terminal(void);
@@ -354,6 +360,17 @@ void keys_grab_all(void)
GrabModeAsync, GrabModeAsync); GrabModeAsync, GrabModeAsync);
} }
} }
KeyCode super_l = XKeysymToKeycode(dpy, XK_Super_L);
KeyCode super_r = XKeysymToKeycode(dpy, XK_Super_R);
unsigned int lock_mods[] = { 0, Mod2Mask, LockMask, Mod2Mask | LockMask };
for (size_t i = 0; i < sizeof(lock_mods) / sizeof(lock_mods[0]); i++) {
if (super_l) XGrabKey(dpy, super_l, lock_mods[i], root, True,
GrabModeAsync, GrabModeAsync);
if (super_r) XGrabKey(dpy, super_r, lock_mods[i], root, True,
GrabModeAsync, GrabModeAsync);
}
} }
void keys_ungrab_all(void) void keys_ungrab_all(void)
@@ -412,6 +429,16 @@ void keys_handle_press(XKeyEvent *ev)
KeySym keysym = XLookupKeysym(ev, 0); KeySym keysym = XLookupKeysym(ev, 0);
if (keysym == XK_Super_L || keysym == XK_Super_R) {
super_pressed = true;
super_used_in_combo = false;
return;
}
if (super_pressed && (ev->state & Mod4Mask)) {
super_used_in_combo = true;
}
/* Clean modifiers (remove NumLock, CapsLock) */ /* Clean modifiers (remove NumLock, CapsLock) */
unsigned int clean_mask = ev->state & ~(Mod2Mask | LockMask); unsigned int clean_mask = ev->state & ~(Mod2Mask | LockMask);
@@ -434,8 +461,19 @@ void keys_handle_press(XKeyEvent *ev)
void keys_handle_release(XKeyEvent *ev) void keys_handle_release(XKeyEvent *ev)
{ {
/* Currently no release handling needed */ if (ev == NULL || dwn == NULL || dwn->display == NULL) {
(void)ev; return;
}
KeySym keysym = XLookupKeysym(ev, 0);
if (keysym == XK_Super_L || keysym == XK_Super_R) {
if (super_pressed && !super_used_in_combo) {
key_spawn_launcher();
}
super_pressed = false;
super_used_in_combo = false;
}
} }
/* ========== Default key bindings (XFCE-style) ========== */ /* ========== Default key bindings (XFCE-style) ========== */
@@ -770,7 +808,7 @@ void key_show_shortcuts(void)
const char *shortcuts = const char *shortcuts =
"=== Applications ===\n" "=== Applications ===\n"
"Ctrl+Alt+T Terminal\n" "Ctrl+Alt+T Terminal\n"
"Alt+F2 App launcher\n" "Super / Alt+F2 App launcher\n"
"Super+E File manager\n" "Super+E File manager\n"
"Super+B Web browser\n" "Super+B Web browser\n"
"Print Screenshot\n" "Print Screenshot\n"
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Layout algorithms implementation * Layout algorithms implementation
*/ */
+9 -4
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Main entry point and event loop * Main entry point and event loop
*/ */
@@ -456,15 +457,19 @@ static void handle_button_press(XButtonEvent *ev)
return; return;
} }
/* Focus on click */ /* If click was on client window content, replay the event to the application FIRST
client_focus(c); * before any other X operations. The synchronous grab freezes pointer events until
* XAllowEvents is called. Calling XAllowEvents before client_focus ensures the
/* If click was on client window content, replay the event to the application */ * click reaches the application (tabs, buttons, etc.) without timing issues. */
if (is_client_window) { if (is_client_window) {
XAllowEvents(dwn->display, ReplayPointer, ev->time); XAllowEvents(dwn->display, ReplayPointer, ev->time);
client_focus(c);
return; return;
} }
/* Focus on click */
client_focus(c);
/* Check for button clicks in decorations */ /* Check for button clicks in decorations */
if (c->frame != None && ev->window == c->frame) { if (c->frame != None && ev->window == c->frame) {
ButtonType btn = decorations_hit_test_button(c, ev->x, ev->y); ButtonType btn = decorations_hit_test_button(c, ev->x, ev->y);
+41 -1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* News ticker implementation * News ticker implementation
*/ */
@@ -12,6 +13,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h>
#include <unistd.h> #include <unistd.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <pthread.h> #include <pthread.h>
@@ -24,6 +26,20 @@
/* Fetch interval in milliseconds (5 minutes) */ /* Fetch interval in milliseconds (5 minutes) */
#define FETCH_INTERVAL 300000 #define FETCH_INTERVAL 300000
/* Sentiment colors (RGB hex values) */
#define SENTIMENT_COLOR_POSITIVE 0x81C784
#define SENTIMENT_COLOR_NEUTRAL 0xB0BEC5
#define SENTIMENT_COLOR_NEGATIVE 0xE57373
static unsigned long news_sentiment_color(NewsSentiment sentiment)
{
switch (sentiment) {
case SENTIMENT_POSITIVE: return SENTIMENT_COLOR_POSITIVE;
case SENTIMENT_NEGATIVE: return SENTIMENT_COLOR_NEGATIVE;
default: return SENTIMENT_COLOR_NEUTRAL;
}
}
/* Global state */ /* Global state */
NewsState news_state = {0}; NewsState news_state = {0};
@@ -225,6 +241,27 @@ static int parse_news_json(const char *json_str)
strncpy(art->author, author->valuestring, sizeof(art->author) - 1); strncpy(art->author, author->valuestring, sizeof(art->author) - 1);
} }
cJSON *sentiment_obj = cJSON_GetObjectItemCaseSensitive(article, "sentiment");
if (cJSON_IsObject(sentiment_obj)) {
cJSON *sentiment_type = cJSON_GetObjectItemCaseSensitive(sentiment_obj, "sentiment");
cJSON *sentiment_score = cJSON_GetObjectItemCaseSensitive(sentiment_obj, "score");
if (cJSON_IsString(sentiment_type) && sentiment_type->valuestring) {
if (strcasecmp(sentiment_type->valuestring, "Positive") == 0) {
art->sentiment = SENTIMENT_POSITIVE;
} else if (strcasecmp(sentiment_type->valuestring, "Negative") == 0) {
art->sentiment = SENTIMENT_NEGATIVE;
} else {
art->sentiment = SENTIMENT_NEUTRAL;
}
}
if (cJSON_IsNumber(sentiment_score)) {
art->sentiment_score = (float)sentiment_score->valuedouble;
}
}
count++; count++;
} }
@@ -630,9 +667,12 @@ void news_render(Panel *panel, int x, int max_width, int *used_width)
char display_text[2048]; char display_text[2048];
get_article_display_text(current_article, display_text, sizeof(display_text)); get_article_display_text(current_article, display_text, sizeof(display_text));
unsigned long article_color = news_sentiment_color(
news_state.articles[current_article].sentiment);
if (draw_x + news_state.display_widths[current_article] > x) { if (draw_x + news_state.display_widths[current_article] > x) {
news_draw_text_clipped(panel->buffer, draw_x, text_y, display_text, news_draw_text_clipped(panel->buffer, draw_x, text_y, display_text,
colors->panel_fg, &clip_rect); article_color, &clip_rect);
} }
draw_x += news_state.display_widths[current_article]; draw_x += news_state.display_widths[current_article];
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* D-Bus Notification daemon implementation * D-Bus Notification daemon implementation
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Panel system implementation * Panel system implementation
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* System tray widgets implementation with UTF-8 support * System tray widgets implementation with UTF-8 support
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Utility functions implementation * Utility functions implementation
*/ */
+1
View File
@@ -1,5 +1,6 @@
/* /*
* DWN - Desktop Window Manager * DWN - Desktop Window Manager
* retoor <retoor@molodetz.nl>
* Workspace management implementation * Workspace management implementation
*/ */