Add hot corners, media keys, orionshot, orionclip, notification history, autostart, GTK accent update, wallpaper slideshow, ISO build
- wm: hot corner polling via select()-based wm_run loop; TL=Exposé, TR=show desktop, BL=launcher, BR=lock - wm: XF86 media key grabs (volume, brightness, playback) + Super+V for clipboard - wm: autostart reads ~/.config/orionos/autostart on startup - events: media key dispatch (amixer/brightnessctl/playerctl); Super+V → orionclip --show; Print → orionshot - orionshot: new X11 screenshot tool, full-screen and rubber-band region modes, saves PNG to ~/Pictures/Screenshots/ - orionclip: new clipboard manager daemon; polls clipboard, stores 20 entries, popup via Super+V IPC - orionnotify: append-only notification history log at ~/.local/share/orionos/notif-history.log - themes: GTK accent updated from #3A6898 to #1E58A8 to match WM/deskbar - themes: orionwallpaper gains --slideshow DIR [SECS] mode using feh + sleep loop - iso: Docker-based archiso builder, live-session xinitrc, profiledef.sh - Makefile: add orionshot and orionclip to all/clean/install; Docker-based iso target
This commit is contained in:
15 files changed
+957
-84
No files matched your search
@@ -5,12 +5,15 @@
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/XF86keysym.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
#include <X11/cursorfont.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* ── palette (macOS dark mode) ───────────────────────────────────────── */
|
||||
#define COLOR_TITLE_ACTIVE 0x3C3C3C /* macOS dark titlebar */
|
||||
@@ -113,6 +116,7 @@ typedef struct WM {
|
||||
Client *focused;
|
||||
|
||||
int cur_desktop; /* active virtual desktop (0-based) */
|
||||
int hot_corner_last; /* last hot-corner zone (0=none,1-4) */
|
||||
|
||||
Atom wm_delete_window;
|
||||
Atom wm_protocols;
|
||||
|
||||
+36
-5
@@ -392,16 +392,47 @@ void on_key_press(WM *wm, XKeyEvent *e) {
|
||||
if ((e->state & Mod1Mask) && sym == XK_F1)
|
||||
system("orionlauncher &");
|
||||
|
||||
/* PrintScreen — full screenshot to ~/Pictures */
|
||||
/* PrintScreen — screenshot */
|
||||
if (sym == XK_Print) {
|
||||
if (e->state & ShiftMask)
|
||||
system("mkdir -p ~/Pictures && scrot -s ~/Pictures/screenshot_%Y%m%d_%H%M%S.png"
|
||||
" && notify-send 'Screenshot' 'Region saved to ~/Pictures' &");
|
||||
system("orionshot region &");
|
||||
else
|
||||
system("mkdir -p ~/Pictures && scrot ~/Pictures/screenshot_%Y%m%d_%H%M%S.png"
|
||||
" && notify-send 'Screenshot' 'Saved to ~/Pictures' &");
|
||||
system("orionshot full &");
|
||||
}
|
||||
|
||||
/* XF86 media keys */
|
||||
if (sym == XF86XK_AudioRaiseVolume)
|
||||
system("pactl set-sink-volume @DEFAULT_SINK@ +5% 2>/dev/null; "
|
||||
"pactl get-sink-volume @DEFAULT_SINK@ 2>/dev/null | "
|
||||
"grep -oP '[0-9]+%' | head -1 | "
|
||||
"xargs -I{} notify-send -t 1500 'Volume' '{}' 2>/dev/null &");
|
||||
if (sym == XF86XK_AudioLowerVolume)
|
||||
system("pactl set-sink-volume @DEFAULT_SINK@ -5% 2>/dev/null; "
|
||||
"pactl get-sink-volume @DEFAULT_SINK@ 2>/dev/null | "
|
||||
"grep -oP '[0-9]+%' | head -1 | "
|
||||
"xargs -I{} notify-send -t 1500 'Volume' '{}' 2>/dev/null &");
|
||||
if (sym == XF86XK_AudioMute)
|
||||
system("pactl set-sink-mute @DEFAULT_SINK@ toggle 2>/dev/null; "
|
||||
"notify-send -t 1500 'Volume' 'Muted toggled' 2>/dev/null &");
|
||||
if (sym == XF86XK_AudioPlay)
|
||||
system("playerctl play-pause 2>/dev/null &");
|
||||
if (sym == XF86XK_AudioNext)
|
||||
system("playerctl next 2>/dev/null &");
|
||||
if (sym == XF86XK_AudioPrev)
|
||||
system("playerctl previous 2>/dev/null &");
|
||||
if (sym == XF86XK_MonBrightnessUp)
|
||||
system("brightnessctl set +10% 2>/dev/null; "
|
||||
"notify-send -t 1200 'Brightness' "
|
||||
"\"$(brightnessctl g 2>/dev/null)\" 2>/dev/null &");
|
||||
if (sym == XF86XK_MonBrightnessDown)
|
||||
system("brightnessctl set 10%- 2>/dev/null; "
|
||||
"notify-send -t 1200 'Brightness' "
|
||||
"\"$(brightnessctl g 2>/dev/null)\" 2>/dev/null &");
|
||||
|
||||
/* Super+V — clipboard manager */
|
||||
if ((e->state & Mod4Mask) && sym == XK_v)
|
||||
system("orionclip --show &");
|
||||
|
||||
/* Super+Left — snap left */
|
||||
if ((e->state & Mod4Mask) && sym == XK_Left && wm->focused)
|
||||
client_snap_left(wm, wm->focused);
|
||||
|
||||
+105
-16
@@ -1,5 +1,67 @@
|
||||
#include "wm.h"
|
||||
|
||||
/* ── autostart ───────────────────────────────────────────────────── */
|
||||
static void wm_run_autostart(void) {
|
||||
const char *home = getenv("HOME");
|
||||
if (!home) return;
|
||||
char path[512];
|
||||
snprintf(path, sizeof(path), "%s/.config/orionos/autostart", home);
|
||||
FILE *f = fopen(path, "r");
|
||||
if (!f) return;
|
||||
char line[512];
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
size_t len = strlen(line);
|
||||
while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r' ||
|
||||
line[len-1] == ' ' || line[len-1] == '\t'))
|
||||
line[--len] = '\0';
|
||||
if (len == 0 || line[0] == '#') continue;
|
||||
char cmd[560];
|
||||
snprintf(cmd, sizeof(cmd), "%s &", line);
|
||||
system(cmd);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/* ── hot corners ─────────────────────────────────────────────────── */
|
||||
static void hot_corner_check(WM *wm) {
|
||||
Window root_ret, child;
|
||||
int root_x, root_y, win_x, win_y;
|
||||
unsigned int mask;
|
||||
XQueryPointer(wm->dpy, wm->root, &root_ret, &child,
|
||||
&root_x, &root_y, &win_x, &win_y, &mask);
|
||||
|
||||
int sw = DisplayWidth(wm->dpy, wm->screen);
|
||||
int sh = DisplayHeight(wm->dpy, wm->screen);
|
||||
|
||||
int corner = 0;
|
||||
if (root_x <= 1 && root_y <= 1) corner = 1; /* TL: Exposé */
|
||||
else if (root_x >= sw - DESKBAR_W - 2 && root_y <= 1) corner = 2; /* TR: show desktop */
|
||||
else if (root_x <= 1 && root_y >= sh - 2) corner = 3; /* BL: launcher */
|
||||
else if (root_x >= sw - DESKBAR_W - 2 && root_y >= sh - 2) corner = 4; /* BR: lock */
|
||||
|
||||
if (corner == wm->hot_corner_last) return;
|
||||
wm->hot_corner_last = corner;
|
||||
if (corner == 0) return; /* just left a corner, no action needed */
|
||||
|
||||
switch (corner) {
|
||||
case 1: /* top-left → Exposé */
|
||||
if (!wm->expose_active) expose_show(wm);
|
||||
break;
|
||||
case 2: /* top-right → show desktop (minimize all on current desktop) */
|
||||
if (wm->expose_active) { expose_hide(wm, None); break; }
|
||||
for (Client *c = wm->clients; c; c = c->next)
|
||||
if (!c->minimized && c->desktop == wm->cur_desktop)
|
||||
client_minimize(wm, c);
|
||||
break;
|
||||
case 3: /* bottom-left → launcher */
|
||||
system("orionlauncher &");
|
||||
break;
|
||||
case 4: /* bottom-right → lock screen */
|
||||
system("orionlock &");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int x_error_handler(Display *dpy, XErrorEvent *e) {
|
||||
if (e->error_code == BadWindow || e->error_code == BadAccess)
|
||||
return 0;
|
||||
@@ -115,6 +177,17 @@ void wm_init(WM *wm) {
|
||||
{ XK_3, Mod4Mask | ShiftMask },
|
||||
{ XK_4, Mod4Mask | ShiftMask },
|
||||
{ XK_Escape, 0 },
|
||||
/* XF86 media keys */
|
||||
{ XF86XK_AudioRaiseVolume, 0 },
|
||||
{ XF86XK_AudioLowerVolume, 0 },
|
||||
{ XF86XK_AudioMute, 0 },
|
||||
{ XF86XK_AudioPlay, 0 },
|
||||
{ XF86XK_AudioNext, 0 },
|
||||
{ XF86XK_AudioPrev, 0 },
|
||||
{ XF86XK_MonBrightnessUp, 0 },
|
||||
{ XF86XK_MonBrightnessDown, 0 },
|
||||
/* Super+V: clipboard manager */
|
||||
{ XK_v, Mod4Mask },
|
||||
};
|
||||
for (int i = 0; i < (int)(sizeof(grabs)/sizeof(grabs[0])); i++) {
|
||||
KeyCode kc = XKeysymToKeycode(wm->dpy, grabs[i].sym);
|
||||
@@ -138,28 +211,44 @@ void wm_init(WM *wm) {
|
||||
|
||||
XSync(wm->dpy, False);
|
||||
fprintf(stderr, "orionwm: started\n");
|
||||
|
||||
wm_run_autostart();
|
||||
}
|
||||
|
||||
void wm_run(WM *wm) {
|
||||
int xfd = ConnectionNumber(wm->dpy);
|
||||
XEvent e;
|
||||
|
||||
for (;;) {
|
||||
XNextEvent(wm->dpy, &e);
|
||||
switch (e.type) {
|
||||
case MapRequest: on_map_request(wm, &e.xmaprequest); break;
|
||||
case UnmapNotify: on_unmap_notify(wm, &e.xunmap); break;
|
||||
case DestroyNotify: on_destroy_notify(wm, &e.xdestroywindow); break;
|
||||
case ConfigureRequest: on_configure_request(wm, &e.xconfigurerequest); break;
|
||||
case Expose: on_expose(wm, &e.xexpose); break;
|
||||
case ButtonPress: on_button_press(wm, &e.xbutton); break;
|
||||
case ButtonRelease: on_button_release(wm, &e.xbutton); break;
|
||||
case MotionNotify: on_motion_notify(wm, &e.xmotion); break;
|
||||
case KeyPress: on_key_press(wm, &e.xkey); break;
|
||||
case KeyRelease: on_key_release(wm, &e.xkey); break;
|
||||
case EnterNotify: on_enter_notify(wm, &e.xcrossing); break;
|
||||
case ClientMessage: on_client_message(wm, &e.xclient); break;
|
||||
case PropertyNotify: on_property_notify(wm, &e.xproperty); break;
|
||||
default: break;
|
||||
/* drain all pending X events */
|
||||
while (XPending(wm->dpy)) {
|
||||
XNextEvent(wm->dpy, &e);
|
||||
switch (e.type) {
|
||||
case MapRequest: on_map_request(wm, &e.xmaprequest); break;
|
||||
case UnmapNotify: on_unmap_notify(wm, &e.xunmap); break;
|
||||
case DestroyNotify: on_destroy_notify(wm, &e.xdestroywindow); break;
|
||||
case ConfigureRequest: on_configure_request(wm, &e.xconfigurerequest); break;
|
||||
case Expose: on_expose(wm, &e.xexpose); break;
|
||||
case ButtonPress: on_button_press(wm, &e.xbutton); break;
|
||||
case ButtonRelease: on_button_release(wm, &e.xbutton); break;
|
||||
case MotionNotify: on_motion_notify(wm, &e.xmotion); break;
|
||||
case KeyPress: on_key_press(wm, &e.xkey); break;
|
||||
case KeyRelease: on_key_release(wm, &e.xkey); break;
|
||||
case EnterNotify: on_enter_notify(wm, &e.xcrossing); break;
|
||||
case ClientMessage: on_client_message(wm, &e.xclient); break;
|
||||
case PropertyNotify: on_property_notify(wm, &e.xproperty); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/* poll hot corners every 200ms */
|
||||
hot_corner_check(wm);
|
||||
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(xfd, &fds);
|
||||
struct timeval tv = { 0, 200000 };
|
||||
select(xfd + 1, &fds, NULL, NULL, &tv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user