diff options
Diffstat (limited to 'manager.c')
| -rw-r--r-- | manager.c | 151 |
1 files changed, 59 insertions, 92 deletions
| @@ -37,6 +37,58 @@ static Atom WM_DELETE_WINDOW; | |||
| 37 | static Atom WM_TAKE_FOCUS; | 37 | static Atom WM_TAKE_FOCUS; |
| 38 | static Atom _NET_SUPPORTED; | 38 | static Atom _NET_SUPPORTED; |
| 39 | 39 | ||
| 40 | static void update_window_border(Window window, int active) { | ||
| 41 | if (window == None) return; | ||
| 42 | if (!window_exists(window)) return; | ||
| 43 | |||
| 44 | Atom actual_type; | ||
| 45 | int actual_format; | ||
| 46 | unsigned long nitems, bytes_after; | ||
| 47 | unsigned char *prop = NULL; | ||
| 48 | int has_decorations = 1; | ||
| 49 | |||
| 50 | // Check _MOTIF_WM_HINTS to see if the window requested no decorations | ||
| 51 | XErrorHandler old = XSetErrorHandler(ignore_x_error); | ||
| 52 | int status = XGetWindowProperty(wm.dpy, window, _MOTIF_WM_HINTS, 0, 5, False, AnyPropertyType, | ||
| 53 | &actual_type, &actual_format, &nitems, &bytes_after, &prop); | ||
| 54 | XSync(wm.dpy, False); | ||
| 55 | XSetErrorHandler(old); | ||
| 56 | |||
| 57 | if (status == Success) { | ||
| 58 | if (prop && nitems >= 3) { | ||
| 59 | unsigned long flags = ((unsigned long *)prop)[0]; | ||
| 60 | unsigned long decorations = ((unsigned long *)prop)[2]; | ||
| 61 | // If flags bit 1 is set (MWM_HINTS_DECORATIONS) and decorations bit 0 is cleared (MWM_DECOR_ALL/BORDER), then no border. | ||
| 62 | // Simplification: if decorations is 0, assume no border. | ||
| 63 | if ((flags & 2) && (decorations & 1) == 0) { | ||
| 64 | has_decorations = 0; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | if (prop) XFree(prop); | ||
| 68 | } | ||
| 69 | |||
| 70 | unsigned int bw = has_decorations ? border_size : 0; | ||
| 71 | XSetWindowBorderWidth(wm.dpy, window, bw); | ||
| 72 | |||
| 73 | if (active) { | ||
| 74 | if (is_always_on_top(window)) { | ||
| 75 | XSetWindowBorder(wm.dpy, window, wm.borders.on_top_active); | ||
| 76 | } else if (is_sticky(window)) { | ||
| 77 | XSetWindowBorder(wm.dpy, window, wm.borders.sticky_active); | ||
| 78 | } else { | ||
| 79 | XSetWindowBorder(wm.dpy, window, wm.borders.normal_active); | ||
| 80 | } | ||
| 81 | } else { | ||
| 82 | if (is_always_on_top(window)) { | ||
| 83 | XSetWindowBorder(wm.dpy, window, wm.borders.on_top_inactive); | ||
| 84 | } else if (is_sticky(window)) { | ||
| 85 | XSetWindowBorder(wm.dpy, window, wm.borders.sticky_inactive); | ||
| 86 | } else { | ||
| 87 | XSetWindowBorder(wm.dpy, window, wm.borders.normal_inactive); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 40 | static void update_wm_state(Window w, Atom state_atom, int add); | 92 | static void update_wm_state(Window w, Atom state_atom, int add); |
| 41 | static int has_wm_state(Window w, Atom state_atom); | 93 | static int has_wm_state(Window w, Atom state_atom); |
| 42 | static void check_and_clear_maximized_state(Window w, int horizontal, int vertical); | 94 | static void check_and_clear_maximized_state(Window w, int horizontal, int vertical); |
| @@ -140,15 +192,7 @@ static void scan_windows(void) { | |||
| 140 | add_client(wins[i]); | 192 | add_client(wins[i]); |
| 141 | XSelectInput(wm.dpy, wins[i], EnterWindowMask | LeaveWindowMask); | 193 | XSelectInput(wm.dpy, wins[i], EnterWindowMask | LeaveWindowMask); |
| 142 | grab_buttons(wins[i]); | 194 | grab_buttons(wins[i]); |
| 143 | 195 | update_window_border(wins[i], 0); | |
| 144 | XSetWindowBorderWidth(wm.dpy, wins[i], border_size); | ||
| 145 | if (is_sticky(wins[i])) { | ||
| 146 | XSetWindowBorder(wm.dpy, wins[i], wm.borders.sticky_inactive); | ||
| 147 | } else if (is_always_on_top(wins[i])) { | ||
| 148 | XSetWindowBorder(wm.dpy, wins[i], wm.borders.on_top_inactive); | ||
| 149 | } else { | ||
| 150 | XSetWindowBorder(wm.dpy, wins[i], wm.borders.normal_inactive); | ||
| 151 | } | ||
| 152 | } | 196 | } |
| 153 | } | 197 | } |
| 154 | if (wins) XFree(wins); | 198 | if (wins) XFree(wins); |
| @@ -339,8 +383,6 @@ void init_window_manager(void) { | |||
| 339 | 383 | ||
| 340 | wm.running = 1; | 384 | wm.running = 1; |
| 341 | 385 | ||
| 342 | scan_windows(); | ||
| 343 | |||
| 344 | // Grab keys for keybinds. | 386 | // Grab keys for keybinds. |
| 345 | for (unsigned int i = 0; i < LENGTH(keybinds); i++) { | 387 | for (unsigned int i = 0; i < LENGTH(keybinds); i++) { |
| 346 | KeyCode keycode = XKeysymToKeycode(wm.dpy, keybinds[i].keysym); | 388 | KeyCode keycode = XKeysymToKeycode(wm.dpy, keybinds[i].keysym); |
| @@ -399,24 +441,10 @@ void init_window_manager(void) { | |||
| 399 | wm.borders.on_top_inactive = on_top_inactive.pixel; | 441 | wm.borders.on_top_inactive = on_top_inactive.pixel; |
| 400 | } | 442 | } |
| 401 | 443 | ||
| 402 | // Scan for existing windows. | 444 | // Scan for existing windows and apply initial layout. |
| 403 | unsigned int nchildren; | 445 | scan_windows(); |
| 404 | Window root_return, parent_return, *children; | 446 | apply_tiling_layout(); |
| 405 | XWindowAttributes wa; | ||
| 406 | 447 | ||
| 407 | if (XQueryTree(wm.dpy, wm.root, &root_return, &parent_return, &children, &nchildren)) { | ||
| 408 | for (unsigned int i = 0; i < nchildren; i++) { | ||
| 409 | if (!XGetWindowAttributes(wm.dpy, children[i], &wa) || wa.override_redirect) | ||
| 410 | continue; | ||
| 411 | if (wa.map_state == IsViewable) { | ||
| 412 | grab_buttons(children[i]); | ||
| 413 | XSelectInput(wm.dpy, children[i], EnterWindowMask | LeaveWindowMask); | ||
| 414 | add_client(children[i]); | ||
| 415 | log_message(stdout, LOG_DEBUG, "Grabbed existing window 0x%lx", children[i]); | ||
| 416 | } | ||
| 417 | } | ||
| 418 | if (children) XFree(children); | ||
| 419 | } | ||
| 420 | redraw_widgets(); | 448 | redraw_widgets(); |
| 421 | update_client_list(); | 449 | update_client_list(); |
| 422 | init_audio(); | 450 | init_audio(); |
| @@ -1115,75 +1143,14 @@ void set_active_border(Window window) { | |||
| 1115 | if (window == None) return; | 1143 | if (window == None) return; |
| 1116 | if (!window_exists(window)) return; | 1144 | if (!window_exists(window)) return; |
| 1117 | 1145 | ||
| 1118 | Atom actual_type; | ||
| 1119 | int actual_format; | ||
| 1120 | unsigned long nitems, bytes_after; | ||
| 1121 | unsigned char *prop = NULL; | ||
| 1122 | int has_decorations = 1; | ||
| 1123 | |||
| 1124 | // Check _MOTIF_WM_HINTS to see if the window requested no decorations | ||
| 1125 | XErrorHandler old = XSetErrorHandler(ignore_x_error); | ||
| 1126 | int status = XGetWindowProperty(wm.dpy, window, _MOTIF_WM_HINTS, 0, 5, False, AnyPropertyType, | ||
| 1127 | &actual_type, &actual_format, &nitems, &bytes_after, &prop); | ||
| 1128 | XSync(wm.dpy, False); | ||
| 1129 | XSetErrorHandler(old); | ||
| 1130 | |||
| 1131 | if (status == Success) { | ||
| 1132 | if (prop && nitems >= 3) { | ||
| 1133 | unsigned long flags = ((unsigned long *)prop)[0]; | ||
| 1134 | unsigned long decorations = ((unsigned long *)prop)[2]; | ||
| 1135 | // If flags bit 1 is set (MWM_HINTS_DECORATIONS) and decorations bit 0 is cleared (MWM_DECOR_ALL/BORDER), then no border. | ||
| 1136 | // Simplification: if decorations is 0, assume no border. | ||
| 1137 | if ((flags & 2) && (decorations & 1) == 0) { | ||
| 1138 | has_decorations = 0; | ||
| 1139 | } | ||
| 1140 | } | ||
| 1141 | if (prop) XFree(prop); | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | unsigned int bw = has_decorations ? border_size : 0; | ||
| 1145 | |||
| 1146 | // Setting current active window to inactive. | 1146 | // Setting current active window to inactive. |
| 1147 | if (wm.active != None) { | 1147 | if (wm.active != None && wm.active != window) { |
| 1148 | // For safety/speed, let's re-check hints for the old active window too. | 1148 | update_window_border(wm.active, 0); |
| 1149 | int old_has_decorations = 1; | ||
| 1150 | |||
| 1151 | old = XSetErrorHandler(ignore_x_error); | ||
| 1152 | status = XGetWindowProperty(wm.dpy, wm.active, _MOTIF_WM_HINTS, 0, 5, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); | ||
| 1153 | XSync(wm.dpy, False); | ||
| 1154 | XSetErrorHandler(old); | ||
| 1155 | |||
| 1156 | if (status == Success) { | ||
| 1157 | if (prop && nitems >= 3) { | ||
| 1158 | unsigned long flags = ((unsigned long *)prop)[0]; | ||
| 1159 | unsigned long decorations = ((unsigned long *)prop)[2]; | ||
| 1160 | if ((flags & 2) && (decorations & 1) == 0) { | ||
| 1161 | old_has_decorations = 0; | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | if (prop) XFree(prop); | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | XSetWindowBorderWidth(wm.dpy, wm.active, old_has_decorations ? border_size : 0); | ||
| 1168 | if (is_always_on_top(wm.active)) { | ||
| 1169 | XSetWindowBorder(wm.dpy, wm.active, wm.borders.on_top_inactive); | ||
| 1170 | } else if (is_sticky(wm.active)) { | ||
| 1171 | XSetWindowBorder(wm.dpy, wm.active, wm.borders.sticky_inactive); | ||
| 1172 | } else { | ||
| 1173 | XSetWindowBorder(wm.dpy, wm.active, wm.borders.normal_inactive); | ||
| 1174 | } | ||
| 1175 | log_message(stdout, LOG_DEBUG, "Active window 0x%lx border set to inactive", wm.active); | 1149 | log_message(stdout, LOG_DEBUG, "Active window 0x%lx border set to inactive", wm.active); |
| 1176 | } | 1150 | } |
| 1177 | 1151 | ||
| 1178 | // Setting desired window to active. | 1152 | // Setting desired window to active. |
| 1179 | XSetWindowBorderWidth(wm.dpy, window, bw); | 1153 | update_window_border(window, 1); |
| 1180 | if (is_always_on_top(window)) { | ||
| 1181 | XSetWindowBorder(wm.dpy, window, wm.borders.on_top_active); | ||
| 1182 | } else if (is_sticky(window)) { | ||
| 1183 | XSetWindowBorder(wm.dpy, window, wm.borders.sticky_active); | ||
| 1184 | } else { | ||
| 1185 | XSetWindowBorder(wm.dpy, window, wm.borders.normal_active); | ||
| 1186 | } | ||
| 1187 | XFlush(wm.dpy); | 1154 | XFlush(wm.dpy); |
| 1188 | 1155 | ||
| 1189 | log_message(stdout, LOG_DEBUG, "Desired window 0x%lx border set to active", window); | 1156 | log_message(stdout, LOG_DEBUG, "Desired window 0x%lx border set to active", window); |
