// event handler implementations void configurerequest(XEvent* event) { XConfigureRequestEvent* cre = &event->xconfigurerequest; Client* client = get_client_from_window(cre->window); if (client) { XConfigureEvent ce; ce.type = ConfigureNotify; ce.display = gDisplay; ce.event = cre->window; ce.window = cre->window; ce.x = client->last_size.x; ce.y = client->last_size.y; ce.width = client->last_size.width; ce.height = client->last_size.height; ce.override_redirect = False; ce.border_width = cre->border_width; ce.above = cre->above; XSendEvent(gDisplay, cre->window, False, StructureNotifyMask, (XEvent*)&ce); } else { // if client not known.. then allow configure. // its probably a nice conky or dzen2 bar :) XWindowChanges wc; wc.x = cre->x; wc.y = cre->y; wc.width = cre->width; wc.height = cre->height; wc.border_width = cre->border_width; wc.sibling = cre->above; wc.stack_mode = cre->detail; XConfigureWindow(gDisplay, cre->window, cre->value_mask, &wc); } }
void set_floating(const Arg *arg){ Window win = frame_focused_window(g_cur_frame); if (!win) return; Client *client = get_client_from_window(win); if (!client) return; client_set_floating(client, !client->floating); }
void window_focus(Window window) { window_unfocus(lastfocus); XSetWindowBorder(gDisplay, window, wincolors[1][ColWindowBorder]); if(!get_client_from_window(window)->neverfocus) XSetInputFocus(gDisplay, window, RevertToPointerRoot, CurrentTime); lastfocus = window; }
void mapnotify(XEvent* event) { Client* c; if ((c = get_client_from_window(event->xmap.window))) { // reset focus. so a new window gets the focus if it shall have the input focus frame_focus_recursive(g_cur_frame); // also update the window title - just to be sure client_update_title(c); } }
void mouse_handle_event(XEvent* ev) { XButtonEvent* be = &(ev->xbutton); MouseBinding* b = mouse_binding_find(be->state, be->button); HSClient* client = get_client_from_window(ev->xbutton.window); if (!b || !client) { // there is no valid bind for this type of mouse event return; } b->action(client, b->argc, b->argv); }
void window_focus(Window window) { HSClient* client = get_client_from_window(window); assert(client != NULL); // set keyboard focus if (!client->neverfocus) { XSetInputFocus(g_display, window, RevertToPointerRoot, CurrentTime); } else client_sendevent(client, g_wmatom[WMTakeFocus]); if (window != lastfocus) { /* FIXME: this is a workaround because window_focus always is called * twice. see BUGS for more information * * only emit the hook if the focus *really* changes */ // unfocus last one window_unfocus(lastfocus); hsobject_link(g_client_object, &client->object, "focus"); ewmh_update_active_window(window); tag_update_each_focus_layer(); char* title = client ? client->title->str : "?"; char winid_str[STRING_BUF_SIZE]; snprintf(winid_str, STRING_BUF_SIZE, "0x%x", (unsigned int)window); hook_emit_list("focus_changed", winid_str, title, NULL); } // change window-colors HSDebug("window_focus ACTIVE\n"); window_update_border(window, g_window_border_active_color); lastfocus = window; /* do some specials for the max layout */ bool is_max_layout = frame_focused_window(g_cur_frame) == window && g_cur_frame->content.clients.layout == LAYOUT_MAX && get_current_monitor()->tag->floating == false; if (*g_raise_on_focus || is_max_layout) { client_raise(client); } tag_update_focus_layer(get_current_monitor()->tag); grab_client_buttons(get_client_from_window(window), true); client_set_urgent(client, false); }
void window_unfocus(Window window) { HSDebug("window_unfocus NORMAL\n"); window_update_border(window, g_window_border_normal_color); HSClient* c = get_client_from_window(window); if (c) { if (c->urgent) { HSDebug("window_unfocus URGENT\n"); window_update_border(window, g_window_border_urgent_color); } grab_client_buttons(c, false); } }
/** * \brief Resolve a window description to a client or a window id * * \param str Describes the window: "" means the focused one, "urgent" * resolves to a arbitrary urgent window, "0x..." just * resolves to the given window. * \param ret_client The client pointer is stored there if ret_client is * given and the specified window is managed. * \return The resolved window id is stored there if the according * window has been found */ Window string_to_client(char* str, HSClient** ret_client) { Window win = 0; if (!strcmp(str, "")) { win = frame_focused_window(g_cur_frame); if (ret_client) { *ret_client = get_client_from_window(win); } } else if (!strcmp(str, "urgent")) { HSClient* client = get_urgent_client(); if (client) { win = client->window; } if (ret_client) { *ret_client = client; } } else if (1 == sscanf(str, "0x%lx", (long unsigned int*)&win)) { if (ret_client) { *ret_client = get_client_from_window(win); } } return win; }
Client* manage_client(Window win) { if (get_client_from_window(win)) return NULL; // init client Client* client = create_client(); Monitor* m = get_current_monitor(); // set to window properties client->window = win; client_update_title(client); // apply rules int manage = 1; rules_apply(client, &manage); if (!manage) { destroy_client(client); // map it... just to be sure XMapWindow(gDisplay, win); return NULL; } unsigned int border, depth; Window root_win; int x, y; unsigned int w, h; XGetGeometry(gDisplay, win, &root_win, &x, &y, &w, &h, &border, &depth); // treat wanted coordinates as floating coords XRectangle size = client->float_size; size.width = w; size.height = h; size.x = m->rect.x + m->rect.width/2 - size.width/2; size.y = m->rect.y + m->rect.height/2 - size.height/2 + bar_height; client->float_size = size; client->last_size = size; XMoveResizeWindow(gDisplay, client->window, size.x, size.y, size.width, size.height); // actually manage it g_array_append_val(g_clients, client); XSetWindowBorderWidth(gDisplay, win, window_border_width); // insert to layout if (!client->tag) client->tag = m->tag; // get events from window client_update_wm_hints(client); XSelectInput(gDisplay, win, CLIENT_EVENT_MASK); window_grab_button(win); frame_insert_window(client->tag->frame, win); monitor_apply_layout(find_monitor_with_tag(client->tag)); return client; }
void event_on_configure(XEvent event) { XConfigureRequestEvent* cre = &event.xconfigurerequest; HSClient* client = get_client_from_window(cre->window); XConfigureEvent ce; ce.type = ConfigureNotify; ce.display = g_display; ce.event = cre->window; ce.window = cre->window; if (client) { bool changes = false; if (client->sizehints && !client->dragged) { cre->width += 2*cre->border_width - 2*client->last_border_width; cre->height += 2*cre->border_width - 2*client->last_border_width; if (client->float_size.width != cre->width) changes = true; if (client->float_size.height != cre->height) changes = true; client->float_size.width = cre->width; client->float_size.height = cre->height; ce.x = client->last_size.x; ce.y = client->last_size.y; ce.width = client->last_size.width; ce.height = client->last_size.height; ce.override_redirect = False; ce.border_width = cre->border_width; ce.above = cre->above; } if (changes && client->tag->floating) { client_resize_floating(client, find_monitor_with_tag(client->tag)); } else if (changes && client->pseudotile) { monitor_apply_layout(find_monitor_with_tag(client->tag)); } else { // FIXME: why send event and not XConfigureWindow or XMoveResizeWindow?? XSendEvent(g_display, cre->window, False, StructureNotifyMask, (XEvent*)&ce); } } else { // if client not known.. then allow configure. // its probably a nice conky or dzen2 bar :) XWindowChanges wc; wc.x = cre->x; wc.y = cre->y; wc.width = cre->width; wc.height = cre->height; wc.border_width = cre->border_width; wc.sibling = cre->above; wc.stack_mode = cre->detail; XConfigureWindow(g_display, cre->window, cre->value_mask, &wc); } }
void maprequest(XEvent* event) { XMapRequestEvent* mapreq = &event->xmaprequest; Client *c; if((c = wintosystrayicon(mapreq->window))) { resizebarwin(get_current_monitor()); updatesystray(); } if (!get_client_from_window(mapreq->window)) { // client should be managed (is not ignored but is not managed yet Client* client = manage_client(mapreq->window); if (client && find_monitor_with_tag(client->tag)) XMapWindow(gDisplay, mapreq->window); } }
void buttonpress(XEvent* event) { XButtonEvent* be = &(event->xbutton); HSDebug("name is: ButtonPress on sub %lx, win %lx\n", be->subwindow, be->window); if (mouse_binding_find(be->state, be->button)) { mouse_start_drag(event); } else { focus_window(be->window, false, true); if (*g_raise_on_click) { HSClient* client = get_client_from_window(be->window); if (client) { client_raise(client); } } } XAllowEvents(g_display, ReplayPointer, be->time); }
void event_on_configure(XEvent event) { XConfigureRequestEvent* cre = &event.xconfigurerequest; HSClient* client = get_client_from_window(cre->window); if (client) { bool changes = false; Rectangle newRect = client->float_size; if (client->sizehints_floating && (is_client_floated(client) || client->pseudotile)) { bool width_requested = 0 != (cre->value_mask & CWWidth); bool height_requested = 0 != (cre->value_mask & CWHeight); bool x_requested = 0 != (cre->value_mask & CWX); bool y_requested = 0 != (cre->value_mask & CWY); cre->width += 2*cre->border_width; cre->height += 2*cre->border_width; if (width_requested && newRect.width != cre->width) changes = true; if (height_requested && newRect.height != cre->height) changes = true; if (x_requested || y_requested) changes = true; if (x_requested) newRect.x = cre->x; if (y_requested) newRect.y = cre->y; if (width_requested) newRect.width = cre->width; if (height_requested) newRect.height = cre->height; } if (changes && is_client_floated(client)) { client->float_size = newRect; client_resize_floating(client, find_monitor_with_tag(client->tag)); } else if (changes && client->pseudotile) { client->float_size = newRect; monitor_apply_layout(find_monitor_with_tag(client->tag)); } else { // FIXME: why send event and not XConfigureWindow or XMoveResizeWindow?? client_send_configure(client); } } else { // if client not known.. then allow configure. // its probably a nice conky or dzen2 bar :) XWindowChanges wc; wc.x = cre->x; wc.y = cre->y; wc.width = cre->width; wc.height = cre->height; wc.border_width = cre->border_width; wc.sibling = cre->above; wc.stack_mode = cre->detail; XConfigureWindow(g_display, cre->window, cre->value_mask, &wc); } }
void unmanage_client(Window win) { Client* client = get_client_from_window(win); if (!client) return; // remove from tag frame_remove_window(client->tag->frame, win); // and arrange monitor Monitor* m = find_monitor_with_tag(client->tag); if (m) monitor_apply_layout(m); // ignore events from it XSelectInput(gDisplay, win, 0); XUngrabButton(gDisplay, AnyButton, AnyModifier, win); // permanently remove it for(int i=0; i<g_clients->len; i++){ if(g_array_index(g_clients, Client*, i) == client) g_array_remove_index(g_clients, i); } }
void enternotify(XEvent* event) { XCrossingEvent *ce = &event->xcrossing; HSDebug("name is: EnterNotify, focus = %d\n", event->xcrossing.focus); if (!mouse_is_dragging() && *g_focus_follows_mouse && false == ce->focus) { HSClient* c = get_client_from_window(ce->window); HSFrame* target; if (c && c->tag->floating == false && (target = find_frame_with_window(c->tag->frame, ce->window)) && target->content.clients.layout == LAYOUT_MAX && frame_focused_window(target) != ce->window) { // don't allow focus_follows_mouse if another window would be // hidden during that focus change (which only occurs in max layout) } else { focus_window(ce->window, false, true); } } }
void maprequest(XEvent* event) { HSDebug("name is: MapRequest\n"); XMapRequestEvent* mapreq = &event->xmaprequest; if (is_herbstluft_window(g_display, mapreq->window)) { // just map the window if it wants that XWindowAttributes wa; if (!XGetWindowAttributes(g_display, mapreq->window, &wa)) { return; } XMapWindow(g_display, mapreq->window); } else if (!get_client_from_window(mapreq->window)) { // client should be managed (is not ignored) // but is not managed yet HSClient* client = manage_client(mapreq->window); if (client && find_monitor_with_tag(client->tag)) { XMapWindow(g_display, mapreq->window); } } // else: ignore all other maprequests from windows // that are managed already }
void propertynotify(XEvent* event) { XPropertyEvent *ev = &event->xproperty; Client* client; if((client = wintosystrayicon(ev->window))) { if(ev->atom == XA_WM_NORMAL_HINTS) updatesystrayicongeom(client, client->last_size.width, client->last_size.height); resizebarwin(get_current_monitor()); updatesystray(); } if((ev->window == gRoot) && (ev->atom == XA_WM_NAME)) update_status(); if (ev->state == PropertyNewValue && (client = get_client_from_window(ev->window))) { if (ev->atom == XA_WM_HINTS) client_update_wm_hints(client); else if (ev->atom == XA_WM_NAME) client_update_title(client); } draw_bars(); }
void propertynotify(XEvent* event) { // printf("name is: PropertyNotify\n"); XPropertyEvent *ev = &event->xproperty; HSClient* client; if (ev->state == PropertyNewValue) { if (is_ipc_connectable(event->xproperty.window)) { ipc_handle_connection(event->xproperty.window); } else if((client = get_client_from_window(ev->window))) { if (ev->atom == XA_WM_HINTS) { client_update_wm_hints(client); } else if (ev->atom == XA_WM_NORMAL_HINTS) { updatesizehints(client); HSMonitor* m = find_monitor_with_tag(client->tag); if (m) monitor_apply_layout(m); } else if (ev->atom == XA_WM_NAME || ev->atom == g_netatom[NetWmName]) { client_update_title(client); } } } }
void propertynotify(XEvent* event) { // printf("name is: PropertyNotify\n"); XPropertyEvent *ev = &event->xproperty; HSClient* client; if (ev->state == PropertyNewValue) { if (is_ipc_connectable(event->xproperty.window)) { ipc_handle_connection(event->xproperty.window); } else if((client = get_client_from_window(ev->window))) { switch (ev->atom) { case XA_WM_HINTS: client_update_wm_hints(client); break; case XA_WM_NAME: client_update_title(client); break; default: break; } } } }
// scan for windows and add them to the list of managed clients // from dwm.c void scan(void) { unsigned int num; Window d1, d2, *cl, *wins = NULL; unsigned long cl_count; XWindowAttributes wa; ewmh_get_original_client_list(&cl, &cl_count); if (XQueryTree(g_display, g_root, &d1, &d2, &wins, &num)) { for (int i = 0; i < num; i++) { if(!XGetWindowAttributes(g_display, wins[i], &wa) || wa.override_redirect || XGetTransientForHint(g_display, wins[i], &d1)) continue; // only manage mapped windows.. no strange wins like: // luakit/dbus/(ncurses-)vim // but manage it if it was in the ewmh property _NET_CLIENT_LIST by // the previous window manager // TODO: what would dwm do? if (is_window_mapped(g_display, wins[i]) || 0 <= array_find(cl, cl_count, sizeof(Window), wins+i)) { manage_client(wins[i]); XMapWindow(g_display, wins[i]); } } if(wins) XFree(wins); } // ensure every original client is managed again for (int i = 0; i < cl_count; i++) { if (get_client_from_window(cl[i])) continue; if (!XGetWindowAttributes(g_display, cl[i], &wa) || wa.override_redirect || XGetTransientForHint(g_display, cl[i], &d1)) { continue; } XReparentWindow(g_display, cl[i], g_root, 0,0); manage_client(cl[i]); } }
void unmanage_client(Window win) { HSClient* client = get_client_from_window(win); if (!client) { return; } if (client->dragged) { mouse_stop_drag(); } // remove from tag frame_remove_window(client->tag->frame, win); // ignore events from it XSelectInput(g_display, win, 0); //XUngrabButton(g_display, AnyButton, AnyModifier, win); // permanently remove it HSTag* tag = client->tag; g_hash_table_remove(g_clients, &win); // and arrange monitor after the client has been removed from the stack HSMonitor* m = find_monitor_with_tag(tag); tag_update_focus_layer(tag); if (m) monitor_apply_layout(m); ewmh_remove_client(win); tag_set_flags_dirty(); }
//------ void ewmh_handle_client_message(XEvent* event) { XWindowAttributes wa; XSetWindowAttributes swa; XClientMessageEvent* me = &(event->xclient); Client* client; if(systray_visible && me->window == gSystray->window && me->message_type == g_netatom[NetSystemTrayOP]) { // add systray icons if(me->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { if(!(client = (Client *)calloc(1, sizeof(Client)))) die("FATAL", "Could not malloc() %u bytes", sizeof(Client)); client->window = me->data.l[2]; client->next = gSystray->icon; gSystray->icon = client; XGetWindowAttributes(gDisplay, client->window, &wa); client->last_size.x = client->last_size.y = 0; client->last_size.width = wa.width; client->last_size.height = wa.height; client->float_size = client->last_size; client->floating = True; /* reuse tags field as mapped status */ client->tag = g_array_index(g_tags, Tag*, 1); updatesystrayicongeom(client, wa.width, wa.height); XAddToSaveSet(gDisplay, client->window); XSelectInput(gDisplay, client->window, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); XReparentWindow(gDisplay, client->window, gSystray->window, 0, 0); /* use parents background pixmap */ swa.background_pixmap = ParentRelative; swa.background_pixel = dc.colors[0][ColBG]; XChangeWindowAttributes(gDisplay, client->window, CWBackPixmap|CWBackPixel, &swa); updatesystray(); resizebarwin(get_current_monitor()); //update_bars(); //setclientstate(c, NormalState); long data[] = {NormalState, None}; XChangeProperty(gDisplay, client->window, g_wmatom[WMState], g_wmatom[WMState], 32, PropModeReplace, (unsigned char*)data, 2); } return; } client = get_client_from_window(me->window); if (!client) return; if(me->message_type == g_netatom[NetWmState]){ /* me->data.l[1] and [2] describe the properties to alter */ for (int prop = 1; prop <= 2; prop++) { if (me->data.l[prop] == 0) continue; if (!(g_netatom[NetWmStateFullscreen] == me->data.l[prop])) continue; bool new_value[] = { [ _NET_WM_STATE_REMOVE ] = false, [ _NET_WM_STATE_ADD ] = true, [ _NET_WM_STATE_TOGGLE ] = !client->fullscreen, }; int action = me->data.l[0]; client_set_fullscreen(client, new_value[action]); } } }
void ewmh_handle_client_message(XEvent* event) { HSDebug("Received event: ClientMessage\n"); XClientMessageEvent* me = &(event->xclient); int index; for (index = 0; index < NetCOUNT; index++) { if (me->message_type == g_netatom[index]) { break; } } if (index >= NetCOUNT) { HSDebug("received unknown client message\n"); return; } HSClient* client; int desktop_index; switch (index) { case NetActiveWindow: // only steal focus it allowed to the current source // (i.e. me->data.l[0] in this case as specified by EWMH) if (focus_stealing_allowed(me->data.l[0])) { HSClient* client = get_client_from_window(me->window); if (client) { focus_client(client, true, true); } } break; case NetCurrentDesktop: { desktop_index = me->data.l[0]; if (desktop_index < 0 || desktop_index >= tag_get_count()) { HSDebug("_NET_CURRENT_DESKTOP: invalid index \"%d\"\n", desktop_index); break; } HSTag* tag = get_tag_by_index(desktop_index); monitor_set_tag(get_current_monitor(), tag); break; } case NetWmDesktop: { desktop_index = me->data.l[0]; if (!focus_stealing_allowed(me->data.l[1])) { break; } HSTag* target = get_tag_by_index(desktop_index); client = get_client_from_window(me->window); if (client && target) { tag_move_client(client, target); } break; } case NetWmState: { client = get_client_from_window(me->window); /* ignore requests for unmanaged windows */ if (!client || !client->ewmhrequests) break; /* mapping between EWMH atoms and client struct members */ struct { int atom_index; bool enabled; void (*callback)(HSClient*, bool); } client_atoms[] = { { NetWmStateFullscreen, client->fullscreen, client_set_fullscreen }, { NetWmStateDemandsAttention, client->urgent, client_set_urgent }, }; /* me->data.l[1] and [2] describe the properties to alter */ for (int prop = 1; prop <= 2; prop++) { if (me->data.l[prop] == 0) { /* skip if no property is specified */ continue; } /* check if we support the property data[prop] */ int i; for (i = 0; i < LENGTH(client_atoms); i++) { if (g_netatom[client_atoms[i].atom_index] == me->data.l[prop]) { break; } } if (i >= LENGTH(client_atoms)) { /* property will not be handled */ continue; } auto new_value = ArrayInitializer<bool,3>({ { _NET_WM_STATE_REMOVE , false }, { _NET_WM_STATE_ADD , true }, { _NET_WM_STATE_TOGGLE , !client_atoms[i].enabled }, }).a; int action = me->data.l[0]; if (action >= new_value.size()) { HSDebug("_NET_WM_STATE: invalid action %d\n", action); } /* change the value */ client_atoms[i].callback(client, new_value[action]); } break; } case NetWmMoveresize: { client = get_client_from_window(me->window); if (!client) { break; } int direction = me->data.l[2]; if (direction == _NET_WM_MOVERESIZE_MOVE || direction == _NET_WM_MOVERESIZE_MOVE_KEYBOARD) { mouse_initiate_move(client, 0, NULL); } else if (direction == _NET_WM_MOVERESIZE_CANCEL) { if (mouse_is_dragging()) mouse_stop_drag(); } else { // anything else is a resize mouse_initiate_resize(client, 0, NULL); } break; } default: HSDebug("no handler for the client message \"%s\"\n", g_netatom_names[index]); break; } }
HSClient* manage_client(Window win) { if (is_herbstluft_window(g_display, win)) { // ignore our own window return NULL; } if (get_client_from_window(win)) { return NULL; } // init client HSClient* client = create_client(); client->pid = window_pid(g_display, win); HSMonitor* m = get_current_monitor(); // set to window properties client->window = win; client_update_title(client); unsigned int border, depth; Window root_win; int x, y; unsigned int w, h; XGetGeometry(g_display, win, &root_win, &x, &y, &w, &h, &border, &depth); // treat wanted coordinates as floating coords client->float_size.x = x; client->float_size.y = y; client->float_size.width = w; client->float_size.height = h; // apply rules HSClientChanges changes; client_changes_init(&changes, client); rules_apply(client, &changes); if (changes.tag_name) { client->tag = find_tag(changes.tag_name->str); } if (!changes.manage) { client_changes_free_members(&changes); client_destroy(client); // map it... just to be sure XMapWindow(g_display, win); return NULL; } // actually manage it g_hash_table_insert(g_clients, &(client->window), client); client->window_str = g_string_sized_new(10); g_string_printf(client->window_str, "0x%lx", win); hsobject_link(g_client_object, &client->object, client->window_str->str); // insert to layout if (!client->tag) { client->tag = m->tag; } // get events from window XSelectInput(g_display, win, CLIENT_EVENT_MASK); // insert window to the stack client->slice = slice_create_client(client); stack_insert_slice(client->tag->stack, client->slice); // insert window to the tag frame_insert_window(lookup_frame(client->tag->frame, changes.tree_index->str), win); client_update_wm_hints(client); if (changes.focus) { // give focus to window if wanted // TODO: make this faster! // WARNING: this solution needs O(C + exp(D)) time where W is the count // of clients on this tag and D is the depth of the binary layout tree frame_focus_window(client->tag->frame, win); } HSAttribute attributes[] = { ATTRIBUTE_STRING( "winid", client->window_str, ATTR_READ_ONLY), ATTRIBUTE_STRING( "title", client->title, ATTR_READ_ONLY), ATTRIBUTE_BOOL( "fullscreen", client->fullscreen, client_attr_fullscreen), ATTRIBUTE_BOOL( "pseudotile", client->pseudotile, client_attr_pseudotile), ATTRIBUTE_BOOL( "ewmhrequests", client->ewmhrequests, ATTR_ACCEPT_ALL), ATTRIBUTE_BOOL( "ewmhnotify", client->ewmhnotify, ATTR_ACCEPT_ALL), ATTRIBUTE_BOOL( "sizehints", client->sizehints, ATTR_ACCEPT_ALL), ATTRIBUTE_BOOL( "urgent", client->urgent, client_attr_urgent), ATTRIBUTE_LAST, }; hsobject_set_attributes(&client->object, attributes); ewmh_window_update_tag(client->window, client->tag); tag_set_flags_dirty(); client_set_fullscreen(client, changes.fullscreen); ewmh_update_window_state(client); // add client after setting the correct tag for the new client // this ensures a panel can read the tag property correctly at this point ewmh_add_client(client->window); HSMonitor* monitor = find_monitor_with_tag(client->tag); if (monitor) { if (monitor != get_current_monitor() && changes.focus && changes.switchtag) { monitor_set_tag(get_current_monitor(), client->tag); } // TODO: monitor_apply_layout() maybe is called twice here if it // already is called by monitor_set_tag() monitor_apply_layout(monitor); } else { if (changes.focus && changes.switchtag) { monitor_set_tag(get_current_monitor(), client->tag); } } client_changes_free_members(&changes); grab_client_buttons(client, false); return client; }
void ewmh_handle_client_message(XEvent* event) { HSDebug("Received event: ClientMessage\n"); XClientMessageEvent* me = &(event->xclient); int index; for (index = 0; index < NetCOUNT; index++) { if (me->message_type == g_netatom[index]) { break; } } if (index >= NetCOUNT) { HSDebug("received unknown client message\n"); return; } HSClient* client; int desktop_index; switch (index) { case NetActiveWindow: // only steal focus it allowed to the current source // (i.e. me->data.l[0] in this case as specified by EWMH) if (focus_stealing_allowed(me->data.l[0])) { focus_window(me->window, true, true); } break; case NetCurrentDesktop: desktop_index = me->data.l[0]; if (desktop_index < 0 || desktop_index >= g_tags->len) { HSDebug("_NET_CURRENT_DESKTOP: invalid index \"%d\"\n", desktop_index); break; } HSTag* tag = g_array_index(g_tags, HSTag*, desktop_index); monitor_set_tag(get_current_monitor(), tag); break; case NetWmDesktop: desktop_index = me->data.l[0]; if (!focus_stealing_allowed(me->data.l[1])) { break; } HSTag* target = get_tag_by_index(desktop_index); client = get_client_from_window(me->window); if (client && target) { tag_move_client(client, target); } break; case NetWmState: client = get_client_from_window(me->window); /* ignore requests for unmanaged windows */ if (!client || !client->ewmhrequests) break; /* mapping between EWMH atoms and client struct members */ struct { int atom_index; bool enabled; void (*callback)(HSClient*, bool); } client_atoms[] = { { NetWmStateFullscreen, client->fullscreen, client_set_fullscreen }, { NetWmStateDemandsAttention, client->urgent, client_set_urgent }, }; /* me->data.l[1] and [2] describe the properties to alter */ for (int prop = 1; prop <= 2; prop++) { if (me->data.l[prop] == 0) { /* skip if no property is specified */ continue; } /* check if we support the property data[prop] */ int i; for (i = 0; i < LENGTH(client_atoms); i++) { if (g_netatom[client_atoms[i].atom_index] == me->data.l[prop]) { break; } } if (i >= LENGTH(client_atoms)) { /* property will not be handled */ continue; } bool new_value[] = { [ _NET_WM_STATE_REMOVE ] = false, [ _NET_WM_STATE_ADD ] = true, [ _NET_WM_STATE_TOGGLE ] = !client_atoms[i].enabled, }; int action = me->data.l[0]; if (action >= LENGTH(new_value)) { HSDebug("_NET_WM_STATE: invalid action %d\n", action); } /* change the value */ client_atoms[i].callback(client, new_value[action]); } break; default: HSDebug("no handler for the client message \"%s\"\n", g_netatom_names[index]); break; } }
HSClient* get_current_client() { Window win = frame_focused_window(g_cur_frame); if (!win) return NULL; return get_client_from_window(win); }