#include #include #include #include #include #include "extras/ewmh/ewmh.h" #ifdef XINERAMA #include "extras/xinerama.h" #endif #ifdef MASTERSTACK #include "extras/tile/masterstack.h" #endif #ifdef BAR #include "extras/bar.h" #endif #define max_val(a, b) ((a) > (b) ? (a) : (b)) #define mod_key Mod1Mask #define max_windows 4096 #define cmd_workspace 1 #define cmd_move 2 #define cmd_kill 3 #define cmd_bar_position 4 #define cmd_bar_margin_x 5 #define cmd_bar_margin_y 6 #define cmd_reload 7 #define cmd_bar_nf 8 #define cmd_bar_nb 9 #define cmd_bar_sf 10 #define cmd_bar_sb 11 #define cmd_bar_sa 12 #define cmd_gap_inner 13 #define cmd_gap_outer 14 #define cmd_gap_top 15 #define cmd_tile_focused 16 #define cmd_bar_height 17 #define cmd_bar_font 18 #define cmd_bar_showempty 19 #define num_workspaces 9 #define modifier_variants 4 #define max_monitors 16 static Window windows[max_windows]; static int window_workspace[max_windows], window_floating[max_windows], window_count; static int current_workspace[max_monitors], monitor_count; static Atom net_wm_desktop_atom; #ifdef BAR static Atom wm_bar_margin_x_atom, wm_bar_margin_y_atom, wm_bar_bottom_atom; static Atom wm_bar_nf_atom, wm_bar_nb_atom, wm_bar_sf_atom, wm_bar_sb_atom, wm_bar_sa_atom; static Atom wm_bar_height_atom, wm_bar_font_atom; static Atom wm_bar_showempty_atom; static Atom net_wm_name_atom, utf8_string_atom; #endif #ifdef MASTERSTACK static Atom wm_gap_inner_atom, wm_gap_outer_atom, wm_gap_top_atom; #endif static int is_root_child(Display *display, Window root_window, Window window); static void select_window_events(Display *display, Window window); static int monitor_for_window(Display *display, Window root_window, Window window) { #ifdef XINERAMA int mon; mon = xinerama_monitor_for_window(display, root_window, window); if (mon < 0 || mon >= monitor_count) return 0; return mon; #else (void)display; (void)root_window; (void)window; return 0; #endif } static int active_monitor(Display *display, Window root_window) { Window root_return, child_return; int root_x, root_y, window_x, window_y; unsigned int mask; if (!XQueryPointer(display, root_window, &root_return, &child_return, &root_x, &root_y, &window_x, &window_y, &mask)) return 0; #ifdef XINERAMA { int mon; mon = xinerama_monitor_for_point(root_x, root_y); if (mon < 0 || mon >= monitor_count) return 0; return mon; } #else (void)root_x; (void)root_y; return 0; #endif } #ifdef MASTERSTACK static void apply_layout(Display *display, Window root_window) { int mon; mon = active_monitor(display, root_window); tile_masterstack_apply(display, root_window, windows, window_workspace, window_floating, window_count, current_workspace[mon]); } #else static void apply_layout(Display *display, Window root_window) { (void)display; (void)root_window; } #endif static int find_window_index(Window window) { int i; for (i = 0; i < window_count; i++) if (windows[i] == window) return i; return -1; } static void place_window_at_pointer(Display *display, Window root_window, Window window) { Window root_return, child_return; XWindowAttributes root_attrs; XWindowAttributes window_attrs; int root_x, root_y, window_x, window_y; int area_x, area_y, area_width, area_height; unsigned int mask; if (!XQueryPointer(display, root_window, &root_return, &child_return, &root_x, &root_y, &window_x, &window_y, &mask)) return; if (!XGetWindowAttributes(display, root_window, &root_attrs)) return; if (!XGetWindowAttributes(display, window, &window_attrs)) return; area_x = 0; area_y = 0; area_width = root_attrs.width; area_height = root_attrs.height; #ifdef XINERAMA { int monitor; monitor = xinerama_monitor_for_point(root_x, root_y); if (!xinerama_monitor_geometry(monitor, &area_x, &area_y, &area_width, &area_height)) { area_x = 0; area_y = 0; area_width = root_attrs.width; area_height = root_attrs.height; } } #endif window_x = root_x - (window_attrs.width / 2); window_y = root_y - (window_attrs.height / 2); if (window_x < area_x) window_x = area_x; if (window_y < area_y) window_y = area_y; if (window_x + window_attrs.width > area_x + area_width) window_x = area_x + area_width - window_attrs.width; if (window_y + window_attrs.height > area_y + area_height) window_y = area_y + area_height - window_attrs.height; if (window_x < area_x) window_x = area_x; if (window_y < area_y) window_y = area_y; XMoveWindow(display, window, window_x, window_y); } #ifdef BAR static void set_bar_title_from_window(Display *display, Window window) { Atom actual_type; int actual_format; unsigned long nitems, bytes_after; unsigned char *prop_data; char *window_name; prop_data = NULL; if (window != None && window != PointerRoot && XGetWindowProperty(display, window, net_wm_name_atom, 0, 2048, False, utf8_string_atom, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data) == Success && prop_data != NULL && actual_type == utf8_string_atom && actual_format == 8 && nitems > 0) { bar_set_title((char *)prop_data); XFree(prop_data); return; } if (prop_data != NULL) XFree(prop_data); window_name = NULL; if (window != None && window != PointerRoot && XFetchName(display, window, &window_name) && window_name != NULL) { bar_set_title(window_name); XFree(window_name); return; } bar_set_title(""); } static void refresh_bar(Display *display) { static int tags[num_workspaces] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int mon_tags[max_monitors]; int usage[max_monitors * num_workspaces]; Window focused_window; int revert_to; int i, j; for (i = 0; i < max_monitors * num_workspaces; i++) usage[i] = 0; for (i = 0; i < window_count; i++) { int mon; int ws; mon = monitor_for_window(display, DefaultRootWindow(display), windows[i]); ws = window_workspace[i]; if (mon >= 0 && mon < max_monitors && ws >= 0 && ws < num_workspaces) usage[mon * num_workspaces + ws] = 1; } for (i = 0; i < monitor_count && i < max_monitors; i++) mon_tags[i] = current_workspace[i]; if (i < 1) { mon_tags[0] = 0; i = 1; } for (j = i; j < max_monitors; j++) mon_tags[j] = mon_tags[0]; bar_set_tags(tags, num_workspaces, mon_tags[0]); bar_set_selected_tags(mon_tags, i); bar_set_workspace_usage(usage, monitor_count, num_workspaces); XGetInputFocus(display, &focused_window, &revert_to); set_bar_title_from_window(display, focused_window); bar_set_status(""); bar_draw(); } #endif static int x_error_handler(Display *display, XErrorEvent *error) { (void)display; if (error->error_code == BadWindow || error->error_code == BadDrawable || error->error_code == BadMatch) return 0; return 0; } static int get_window_index(Window window) { int i; for (i = 0; i < window_count; i++) if (windows[i] == window) return i; if (window == None || window_count >= max_windows) return -1; windows[window_count] = window; window_workspace[window_count] = 0; window_floating[window_count] = 0; return window_count++; } static int get_window_desktop(Display *display, Window window) { Atom actual_type; int actual_format; unsigned long nitems, bytes_after; unsigned char *prop_data; unsigned long desktop; if (net_wm_desktop_atom == None) return -1; prop_data = NULL; if (XGetWindowProperty(display, window, net_wm_desktop_atom, 0, 1, False, XA_CARDINAL, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data) != Success) return -1; if (prop_data == NULL) return -1; if (actual_type != XA_CARDINAL || actual_format != 32 || nitems < 1) { XFree(prop_data); return -1; } desktop = *((unsigned long *)prop_data); XFree(prop_data); if (desktop >= num_workspaces) return -1; return (int)desktop; } #if defined(BAR) || defined(MASTERSTACK) static int read_root_int_property(Display *display, Window root_window, Atom atom, int default_value) { Atom actual_type; int actual_format; unsigned long nitems, bytes_after; unsigned char *prop_data; unsigned long value; prop_data = NULL; if (XGetWindowProperty(display, root_window, atom, 0, 1, False, XA_CARDINAL, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data) != Success) return default_value; if (prop_data == NULL) return default_value; if (actual_type != XA_CARDINAL || actual_format != 32 || nitems < 1) { XFree(prop_data); return default_value; } value = *((unsigned long *)prop_data); XFree(prop_data); return (int)value; } static void write_root_int_property(Display *display, Window root_window, Atom atom, int value) { unsigned long card; card = (unsigned long)value; XChangeProperty(display, root_window, atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&card, 1); } #endif #ifdef BAR static char * read_root_string_property(Display *display, Window root_window, Atom atom) { Atom actual_type; int actual_format; unsigned long nitems, bytes_after; unsigned char *prop_data; char *out; prop_data = NULL; if (XGetWindowProperty(display, root_window, atom, 0, 256, False, XA_STRING, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data) != Success) return NULL; if (prop_data == NULL) return NULL; if (actual_type != XA_STRING || actual_format != 8 || nitems < 1) { XFree(prop_data); return NULL; } out = (char *)malloc(nitems + 1); if (out == NULL) { XFree(prop_data); return NULL; } memcpy(out, prop_data, nitems); out[nitems] = '\0'; XFree(prop_data); return out; } static void write_root_string_property(Display *display, Window root_window, Atom atom, const char *value) { if (value == NULL || value[0] == '\0') { XDeleteProperty(display, root_window, atom); return; } XChangeProperty(display, root_window, atom, XA_STRING, 8, PropModeReplace, (unsigned char *)value, (int)strlen(value)); } #endif static void remove_window(Window window) { int i; for (i = 0; i < window_count; i++) { if (windows[i] == window) { for (; i < window_count - 1; i++) { windows[i] = windows[i + 1]; window_workspace[i] = window_workspace[i + 1]; window_floating[i] = window_floating[i + 1]; } window_count--; return; } } } static void grab_button_variants(Display *display, unsigned int button, unsigned int modifiers, Window root_window, int pointer_mode) { unsigned int extra_mods[modifier_variants]; int i; extra_mods[0] = 0; extra_mods[1] = LockMask; extra_mods[2] = Mod2Mask; extra_mods[3] = LockMask | Mod2Mask; for (i = 0; i < modifier_variants; i++) XGrabButton(display, button, modifiers | extra_mods[i], root_window, True, ButtonPressMask, pointer_mode, GrabModeAsync, None, None); } static void get_window_attrs(Display *display, Window window, XWindowAttributes *window_attrs) { if (!XGetWindowAttributes(display, window, window_attrs)) window_attrs->override_redirect = True; } static void select_window_events(Display *display, Window window) { XSelectInput(display, window, EnterWindowMask | PropertyChangeMask); } static int is_managed_window(Display *display, Window root_window, Window window) { XWindowAttributes window_attrs; if (ewmh_is_internal_window(window)) return 0; if (!is_root_child(display, root_window, window)) return 0; get_window_attrs(display, window, &window_attrs); return !window_attrs.override_redirect; } static void track_windows(Display *display, Window root_window) { Window root_return, parent, *children; int i, j; if (XQueryTree(display, root_window, &root_return, &parent, &children, (unsigned int *)&j)) { for (i = 0; i < j; i++) { int window_index, desktop; if (!is_managed_window(display, root_window, children[i])) continue; select_window_events(display, children[i]); window_index = get_window_index(children[i]); desktop = get_window_desktop(display, children[i]); if (window_index >= 0 && desktop >= 0) window_workspace[window_index] = desktop; } if (children != None) XFree(children); } } static int is_root_child(Display *display, Window root_window, Window window) { Window root_return, parent, *children; unsigned int child_count; if (window == None || window == PointerRoot || window == root_window) return 0; if (!XQueryTree(display, window, &root_return, &parent, &children, &child_count)) return 0; if (children != None) XFree(children); return parent == root_window; } static void show_workspace(Display *display, Window root_window, int target_monitor) { Window root_return, parent, *children; int i, j, window_index; if (XQueryTree(display, root_window, &root_return, &parent, &children, (unsigned int *)&j)) { for (i = 0; i < j; i++) { int mon; if (!is_managed_window(display, root_window, children[i])) continue; mon = monitor_for_window(display, root_window, children[i]); if (mon != target_monitor) continue; window_index = get_window_index(children[i]); if (window_index >= 0) { if (window_workspace[window_index] == current_workspace[target_monitor]) XMapWindow(display, children[i]); else XUnmapWindow(display, children[i]); } } if (children != None) XFree(children); } } int main(int argc, char **argv) { Display *display; Window root_window; Window drag_window; Window focused_window; XWindowAttributes window_attrs; XButtonEvent drag_start; XEvent event; Atom control_atom; int is_dragging; int i, j; is_dragging = 0; drag_window = None; (void)argc; monitor_count = 1; for (i = 0; i < max_monitors; i++) current_workspace[i] = 0; if ((display = XOpenDisplay(NULL)) == NULL) return 1; XSetErrorHandler(x_error_handler); root_window = DefaultRootWindow(display); control_atom = XInternAtom(display, "_WM_CTL", False); net_wm_desktop_atom = XInternAtom(display, "_NET_WM_DESKTOP", False); #ifdef BAR wm_bar_margin_x_atom = XInternAtom(display, "_WM_BAR_MARGIN_X", False); wm_bar_margin_y_atom = XInternAtom(display, "_WM_BAR_MARGIN_Y", False); wm_bar_bottom_atom = XInternAtom(display, "_WM_BAR_BOTTOM", False); wm_bar_nf_atom = XInternAtom(display, "_WM_BAR_NF", False); wm_bar_nb_atom = XInternAtom(display, "_WM_BAR_NB", False); wm_bar_sf_atom = XInternAtom(display, "_WM_BAR_SF", False); wm_bar_sb_atom = XInternAtom(display, "_WM_BAR_SB", False); wm_bar_sa_atom = XInternAtom(display, "_WM_BAR_SA", False); wm_bar_height_atom = XInternAtom(display, "_WM_BAR_HEIGHT", False); wm_bar_font_atom = XInternAtom(display, "_WM_BAR_FONT", False); wm_bar_showempty_atom = XInternAtom(display, "_WM_BAR_SHOWEMPTY", False); net_wm_name_atom = XInternAtom(display, "_NET_WM_NAME", False); utf8_string_atom = XInternAtom(display, "UTF8_STRING", False); #endif #ifdef MASTERSTACK wm_gap_inner_atom = XInternAtom(display, "_WM_GAP_INNER", False); wm_gap_outer_atom = XInternAtom(display, "_WM_GAP_OUTER", False); wm_gap_top_atom = XInternAtom(display, "_WM_GAP_TOP", False); #endif XSelectInput(display, root_window, SubstructureNotifyMask | StructureNotifyMask); track_windows(display, root_window); #ifdef XINERAMA monitor_count = xinerama_init(display, root_window); if (monitor_count < 1) monitor_count = 1; if (monitor_count > max_monitors) monitor_count = max_monitors; #endif ewmh_init(display, root_window); ewmh_sync(display, root_window, windows, window_workspace, window_count); #ifdef BAR bar_init(display, root_window); { char *nf, *nb, *sf, *sb, *sa; nf = read_root_string_property(display, root_window, wm_bar_nf_atom); nb = read_root_string_property(display, root_window, wm_bar_nb_atom); sf = read_root_string_property(display, root_window, wm_bar_sf_atom); sb = read_root_string_property(display, root_window, wm_bar_sb_atom); sa = read_root_string_property(display, root_window, wm_bar_sa_atom); bar_set_colors(nf, nb, sf, sb, sa); free(nf); free(nb); free(sf); free(sb); free(sa); } bar_set_margins(read_root_int_property(display, root_window, wm_bar_margin_x_atom, 0), read_root_int_property(display, root_window, wm_bar_margin_y_atom, 0)); bar_set_bottom(read_root_int_property(display, root_window, wm_bar_bottom_atom, 0) ? 1 : 0); bar_set_height(read_root_int_property(display, root_window, wm_bar_height_atom, 18)); bar_set_show_empty(read_root_int_property(display, root_window, wm_bar_showempty_atom, 1)); { char *font_name; font_name = read_root_string_property(display, root_window, wm_bar_font_atom); if (font_name != NULL) { bar_set_font(font_name); free(font_name); } } refresh_bar(display); #endif #ifdef MASTERSTACK tile_masterstack_set_gaps( read_root_int_property(display, root_window, wm_gap_inner_atom, 0), read_root_int_property(display, root_window, wm_gap_outer_atom, 0)); tile_masterstack_set_top_gap( read_root_int_property(display, root_window, wm_gap_top_atom, 0)); #endif grab_button_variants(display, 1, 0, root_window, GrabModeSync); grab_button_variants(display, 1, mod_key, root_window, GrabModeAsync); grab_button_variants(display, 3, mod_key, root_window, GrabModeAsync); for (;;) { XNextEvent(display, &event); if (event.type == ClientMessage && event.xclient.message_type == control_atom) { int command; #if defined(BAR) || defined(MASTERSTACK) int value; #endif command = (int)event.xclient.data.l[0]; i = (int)event.xclient.data.l[1]; #if defined(BAR) || defined(MASTERSTACK) value = (int)event.xclient.data.l[1]; #endif #ifdef BAR if (command == cmd_bar_position) { bar_set_bottom(value ? 1 : 0); write_root_int_property(display, root_window, wm_bar_bottom_atom, value ? 1 : 0); refresh_bar(display); continue; } else if (command == cmd_bar_height) { bar_set_height(value); write_root_int_property(display, root_window, wm_bar_height_atom, value); refresh_bar(display); continue; } else if (command == cmd_bar_showempty) { int show_empty; show_empty = read_root_int_property(display, root_window, wm_bar_showempty_atom, 1); show_empty = show_empty ? 0 : 1; bar_set_show_empty(show_empty); write_root_int_property(display, root_window, wm_bar_showempty_atom, show_empty); refresh_bar(display); continue; } else if (command == cmd_bar_margin_x) { bar_set_margins(value, -1); write_root_int_property(display, root_window, wm_bar_margin_x_atom, value); refresh_bar(display); continue; } else if (command == cmd_bar_margin_y) { bar_set_margins(-1, value); write_root_int_property(display, root_window, wm_bar_margin_y_atom, value); refresh_bar(display); continue; } else if (command == cmd_bar_font || command == cmd_bar_nf || command == cmd_bar_nb || command == cmd_bar_sf || command == cmd_bar_sb || command == cmd_bar_sa) { Atom source_atom; Atom actual_type; int actual_format; unsigned long nitems, bytes_after; unsigned char *prop_data; source_atom = (Atom)event.xclient.data.l[1]; prop_data = NULL; if (XGetWindowProperty(display, root_window, source_atom, 0, 256, False, XA_STRING, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data) == Success && prop_data != NULL && actual_type == XA_STRING && actual_format == 8 && nitems > 0) { if (command == cmd_bar_font) { bar_set_font((char *)prop_data); write_root_string_property(display, root_window, wm_bar_font_atom, (char *)prop_data); } else if (command == cmd_bar_nf) { bar_set_colors((char *)prop_data, NULL, NULL, NULL, NULL); write_root_string_property(display, root_window, wm_bar_nf_atom, (char *)prop_data); } else if (command == cmd_bar_nb) { bar_set_colors(NULL, (char *)prop_data, NULL, NULL, NULL); write_root_string_property(display, root_window, wm_bar_nb_atom, (char *)prop_data); } else if (command == cmd_bar_sf) { bar_set_colors(NULL, NULL, (char *)prop_data, NULL, NULL); write_root_string_property(display, root_window, wm_bar_sf_atom, (char *)prop_data); } else if (command == cmd_bar_sb) { bar_set_colors(NULL, NULL, NULL, (char *)prop_data, NULL); write_root_string_property(display, root_window, wm_bar_sb_atom, (char *)prop_data); } else if (command == cmd_bar_sa) { bar_set_colors(NULL, NULL, NULL, NULL, (char *)prop_data); write_root_string_property(display, root_window, wm_bar_sa_atom, (char *)prop_data); } refresh_bar(display); } if (prop_data != NULL) XFree(prop_data); XDeleteProperty(display, root_window, source_atom); continue; } #endif #ifdef MASTERSTACK if (command == cmd_gap_inner) { tile_masterstack_set_gaps(value, -1); write_root_int_property(display, root_window, wm_gap_inner_atom, value); apply_layout(display, root_window); continue; } else if (command == cmd_gap_outer) { tile_masterstack_set_gaps(-1, value); write_root_int_property(display, root_window, wm_gap_outer_atom, value); apply_layout(display, root_window); continue; } else if (command == cmd_gap_top) { tile_masterstack_set_top_gap(value); write_root_int_property(display, root_window, wm_gap_top_atom, value); apply_layout(display, root_window); continue; } #endif if (command == cmd_kill) { XGetInputFocus(display, &focused_window, &j); if (!is_root_child(display, root_window, focused_window)) continue; XKillClient(display, focused_window); } else if (command == cmd_tile_focused) { XGetInputFocus(display, &focused_window, &j); if (!is_root_child(display, root_window, focused_window)) continue; j = get_window_index(focused_window); if (j >= 0) { int mon; mon = monitor_for_window(display, root_window, focused_window); window_floating[j] = 0; window_workspace[j] = current_workspace[mon]; apply_layout(display, root_window); ewmh_sync(display, root_window, windows, window_workspace, window_count); #ifdef BAR refresh_bar(display); #endif } } else if (command == cmd_reload) { #ifdef BAR bar_cleanup(); #endif XCloseDisplay(display); execvp(argv[0], argv); return 1; } else if (i >= 0 && i < num_workspaces) { if (command == cmd_workspace) { int mon; mon = active_monitor(display, root_window); if (i == current_workspace[mon]) continue; track_windows(display, root_window); current_workspace[mon] = i; show_workspace(display, root_window, mon); apply_layout(display, root_window); ewmh_set_current_desktop(display, root_window, current_workspace[mon]); ewmh_sync(display, root_window, windows, window_workspace, window_count); #ifdef BAR refresh_bar(display); #endif } else if (command == cmd_move) { XGetInputFocus(display, &focused_window, &j); if (!is_root_child(display, root_window, focused_window)) continue; ewmh_set_active_window(display, root_window, focused_window); j = get_window_index(focused_window); if (j >= 0) { int mon; mon = monitor_for_window(display, root_window, focused_window); window_workspace[j] = i; window_floating[j] = 0; if (i != current_workspace[mon]) XUnmapWindow(display, focused_window); apply_layout(display, root_window); ewmh_sync(display, root_window, windows, window_workspace, window_count); #ifdef BAR refresh_bar(display); #endif } } } } else if (event.type == DestroyNotify) { remove_window(event.xdestroywindow.window); apply_layout(display, root_window); ewmh_sync(display, root_window, windows, window_workspace, window_count); #ifdef BAR refresh_bar(display); #endif } else if (event.type == MapNotify) { Window mapped_window; mapped_window = event.xmap.window; if (!is_managed_window(display, root_window, mapped_window)) continue; if (find_window_index(mapped_window) < 0) { int mon; place_window_at_pointer(display, root_window, mapped_window); select_window_events(display, mapped_window); get_window_index(mapped_window); mon = monitor_for_window(display, root_window, mapped_window); j = find_window_index(mapped_window); if (j >= 0) { window_workspace[j] = current_workspace[mon]; window_floating[j] = 0; } apply_layout(display, root_window); ewmh_sync(display, root_window, windows, window_workspace, window_count); #ifdef BAR refresh_bar(display); #endif } } else if (event.type == ButtonPress && event.xbutton.subwindow != None) { drag_window = event.xbutton.subwindow; if (!is_managed_window(display, root_window, drag_window)) { if (!(event.xbutton.state & mod_key)) XAllowEvents(display, ReplayPointer, event.xbutton.time); continue; } ewmh_set_active_window(display, root_window, drag_window); XSetInputFocus(display, drag_window, RevertToPointerRoot, CurrentTime); j = get_window_index(drag_window); if (j >= 0) { int mon; mon = monitor_for_window(display, root_window, drag_window); window_workspace[j] = current_workspace[mon]; if ((event.xbutton.state & mod_key) && (event.xbutton.button == 1 || event.xbutton.button == 3)) { window_floating[j] = 1; apply_layout(display, root_window); } } ewmh_sync(display, root_window, windows, window_workspace, window_count); #ifdef BAR refresh_bar(display); #endif if (!(event.xbutton.state & mod_key) && event.xbutton.button == 1) { XAllowEvents(display, ReplayPointer, event.xbutton.time); continue; } if (!(event.xbutton.state & mod_key)) continue; XGrabPointer(display, drag_window, True, PointerMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); get_window_attrs(display, drag_window, &window_attrs); drag_start = event.xbutton; if (drag_start.button == 3) { drag_start.x_root = window_attrs.x + window_attrs.width - 1; drag_start.y_root = window_attrs.y + window_attrs.height - 1; XWarpPointer(display, None, root_window, 0, 0, 0, 0, drag_start.x_root, drag_start.y_root); } is_dragging = 1; } else if (event.type == ButtonPress && event.xbutton.subwindow == None) { XAllowEvents(display, AsyncPointer, event.xbutton.time); } else if (event.type == EnterNotify && event.xcrossing.window != None) { Window hover_window; hover_window = event.xcrossing.window; if (event.xcrossing.mode != NotifyNormal || event.xcrossing.detail == NotifyInferior) continue; if (!is_managed_window(display, root_window, hover_window)) continue; XSetInputFocus(display, hover_window, RevertToPointerRoot, CurrentTime); ewmh_set_active_window(display, root_window, hover_window); #ifdef BAR refresh_bar(display); #endif } else if (event.type == PropertyNotify) { #ifdef BAR if (event.xproperty.state == PropertyNewValue && (event.xproperty.atom == net_wm_name_atom || event.xproperty.atom == XA_WM_NAME)) refresh_bar(display); #endif } else if (event.type == MotionNotify && is_dragging) { int x_diff, y_diff; while (XCheckTypedEvent(display, MotionNotify, &event)) continue; x_diff = event.xmotion.x_root - drag_start.x_root; y_diff = event.xmotion.y_root - drag_start.y_root; XMoveResizeWindow(display, drag_window, window_attrs.x + (drag_start.button == 1 ? x_diff : 0), window_attrs.y + (drag_start.button == 1 ? y_diff : 0), max_val(1, window_attrs.width + (drag_start.button == 3 ? x_diff : 0)), max_val(1, window_attrs.height + (drag_start.button == 3 ? y_diff : 0))); } else if (event.type == ButtonRelease) { is_dragging = 0; drag_window = None; XUngrabPointer(display, CurrentTime); } else if (event.type == ConfigureNotify && event.xconfigure.window == root_window) { #ifdef XINERAMA monitor_count = xinerama_init(display, root_window); if (monitor_count < 1) monitor_count = 1; if (monitor_count > max_monitors) monitor_count = max_monitors; #endif #ifdef BAR bar_reconfigure(); #endif } } }