/** EnterNotify handle event * \param ev XCrossingEvent pointer */ static void enternotify(XCrossingEvent *ev) { Client *c; int n; if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != ROOT) return; /* Don't handle EnterNotify event if it's about systray */ if(systray_find(ev->window) || ev->window == traywin) return; if(conf.focus_fmouse) { if((c = client_gb_win(ev->window)) || (c = client_gb_frame(ev->window)) || (c = client_gb_titlebar(ev->window)) || (c = client_gb_button(ev->window, &n))) client_focus(c); else client_focus(NULL); } return; }
/** Manage _NET_WM_STATE_* ewmh */ void ewmh_manage_net_wm_state(long data_l[], Client *c) { /* Manage _NET_WM_STATE_FULLSCREEN */ if(data_l[1] == (long)net_atom[net_wm_state_fullscreen]) { if(data_l[0] == _NET_WM_STATE_ADD && !(c->flags & FSSFlag)) { c->screen = screen_get_with_geo(c->geo.x, c->geo.y); c->flags &= ~UnmapFlag; XMapWindow(dpy, c->win); XReparentWindow(dpy, c->win, ROOT, spgeo[c->screen].x, spgeo[c->screen].y); XResizeWindow(dpy, c->win, spgeo[c->screen].width, spgeo[c->screen].height); XChangeProperty(dpy, c->win, net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace, (uchar *)&net_atom[net_wm_state_fullscreen], 1); c->tmp_geo = c->geo; if(c->flags & FreeFlag) c->ogeo = c->geo; c->flags |= (FSSFlag | MaxFlag); client_raise(c); client_focus(c); XUnmapWindow(dpy, c->frame); } else if(data_l[0] == _NET_WM_STATE_REMOVE && (c->flags & FSSFlag)) { XChangeProperty(dpy, c->win, net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace, (uchar *)0, 0); c->flags &= ~(FSSFlag | MaxFlag); client_map(c); XReparentWindow(dpy, c->win, c->frame, BORDH, TBARH); client_moveresize(c, c->tmp_geo, False); } } /* Manage _NET_WM_STATE_STICKY */ else if(data_l[1] == (long)net_atom[net_wm_state_sticky]) { /* == client_ignore_tag */ c->tag = MAXTAG + 1; arrange(c->screen, True); } /* Manage _NET_WM_STATE_DEMANDS_ATTENTION */ else if(data_l[1] == (long)net_atom[net_wm_state_demands_attention]) { if(data_l[0] == _NET_WM_STATE_ADD) client_urgent(c, True); if(data_l[0] == _NET_WM_STATE_REMOVE) if(c == sel) client_focus(NULL); } return; }
/** Go to the current urgent tag *\param cmd uicb_t type unused */ void uicb_tag_urgent(uicb_t cmd) { Client *c; Bool b = False; (void)cmd; /* Check if there is a urgent client */ for(c = clients; c; c = c->next) if(c->flags & UrgentFlag) { b = True; break; } if(!b) return; screen_set_sel(c->screen); tag_set(c->tag); client_focus(c); return; }
static void event_buttonpress(XEvent *e) { XButtonEvent *ev = &e->xbutton; struct mousebind *m; struct barwin *b; struct client *c; screen_update_sel(); status_flush_surface(); SLIST_FOREACH(b, &W->h.barwin, next) if(b->win == ev->window) { W->last_clicked_barwin = b; SLIST_FOREACH(m, &b->mousebinds, next) MOUSE_DO_BIND(m); SLIST_FOREACH(m, &b->statusmousebinds, next) MOUSE_DO_BIND(m); break; } if((c = client_gb_win(ev->window)) && c != W->client && ev->button == 1 && W->cfocus & CFOCUS_CLICK) client_focus(c); }
static void event_enternotify(XEvent *e) { XCrossingEvent *ev = &e->xcrossing; struct client *c; if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != W->root) return; if(ev->window == W->systray.win || systray_find(ev->window)) return; if((c = client_gb_win(ev->window)) || (c = client_gb_frame(ev->window))) { if(c->flags & CLIENT_IGNORE_ENTER) c->flags ^= CLIENT_IGNORE_ENTER; else if(c->tag->flags & TAG_IGNORE_ENTER) c->tag->flags ^= TAG_IGNORE_ENTER; else if(c != W->client && !(c->flags & CLIENT_TABBED) && W->cfocus & CFOCUS_ENTER) client_focus(c); } }
void client_remove(struct WM_t *W, struct wmclient *C) { int idx = get_client_index(W, C->win), i; if (W->clients[idx] != C) { msg("client_remove: somehow get_client_index failed! :o\n"); return; } W->clients[idx] = NULL; /* Update all the focus numbers, i.e. decrease (bring forward) all the windows with bigger focus numbers. */ for (i = idx; i < W->nclients; i++) W->clients[i] = W->clients[i + 1]; W->nclients--; msg("Removing client \'%s\'\n", C->name); free(C->name); free(C); msg("About to print\n"); print_clients(W); msg("Printed, about to focus\n"); client_focus(W, W->clients[0]); msg("Focused\n"); }
void tag_screen(struct screen *s, struct tag *t) { struct client *c; /* Return to the previous tag */ if(t == s->seltag && TAILQ_NEXT(TAILQ_FIRST(&s->tags), next)) t = t->prev; if(!t) t = TAILQ_FIRST(&s->tags); /* Move clients which ignore tags */ SLIST_FOREACH(c, &W->h.client, next) if (c->flags & CLIENT_IGNORE_TAG) tag_client(t, c); t->prev = s->seltag; s->seltag = t; clients_arrange_map(); /* Update focus */ if(!SLIST_EMPTY(&t->clients) && !(W->flags & WMFS_SCAN)) client_focus( client_tab_next(t->sel)); t->flags &= ~TAG_URGENT; infobar_elem_screen_update(s, ElemTag); ewmh_update_wmfs_props(); }
/** Toggle abovefc option *\param cmd uicb_t type */ void uicb_toggle_abovefc(uicb_t cmd) { Client *c; (void)cmd; screen_get_sel(); if(!(tags[selscreen][seltag[selscreen]].abovefc = !tags[selscreen][seltag[selscreen]].abovefc)) { for(c = clients; c; c = c->next) if(c->flags & AboveFlag && c->screen == selscreen && c->tag == (uint)seltag[selscreen]) { c->flags &= ~AboveFlag; break; } tags[selscreen][seltag[selscreen]].layout.func(selscreen); } client_focus(sel); return; }
void area_focus(Area *a) { Frame *f; View *v; Area *old_a; v = a->view; f = a->sel; old_a = v->sel; if(!a->floating && view_fullscreen_p(v, a->screen)) return; v->sel = a; if(!a->floating) { v->selcol = area_idx(a); v->selscreen = a->screen; } if(a != old_a) v->oldsel = nil; if(old_a && a->floating != old_a->floating) { v->revert = old_a; if(v->floating->max) view_update(v); } if(v == selview) { move_focus(old_a->sel, f); client_focus(f ? f->client : nil); if(a != old_a) event("AreaFocus %a\n", a); } }
/** FocusChange handle event * \param ev XFocusChangeEvent pointer * \return */ static void focusin(XFocusChangeEvent *ev) { if(sel && ev->window != sel->win) client_focus(sel); return; }
static void event_focusin(XEvent *e) { if(W->client && e->xfocus.window != W->client->win && e->xfocus.window != W->client->frame) client_focus(W->client); }
void area_focus(Area *a) { Frame *f; View *v; Area *old_a; v = a->view; f = a->sel; old_a = v->sel; if(!a->floating && view_fullscreen_p(v, a->screen)) return; v->sel = a; if(!a->floating) { v->selcol = area_idx(a); v->selscreen = a->screen; } if(a != old_a) v->oldsel = nil; if((old_a) && (a->floating != old_a->floating)) { v->revert = old_a; if(v->floating->max) view_update(v); } if(v != selview) return; move_focus(old_a->sel, f); if(f) client_focus(f->client); else client_focus(nil); if(a != old_a) { event("AreaFocus %a\n", a); /* Deprecated */ if(a->floating) event("FocusFloating\n"); else event("ColumnFocus %d\n", area_idx(a)); } }
/* Set t to NULL to untag c from c->tag */ void tag_client(struct tag *t, struct client *c) { /* Remove client from its previous tag */ if(c->tag && !(c->flags & CLIENT_RULED)) { if(c->tag == t) return; if(!(c->flags & (CLIENT_IGNORE_LAYOUT | CLIENT_FREE))) layout_split_arrange_closed(c); if(!(c->flags & CLIENT_REMOVEALL)) { SLIST_REMOVE(&c->tag->clients, c, client, tnext); if(c->tag->sel == c || W->client == c) client_focus( client_tab_next( client_next(c))); } } c->flags &= ~CLIENT_RULED; /* Client remove */ if(!t) { infobar_elem_screen_update(c->screen, ElemTag); return; } c->prevtag = c->tag; c->tag = t; c->screen = t->screen; client_update_props(c, CPROP_LOC); SLIST_INSERT_HEAD(&t->clients, c, tnext); infobar_elem_screen_update(c->screen, ElemTag); if(c->flags & CLIENT_TABMASTER && c->prevtag) { struct client *cc; SLIST_FOREACH(cc, &c->prevtag->clients, tnext) if(cc->tabmaster == c) { cc->flags |= CLIENT_IGNORE_LAYOUT; tag_client(t, cc); } } layout_client(c); if(t != c->screen->seltag || c->flags & CLIENT_TABBED) client_unmap(c); }
void client_send_to_monitor(Client *c, Monitor *m) { if(c->mon == m) return; client_unfocus(c, true); client_detach(c); client_detach_stack(c); c->mon = m; c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ client_attach(c); client_attach_stack(c); client_focus(NULL); arrange(NULL); }
/** XMotionNotify handle event * \param ev XMotionEvent pointer */ static void motionnotify(XMotionEvent *ev) { Client *c; if(!conf.focus_fmouse || !conf.focus_fmov) return; if((c = client_gb_win(ev->subwindow))) if(c != sel) client_focus(c); return; }
/** Set the selected screen *\param screen Number of the wanted selected screen */ void screen_set_sel(int screen) { if(screen < 0 || screen > screen_count() - 1) screen = 0; if(selscreen != screen) prevselscreen = selscreen; client_focus(NULL); XWarpPointer(dpy, None, ROOT, 0, 0, 0, 0, sgeo[screen].x + sgeo[screen].width / 2, sgeo[screen].y + sgeo[screen].height / 2); selscreen = screen; return; }
/* Register a client, steal its border, grap events, etc */ void client_register(struct WM_t *W, Window xwindow_id) { struct wmclient *C = malloc(sizeof(*C)); XFetchName(W->XDisplay, xwindow_id, &(C->name)); if (!(C->name)) C->name = strdup("<notitle>"); msg("Registering \'%s\':\n", C->name); C->win = xwindow_id; decide_new_window_size_pos(W, C); /* Unless it's a window found at startup, move it * to the current head/screen */ if (!registering_existing_windows) { C->x += curr_head_x(W); C->y += curr_head_y(W); } C->fullscreen = 0; XMapWindow(W->XDisplay, C->win); set_size_pos_border(W, C); client_select_events(W, C); get_pid(W, C); W->clients[W->nclients++] = C; client_focus(W, C); XFlush(W->XDisplay); print_clients(W); }
void client_unmanage(Client *c, bool destroyed) { Monitor *m = c->mon; /* The server grab construct avoids race conditions. */ client_detach(c); client_detach_stack(c); printf("unmanage %i, %i\n", destroyed, c->win); if(!destroyed) { uint32_t values[] = { c->oldbw }; xcb_grab_server(conn); xcb_configure_window_checked(conn, c->win, XCB_CONFIG_WINDOW_BORDER_WIDTH, values); xcb_ungrab_button_checked(conn, XCB_BUTTON_INDEX_ANY, c->win, XCB_GRAB_ANY); client_set_state(c, XCB_ICCCM_WM_STATE_WITHDRAWN); xcb_flush(conn); xcb_ungrab_server(conn); } free(c); client_focus(NULL); arrange(m); }
void ewmh_manage_state(long data[], struct client *c) { /* _NET_WM_STATE_FULLSCREEN */ if(data[1] == (long)W->net_atom[net_wm_state_fullscreen] || data[2] == (long)W->net_atom[net_wm_state_fullscreen]) { if(data[0] == _NET_WM_STATE_ADD || (data[0] == _NET_WM_STATE_TOGGLE && !(c->flags & CLIENT_FULLSCREEN))) { c->flags |= CLIENT_FULLSCREEN; XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace, (unsigned char*)&W->net_atom[net_wm_state_fullscreen], 1); XReparentWindow(W->dpy, c->win, W->root, c->screen->geo.x, c->screen->geo.y); XResizeWindow(W->dpy, c->win, c->screen->geo.w, c->screen->geo.h); if(c->tag) client_focus(c); XRaiseWindow(W->dpy, c->win); } else { c->flags &= ~CLIENT_FULLSCREEN; XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace, (unsigned char*)0, 0); XReparentWindow(W->dpy, c->win, c->frame, c->wgeo.x, c->wgeo.y); if(c->flags & CLIENT_FREE) client_moveresize(c, &c->geo); else layout_fix_hole(c); } } }
/** Move a client in tile grid with the mouse *\param c Client double pointer */ static void mouse_move_tile_client(Client **c) { Client *sc; Window w; int d; if(!((*c)->flags & TileFlag) && !((*c)->flags & LMaxFlag)) return; XQueryPointer(dpy, ROOT, &w, &w, &d, &d, &d, &d, (uint*)&d); if(((sc = client_gb_win(w)) || (sc = client_gb_frame(w)) || (sc = client_gb_titlebar(w))) && (*c)->win != sc->win && !((*c)->flags & HideFlag) && !(sc->flags & HideFlag)) { client_swap(sc, *c); client_focus(sc); swap_ptr((void**)c, (void**)&sc); } return; }
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(); } } } }
/** Manage the client hints *\param c Client pointer */ void ewmh_manage_window_type(Client *c) { Atom *atom, rf; int f; ulong n, il, i; uchar *data = NULL; long ldata[5] = { 0 }; if(XGetWindowProperty(dpy, c->win, net_atom[net_wm_window_type], 0L, 0x7FFFFFFFL, False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n) { atom = (Atom*)data; for(i = 0; i < n; ++i) { /* Manage _NET_WM_WINDOW_TYPE_DOCK & _NET_WM_WINDOW_TYPE_SPLASH */ if(atom[i] == net_atom[net_wm_window_type_dock] || atom[i] == net_atom[net_wm_window_type_splash]) { /* Unmap frame, decoration.. */ client_unmap(c); /* Map only window */ XMapWindow(dpy, c->win); /* Reparent it to ROOT win */ XReparentWindow(dpy, c->win, ROOT, c->geo.x, c->geo.y); XRaiseWindow(dpy, c->win); c->flags |= DockFlag; } /* MANAGE _NET_WM_WINDOW_TYPE_DIALOG */ else if(atom[i] == net_atom[net_wm_window_type_dialog]) { c->flags |= FreeFlag; c->flags &= ~(TileFlag | MaxFlag | LMaxFlag); client_moveresize(c, c->ogeo, True); client_focus(c); tags[selscreen][seltag[selscreen]].layout.func(selscreen); } } XFree(data); } /* Get NET_WM_STATE set without sending client message event */ if(XGetWindowProperty(dpy, c->win, net_atom[net_wm_state], 0L, 0x7FFFFFFFL, False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n) { atom = (Atom*)data; for(i = 0; i < n; ++i) { ldata[0] = _NET_WM_STATE_ADD; ldata[1] = atom[i]; ewmh_manage_net_wm_state(ldata, c); } XFree(data); } return; }
/* ClientMessage handle event *\param ev XClientMessageEvent pointer */ static void clientmessageevent(XClientMessageEvent *ev) { Client *c; Systray *sy; int s, i, mess_t = 0; Atom rt; int rf; ulong ir, il; uchar *ret = NULL; uchar *ret_cmd = NULL; void (*func)(uicb_t); if(ev->format != 32) return; s = screen_count(); for(i = 0; i < net_last + s; ++i) if(net_atom[i] == ev->message_type) mess_t = i; if(ev->window == ROOT) { /* Manage _NET_CURRENT_DESKTOP */ if(mess_t == net_current_desktop && ev->data.l[0] >= 0 && ev->data.l[0] < conf.ntag[selscreen]) tag_set((int)(ev->data.l[0] + 1)); /* Manage _WMFS_SET_SCREEN */ if(mess_t == wmfs_set_screen && ev->data.l[0] >= 0 && ev->data.l[0] <= s) screen_set_sel((int)(ev->data.l[0])); /* Manage _NET_ACTIVE_WINDOW */ else if(mess_t == net_active_window) { if((c = client_gb_win(ev->window))) client_focus(c); else if((sy = systray_find(ev->data.l[0]))) XSetInputFocus(dpy, sy->win, RevertToNone, CurrentTime); } } else if(ev->window == traywin) { /* Manage _NET_WM_SYSTEM_TRAY_OPCODE */ if(mess_t == net_wm_system_tray_opcode) { if(ev->data.l[1] == XEMBED_EMBEDDED_NOTIFY) { systray_add(ev->data.l[2]); systray_update(); } else if(ev->data.l[1] == XEMBED_REQUEST_FOCUS) if((sy = systray_find(ev->data.l[2]))) ewmh_send_message(sy->win, sy->win, "_XEMBED", XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0, 0); } } /* Manage _NET_WM_STATE */ if(mess_t == net_wm_state) if((c = client_gb_win(ev->window))) ewmh_manage_net_wm_state(ev->data.l, c); /* Manage _NET_CLOSE_WINDOW */ if(mess_t == net_close_window) if((c = client_gb_win(ev->window))) client_kill(c); /* Manage _NET_WM_DESKTOP */ if(mess_t == net_wm_desktop) if((c = client_gb_win(ev->window)) && ev->data.l[0] != (long)0xFFFFFFFF) tag_transfert(c, ev->data.l[0]); /* Manage _WMFS_STATUSTEXT_x */ if(mess_t >= wmfs_statustext && ev->data.l[4] == True) { if(XGetWindowProperty(dpy, ROOT, net_atom[mess_t], 0, 4096, False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret) == Success) { statustext_handle(mess_t - wmfs_statustext, (char*)ret); XFree(ret); } } /* Manage _WMFS_FUNCTION && _WMFS_CMD */ if((mess_t == wmfs_function && ev->data.l[4] == True) || (mess_t == wmfs_cmd && ev->data.l[4] == True)) { XGetWindowProperty(dpy, ROOT, net_atom[wmfs_function], 0, 4096, False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret); XGetWindowProperty(dpy, ROOT, net_atom[wmfs_cmd], 0, 4096, False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret_cmd); if((func = name_to_func((char*)ret, func_list))) func((uicb_t)ret_cmd); XFree(ret_cmd); XFree(ret); } /* Manage _WMFS_UPDATE_HINTS */ if(mess_t == wmfs_update_hints) { ewmh_get_number_of_desktop(); ewmh_update_current_tag_prop(); ewmh_get_client_list(); ewmh_get_desktop_names(); ewmh_set_desktop_geometry(); screen_count(); screen_get_sel(); } if(mess_t == wmfs_update_status && estatus) spawn(conf.status_path); return; }
/** ButtonPress handle event * \param ev XButtonEvent pointer */ static void buttonpress(XButtonEvent *ev) { Client *c; int i, j, n; screen_get_sel(); /* If the mouse is on a not selected client and you click on it. */ if(((c = client_gb_win(ev->window)) || (c = client_gb_titlebar(ev->window))) && c != sel && (ev->button == Button1 || ev->button == Button2 || ev->button == Button3)) { client_focus(c); client_raise(c); return; } /* Titlebar */ if((c = client_gb_titlebar(ev->window)) && c == sel) for(i = 0; i < conf.titlebar.nmouse; ++i) if(ev->button == conf.titlebar.mouse[i].button) if(conf.titlebar.mouse[i].func) conf.titlebar.mouse[i].func(conf.titlebar.mouse[i].cmd); /* Titlebar buttons */ if((c = client_gb_button(ev->window, &n))) for(i = 0; i < conf.titlebar.button[n].nmouse; ++i) if(ev->button == conf.titlebar.button[n].mouse[i].button) if(conf.titlebar.button[n].mouse[i].func) { client_focus(c); conf.titlebar.button[n].mouse[i].func(conf.titlebar.button[n].mouse[i].cmd); } /* Frame Resize Area */ if((c = client_gb_resize(ev->window))) mouse_resize(c); /* Client */ if((c = client_gb_win(ev->window)) && c == sel) for(i = 0; i < conf.client.nmouse; ++i) if(ev->button == conf.client.mouse[i].button) if(conf.client.mouse[i].func) conf.client.mouse[i].func(conf.client.mouse[i].cmd); /* Root */ if(ev->window == ROOT) for(i = 0; i < conf.root.nmouse; ++i) if(conf.root.mouse[i].tag == seltag[conf.root.mouse[i].screen] || conf.root.mouse[i].tag < 0) if(ev->button == conf.root.mouse[i].button) if(conf.root.mouse[i].func) conf.root.mouse[i].func(conf.root.mouse[i].cmd); /* Infobars */ for(i = 0; i < screen_count(); ++i) if(ev->window == infobar[i].bar->win) for(j = 0; j < conf.bars.nmouse; ++j) if(conf.bars.mouse[j].screen == i || conf.bars.mouse[j].screen < 0) if(conf.bars.mouse[j].tag == seltag[i] || conf.bars.mouse[j].tag < 0) if(ev->button == conf.bars.mouse[j].button) if(conf.bars.mouse[j].func) conf.bars.mouse[j].func(conf.bars.mouse[j].cmd); /* Selbar */ if(conf.bars.selbar && ev->window == infobar[selscreen].selbar->win) for(i = 0; i < conf.selbar.nmouse; ++i) if(conf.selbar.mouse[i].tag == seltag[conf.selbar.mouse[i].screen] || conf.selbar.mouse[i].tag < 0) if(ev->button == conf.selbar.mouse[i].button) if(conf.selbar.mouse[i].func) conf.selbar.mouse[i].func(conf.selbar.mouse[i].cmd); /* Tags */ for(i = 1; i < conf.ntag[selscreen] + 1; ++i) if(ev->window == infobar[selscreen].tags[i]->win) { for(j = 0; j < tags[selscreen][i].nmouse; ++j) if(ev->button == tags[selscreen][i].mouse[j].button) if(tags[selscreen][i].mouse[j].func) tags[selscreen][i].mouse[j].func(tags[selscreen][i].mouse[j].cmd); /* Mouse button action on tag */ if(ev->button == conf.mouse_tag_action[TagSel]) tag_set(i); else if(ev->button == conf.mouse_tag_action[TagTransfert]) tag_transfert(sel, i); else if(ev->button == conf.mouse_tag_action[TagAdd]) tag_additional(selscreen, seltag[selscreen], i); else if(ev->button == conf.mouse_tag_action[TagNext]) tag_set(seltag[selscreen] + 1); else if(ev->button == conf.mouse_tag_action[TagPrev]) tag_set(seltag[selscreen] - 1); } /* Layout button */ if(ev->window == infobar[selscreen].layout_button->win && conf.nlayout > 1) { if(conf.layout_system && (ev->button == Button1 || ev->button == Button3)) /* True -> menu */ { menulayout.y = spgeo[selscreen].y + infobar[selscreen].layout_button->geo.y + INFOBARH; menulayout.x = infobar[selscreen].layout_button->geo.x + (sgeo[selscreen].x - BORDH); if(infobar[selscreen].geo.y != spgeo[selscreen].y) menulayout.y = infobar[selscreen].geo.y - (INFOBARH * menulayout.nitem) - SHADH; uicb_menu("menulayout"); } else { switch(ev->button) { case Button1: case Button4: layoutswitch(True); break; case Button3: case Button5: layoutswitch(False); break; } } } return; }
/* Set the tag * \param tag The tag number */ void tag_set(int tag) { Client *c; Bool al = False; int i; if(tag < 0 || tag > MAXTAG) return; screen_get_sel(); if(seltag[selscreen] != tag) prevseltag[selscreen] = seltag[selscreen]; else if(tag == seltag[selscreen] && tag != prevseltag[selscreen] && conf.tag_auto_prev) tag = seltag[selscreen] = prevseltag[selscreen]; else seltag[selscreen] = tag; if(conf.tag_round) { if(tag <= 0) seltag[selscreen] = conf.ntag[selscreen]; else if(tag > conf.ntag[selscreen]) seltag[selscreen] = 1; else seltag[selscreen] = tag; } else { if(!tag || tag > conf.ntag[selscreen]) return; seltag[selscreen] = tag; } ewmh_update_current_tag_prop(); /* Arrange infobar position */ if(tags[selscreen][prevseltag[selscreen]].barpos != tags[selscreen][seltag[selscreen]].barpos || prevseltag[selscreen] == seltag[selscreen]) infobar_set_position(tags[selscreen][seltag[selscreen]].barpos); /* Check if a layout update is needed with additional tags */ if(tags[selscreen][seltag[selscreen]].tagad) al = True; else if(tags[selscreen][seltag[selscreen]].request_update) { al = True; tags[selscreen][seltag[selscreen]].request_update = False; } for(i = 1; i < conf.ntag[selscreen] + 1; ++i) if(tags[selscreen][i].tagad & TagFlag(seltag[selscreen])) { al = True; break; } /* Check for ignore_tag clients */ for(c = clients; c; c = c->next) if(c->tag == MAXTAG + 1 && c->screen == selscreen) { al = True; break; } arrange(selscreen, al); if(tags[selscreen][tag].request_update) { tags[selscreen][seltag[selscreen]].layout.func(selscreen); tags[selscreen][tag].request_update = False; } /* To focus selected client of the via focusontag option */ for(c = clients; c; c = c->next) if(c->focusontag == tag && c->screen == selscreen) break; /* No focusontag option found on any client, try to find the first of the tag */ if(!c) for(c = clients; c; c = c->next) if(c->tag == (uint)seltag[selscreen] && c->screen == selscreen) break; client_focus((c) ? c : NULL); return; }
bool ewmh_handle_event(XEvent *ev) { client *c; int i, j, xo, yo; long extents[4]; Atom rt; int rf; unsigned long nir, bar; switch(ev->type) { case ClientMessage: c = owner(ev->xclient.window); if(ev->xclient.message_type == ewmh_atoms[NET_WM_MOVERESIZE]) { if(c) { #ifdef DEBUG_EVENTS printf(NAME ": ewmh_handle_event(): handling ClientMessage event\n\tatom: _NET_WM_MOVERESIZE\n"); #endif if(ev->xclient.data.l[2] == NET_WM_MOVERESIZE_MOVE || ev->xclient.data.l[2] == NET_WM_MOVERESIZE_MOVE_KEYBOARD) { client_focus(c, true); xo = client_width_total_intern(c) / 2; yo = client_height_total_intern(c) / 2; XWarpPointer(dpy, None, c->parent, 0, 0, 0, 0, xo, yo); drag_start(A_MOVE, AnyButton, client_x(c) + xo, client_y(c) + yo); } if(ev->xclient.data.l[2] == NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT || ev->xclient.data.l[2] == NET_WM_MOVERESIZE_SIZE_KEYBOARD) { client_focus(c, true); drag_start(A_RESIZE, AnyButton, ev->xclient.data.l[0], ev->xclient.data.l[1]); } } return true; } if(ev->xclient.message_type == ewmh_atoms[NET_CLOSE_WINDOW]) { if(c) { #ifdef DEBUG_EVENTS printf(NAME ": ewmh_handle_event(): handling ClientMessage event\n\tatom: _NET_CLOSE_WINDOW\n"); #endif delete_window(c); } return true; } if(ev->xclient.message_type == ewmh_atoms[NET_ACTIVE_WINDOW]) { if(c) { #ifdef DEBUG_EVENTS printf(NAME ": ewmh_handle_event(): handling ClientMessage event\n\tatom: _NET_ACTIVE_WINDOW\n"); #endif if(c->flags & ICONIC) client_restore(c); else { if(c->desktop != desktop && c->desktop != STICKY) desktop_goto(c->desktop); client_raise(c); } if(evh != wlist_handle_event) client_focus(c, true); } return true; } if(ev->xclient.message_type == ewmh_atoms[NET_RESTACK_WINDOW]) { if(c && ev->xclient.data.l[1] == None) { #ifdef DEBUG_EVENTS printf(NAME ": ewmh_handle_event(): handling ClientMessage event\n\tatom: _NET_RESTACK_WINDOW\n"); #endif client_raise(c); } /* schould also add code for handling this when a sibling window is passed */ /* but we schould find/create a way to test this first */ return true; } if(ev->xclient.message_type == ewmh_atoms[NET_WM_STATE]) { if(c) { #ifdef DEBUG_EVENTS printf(NAME ": ewmh_handle_event(): handling ClientMessage event\n\tatom: _NET_WM_STATE\n"); #endif j = 0; for(i = 1; i < 3; i++) { if(((Atom) ev->xclient.data.l[i]) == ewmh_atoms[NET_WM_STATE_MAXIMIZED_HORZ]) j |= MAXIMIZED_L | MAXIMIZED_R; if(((Atom) ev->xclient.data.l[i]) == ewmh_atoms[NET_WM_STATE_MAXIMIZED_VERT]) j |= MAXIMIZED_T | MAXIMIZED_B; } if(j) client_toggle_state(c, j); if(((Atom) ev->xclient.data.l[1]) == ewmh_atoms[NET_WM_STATE_FULLSCREEN] && (ev->xclient.data.l[0] == NET_WM_STATE_TOGGLE || (ev->xclient.data.l[0] == NET_WM_STATE_ADD && !(c->flags & FULLSCREEN)) || (ev->xclient.data.l[0] == NET_WM_STATE_REMOVE && (c->flags & FULLSCREEN)))) client_fullscreen(c); if(((Atom) ev->xclient.data.l[1]) == ewmh_atoms[NET_WM_STATE_ABOVE]) { if(((Atom) ev->xclient.data.l[0]) == ewmh_atoms[NET_WM_STATE_ADD]) client_set_layer(c, TOP); if(((Atom) ev->xclient.data.l[0]) == ewmh_atoms[NET_WM_STATE_REMOVE] && c->layer == TOP) client_set_layer(c, NORMAL); if(((Atom) ev->xclient.data.l[0]) == ewmh_atoms[NET_WM_STATE_TOGGLE]) client_set_layer(c, (c->layer == TOP) ? NORMAL : TOP); } if(((Atom) ev->xclient.data.l[1]) == ewmh_atoms[NET_WM_STATE_BELOW]) { if(((Atom) ev->xclient.data.l[0]) == ewmh_atoms[NET_WM_STATE_ADD]) client_set_layer(c, BOTTOM); if(((Atom) ev->xclient.data.l[0]) == ewmh_atoms[NET_WM_STATE_REMOVE] && c->layer == BOTTOM) client_set_layer(c, NORMAL); if(((Atom) ev->xclient.data.l[0]) == ewmh_atoms[NET_WM_STATE_TOGGLE]) client_set_layer(c, (c->layer == BOTTOM) ? NORMAL : BOTTOM); } return true; } } if(ev->xclient.message_type == ewmh_atoms[NET_CURRENT_DESKTOP]) { #ifdef DEBUG_EVENTS printf(NAME ": ewmh_handle_event(): handling ClientMessage event\n\tatom: _NET_CURRENT_DESKTOP\n"); #endif desktop_goto(ev->xclient.data.l[0]); return true; } if(ev->xclient.message_type == ewmh_atoms[NET_WM_DESKTOP]) { if(c && ev->xclient.data.l[0] >= STICKY) { #ifdef DEBUG_EVENTS printf(NAME ": ewmh_handle_event(): handling ClientMessage event\n\tatom: _NET_WM_DESKTOP\n"); #endif client_to_desktop(c, (ev->xclient.data.l[0] <= dc) ? ev->xclient.data.l[0] : dc - 1); } return true; } if(ev->xclient.message_type == ewmh_atoms[NET_REQUEST_FRAME_EXTENTS]) { #ifdef DEBUG_EVENTS printf(NAME ": ewmh_handle_event(): handling ClientMessage event\n\tatom: _NET_REQUEST_FRAME_EXTENTS\n"); #endif extents[0] = border_width; extents[1] = border_width; extents[2] = border_width + title_height; extents[3] = border_width; XChangeProperty(dpy, ev->xclient.window, ewmh_atoms[NET_FRAME_EXTENTS], XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &extents, 4); return true; } if(ev->xclient.message_type == ewmh_atoms[NET_SHOWING_DESKTOP]) { #ifdef DEBUG_EVENTS printf(NAME ": ewmh_handle_event(): handling ClientMessage event\n\tatom: _NET_SHOWING_DESKTOP\n"); #endif client_iconify_all(); return true; } break; case PropertyNotify: if(ev->xproperty.atom == ewmh_atoms[NET_WM_STRUT_PARTIAL] || ev->xproperty.atom == ewmh_atoms[NET_WM_STRUT]) { #ifdef DEBUG_EVENTS printf(NAME ": ewmh_handle_event(): handling PropertyNotify event (_NET_WM_STRUT or _NET_WM_STRUT_PARTIAL changed)\n"); #endif ewmh_update_strut(); return true; } c = owner(ev->xproperty.window); if(c && ev->xproperty.atom == ewmh_atoms[NET_WM_NAME]) { if(XGetWindowProperty(dpy, c->window, ewmh_atoms[NET_WM_NAME], 0, 1024, False, xa_utf8_string, &rt, &rf, &nir, &bar, (unsigned char **) &c->ewmh_name) != Success) c->ewmh_name = NULL; else client_update_name(c); return true; } break; } return false; }