From 787416e6a3cead68472619a42385c58b23b51d81 Mon Sep 17 00:00:00 2001 From: Rick Console Date: Thu, 5 Jun 2025 19:10:15 -0400 Subject: added monitor switching --- README.md | 3 +++ default_sxwmrc | 4 ++++ src/config.h | 5 +++- src/defs.h | 2 ++ src/sxwm.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a08fac6..08d0aea 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,8 @@ workspace : modifier + modifier + ... + key : swap n | `decrease_gaps` | Shrinks gaps. | | `focus_next` | Moves focus forward in the stack. | | `focus_previous` | Moves focus backward in the stack. | +| `focus_next_monitor` | Switches focus to the next monitor. | +| `focus_prev_monitor` | Switches focus to the previous monitor. | | `increase_gaps` | Expands gaps. | | `master_next` | Moves focused window down in master/stack order. | | `master_prev` | Moves focused window up in master/stack order. | @@ -147,6 +149,7 @@ workspace : mod + shift + 5 : swap 5 | `MOD` + Left Mouse | Move window by mouse | | `MOD` + Right Mouse | Resize window by mouse | | `MOD` + `j` / `k` | Focus next / previous | +| `MOD` + `,` / `.` | Focus prev / next monitor | | `MOD` + `Shift` + `j` / `k` | Move in master stack | | `MOD` + `Space` | Toggle floating | | `MOD` + `Shift` + `Space` | Toggle all floating | diff --git a/default_sxwmrc b/default_sxwmrc index 6efede7..09aa36f 100644 --- a/default_sxwmrc +++ b/default_sxwmrc @@ -34,6 +34,10 @@ call : mod + shift + e : quit call : mod + j : focus_next call : mod + k : focus_prev +# Monitor Focus: +call : mod + comma : focus_prev_monitor +call : mod + period : focus_next_monitor + # Master/Stack Movement call : mod + shift + j : master_next call : mod + shift + k : master_previous diff --git a/src/config.h b/src/config.h index 7c42764..b67b771 100644 --- a/src/config.h +++ b/src/config.h @@ -13,6 +13,9 @@ const Binding binds[] = { {Mod4Mask, XK_j, {.fn = focus_next}, TYPE_FUNC}, {Mod4Mask, XK_k, {.fn = focus_prev}, TYPE_FUNC}, + {Mod4Mask, XK_comma, {.fn = focus_prev_monitor}, TYPE_FUNC}, + {Mod4Mask, XK_period, {.fn = focus_next_monitor}, TYPE_FUNC}, + {Mod4Mask | ShiftMask, XK_j, {.fn = move_master_next}, TYPE_FUNC}, {Mod4Mask | ShiftMask, XK_k, {.fn = move_master_prev}, TYPE_FUNC}, @@ -53,4 +56,4 @@ const Binding binds[] = { {Mod4Mask | ShiftMask, XK_8, {.ws = 7}, TYPE_MWKSP}, {Mod4Mask, XK_9, {.ws = 8}, TYPE_CWKSP}, {Mod4Mask | ShiftMask, XK_9, {.ws = 8}, TYPE_MWKSP}, -}; \ No newline at end of file +}; diff --git a/src/defs.h b/src/defs.h index 53c7c6a..9bba4be 100644 --- a/src/defs.h +++ b/src/defs.h @@ -107,6 +107,8 @@ extern void close_focused(void); extern void dec_gaps(void); extern void focus_next(void); extern void focus_prev(void); +extern void focus_next_monitor(void); +extern void focus_prev_monitor(void); extern void inc_gaps(void); extern void move_master_next(void); extern void move_master_prev(void); diff --git a/src/sxwm.c b/src/sxwm.c index bc6f922..63c0a24 100644 --- a/src/sxwm.c +++ b/src/sxwm.c @@ -343,6 +343,78 @@ void focus_prev(void) update_borders(); } +void focus_next_monitor(void) +{ + if (monsn <= 1) { + return; /* only one monitor, nothing to switch to */ + } + + int current_mon = focused ? focused->mon : 0; + int target_mon = (current_mon + 1) % monsn; + + /* find the first window on the target monitor in current workspace */ + Client *target_client = NULL; + for (Client *c = workspaces[current_ws]; c; c = c->next) { + if (c->mon == target_mon && c->mapped && !c->fullscreen) { + target_client = c; + break; + } + } + + if (target_client) { + /* focus the window on target monitor */ + focused = target_client; + XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime); + XRaiseWindow(dpy, focused->win); + if (user_config.warp_cursor) { + warp_cursor(focused); + } + update_borders(); + } else { + /* no windows on target monitor, just move cursor to center */ + int center_x = mons[target_mon].x + mons[target_mon].w / 2; + int center_y = mons[target_mon].y + mons[target_mon].h / 2; + XWarpPointer(dpy, None, root, 0, 0, 0, 0, center_x, center_y); + XSync(dpy, False); + } +} + +void focus_prev_monitor(void) +{ + if (monsn <= 1) { + return; /* only one monitor, nothing to switch to */ + } + + int current_mon = focused ? focused->mon : 0; + int target_mon = (current_mon - 1 + monsn) % monsn; + + /* find the first window on the target monitor in current workspace */ + Client *target_client = NULL; + for (Client *c = workspaces[current_ws]; c; c = c->next) { + if (c->mon == target_mon && c->mapped && !c->fullscreen) { + target_client = c; + break; + } + } + + if (target_client) { + /* focus the window on target monitor */ + focused = target_client; + XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime); + XRaiseWindow(dpy, focused->win); + if (user_config.warp_cursor) { + warp_cursor(focused); + } + update_borders(); + } else { + /* no windows on target monitor, just move cursor to center */ + int center_x = mons[target_mon].x + mons[target_mon].w / 2; + int center_y = mons[target_mon].y + mons[target_mon].h / 2; + XWarpPointer(dpy, None, root, 0, 0, 0, 0, center_x, center_y); + XSync(dpy, False); + } +} + int get_monitor_for(Client *c) { int cx = c->x + c->w / 2, cy = c->y + c->h / 2; -- cgit v1.2.3 From 08c1543e60d82ca2bff0b3b1027c546ddff07ca3 Mon Sep 17 00:00:00 2001 From: Rick Console Date: Thu, 5 Jun 2025 19:52:23 -0400 Subject: add monitor switching with shortened config names --- README.md | 7 ++-- default_sxwmrc | 8 +++-- src/config.h | 6 ++-- src/defs.h | 6 ++-- src/sxwm.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 120 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 08d0aea..37d6b10 100644 --- a/README.md +++ b/README.md @@ -110,8 +110,10 @@ workspace : modifier + modifier + ... + key : swap n | `decrease_gaps` | Shrinks gaps. | | `focus_next` | Moves focus forward in the stack. | | `focus_previous` | Moves focus backward in the stack. | -| `focus_next_monitor` | Switches focus to the next monitor. | -| `focus_prev_monitor` | Switches focus to the previous monitor. | +| `focus_next_mon` | Switches focus to the next monitor. | +| `focus_prev_mon` | Switches focus to the previous monitor. | +| `move_next_mon` | Moves the focused window to the next monitor. | +| `move_prev_mon` | Moves the focused window to the previous monitor. | | `increase_gaps` | Expands gaps. | | `master_next` | Moves focused window down in master/stack order. | | `master_prev` | Moves focused window up in master/stack order. | @@ -150,6 +152,7 @@ workspace : mod + shift + 5 : swap 5 | `MOD` + Right Mouse | Resize window by mouse | | `MOD` + `j` / `k` | Focus next / previous | | `MOD` + `,` / `.` | Focus prev / next monitor | +| `MOD` + `Shift` + `,` / `.` | Move window to prev / next monitor | | `MOD` + `Shift` + `j` / `k` | Move in master stack | | `MOD` + `Space` | Toggle floating | | `MOD` + `Shift` + `Space` | Toggle all floating | diff --git a/default_sxwmrc b/default_sxwmrc index 09aa36f..89cf67d 100644 --- a/default_sxwmrc +++ b/default_sxwmrc @@ -35,8 +35,12 @@ call : mod + j : focus_next call : mod + k : focus_prev # Monitor Focus: -call : mod + comma : focus_prev_monitor -call : mod + period : focus_next_monitor +call : mod + comma : focus_prev_mon +call : mod + period : focus_next_mon + +# Move Window Between Monitors: +call : mod + shift + comma : swap_prev_mon +call : mod + shift + period : swap_next_mon # Master/Stack Movement call : mod + shift + j : master_next diff --git a/src/config.h b/src/config.h index b67b771..3c0f0bc 100644 --- a/src/config.h +++ b/src/config.h @@ -13,8 +13,10 @@ const Binding binds[] = { {Mod4Mask, XK_j, {.fn = focus_next}, TYPE_FUNC}, {Mod4Mask, XK_k, {.fn = focus_prev}, TYPE_FUNC}, - {Mod4Mask, XK_comma, {.fn = focus_prev_monitor}, TYPE_FUNC}, - {Mod4Mask, XK_period, {.fn = focus_next_monitor}, TYPE_FUNC}, + {Mod4Mask, XK_comma, {.fn = focus_prev_mon}, TYPE_FUNC}, + {Mod4Mask, XK_period, {.fn = focus_next_mon}, TYPE_FUNC}, + {Mod4Mask | ShiftMask, XK_comma, {.fn = move_prev_mon}, TYPE_FUNC}, + {Mod4Mask | ShiftMask, XK_period, {.fn = move_next_mon}, TYPE_FUNC}, {Mod4Mask | ShiftMask, XK_j, {.fn = move_master_next}, TYPE_FUNC}, {Mod4Mask | ShiftMask, XK_k, {.fn = move_master_prev}, TYPE_FUNC}, diff --git a/src/defs.h b/src/defs.h index 9bba4be..74af271 100644 --- a/src/defs.h +++ b/src/defs.h @@ -107,8 +107,10 @@ extern void close_focused(void); extern void dec_gaps(void); extern void focus_next(void); extern void focus_prev(void); -extern void focus_next_monitor(void); -extern void focus_prev_monitor(void); +extern void focus_next_mon(void); +extern void focus_prev_mon(void); +extern void move_next_mon(void); +extern void move_prev_mon(void); extern void inc_gaps(void); extern void move_master_next(void); extern void move_master_prev(void); diff --git a/src/sxwm.c b/src/sxwm.c index 63c0a24..c76a6c5 100644 --- a/src/sxwm.c +++ b/src/sxwm.c @@ -122,6 +122,7 @@ Window root; Window wm_check_win; Monitor *mons = NULL; int monsn = 0; +int current_monitor = 0; Bool global_floating = False; Bool in_ws_switch = False; Bool running = False; @@ -305,6 +306,7 @@ void focus_next(void) } focused = (focused->next ? focused->next : workspaces[current_ws]); + current_monitor = focused->mon; XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime); XRaiseWindow(dpy, focused->win); if (user_config.warp_cursor) { @@ -335,6 +337,7 @@ void focus_prev(void) focused = prev; } + current_monitor = focused->mon; XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime); XRaiseWindow(dpy, focused->win); if (user_config.warp_cursor) { @@ -343,13 +346,14 @@ void focus_prev(void) update_borders(); } -void focus_next_monitor(void) +void focus_next_mon(void) { if (monsn <= 1) { return; /* only one monitor, nothing to switch to */ } - int current_mon = focused ? focused->mon : 0; + /* use current_monitor if no focused window, otherwise use focused window's monitor */ + int current_mon = focused ? focused->mon : current_monitor; int target_mon = (current_mon + 1) % monsn; /* find the first window on the target monitor in current workspace */ @@ -364,14 +368,17 @@ void focus_next_monitor(void) if (target_client) { /* focus the window on target monitor */ focused = target_client; + current_monitor = target_mon; XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime); XRaiseWindow(dpy, focused->win); if (user_config.warp_cursor) { warp_cursor(focused); } update_borders(); - } else { - /* no windows on target monitor, just move cursor to center */ + } + else { + /* no windows on target monitor, just move cursor to center and update current_monitor */ + current_monitor = target_mon; int center_x = mons[target_mon].x + mons[target_mon].w / 2; int center_y = mons[target_mon].y + mons[target_mon].h / 2; XWarpPointer(dpy, None, root, 0, 0, 0, 0, center_x, center_y); @@ -379,13 +386,14 @@ void focus_next_monitor(void) } } -void focus_prev_monitor(void) +void focus_prev_mon(void) { if (monsn <= 1) { return; /* only one monitor, nothing to switch to */ } - int current_mon = focused ? focused->mon : 0; + /* use current_monitor if no focused window, otherwise use focused window's monitor */ + int current_mon = focused ? focused->mon : current_monitor; int target_mon = (current_mon - 1 + monsn) % monsn; /* find the first window on the target monitor in current workspace */ @@ -400,14 +408,17 @@ void focus_prev_monitor(void) if (target_client) { /* focus the window on target monitor */ focused = target_client; + current_monitor = target_mon; XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime); XRaiseWindow(dpy, focused->win); if (user_config.warp_cursor) { warp_cursor(focused); } update_borders(); - } else { - /* no windows on target monitor, just move cursor to center */ + } + else { + /* no windows on target monitor, just move cursor to center and update current_monitor */ + current_monitor = target_mon; int center_x = mons[target_mon].x + mons[target_mon].w / 2; int center_y = mons[target_mon].y + mons[target_mon].h / 2; XWarpPointer(dpy, None, root, 0, 0, 0, 0, center_x, center_y); @@ -415,6 +426,88 @@ void focus_prev_monitor(void) } } +void move_next_mon(void) +{ + if (!focused || monsn <= 1) { + return; /* no focused window or only one monitor */ + } + + int target_mon = (focused->mon + 1) % monsn; + + /* update window's monitor assignment */ + focused->mon = target_mon; + current_monitor = target_mon; + + /* if window is floating, center it on the target monitor */ + if (focused->floating) { + int mx = mons[target_mon].x, my = mons[target_mon].y; + int mw = mons[target_mon].w, mh = mons[target_mon].h; + int x = mx + (mw - focused->w) / 2; + int y = my + (mh - focused->h) / 2; + + /* ensure window stays within monitor bounds */ + if (x < mx) x = mx; + if (y < my) y = my; + if (x + focused->w > mx + mw) x = mx + mw - focused->w; + if (y + focused->h > my + mh) y = my + mh - focused->h; + + focused->x = x; + focused->y = y; + XMoveWindow(dpy, focused->win, x, y); + } + + /* retile to update layouts on both monitors */ + tile(); + + /* follow the window with cursor if enabled */ + if (user_config.warp_cursor) { + warp_cursor(focused); + } + + update_borders(); +} + +void move_prev_mon(void) +{ + if (!focused || monsn <= 1) { + return; /* no focused window or only one monitor */ + } + + int target_mon = (focused->mon - 1 + monsn) % monsn; + + /* update window's monitor assignment */ + focused->mon = target_mon; + current_monitor = target_mon; + + /* if window is floating, center it on the target monitor */ + if (focused->floating) { + int mx = mons[target_mon].x, my = mons[target_mon].y; + int mw = mons[target_mon].w, mh = mons[target_mon].h; + int x = mx + (mw - focused->w) / 2; + int y = my + (mh - focused->h) / 2; + + /* ensure window stays within monitor bounds */ + if (x < mx) x = mx; + if (y < my) y = my; + if (x + focused->w > mx + mw) x = mx + mw - focused->w; + if (y + focused->h > my + mh) y = my + mh - focused->h; + + focused->x = x; + focused->y = y; + XMoveWindow(dpy, focused->win, x, y); + } + + /* retile to update layouts on both monitors */ + tile(); + + /* follow the window with cursor if enabled */ + if (user_config.warp_cursor) { + warp_cursor(focused); + } + + update_borders(); +} + int get_monitor_for(Client *c) { int cx = c->x + c->w / 2, cy = c->y + c->h / 2; -- cgit v1.2.3