void map_client(client_t *c) { XWindowAttributes attr; strut_t s = { 0, 0, 0, 0 }; XWMHints *hints; int btn, want_raise = 1; XGrabServer(dpy); XGetWindowAttributes(dpy, c->win, &attr); collect_struts(c, &s); if (attr.map_state == IsViewable) { c->ignore_unmap++; reparent(c, &s); if (get_wm_state(c->win) == IconicState) { c->ignore_unmap++; XUnmapWindow(dpy, c->win); } else { set_wm_state(c, NormalState); do_map(c, want_raise); } } else { if ((hints = XGetWMHints(dpy, c->win))) { if (hints->flags & StateHint) set_wm_state(c, hints->initial_state); XFree(hints); } else { set_wm_state(c, NormalState); } if (!init_geom(c, &s) && opt_imap) { btn = sweep(c, map_curs, recalc_map, SWEEP_DOWN, &s); if (btn == Button2) btn = sweep(c, resize_curs, recalc_resize, SWEEP_UP, &s); if (btn == Button3) want_raise = 0; } #ifdef DEBUG dump_geom(c, "set to"); dump_info(c); #endif reparent(c, &s); if (get_wm_state(c->win) == NormalState) do_map(c, want_raise); } XSync(dpy, False); c->name = get_wm_name(c->win); // horrible kludge XUngrabServer(dpy); }
void remove_client(Client *c) { Client *p; LOG_DEBUG("remove_client() : Removing...\n"); if (!c || !c->xstuff) return; XGrabServer(dpy); ignore_xerror = 1; /* ICCCM 4.1.3.1 * "When the window is withdrawn, the window manager will either * change the state field's value to WithdrawnState or it will * remove the WM_STATE property entirely." * EWMH 1.3 * "The Window Manager should remove the property whenever a * window is withdrawn but it should leave the property in * place when it is shutting down." (both _NET_WM_DESKTOP and * _NET_WM_STATE) */ if (c->remove) { LOG_DEBUG("\tremove_client() : setting WithdrawnState\n"); set_wm_state(c, WithdrawnState); XDeleteProperty(dpy, c->xstuff->window, xa_net_wm_desktop); XDeleteProperty(dpy, c->xstuff->window, xa_net_wm_state); } ungravitate(c); if (c->xstuff->screen) XReparentWindow(dpy, c->xstuff->window, c->xstuff->screen->root, c->x, c->y); XSetWindowBorderWidth(dpy, c->xstuff->window, c->old_border); XRemoveFromSaveSet(dpy, c->xstuff->window); if (c->xstuff->parent) XDestroyWindow(dpy, c->xstuff->parent); if (head_client == c) head_client = c->next; else for (p = head_client; p && p->next; p = p->next) if (p->next == c) p->next = c->next; if (current == c) current = NULL; /* an enter event should set this up again */ free(c->xstuff); free(c); #ifdef DEBUG { Client *pp; int i = 0; for (pp = head_client; pp; pp = pp->next) i++; LOG_DEBUG("\tremove_client() : free(), window count now %d\n", i); } #endif XUngrabServer(dpy); XFlush(dpy); ignore_xerror = 0; LOG_DEBUG("remove_client() returning\n"); }
void del_client(client_t *c, int mode) { client_t *p; XGrabServer(dpy); XSetErrorHandler(ignore_xerror); #ifdef DEBUG dump_name(c, "removing", 'r'); dump_removal(c, mode); #endif if (mode == DEL_WITHDRAW) { set_wm_state(c, WithdrawnState); } else /* mode == DEL_REMAP */ { if (c->zoomed) { c->geom.x = c->save.x; c->geom.y = c->save.y; c->geom.w = c->save.w; c->geom.h = c->save.h; XResizeWindow(dpy, c->win, c->geom.w, c->geom.h); } XMapWindow(dpy, c->win); } remove_atom(root, net_client_list, XA_WINDOW, c->win); remove_atom(root, net_client_stack, XA_WINDOW, c->win); XSetWindowBorderWidth(dpy, c->win, c->old_bw); #ifdef XFT if (c->xftdraw) XftDrawDestroy(c->xftdraw); #endif XReparentWindow(dpy, c->win, root, c->geom.x, c->geom.y); XRemoveFromSaveSet(dpy, c->win); XDestroyWindow(dpy, c->frame); if (head == c) head = c->next; else for (p = head; p && p->next; p = p->next) if (p->next == c) p->next = c->next; if (c->name) XFree(c->name); free(c); XSync(dpy, False); XSetErrorHandler(handle_xerror); XUngrabServer(dpy); }
void remove_client(Client *c, int from_cleanup) { Client *p = NULL; XGrabServer(dpy); XSetErrorHandler(ignore_xerror); if (c->name && c->name != null_str) XFree(c->name); if (from_cleanup) unhide(c, NO_RAISE); else if (!from_cleanup) set_wm_state(c, WithdrawnState); ungravitate(c); XReparentWindow(dpy, c->window, root, c->x, c->y); XRemoveFromSaveSet(dpy, c->window); XSetWindowBorderWidth(dpy, c->window, 1); XDestroyWindow(dpy, c->parent); if (head_client == c) head_client = c->next; else { for (p = head_client; p && p->next; p = p->next) if (p->next == c) p->next = c->next; } if (c->size) XFree(c->size); /* an enter event should set this up again */ if (c == current) { current = NULL; if (prev_focused[c->vdesk] == c) prev_focused[c->vdesk] = NULL; } free(c); XSync(dpy, False); XSetErrorHandler(handle_xerror); XUngrabServer(dpy); }
/** Changes the EWMH state of the window */ static void set_wm_state (vout_window_t *wnd, bool on, xcb_atom_t state) { vout_window_sys_t *sys = wnd->sys; /* From EWMH "_WM_STATE" */ xcb_client_message_event_t ev = { .response_type = XCB_CLIENT_MESSAGE, .format = 32, .window = wnd->handle.xid, .type = sys->wm_state, }; ev.data.data32[0] = on ? NET_WM_STATE_ADD : NET_WM_STATE_REMOVE; ev.data.data32[1] = state; ev.data.data32[2] = 0; ev.data.data32[3] = 1; /* From ICCCM "Changing Window State" */ xcb_send_event (sys->conn, 0, sys->root, XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&ev); } static int Control (vout_window_t *wnd, int cmd, va_list ap) { vout_window_sys_t *p_sys = wnd->sys; xcb_connection_t *conn = p_sys->conn; switch (cmd) { case VOUT_WINDOW_SET_SIZE: { if (p_sys->embedded) return VLC_EGENERIC; unsigned width = va_arg (ap, unsigned); unsigned height = va_arg (ap, unsigned); const uint32_t values[] = { width, height, }; xcb_configure_window (conn, wnd->handle.xid, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); break; } case VOUT_WINDOW_SET_STATE: { unsigned state = va_arg (ap, unsigned); bool above = (state & VOUT_WINDOW_STATE_ABOVE) != 0; bool below = (state & VOUT_WINDOW_STATE_BELOW) != 0; set_wm_state (wnd, above, p_sys->wm_state_above); set_wm_state (wnd, below, p_sys->wm_state_below); break; } case VOUT_WINDOW_SET_FULLSCREEN: { bool fs = va_arg (ap, int); if (!fs && var_GetBool (wnd, "video-wallpaper")) return VLC_EGENERIC; set_wm_state (wnd, fs, p_sys->wm_state_fullscreen); break; } default: msg_Err (wnd, "request %d not implemented", cmd); return VLC_EGENERIC; } xcb_flush (p_sys->conn); return VLC_SUCCESS; }
void make_new_client(Window w) { Client *c, *p; XWindowAttributes attr; long dummy; XWMHints *hints; XSizeHints* shints; XGrabServer(dpy); XSetErrorHandler(ignore_xerror); hints = XGetWMHints(dpy, w); shints = XAllocSizeHints(); XGetWMNormalHints(dpy, w, shints, &dummy); c = (Client *)calloc(1, sizeof(Client)); c->next = head_client; head_client = c; c->window = w; c->name = null_str; /* try these here instead */ c->size = shints; XClassHint* hint = XAllocClassHint(); XGetClassHint(dpy, w, hint); if (hint->res_class) { c->name = hint->res_class; if (hint->res_name) XFree(hint->res_name); } XFree(hint); XGetWindowAttributes(dpy, c->window, &attr); c->x = attr.x; c->y = attr.y; c->width = attr.width; c->height = attr.height; c->border = opt_bw; c->oldw = c->oldh = 0; c->vdesk = vdesk; c->index = 0; if (!(attr.map_state == IsViewable)) { init_position(c); if (hints && hints->flags & StateHint) set_wm_state(c, hints->initial_state); } if (hints) XFree(hints); /* client is initialised */ gravitate(c); reparent(c); XGrabButton(dpy, AnyButton, Mod1Mask, c->parent, False, ButtonMask, GrabModeSync, GrabModeAsync, None, None); XGrabButton(dpy, AnyButton, 0, c->parent, False, ButtonPressMask, GrabModeSync, GrabModeAsync, None, None); XMapWindow(dpy, c->window); XMapRaised(dpy, c->parent); set_wm_state(c, NormalState); XSync(dpy, False); XSetErrorHandler(handle_xerror); XUngrabServer(dpy); throwUnmaps = 0; again: for (p = c->next; p; p = p->next) { if (c->index == p->index && !strcmp(c->name, p->name)) { c->index++; goto again; } } }
void handle_event(XEvent *ev) { client *c = owner(ev->xany.window); #ifdef DEBUG_EVENTS if(ev->type != Expose && ev->type != MotionNotify && !(ev->type == ConfigureNotify && ev->xconfigure.window != root)) /* this makes the output slightly more manageable */ printf(NAME ": handle_event(): got %s\n\twindow: 0x%X (%s)\n", event_name(ev), (unsigned int) ev->xany.window, c ? c->name : ((ev->xany.window == root) ? "root" : "unknown")); #endif if((evh && evh(ev)) || button_handle_event(ev) || ewmh_handle_event(ev) || screens_handle_event(ev)) { #ifdef DEBUG_EVENTS if(ev->type != Expose && ev->type != MotionNotify && (ev->type != ConfigureNotify && ev->xconfigure.window != root)) printf(NAME ": handle_event(): external event handler claimed last event\n"); #endif return; } if(c) { if(!has_child(c->parent, c->window) && ev->type != DestroyNotify && ev->type != UnmapNotify) return; switch(ev->type) { case UnmapNotify: if(c->window == ev->xunmap.window) { #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling UnmapNotify event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name); #endif if(has_child(c->parent, c->window)) { client_deparent(c); set_wm_state(c->window, WithdrawnState); } client_remove(c); ewmh_update_clist(); } return; case PropertyNotify: if(ev->xproperty.atom == XA_WM_NAME) { #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling PropertyNotify event\n\twindow: 0x%X (%s)\n\tproperty: XA_WM_NAME\n", (unsigned int) c->window, c->name); #endif if(c->name != no_title) XFree(c->name); #ifdef USE_XFT if(xftfont) XftDrawDestroy(c->title_draw); #endif XFreePixmap(dpy, c->title_pixmap); XFetchName(dpy, c->window, &c->name); client_update_name(c); XClearWindow(dpy, c->title); if(evh == wlist_handle_event) { XClearWindow(dpy, c->wlist_item); wlist_item_draw(c); } } if(ev->xproperty.atom == XA_WM_NORMAL_HINTS) { #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling PropertyNotify event\n\twindow: 0x%X (%s)\n\tproperty: XA_WM_NORMAL_HINTS\n", (unsigned int) c->window, c->name); #endif get_normal_hints(c); } return; case ClientMessage: if(ev->xclient.message_type == xa_wm_change_state && ev->xclient.data.l[0] == IconicState) { #ifdef DEBUG_EVENTS printf(NAME ": handling ClientMessage event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name); #endif client_iconify(c); return; } break; /* we might later need this event */ case EnterNotify: if(c != current && !(c->flags & CLICK_FOCUS) && !click_focus && ev->xcrossing.mode != NotifyGrab && ev->xcrossing.mode != NotifyUngrab && ev->xcrossing.detail != NotifyInferior && (ev->xcrossing.window == c->parent || ev->xcrossing.window == c->wlist_item) && ev->xcrossing.send_event == False) { #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling EnterNotify event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name); #endif client_focus(c, true); } return; case Expose: if(ev->xexpose.count == 0 && evh == wlist_handle_event && c && ev->xexpose.window == c->wlist_item) wlist_item_draw(c); return; case ButtonPress: #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling ButtonPress event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name); #endif if(c != current) client_focus(c, true); XAllowEvents(dpy, ReplayPointer, CurrentTime); if(ev->xbutton.window != c->window) { if(lastclick + doubleclick_time > ev->xbutton.time && lastbutton == ev->xbutton.button && lastclick_client == c) { client_action(c, buttonaction(ev->xbutton.button, true), ev); lastclick = 0; lastclick_client = NULL; lastbutton = None; return; } lastclick = ev->xbutton.time; lastclick_client = c; lastbutton = ev->xbutton.button; client_action(c, buttonaction(ev->xbutton.button, false), ev); } else if(click_raise) client_raise(c); return; case FocusIn: /* we ignore pointer events, these happen if the input focus is on the root window */ if(allow_focus_stealing && c != current && ev->xfocus.mode != NotifyGrab && ev->xfocus.mode != NotifyUngrab && ev->xfocus.detail != NotifyPointer) { #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling FocusIn event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name); #endif client_focus(c, false); } return; case FocusOut: if(c == current && ev->xfocus.mode != NotifyGrab && ev->xfocus.mode != NotifyUngrab && ev->xfocus.detail != NotifyInferior) { #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling FocusOut event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name); #endif if(allow_focus_stealing && ev->xfocus.detail != NotifyAncestor) { #ifdef DEBUG_EVENTS printf("\tfocus lost\n"); #endif client_focus(NULL, false); /* we do this so windows that aren't managed can take focus */ } else { #ifdef DEBUG_EVENTS printf("\tre-focussing this window\n"); #endif take_focus(c); } } return; #ifdef USE_SHAPE default: if(ev->type == shape_event) { #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling ShapeNotify event\n\twindow 0x%X (%s)\n", (unsigned int) c->window, c->name); #endif set_shape(c); return; } #endif } } switch(ev->type) { case MapRequest: c = owner(ev->xmaprequest.window); #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling MapRequest event\n\twindow: 0x%X (%s)\n", (unsigned int) ev->xmaprequest.window, c ? c->name : "unknown"); #endif if(c) { if(c->flags & ICONIC && has_child(c->parent, c->window)) { client_restore(c); if(focus_new) client_focus(c, true); } } else if(has_child(root, ev->xmaprequest.window)) client_add(ev->xmaprequest.window, false); return; case DestroyNotify: c = owner(ev->xdestroywindow.window); if(c) if(c->window == ev->xdestroywindow.window) { #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling DestroyNotify event\n\twindow 0x%X (%s)\n", (unsigned int) c->window, c->name); #endif client_remove(c); } return; case ConfigureRequest: c = owner(ev->xconfigurerequest.window); #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling ConfigureRequest event\n\twindow 0x%X (%s)\n", (unsigned int) ev->xconfigurerequest.window, c ? c->name : "unknown"); #endif if(correct_center) screens_correct_center(&ev->xconfigurerequest.x, &ev->xconfigurerequest.y, &ev->xconfigurerequest.width, &ev->xconfigurerequest.height); if(c) { if(!has_child(c->parent, c->window)) return; if(ev->xconfigurerequest.value_mask & CWX) c->x = ev->xconfigurerequest.x - gxo(c, false); if(ev->xconfigurerequest.value_mask & CWY) c->y = ev->xconfigurerequest.y - gyo(c, false); if(ev->xconfigurerequest.value_mask & CWWidth) c->width = ev->xconfigurerequest.width; if(ev->xconfigurerequest.value_mask & CWHeight) c->height = ev->xconfigurerequest.height; client_update(c); #ifdef DEBUG printf(NAME ": handle_event(): reconfigured client 0x%X (%s) to %ix%i+%i+%i\n", (unsigned int) c->window, c->name, c->width, c->height, c->x, c->y); #endif } else if(has_child(root, ev->xconfigurerequest.window)) { XWindowChanges wc; wc.sibling = ev->xconfigurerequest.above; wc.stack_mode = ev->xconfigurerequest.detail; wc.x = ev->xconfigurerequest.x; wc.y = ev->xconfigurerequest.y; wc.width = ev->xconfigurerequest.width; wc.height = ev->xconfigurerequest.height; XConfigureWindow(dpy, ev->xconfigurerequest.window, ev->xconfigurerequest.value_mask, &wc); } return; case MapNotify: if(correct_center_unmanaged && ev->xany.window == root && !owner(ev->xmap.window)) { #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling MapNotify event\n\twindow 0x%X (unknown)\n", (unsigned int) ev->xmap.window); #endif window_correct_center(ev->xmap.window); } return; case MappingNotify: if(ev->xmapping.request != MappingPointer) { #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling MappingNotify event\n"); #endif keys_ungrab(); XRefreshKeyboardMapping(&ev->xmapping); keys_update(); } return; case KeyPress: #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling KeyPress event\n"); #endif client_action(current, keyaction(ev), ev); return; case ButtonPress: if(ev->xbutton.window != root) return; #ifdef DEBUG_EVENTS printf(NAME ": handle_event(): handling ButtonPress event\n"); #endif if(lastclick + doubleclick_time > ev->xbutton.time && lastbutton == ev->xbutton.button && lastclick_client == NULL) { client_action(current, root_buttonaction(ev->xbutton.button, true), ev); lastclick = 0; lastclick_client = NULL; lastbutton = None; return; } lastclick = ev->xbutton.time; lastclick_client = NULL; lastbutton = ev->xbutton.button; client_action(current, root_buttonaction(ev->xbutton.button, false), ev); return; case ClientMessage: if(ev->xclient.message_type == xa_internal_message) { if(((Atom) ev->xclient.data.l[0]) == xa_quit) { #ifdef DEBUG printf(NAME ": handle_event(): quit message received\n"); #endif exit(0); } if(((Atom) ev->xclient.data.l[0]) == xa_reinit) { #ifdef DEBUG printf(NAME ": handle_event(): reinitialize message received\n"); #endif cfg_reinitialize(); } } } }