#include "unmap_all.h" #include // for Window, None, IsUnmapped #include // for XFree, XGetWindowAttributes, XMapWindow #include // for XmuClientWindow #include // for XClassHint, XGetClassHint #include // for NULL, strcmp int InitUnmapAllWindowsState(UnmapAllWindowsState* state, Display* display, Window root_window, const Window* ignored_windows, unsigned int n_ignored_windows, const char* my_res_class, const char* my_res_name, int include_frame) { int should_proceed = 1; state->display = display; state->root_window = root_window; state->windows = NULL; state->n_windows = 0; Window unused_root_return, unused_parent_return; XQueryTree(state->display, state->root_window, &unused_root_return, &unused_parent_return, &state->windows, &state->n_windows); state->first_unmapped_window = state->n_windows; // That means none unmapped. for (unsigned int i = 0; i < state->n_windows; ++i) { XWindowAttributes xwa; XGetWindowAttributes(display, state->windows[i], &xwa); // Not mapped -> nothing to do. if (xwa.map_state == IsUnmapped) { state->windows[i] = None; continue; } // Go down to the next WM_STATE window if available, as unmapping window // frames may confuse WMs. if (!include_frame) { state->windows[i] = XmuClientWindow(display, state->windows[i]); } // If any window we'd be unmapping is in the ignore list, skip it. for (unsigned int j = 0; j < n_ignored_windows; ++j) { if (state->windows[i] == ignored_windows[j]) { state->windows[i] = None; } } if (state->windows[i] == None) { continue; } XClassHint cls; if (XGetClassHint(state->display, state->windows[i], &cls)) { // If any window has my window class, we better not proceed with // unmapping as doing so could accidentally unlock the screen or // otherwise cause more damage than good. if ((my_res_class || my_res_name) && (!my_res_class || strcmp(my_res_class, cls.res_class) == 0) && (!my_res_name || strcmp(my_res_name, cls.res_name) == 0)) { state->windows[i] = None; should_proceed = 0; } // HACK: Bspwm creates some subwindows of the root window that we // absolutely shouldn't ever unmap, as remapping them confuses Bspwm. if (!strcmp(cls.res_class, "Bspwm")) { state->windows[i] = None; } XFree(cls.res_class); cls.res_class = NULL; XFree(cls.res_name); cls.res_name = NULL; } } return should_proceed; } int UnmapAllWindows(UnmapAllWindowsState* state, int (*just_unmapped_can_we_stop)(Window w, void* arg), void* arg) { if (state->first_unmapped_window == 0) { // Already all unmapped. return 0; } for (unsigned int i = state->first_unmapped_window - 1;; --i) { // Top-to-bottom order! if (state->windows[i] != None) { XUnmapWindow(state->display, state->windows[i]); state->first_unmapped_window = i; int ret; if (just_unmapped_can_we_stop != NULL && (ret = just_unmapped_can_we_stop(state->windows[i], arg))) { return ret; } } if (i == 0) { return 0; } } } void RemapAllWindows(UnmapAllWindowsState* state) { for (unsigned int i = state->first_unmapped_window; i < state->n_windows; ++i) { if (state->windows[i] != None) { XMapWindow(state->display, state->windows[i]); } } state->first_unmapped_window = state->n_windows; } void ClearUnmapAllWindowsState(UnmapAllWindowsState* state) { state->display = NULL; state->root_window = None; XFree(state->windows); state->windows = NULL; state->n_windows = 0; state->first_unmapped_window = 0; }