summaryrefslogtreecommitdiff
path: root/src/sxwm.c
diff options
context:
space:
mode:
authorAbhinav Prasai <abhinav.prsai@gmail.com>2025-08-27 16:01:15 +0100
committerAbhinav Prasai <abhinav.prsai@gmail.com>2025-08-28 09:54:09 +0100
commitcf361ebd2a95ad5f62249c37223b59dc0c3e12c7 (patch)
tree0f3201bac15edf558f071d9d5292e1f1bb60ce60 /src/sxwm.c
parent1dee8f0617691db0caccec64f2b94b967de9d0da (diff)
new helper set_input_focus + better handling of eg. dialogue boxes
Diffstat (limited to 'src/sxwm.c')
-rw-r--r--src/sxwm.c261
1 files changed, 144 insertions, 117 deletions
diff --git a/src/sxwm.c b/src/sxwm.c
index 0c66c1d..1dca057 100644
--- a/src/sxwm.c
+++ b/src/sxwm.c
@@ -16,13 +16,7 @@
#include <X11/X.h>
#include <err.h>
#include <stdio.h>
-
-#ifdef __linux__
-#include <linux/limits.h>
-#else
#include <limits.h>
-#endif
-
#include <signal.h>
#include <stdlib.h>
#include <string.h>
@@ -39,6 +33,10 @@
#include <X11/extensions/Xinerama.h>
#include <X11/Xcursor/Xcursor.h>
+#ifdef __linux__
+#include <linux/limits.h>
+#endif
+
#include "defs.h"
#include "parser.h"
@@ -48,6 +46,7 @@ void change_workspace(int ws);
int clean_mask(int mask);
/* void close_focused(void); */
/* void dec_gaps(void); */
+Client *find_client(Window w);
Window find_toplevel(Window w);
/* void focus_next(void); */
/* void focus_prev(void); */
@@ -95,6 +94,7 @@ void send_wm_take_focus(Window w);
void setup(void);
void setup_atoms(void);
void set_frame_extents(Window w);
+void set_input_focus(Client *c, Bool raise_win, Bool warp);
void set_win_scratchpad(int n);
int snap_coordinate(int pos, int size, int screen_size, int snap_dist);
void spawn(const char **argv);
@@ -146,6 +146,12 @@ Atom _NET_WM_WINDOW_TYPE_DIALOG;
Atom _NET_WM_WINDOW_TYPE_TOOLBAR;
Atom _NET_WM_WINDOW_TYPE_SPLASH;
Atom _NET_WM_WINDOW_TYPE_POPUP_MENU;
+Atom _NET_WM_WINDOW_TYPE_MENU;
+Atom _NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
+Atom _NET_WM_WINDOW_TYPE_TOOLTIP;
+Atom _NET_WM_WINDOW_TYPE_NOTIFICATION;
+Atom _NET_WM_STATE_MODAL;
+
Cursor cursor_normal;
Cursor cursor_move;
@@ -399,18 +405,7 @@ void change_workspace(int ws)
current_mon = c->mon;
}
}
-
- if (focused) {
- focused->win = find_toplevel(focused->win);
- XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime);
- if (user_config.warp_cursor) {
- warp_cursor(focused);
- }
- update_borders();
- }
- else {
- XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
- }
+ set_input_focus(focused, False, True);
long current_desktop = current_ws;
XChangeProperty(dpy, root, _NET_CURRENT_DESKTOP, XA_CARDINAL, 32,
@@ -477,6 +472,18 @@ void dec_gaps(void)
}
}
+Client *find_client(Window w)
+{
+ for (int ws = 0; ws < NUM_WORKSPACES; ws++) {
+ for (Client *c = workspaces[ws]; c; c = c->next) {
+ if (c->win == w) {
+ return c;
+ }
+ }
+ }
+ return NULL;
+}
+
Window find_toplevel(Window w)
{
Window root = None;
@@ -521,12 +528,7 @@ void focus_next(void)
focused = c;
current_mon = c->mon;
- XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
- XRaiseWindow(dpy, c->win);
- if (user_config.warp_cursor) {
- warp_cursor(c);
- }
- update_borders();
+ set_input_focus(focused, True, True);
}
void focus_prev(void)
@@ -566,13 +568,7 @@ void focus_prev(void)
focused = c;
current_mon = c->mon;
-
- XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
- XRaiseWindow(dpy, c->win);
- if (user_config.warp_cursor) {
- warp_cursor(c);
- }
- update_borders();
+ set_input_focus(focused, True, True);
}
void focus_next_mon(void)
@@ -595,12 +591,7 @@ void focus_next_mon(void)
/* focus the window on target monitor */
focused = target_client;
current_mon = target_mon;
- XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime);
- XRaiseWindow(dpy, focused->win);
- if (user_config.warp_cursor) {
- warp_cursor(focused);
- }
- update_borders();
+ set_input_focus(focused, True, True);
}
else {
/* no windows on target monitor, just move cursor to center and update current_mon */
@@ -632,12 +623,7 @@ void focus_prev_mon(void)
/* focus the window on target monitor */
focused = target_client;
current_mon = target_mon;
- XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime);
- XRaiseWindow(dpy, focused->win);
- if (user_config.warp_cursor) {
- warp_cursor(focused);
- }
- update_borders();
+ set_input_focus(focused, True, True);
}
else {
current_mon = target_mon;
@@ -778,8 +764,7 @@ void hdl_button(XEvent *xev)
Bool is_swap_mode =
(xbutton->state & user_config.modkey) &&
(xbutton->state & ShiftMask) &&
- xbutton->button == left_click &&
- !c->floating;
+ xbutton->button == left_click && !c->floating;
if (is_swap_mode) {
drag_client = c;
drag_start_x = xbutton->x_root;
@@ -792,16 +777,15 @@ void hdl_button(XEvent *xev)
XGrabPointer(dpy, root, True, ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync, None, cursor_move, CurrentTime);
focused = c;
- XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
+ set_input_focus(focused, False, False);
XSetWindowBorder(dpy, c->win, user_config.border_swap_col);
- XRaiseWindow(dpy, c->win);
return;
}
Bool is_move_resize =
(xbutton->state & user_config.modkey) &&
- (xbutton->button == left_click || xbutton->button == right_click) &&
- !c->floating;
+ (xbutton->button == left_click ||
+ xbutton->button == right_click) && !c->floating;
if (is_move_resize) {
focused = c;
toggle_floating();
@@ -812,10 +796,7 @@ void hdl_button(XEvent *xev)
xbutton->button == left_click;
if (is_single_click) {
focused = c;
- XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
- send_wm_take_focus(c->win);
- XRaiseWindow(dpy, c->win);
- update_borders();
+ set_input_focus(focused, True, False);
return;
}
@@ -827,9 +808,9 @@ void hdl_button(XEvent *xev)
return;
}
- Cursor cur = (xbutton->button == left_click) ? cursor_move : cursor_resize;
+ Cursor cursor = (xbutton->button == left_click) ? cursor_move : cursor_resize;
XGrabPointer(dpy, root, True, ButtonReleaseMask | PointerMotionMask,
- GrabModeAsync, GrabModeAsync, None, cur, CurrentTime);
+ GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
drag_client = c;
drag_start_x = xbutton->x_root;
@@ -841,9 +822,7 @@ void hdl_button(XEvent *xev)
drag_mode = (xbutton->button == left_click) ? DRAG_MOVE : DRAG_RESIZE;
focused = c;
- XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
- update_borders();
- XRaiseWindow(dpy, c->win);
+ set_input_focus(focused, True, False);
return;
}
}
@@ -996,11 +975,7 @@ void hdl_destroy_ntf(XEvent *xev)
update_borders();
if (focused) {
- XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime);
- XRaiseWindow(dpy, focused->win);
- if (user_config.warp_cursor) {
- warp_cursor(focused);
- }
+ set_input_focus(focused, True, True);
}
}
return;
@@ -1070,29 +1045,24 @@ void hdl_map_req(XEvent *xev)
}
/* check if this window is already managed on any workspace */
- for (int ws = 0; ws < NUM_WORKSPACES; ws++) {
- for (Client *c = workspaces[ws]; c; c = c->next) {
- if (c->win == w) {
- if (ws == current_ws) {
- if (!c->mapped) {
- XMapWindow(dpy, w);
- c->mapped = True;
- }
- if (user_config.new_win_focus) {
- focused = c;
- XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
- send_wm_take_focus(c->win);
- if (user_config.warp_cursor) {
- warp_cursor(c);
- }
- }
- update_borders();
- }
- return;
+ Client *c = find_client(w);
+ if (c) {
+ if (c->ws == current_ws) {
+ if (!c->mapped) {
+ XMapWindow(dpy, w);
+ c->mapped = True;
+ }
+ if (user_config.new_win_focus) {
+ focused = c;
+ set_input_focus(c, True, True);
+ return; /* set_input_focus already calls update_borders */
}
+ update_borders();
}
+ return;
}
+
Atom type;
int format;
unsigned long n_items, after;
@@ -1109,11 +1079,16 @@ void hdl_map_req(XEvent *xev)
return;
}
- should_float =
- types[i] == _NET_WM_WINDOW_TYPE_UTILITY || types[i] == _NET_WM_WINDOW_TYPE_DIALOG ||
- types[i] == _NET_WM_WINDOW_TYPE_TOOLBAR || types[i] == _NET_WM_WINDOW_TYPE_SPLASH ||
- types[i] == _NET_WM_WINDOW_TYPE_POPUP_MENU;
- if (should_float) {
+ if (types[i] == _NET_WM_WINDOW_TYPE_UTILITY ||
+ types[i] == _NET_WM_WINDOW_TYPE_DIALOG ||
+ types[i] == _NET_WM_WINDOW_TYPE_TOOLBAR ||
+ types[i] == _NET_WM_WINDOW_TYPE_SPLASH ||
+ types[i] == _NET_WM_WINDOW_TYPE_POPUP_MENU ||
+ types[i] == _NET_WM_WINDOW_TYPE_DROPDOWN_MENU ||
+ types[i] == _NET_WM_WINDOW_TYPE_MENU ||
+ types[i] == _NET_WM_WINDOW_TYPE_TOOLTIP ||
+ types[i] == _NET_WM_WINDOW_TYPE_NOTIFICATION) {
+ should_float = True;
break;
}
}
@@ -1124,13 +1099,32 @@ void hdl_map_req(XEvent *xev)
should_float = window_should_float(w);
}
+ if (!should_float) {
+ Atom state_type;
+ Atom *state_atoms = NULL;
+ int state_format;
+ unsigned long n_items;
+ unsigned long bytes_after;
+
+ if (XGetWindowProperty(dpy, w, _NET_WM_STATE, 0, 8, False, XA_ATOM, &state_type, &state_format,&n_items,
+ &bytes_after, (unsigned char**)&state_atoms) == Success && state_atoms) {
+ for (unsigned long i = 0; i < n_items; i++) {
+ if (state_atoms[i] == _NET_WM_STATE_MODAL) {
+ should_float = True;
+ break;
+ }
+ }
+ XFree(state_atoms);
+ }
+ }
+
if (open_windows == MAX_CLIENTS) {
printf("sxwm: max clients reached, ignoring map request\n");
return;
}
int target_ws = get_workspace_for_window(w);
- Client *c = add_client(w, target_ws);
+ c = add_client(w, target_ws);
if (!c) {
return;
}
@@ -1142,14 +1136,14 @@ void hdl_map_req(XEvent *xev)
XSizeHints size_hints;
long supplied_ret;
- should_float =
- !should_float && XGetWMNormalHints(dpy, w, &size_hints, &supplied_ret) &&
+
+ if (!should_float &&
+ XGetWMNormalHints(dpy, w, &size_hints, &supplied_ret) &&
(size_hints.flags & PMinSize) && (size_hints.flags & PMaxSize) &&
- size_hints.min_width == size_hints.max_width && size_hints.min_height == size_hints.max_height;
+ size_hints.min_width == size_hints.max_width &&
+ size_hints.min_height == size_hints.max_height) {
- if (should_float || global_floating) {
- c->fixed = True;
- c->floating = True;
+ should_float = True;
}
if (window_should_start_fullscreen(w)) {
@@ -1256,11 +1250,8 @@ void hdl_map_req(XEvent *xev)
if (user_config.new_win_focus) {
focused = c;
- XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
- send_wm_take_focus(c->win);
- if (user_config.warp_cursor) {
- warp_cursor(c);
- }
+ set_input_focus(focused, False, True);
+ return;
}
update_borders();
}
@@ -1677,7 +1668,7 @@ void move_to_workspace(int ws)
tile();
focused = workspaces[current_ws];
if (focused) {
- XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime);
+ set_input_focus(focused, False, False);
}
}
@@ -2084,6 +2075,12 @@ void setup_atoms(void)
_NET_WM_WINDOW_TYPE_TOOLBAR = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
_NET_WM_WINDOW_TYPE_SPLASH = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
_NET_WM_WINDOW_TYPE_POPUP_MENU = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False);
+ _NET_WM_WINDOW_TYPE_MENU = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_MENU", False);
+ _NET_WM_WINDOW_TYPE_DROPDOWN_MENU = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False);
+ _NET_WM_WINDOW_TYPE_TOOLTIP = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLTIP", False);
+ _NET_WM_WINDOW_TYPE_NOTIFICATION = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NOTIFICATION", False);
+ _NET_WM_STATE_MODAL = XInternAtom(dpy, "_NET_WM_STATE_MODAL", False);
+
Atom support_list[] = {
_NET_CURRENT_DESKTOP, _NET_ACTIVE_WINDOW, _NET_SUPPORTED, _NET_WM_STATE,
@@ -2093,6 +2090,8 @@ void setup_atoms(void)
_NET_WM_WINDOW_TYPE_DOCK, _NET_WM_WINDOW_TYPE_UTILITY, _NET_WM_WINDOW_TYPE_DIALOG,
_NET_WM_WINDOW_TYPE_TOOLBAR, _NET_WM_WINDOW_TYPE_SPLASH, _NET_WM_WINDOW_TYPE_POPUP_MENU,
+ _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DROPDOWN_MENU, _NET_WM_WINDOW_TYPE_TOOLTIP,
+ _NET_WM_WINDOW_TYPE_NOTIFICATION, _NET_WM_STATE_MODAL,
};
/* workspace setup */
@@ -2127,6 +2126,42 @@ void set_frame_extents(Window w)
XChangeProperty(dpy, w, _NET_FRAME_EXTENTS, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)extents, 4);
}
+
+void set_input_focus(Client *c, Bool raise_win, Bool warp)
+{
+ if (c && c->mapped) {
+ focused = c;
+ current_mon = c->mon;
+ Window w = find_toplevel(c->win);
+
+ XSetInputFocus(dpy, w, RevertToPointerRoot, CurrentTime);
+ send_wm_take_focus(w);
+
+ if (raise_win) {
+ XRaiseWindow(dpy, w);
+ }
+
+ /* EWMH */
+ XChangeProperty(dpy, root, _NET_ACTIVE_WINDOW, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *)&w, 1);
+
+ update_borders();
+
+ if (warp && user_config.warp_cursor) {
+ warp_cursor(c);
+ }
+ } else {
+ /* no client */
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, _NET_ACTIVE_WINDOW);
+
+ focused = NULL;
+ update_borders();
+ }
+
+ XFlush(dpy);
+}
+
void set_win_scratchpad(int n)
{
if (focused == NULL) {
@@ -2537,9 +2572,12 @@ void toggle_floating(void)
focused->w = wa.width;
focused->h = wa.height;
- XConfigureWindow(
- dpy, focused->win, CWX | CWY | CWWidth | CWHeight,
- &(XWindowChanges){.x = focused->x, .y = focused->y, .width = focused->w, .height = focused->h});
+ XConfigureWindow(dpy, focused->win, CWX | CWY | CWWidth | CWHeight, &(XWindowChanges){
+ .x = focused->x,
+ .y = focused->y,
+ .width = focused->w,
+ .height = focused->h
+ });
}
}
else {
@@ -2554,8 +2592,7 @@ void toggle_floating(void)
/* raise and refocus floating window */
if (focused->floating) {
- XRaiseWindow(dpy, focused->win);
- XSetInputFocus(dpy, focused->win, RevertToPointerRoot, CurrentTime);
+ set_input_focus(focused, True, False);
}
}
@@ -2667,23 +2704,14 @@ void toggle_scratchpad(int n)
c->mapped = False;
scratchpads[n].enabled = False;
focus_prev();
- if (focused) {
- send_wm_take_focus(focused->win);
- }
}
else {
XMapWindow(dpy, c->win);
c->mapped = True;
- XRaiseWindow(dpy, c->win);
scratchpads[n].enabled = True;
focused = c;
- XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
- send_wm_take_focus(c->win);
-
- if (user_config.warp_cursor) {
- warp_cursor(focused);
- }
+ set_input_focus(focused, True, True);
}
tile();
@@ -2708,8 +2736,7 @@ void unswallow_window(Client *c)
swallower->mapped = True;
focused = swallower;
- XSetInputFocus(dpy, swallower->win, RevertToPointerRoot, CurrentTime);
- XRaiseWindow(dpy, swallower->win);
+ set_input_focus(focused, False, True);
}
tile();