|
diff --git a/manager.c b/manager.c
|
| ... |
| 36 |
static Atom WM_DELETE_WINDOW; |
36 |
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 |
static Atom _NET_FRAME_EXTENTS; |
|
|
40 |
static Atom WM_STATE_ATOM; |
| 39 |
|
41 |
|
| 40 |
static void update_window_border(Window window, int active) { |
42 |
static void update_window_border(Window window, int active) { |
| 41 |
if (window == None) return; |
43 |
if (window == None) return; |
| ... |
| 96 |
static void remove_client(Window w); |
98 |
static void remove_client(Window w); |
| 97 |
static Window get_toplevel_window(Window w); |
99 |
static Window get_toplevel_window(Window w); |
| 98 |
static void set_fullscreen(Window w, int full); |
100 |
static void set_fullscreen(Window w, int full); |
|
|
101 |
static void send_configure(Window w); |
|
|
102 |
static Client *wintoclient(Window w); |
| 99 |
|
103 |
|
| 100 |
int x_error_handler(Display *dpy, XErrorEvent *ee) { |
104 |
int x_error_handler(Display *dpy, XErrorEvent *ee) { |
| 101 |
(void) dpy; |
105 |
(void) dpy; |
| ... |
| 115 |
return 0; |
119 |
return 0; |
| 116 |
} |
120 |
} |
| 117 |
|
121 |
|
|
|
122 |
static void set_client_state(Window w, long state) { |
|
|
123 |
long data[] = { state, None }; |
|
|
124 |
XChangeProperty(wm.dpy, w, WM_STATE_ATOM, WM_STATE_ATOM, 32, PropModeReplace, (unsigned char *)data, 2); |
|
|
125 |
} |
|
|
126 |
|
| 118 |
static void add_client(Window w) { |
127 |
static void add_client(Window w) { |
| 119 |
// Check if already in list or is root. |
128 |
// Check if already in list or is root. |
| 120 |
if (w == wm.root) return; |
129 |
if (w == wm.root) return; |
| ... |
| 141 |
} |
150 |
} |
| 142 |
wm.clients = new_c; |
151 |
wm.clients = new_c; |
| 143 |
log_message(stdout, LOG_DEBUG, "Added client 0x%lx", w); |
152 |
log_message(stdout, LOG_DEBUG, "Added client 0x%lx", w); |
|
|
153 |
|
|
|
154 |
unsigned long extents[4] = {0, 0, 0, 0}; |
|
|
155 |
XChangeProperty(wm.dpy, w, _NET_FRAME_EXTENTS, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)extents, 4); |
|
|
156 |
set_client_state(w, NormalState); |
| 144 |
} |
157 |
} |
| 145 |
|
158 |
|
| 146 |
static void remove_client(Window w) { |
159 |
static void remove_client(Window w) { |
| ... |
| 157 |
c->next->prev = c->prev; |
170 |
c->next->prev = c->prev; |
| 158 |
} |
171 |
} |
| 159 |
|
172 |
|
|
|
173 |
set_client_state(w, WithdrawnState); |
| 160 |
free(c); |
174 |
free(c); |
| 161 |
log_message(stdout, LOG_DEBUG, "Removed client 0x%lx", w); |
175 |
log_message(stdout, LOG_DEBUG, "Removed client 0x%lx", w); |
| 162 |
return; |
176 |
return; |
| ... |
| 258 |
_NET_SUPPORTED = XInternAtom(wm.dpy, "_NET_SUPPORTED", False); |
272 |
_NET_SUPPORTED = XInternAtom(wm.dpy, "_NET_SUPPORTED", False); |
| 259 |
_NET_SUPPORTING_WM_CHECK = XInternAtom(wm.dpy, "_NET_SUPPORTING_WM_CHECK", False); |
273 |
_NET_SUPPORTING_WM_CHECK = XInternAtom(wm.dpy, "_NET_SUPPORTING_WM_CHECK", False); |
| 260 |
_NET_WM_NAME = XInternAtom(wm.dpy, "_NET_WM_NAME", False); |
274 |
_NET_WM_NAME = XInternAtom(wm.dpy, "_NET_WM_NAME", False); |
| 261 |
_GLITCH_PRE_HMAX_GEOM = XInternAtom(wm.dpy, "_GLITCH_PRE_HMAX_GEOM", False); |
275 |
_NET_FRAME_EXTENTS = XInternAtom(wm.dpy, "_NET_FRAME_EXTENTS", False); |
| 262 |
_GLITCH_PRE_VMAX_GEOM = XInternAtom(wm.dpy, "_GLITCH_PRE_VMAX_GEOM", False); |
276 |
WM_STATE_ATOM = XInternAtom(wm.dpy, "WM_STATE", False); |
| 263 |
_GLITCH_PRE_FULLSCREEN_GEOM = XInternAtom(wm.dpy, "_GLITCH_PRE_FULLSCREEN_GEOM", False); |
|
|
| 264 |
_MOTIF_WM_HINTS = XInternAtom(wm.dpy, "_MOTIF_WM_HINTS", False); |
|
|
| 265 |
WM_PROTOCOLS = XInternAtom(wm.dpy, "WM_PROTOCOLS", False); |
|
|
| 266 |
WM_DELETE_WINDOW = XInternAtom(wm.dpy, "WM_DELETE_WINDOW", False); |
|
|
| 267 |
WM_TAKE_FOCUS = XInternAtom(wm.dpy, "WM_TAKE_FOCUS", False); |
|
|
| 268 |
|
277 |
|
| 269 |
// Create supporting window for EWMH compliance. |
278 |
// Create supporting window for EWMH compliance. |
| 270 |
Window check_win = XCreateSimpleWindow(wm.dpy, wm.root, 0, 0, 1, 1, 0, 0, 0); |
279 |
Window check_win = XCreateSimpleWindow(wm.dpy, wm.root, 0, 0, 1, 1, 0, 0, 0); |
|
|
280 |
XMapWindow(wm.dpy, check_win); |
| 271 |
XChangeProperty(wm.dpy, check_win, _NET_SUPPORTING_WM_CHECK, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&check_win, 1); |
281 |
XChangeProperty(wm.dpy, check_win, _NET_SUPPORTING_WM_CHECK, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&check_win, 1); |
| 272 |
XChangeProperty(wm.dpy, check_win, _NET_WM_NAME, XA_STRING, 8, PropModeReplace, (unsigned char *)"glitch", 6); |
282 |
XChangeProperty(wm.dpy, check_win, _NET_WM_NAME, XA_STRING, 8, PropModeReplace, (unsigned char *)"LG3D", 4); |
| 273 |
XChangeProperty(wm.dpy, wm.root, _NET_SUPPORTING_WM_CHECK, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&check_win, 1); |
283 |
XChangeProperty(wm.dpy, wm.root, _NET_SUPPORTING_WM_CHECK, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&check_win, 1); |
| 274 |
XChangeProperty(wm.dpy, wm.root, _NET_WM_NAME, XA_STRING, 8, PropModeReplace, (unsigned char *)"glitch", 6); |
284 |
XChangeProperty(wm.dpy, wm.root, _NET_WM_NAME, XA_STRING, 8, PropModeReplace, (unsigned char *)"LG3D", 4); |
| 275 |
|
285 |
|
| 276 |
// Set supported atoms. |
286 |
// Set supported atoms. |
| 277 |
Atom net_atoms[] = { |
287 |
Atom net_atoms[] = { |
| 278 |
_NET_SUPPORTED, |
288 |
_NET_SUPPORTED, |
| 279 |
_NET_SUPPORTING_WM_CHECK, |
289 |
_NET_SUPPORTING_WM_CHECK, |
| 280 |
_NET_WM_NAME, |
290 |
_NET_WM_NAME, |
|
|
291 |
_NET_FRAME_EXTENTS, |
| 281 |
_NET_WM_DESKTOP, |
292 |
_NET_WM_DESKTOP, |
| 282 |
_NET_CURRENT_DESKTOP, |
293 |
_NET_CURRENT_DESKTOP, |
| 283 |
_NET_NUMBER_OF_DESKTOPS, |
294 |
_NET_NUMBER_OF_DESKTOPS, |
| ... |
| 289 |
_NET_WM_STATE_MAXIMIZED_HORZ, |
300 |
_NET_WM_STATE_MAXIMIZED_HORZ, |
| 290 |
_NET_WM_STATE_MAXIMIZED_VERT, |
301 |
_NET_WM_STATE_MAXIMIZED_VERT, |
| 291 |
_NET_WM_STATE_ABOVE, |
302 |
_NET_WM_STATE_ABOVE, |
|
|
303 |
WM_STATE_ATOM, |
| 292 |
WM_DELETE_WINDOW, |
304 |
WM_DELETE_WINDOW, |
| 293 |
WM_TAKE_FOCUS |
305 |
WM_TAKE_FOCUS |
| 294 |
}; |
306 |
}; |
| ... |
| 600 |
} |
612 |
} |
| 601 |
|
613 |
|
| 602 |
void set_active_window(Window window, Time time) { |
614 |
void set_active_window(Window window, Time time) { |
|
|
615 |
(void)time; // Use CurrentTime for more reliable focus stealing/pulling. |
|
|
616 |
|
| 603 |
if (window != None) { |
617 |
if (window != None) { |
| 604 |
if (!window_exists(window)) return; |
618 |
if (!window_exists(window)) return; |
| 605 |
|
619 |
|
| 606 |
XChangeProperty(wm.dpy, wm.root, _NET_ACTIVE_WINDOW, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&window, 1); |
|
|
| 607 |
wm.active = window; |
620 |
wm.active = window; |
|
|
621 |
XChangeProperty(wm.dpy, wm.root, _NET_ACTIVE_WINDOW, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&window, 1); |
| 608 |
|
622 |
|
| 609 |
// Check for WM_TAKE_FOCUS support. |
623 |
// Check for WM_TAKE_FOCUS support. |
| 610 |
int take_focus = 0; |
624 |
int take_focus = 0; |
| ... |
| 620 |
XFree(protocols); |
634 |
XFree(protocols); |
| 621 |
} |
635 |
} |
| 622 |
|
636 |
|
|
|
637 |
// Check WM_HINTS if needed (logging only for now as we force focus anyway) |
|
|
638 |
XWMHints *hints = XGetWMHints(wm.dpy, window); |
|
|
639 |
if (hints) { |
|
|
640 |
log_message(stdout, LOG_DEBUG, "Window hints: input=%d", !!(hints->flags & InputHint && hints->input)); |
|
|
641 |
XFree(hints); |
|
|
642 |
} |
|
|
643 |
|
|
|
644 |
// Always set X focus for managed windows. |
|
|
645 |
XSetInputFocus(wm.dpy, window, RevertToParent, CurrentTime); |
|
|
646 |
log_message(stdout, LOG_DEBUG, "Set input focus to 0x%lx", window); |
|
|
647 |
|
| 623 |
if (take_focus) { |
648 |
if (take_focus) { |
| 624 |
XEvent ev; |
649 |
XEvent ev = {0}; |
| 625 |
ev.type = ClientMessage; |
650 |
ev.type = ClientMessage; |
| 626 |
ev.xclient.window = window; |
651 |
ev.xclient.window = window; |
| 627 |
ev.xclient.message_type = WM_PROTOCOLS; |
652 |
ev.xclient.message_type = WM_PROTOCOLS; |
| 628 |
ev.xclient.format = 32; |
653 |
ev.xclient.format = 32; |
| 629 |
ev.xclient.data.l[0] = WM_TAKE_FOCUS; |
654 |
ev.xclient.data.l[0] = WM_TAKE_FOCUS; |
| 630 |
ev.xclient.data.l[1] = time; |
655 |
ev.xclient.data.l[1] = CurrentTime; |
| 631 |
XSendEvent(wm.dpy, window, False, NoEventMask, &ev); |
656 |
XSendEvent(wm.dpy, window, False, NoEventMask, &ev); |
| 632 |
log_message(stdout, LOG_DEBUG, "Sent WM_TAKE_FOCUS to 0x%lx with time %lu", window, time); |
657 |
log_message(stdout, LOG_DEBUG, "Sent WM_TAKE_FOCUS to 0x%lx", window); |
| 633 |
} |
|
|
| 634 |
|
|
|
| 635 |
int expects_input = 1; |
|
|
| 636 |
XWMHints *hints = XGetWMHints(wm.dpy, window); |
|
|
| 637 |
if (hints) { |
|
|
| 638 |
if ((hints->flags & InputHint) && !hints->input) { |
|
|
| 639 |
expects_input = 0; |
|
|
| 640 |
} |
|
|
| 641 |
XFree(hints); |
|
|
| 642 |
} |
|
|
| 643 |
|
|
|
| 644 |
if (expects_input) { |
|
|
| 645 |
XSetInputFocus(wm.dpy, window, RevertToPointerRoot, time); |
|
|
| 646 |
log_message(stdout, LOG_DEBUG, "Set input focus to 0x%lx with time %lu", window, time); |
|
|
| 647 |
} else { |
|
|
| 648 |
log_message(stdout, LOG_DEBUG, "Window 0x%lx does not expect input, skipping XSetInputFocus", window); |
|
|
| 649 |
} |
658 |
} |
| 650 |
} else { |
659 |
} else { |
| 651 |
XDeleteProperty(wm.dpy, wm.root, _NET_ACTIVE_WINDOW); |
660 |
XDeleteProperty(wm.dpy, wm.root, _NET_ACTIVE_WINDOW); |
| 652 |
wm.active = None; |
661 |
wm.active = None; |
| 653 |
XSetInputFocus(wm.dpy, wm.root, RevertToPointerRoot, time); |
662 |
XSetInputFocus(wm.dpy, wm.root, RevertToParent, CurrentTime); |
|
|
663 |
log_message(stdout, LOG_DEBUG, "Reset focus to root"); |
| 654 |
} |
664 |
} |
| 655 |
XFlush(wm.dpy); |
665 |
XFlush(wm.dpy); |
| 656 |
} |
666 |
} |
| ... |
| 701 |
log_message(stdout, LOG_DEBUG, "ConfigureRequest for 0x%lx (x=%d, y=%d, w=%d, h=%d)", ev->window, ev->x, ev->y, ev->width, ev->height); |
711 |
log_message(stdout, LOG_DEBUG, "ConfigureRequest for 0x%lx (x=%d, y=%d, w=%d, h=%d)", ev->window, ev->x, ev->y, ev->width, ev->height); |
| 702 |
} |
712 |
} |
| 703 |
|
713 |
|
|
|
714 |
void handle_configure_notify(void) { |
|
|
715 |
XConfigureEvent *ev = &wm.ev.xconfigure; |
|
|
716 |
|
|
|
717 |
if (ev->window == wm.root) return; |
|
|
718 |
|
|
|
719 |
// Only send synthetic events for windows we manage as top-level clients. |
|
|
720 |
Client *c; |
|
|
721 |
for (c = wm.clients; c; c = c->next) { |
|
|
722 |
if (c->window == ev->window) { |
|
|
723 |
log_message(stdout, LOG_DEBUG, "Sending synthetic ConfigureNotify to 0x%lx (x=%d, y=%d, w=%d, h=%d)", ev->window, ev->x, ev->y, ev->width, ev->height); |
|
|
724 |
send_configure(c->window); |
|
|
725 |
break; |
|
|
726 |
} |
|
|
727 |
} |
|
|
728 |
} |
|
|
729 |
|
|
|
730 |
void handle_map_notify(void) { |
|
|
731 |
Window window = wm.ev.xmap.window; |
|
|
732 |
if (window == wm.root) return; |
|
|
733 |
|
|
|
734 |
log_message(stdout, LOG_DEBUG, "MapNotify for 0x%lx", window); |
|
|
735 |
|
|
|
736 |
// Check if this is a managed window. |
|
|
737 |
Client *c; |
|
|
738 |
for (c = wm.clients; c; c = c->next) { |
|
|
739 |
if (c->window == window) { |
|
|
740 |
// Shows, raises and focuses the window. |
|
|
741 |
set_active_border(window); |
|
|
742 |
set_active_window(window, CurrentTime); |
|
|
743 |
|
|
|
744 |
// Ensure it has synthetic configure after mapping. |
|
|
745 |
send_configure(window); |
|
|
746 |
|
|
|
747 |
log_message(stdout, LOG_DEBUG, "Focused and configured 0x%lx after MapNotify", window); |
|
|
748 |
break; |
|
|
749 |
} |
|
|
750 |
} |
|
|
751 |
redraw_widgets(); |
|
|
752 |
} |
|
|
753 |
|
| 704 |
// https://tronche.com/gui/x/xlib/events/structure-control/map.html |
754 |
// https://tronche.com/gui/x/xlib/events/structure-control/map.html |
| 705 |
void handle_map_request(void) { |
755 |
void handle_map_request(void) { |
| 706 |
Window window = wm.ev.xmaprequest.window; |
756 |
Window window = wm.ev.xmaprequest.window; |
| ... |
| 711 |
// Move window under cursor position and clamps inside the screen bounds. |
761 |
// Move window under cursor position and clamps inside the screen bounds. |
| 712 |
XWindowAttributes check_attr; |
762 |
XWindowAttributes check_attr; |
| 713 |
if (XGetWindowAttributes(wm.dpy, window, &check_attr)) { |
763 |
if (XGetWindowAttributes(wm.dpy, window, &check_attr)) { |
| 714 |
XSelectInput(wm.dpy, window, EnterWindowMask | LeaveWindowMask); |
764 |
XSelectInput(wm.dpy, window, EnterWindowMask | LeaveWindowMask | StructureNotifyMask | FocusChangeMask); |
| 715 |
|
765 |
|
| 716 |
Window root_return, child_return; |
766 |
Window root_return, child_return; |
| 717 |
int root_x, root_y, win_x, win_y; |
767 |
int root_x, root_y, win_x, win_y; |
| ... |
| 736 |
// Tag window with current desktop. |
786 |
// Tag window with current desktop. |
| 737 |
unsigned long desktop = wm.current_desktop; |
787 |
unsigned long desktop = wm.current_desktop; |
| 738 |
XChangeProperty(wm.dpy, window, _NET_WM_DESKTOP, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&desktop, 1); |
788 |
XChangeProperty(wm.dpy, window, _NET_WM_DESKTOP, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&desktop, 1); |
| 739 |
|
|
|
| 740 |
XMapWindow(wm.dpy, window); |
|
|
| 741 |
raise_window(window); |
|
|
| 742 |
|
|
|
| 743 |
// Shows, raises and focuses the window. |
|
|
| 744 |
set_active_border(window); |
|
|
| 745 |
set_active_window(window, CurrentTime); |
|
|
| 746 |
|
789 |
|
| 747 |
// Grab buttons for click-to-focus. |
790 |
// Grab buttons for click-to-focus. |
| 748 |
grab_buttons(window); |
791 |
grab_buttons(window); |
| ... |
| 750 |
add_client(window); |
793 |
add_client(window); |
| 751 |
apply_tiling_layout(); |
794 |
apply_tiling_layout(); |
| 752 |
|
795 |
|
|
|
796 |
XMapWindow(wm.dpy, window); |
|
|
797 |
raise_window(window); |
|
|
798 |
|
| 753 |
XSync(wm.dpy, False); |
799 |
XSync(wm.dpy, False); |
| 754 |
XSetErrorHandler(old); |
800 |
XSetErrorHandler(old); |
| 755 |
|
801 |
|
| 756 |
log_message(stdout, LOG_DEBUG, "Window 0x%lx mapped and grabbed on desktop %d", window, wm.current_desktop); |
802 |
log_message(stdout, LOG_DEBUG, "Window 0x%lx added and requested map on desktop %d", window, wm.current_desktop); |
| 757 |
redraw_widgets(); |
|
|
| 758 |
update_client_list(); |
803 |
update_client_list(); |
| 759 |
} |
804 |
} |
| 760 |
|
805 |
|
| ... |
| 762 |
void handle_unmap_notify(void) { |
807 |
void handle_unmap_notify(void) { |
| 763 |
Window window = wm.ev.xunmap.window; |
808 |
Window window = wm.ev.xunmap.window; |
| 764 |
if (window == wm.active) { |
809 |
if (window == wm.active) { |
| 765 |
wm.active = None; |
810 |
set_active_window(None, CurrentTime); |
| 766 |
} |
811 |
} |
| 767 |
|
812 |
|
| 768 |
// So if we get an unmap for a sticky window, it means the application closed it. |
813 |
// So if we get an unmap for a sticky window, it means the application closed it. |
| ... |
| 779 |
void handle_destroy_notify(void) { |
824 |
void handle_destroy_notify(void) { |
| 780 |
Window window = wm.ev.xdestroywindow.window; |
825 |
Window window = wm.ev.xdestroywindow.window; |
| 781 |
if (window == wm.active) { |
826 |
if (window == wm.active) { |
| 782 |
wm.active = None; |
827 |
set_active_window(None, CurrentTime); |
| 783 |
} |
828 |
} |
| 784 |
remove_client(window); |
829 |
remove_client(window); |
| 785 |
apply_tiling_layout(); |
830 |
apply_tiling_layout(); |
| ... |
| 806 |
wm.attr.y + (wm.start.button == 1 ? ydiff : 0), |
851 |
wm.attr.y + (wm.start.button == 1 ? ydiff : 0), |
| 807 |
MAX(100, wm.attr.width + (wm.start.button == 3 ? xdiff : 0)), |
852 |
MAX(100, wm.attr.width + (wm.start.button == 3 ? xdiff : 0)), |
| 808 |
MAX(100, wm.attr.height + (wm.start.button == 3 ? ydiff : 0))); |
853 |
MAX(100, wm.attr.height + (wm.start.button == 3 ? ydiff : 0))); |
|
|
854 |
send_configure(wm.start.subwindow); |
| 809 |
|
855 |
|
| 810 |
// Reset maximization state on manual move/resize. |
856 |
// Reset maximization state on manual move/resize. |
| 811 |
if (wm.start.button == 1) { |
857 |
if (wm.start.button == 1) { |
| ... |
| 847 |
XFlush(wm.dpy); |
893 |
XFlush(wm.dpy); |
| 848 |
} |
894 |
} |
| 849 |
|
895 |
|
|
|
896 |
static Client *wintoclient(Window w) { |
|
|
897 |
if (w == None || w == wm.root) return NULL; |
|
|
898 |
Client *c; |
|
|
899 |
for (c = wm.clients; c; c = c->next) { |
|
|
900 |
if (c->window == w) return c; |
|
|
901 |
} |
|
|
902 |
// Search parent hierarchy |
|
|
903 |
Window root, parent, *children; |
|
|
904 |
unsigned int nchildren; |
|
|
905 |
XErrorHandler old = XSetErrorHandler(ignore_x_error); |
|
|
906 |
while (w != wm.root && w != None) { |
|
|
907 |
if (XQueryTree(wm.dpy, w, &root, &parent, &children, &nchildren)) { |
|
|
908 |
if (children) XFree(children); |
|
|
909 |
for (c = wm.clients; c; c = c->next) { |
|
|
910 |
if (c->window == parent) { |
|
|
911 |
XSetErrorHandler(old); |
|
|
912 |
return c; |
|
|
913 |
} |
|
|
914 |
} |
|
|
915 |
w = parent; |
|
|
916 |
} else { |
|
|
917 |
break; |
|
|
918 |
} |
|
|
919 |
} |
|
|
920 |
XSetErrorHandler(old); |
|
|
921 |
return NULL; |
|
|
922 |
} |
|
|
923 |
|
|
|
924 |
static void send_configure(Window w) { |
|
|
925 |
XWindowAttributes wa; |
|
|
926 |
if (!XGetWindowAttributes(wm.dpy, w, &wa)) return; |
|
|
927 |
|
|
|
928 |
XConfigureEvent ce; |
|
|
929 |
ce.type = ConfigureNotify; |
|
|
930 |
ce.display = wm.dpy; |
|
|
931 |
ce.event = w; |
|
|
932 |
ce.window = w; |
|
|
933 |
ce.x = wa.x; |
|
|
934 |
ce.y = wa.y; |
|
|
935 |
ce.width = wa.width; |
|
|
936 |
ce.height = wa.height; |
|
|
937 |
ce.border_width = wa.border_width; |
|
|
938 |
ce.above = None; |
|
|
939 |
ce.override_redirect = False; |
|
|
940 |
XSendEvent(wm.dpy, w, False, StructureNotifyMask, (XEvent *)&ce); |
|
|
941 |
} |
|
|
942 |
|
| 850 |
static void set_fullscreen(Window window, int full) { |
943 |
static void set_fullscreen(Window window, int full) { |
| 851 |
int currently_fullscreen = has_wm_state(window, _NET_WM_STATE_FULLSCREEN); |
944 |
int currently_fullscreen = has_wm_state(window, _NET_WM_STATE_FULLSCREEN); |
| 852 |
|
945 |
|
| ... |
| 862 |
int screen_height = DisplayHeight(wm.dpy, wm.screen); |
955 |
int screen_height = DisplayHeight(wm.dpy, wm.screen); |
| 863 |
|
956 |
|
| 864 |
XMoveResizeWindow(wm.dpy, window, 0, 0, screen_width, screen_height); |
957 |
XMoveResizeWindow(wm.dpy, window, 0, 0, screen_width, screen_height); |
|
|
958 |
send_configure(window); |
| 865 |
XSetWindowBorderWidth(wm.dpy, window, 0); |
959 |
XSetWindowBorderWidth(wm.dpy, window, 0); |
| 866 |
XRaiseWindow(wm.dpy, window); |
960 |
XRaiseWindow(wm.dpy, window); |
| 867 |
|
961 |
|
| ... |
| 883 |
if (status == Success && prop && nitems == 4) { |
977 |
if (status == Success && prop && nitems == 4) { |
| 884 |
long *geom = (long *)prop; |
978 |
long *geom = (long *)prop; |
| 885 |
XMoveResizeWindow(wm.dpy, window, (int)geom[0], (int)geom[1], (unsigned int)geom[2], (unsigned int)geom[3]); |
979 |
XMoveResizeWindow(wm.dpy, window, (int)geom[0], (int)geom[1], (unsigned int)geom[2], (unsigned int)geom[3]); |
|
|
980 |
send_configure(window); |
| 886 |
} |
981 |
} |
| 887 |
if (prop) XFree(prop); |
982 |
if (prop) XFree(prop); |
| 888 |
|
983 |
|
| ... |
| 921 |
if (new_y < 0) new_y = 0; |
1016 |
if (new_y < 0) new_y = 0; |
| 922 |
|
1017 |
|
| 923 |
XMoveWindow(wm.dpy, wm.active, new_x, new_y); |
1018 |
XMoveWindow(wm.dpy, wm.active, new_x, new_y); |
|
|
1019 |
send_configure(wm.active); |
| 924 |
log_message(stdout, LOG_DEBUG, "Centered window 0x%lx at (%d, %d)", wm.active, new_x, new_y); |
1020 |
log_message(stdout, LOG_DEBUG, "Centered window 0x%lx at (%d, %d)", wm.active, new_x, new_y); |
| 925 |
} |
1021 |
} |
| 926 |
} |
1022 |
} |
| 927 |
|
1023 |
|
| 928 |
// https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html |
1024 |
// https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html |
| 929 |
void handle_button_press(void) { |
1025 |
void handle_button_press(void) { |
| 930 |
Window window; |
1026 |
Window window = None; |
| 931 |
if (wm.ev.xbutton.window == wm.root) { |
1027 |
Client *c = wintoclient(wm.ev.xbutton.window); |
| 932 |
window = wm.ev.xbutton.subwindow; |
1028 |
if (!c) c = wintoclient(wm.ev.xbutton.subwindow); |
| 933 |
} else { |
1029 |
|
|
|
1030 |
if (c) { |
|
|
1031 |
window = c->window; |
|
|
1032 |
} else if (wm.ev.xbutton.window != wm.root) { |
| 934 |
window = wm.ev.xbutton.window; |
1033 |
window = wm.ev.xbutton.window; |
|
|
1034 |
} else { |
|
|
1035 |
window = wm.ev.xbutton.subwindow; |
| 935 |
} |
1036 |
} |
| 936 |
|
1037 |
|
| 937 |
log_message(stdout, LOG_DEBUG, "ButtonPress: window=0x%lx, subwindow=0x%lx, button=%d, state=0x%x, targeting=0x%lx", |
1038 |
log_message(stdout, LOG_DEBUG, "ButtonPress: window=0x%lx, subwindow=0x%lx, button=%d, state=0x%x, targeting=0x%lx", |
| ... |
| 1161 |
|
1262 |
|
| 1162 |
void handle_focus_in(void) { |
1263 |
void handle_focus_in(void) { |
| 1163 |
Window window = wm.ev.xfocus.window; |
1264 |
Window window = wm.ev.xfocus.window; |
| 1164 |
if (window != wm.root) { |
1265 |
if (window == wm.root || window == None) return; |
| 1165 |
log_message(stdout, LOG_DEBUG, "Window 0x%lx focus in", window); |
1266 |
|
|
|
1267 |
Client *c = wintoclient(window); |
|
|
1268 |
if (wm.active != None && (!c || c->window != wm.active)) { |
|
|
1269 |
log_message(stdout, LOG_DEBUG, "Window 0x%lx focus in (foreign), forcing back to active 0x%lx", window, wm.active); |
|
|
1270 |
set_active_window(wm.active, CurrentTime); |
| 1166 |
} |
1271 |
} |
| 1167 |
} |
1272 |
} |
| 1168 |
|
1273 |
|
| ... |
| 1220 |
check_and_clear_maximized_state(wm.active, 1, 0); |
1325 |
check_and_clear_maximized_state(wm.active, 1, 0); |
| 1221 |
log_message(stdout, LOG_DEBUG, "Move window 0x%lx on X by %d", wm.active, arg->i); |
1326 |
log_message(stdout, LOG_DEBUG, "Move window 0x%lx on X by %d", wm.active, arg->i); |
| 1222 |
|
1327 |
|
| 1223 |
XSync(wm.dpy, True); |
1328 |
XSync(wm.dpy, False); |
| 1224 |
XFlush(wm.dpy); |
1329 |
XFlush(wm.dpy); |
| 1225 |
} |
1330 |
} |
| 1226 |
|
1331 |
|
| ... |
| 1233 |
check_and_clear_maximized_state(wm.active, 0, 1); |
1338 |
check_and_clear_maximized_state(wm.active, 0, 1); |
| 1234 |
log_message(stdout, LOG_DEBUG, "Move window 0x%lx on Y by %d", wm.active, arg->i); |
1339 |
log_message(stdout, LOG_DEBUG, "Move window 0x%lx on Y by %d", wm.active, arg->i); |
| 1235 |
|
1340 |
|
| 1236 |
XSync(wm.dpy, True); |
1341 |
XSync(wm.dpy, False); |
| 1237 |
XFlush(wm.dpy); |
1342 |
XFlush(wm.dpy); |
| 1238 |
} |
1343 |
} |
| 1239 |
|
1344 |
|
| ... |
| 1255 |
} |
1360 |
} |
| 1256 |
|
1361 |
|
| 1257 |
if (supported) { |
1362 |
if (supported) { |
| 1258 |
XEvent ev; |
1363 |
XEvent ev = {0}; |
| 1259 |
ev.type = ClientMessage; |
1364 |
ev.type = ClientMessage; |
| 1260 |
ev.xclient.window = wm.active; |
1365 |
ev.xclient.window = wm.active; |
| 1261 |
ev.xclient.message_type = WM_PROTOCOLS; |
1366 |
ev.xclient.message_type = WM_PROTOCOLS; |
| ... |
| 1716 |
if (desktop == wm.current_desktop && !is_sticky(c->window) && !is_always_on_top(c->window) && !has_wm_state(c->window, _NET_WM_STATE_FULLSCREEN)) { |
1821 |
if (desktop == wm.current_desktop && !is_sticky(c->window) && !is_always_on_top(c->window) && !has_wm_state(c->window, _NET_WM_STATE_FULLSCREEN)) { |
| 1717 |
if (n == 1) { |
1822 |
if (n == 1) { |
| 1718 |
XMoveResizeWindow(wm.dpy, c->window, 0, 0, screen_width - 2 * border_size, screen_height - 2 * border_size); |
1823 |
XMoveResizeWindow(wm.dpy, c->window, 0, 0, screen_width - 2 * border_size, screen_height - 2 * border_size); |
|
|
1824 |
send_configure(c->window); |
| 1719 |
} else if (i == 0) { // Master |
1825 |
} else if (i == 0) { // Master |
| 1720 |
XMoveResizeWindow(wm.dpy, c->window, 0, 0, mw - 2 * border_size, screen_height - 2 * border_size); |
1826 |
XMoveResizeWindow(wm.dpy, c->window, 0, 0, mw - 2 * border_size, screen_height - 2 * border_size); |
|
|
1827 |
send_configure(c->window); |
| 1721 |
} else { // Stack |
1828 |
} else { // Stack |
| 1722 |
int h = screen_height / (n - 1); |
1829 |
int h = screen_height / (n - 1); |
| 1723 |
XMoveResizeWindow(wm.dpy, c->window, mw, (i - 1) * h, screen_width - mw - 2 * border_size, h - 2 * border_size); |
1830 |
XMoveResizeWindow(wm.dpy, c->window, mw, (i - 1) * h, screen_width - mw - 2 * border_size, h - 2 * border_size); |
|
|
1831 |
send_configure(c->window); |
| 1724 |
} |
1832 |
} |
| 1725 |
i++; |
1833 |
i++; |
| 1726 |
} |
1834 |
} |
| ... |