/* * wmfs2 by Martin Duquesnoy { for(i = 2011; i < 2111; ++i) ©(i); } * For license, see COPYING. */ #include "event.h" #include "ewmh.h" #include "config.h" #include "util.h" #include "wmfs.h" #include "client.h" #include "barwin.h" #include "screen.h" #include "systray.h" #include "infobar.h" #define EVDPY(e) (e)->xany.display #define MOUSE_DO_BIND(m) \ if(m->button == ev->button) \ if(!m->use_area || (m->use_area && INAREA(ev->x, ev->y, m->area))) \ if(m->func) \ m->func(m->cmd); 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); } } static void event_clientmessageevent(XEvent *e) { XClientMessageEvent *ev = &e->xclient; struct client *c; struct _systray *sy; int type = 0; while(type < net_last && W->net_atom[type] != ev->message_type) ++type; /* * Systray message * _NET_WM_SYSTRAY_TRAY_OPCODE */ if(ev->window == W->systray.win && type == net_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); } } else if(ev->window == W->root) { /* WMFS message */ if(ev->data.l[4]) { /* Manage _WMFS_FUNCTION && _WMFS_CMD */ if(type == wmfs_function || type == wmfs_cmd) { Atom rt; int d; long unsigned int len, il; unsigned char *ret = NULL, *ret_cmd = NULL; void (*func)(Uicb); if(XGetWindowProperty(EVDPY(e), W->root, W->net_atom[wmfs_function], 0, 65536, False, W->net_atom[utf8_string], &rt, &d, &len, &il, &ret) == Success && ret && ((func = uicb_name_func((char*)ret)))) { if(XGetWindowProperty(EVDPY(e), W->root, W->net_atom[wmfs_cmd], 0, 65536, False, W->net_atom[utf8_string], &rt, &d, &len, &il, &ret_cmd) == Success && len && ret_cmd) { func((Uicb)ret_cmd); XFree(ret_cmd); } else func(NULL); XFree(ret); } } } if(type == net_active_window) if((sy = systray_find(ev->data.l[0]))) XSetInputFocus(W->dpy, sy->win, RevertToNone, CurrentTime); } switch(type) { /* _NET_WM_STATE */ case net_wm_state: if((c = client_gb_win(ev->window))) ewmh_manage_state(ev->data.l, c); break; /* _NET_CLOSE_WINDOW */ case net_close_window: if((c = client_gb_win(ev->window))) client_close(c); break; /* _NET_WM_DESKTOP */ case net_wm_desktop: break; } } static void event_configureevent(XEvent *e) { XConfigureRequestEvent *ev = &e->xconfigurerequest; XWindowChanges wc; struct client *c; if((c = client_gb_win(ev->window))) { if(c->flags & CLIENT_FREE) { if(ev->value_mask & CWX) c->geo.x = ev->x; if(ev->value_mask & CWY) c->geo.y = ev->y - c->tbarw - c->border - c->border; if(ev->value_mask & CWWidth) c->geo.w = ev->width + c->border + c->border; if(ev->value_mask & CWHeight) c->geo.h = ev->height + c->tbarw + c->border; client_moveresize(c, &c->geo); } else { if(ev->value_mask & CWWidth) _fac_resize(c, Right, ev->width - c->wgeo.w); if(ev->value_mask & CWHeight) _fac_resize(c, Bottom, ev->height - c->wgeo.h); client_apply_tgeo(c->tag); } } else { wc.x = ev->x; wc.y = ev->y; wc.width = ev->width; wc.height = ev->height; wc.border_width = ev->border_width; wc.sibling = ev->above; wc.stack_mode = ev->detail; XConfigureWindow(EVDPY(e), ev->window, ev->value_mask, &wc); } } static void event_destroynotify(XEvent *e) { XDestroyWindowEvent *ev = &e->xdestroywindow; struct client *c; struct _systray *s; if((c = client_gb_win(ev->window))) client_remove(c); else if((s = systray_find(ev->window))) { ewmh_set_wm_state(s->win, WithdrawnState); systray_del(s); systray_update(); } } 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); } static void event_maprequest(XEvent *e) { XMapRequestEvent *ev = &e->xmaprequest; XWindowAttributes at; struct _systray *s; /* Which windows to manage */ if(!XGetWindowAttributes(EVDPY(e), ev->window, &at) || at.override_redirect || ewmh_manage_window_type_desktop(ev->window) || ewmh_manage_state_sticky(ev->window)) return; if(!client_gb_win(ev->window)) client_new(ev->window, &at, false); else if((s = systray_find(ev->window))) { ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, 0, 0); systray_update(); } } static void event_mappingnotify(XEvent *e) { XMappingEvent *ev = &e->xmapping; XRefreshKeyboardMapping(ev); if(ev->request == MappingKeyboard) wmfs_grab_keys(); } static void event_propertynotify(XEvent *e) { XPropertyEvent *ev = &e->xproperty; XWMHints *h; struct client *c; struct _systray *s; if(ev->state == PropertyDelete) return; if((c = client_gb_win(ev->window))) { switch(ev->atom) { case XA_WM_TRANSIENT_FOR: break; case XA_WM_NORMAL_HINTS: client_get_sizeh(c); break; case XA_WM_HINTS: if((h = XGetWMHints(EVDPY(e), c->win)) && (h->flags & XUrgencyHint) && c->tag != W->screen->seltag) { c->tag->flags |= TAG_URGENT; infobar_elem_screen_update(c->screen, ElemTag); XFree(h); } break; default: if(ev->atom == XA_WM_NAME || ev->atom == W->net_atom[net_wm_name]) client_get_name(c); break; } } else if((s = systray_find(ev->window))) { systray_state(s); systray_update(); } } static void event_unmapnotify(XEvent *e) { XUnmapEvent *ev = &e->xunmap; struct client *c; struct _systray *s; if((c = client_gb_win(ev->window)) && ev->send_event && ev->event == W->root) { Atom rt; unsigned long n, il; int d; unsigned char *ret = NULL; if(XGetWindowProperty(EVDPY(e), c->win, W->net_atom[wm_state], 0, 2, False, W->net_atom[wm_state], &rt, &d, &n, &il, &ret) == Success) if(*ret == NormalState) client_remove(c); } else if((s = systray_find(ev->window))) { systray_del(s); systray_update(); } } static void event_keypress(XEvent *e) { XKeyPressedEvent *ev = &e->xkey; KeySym keysym = XkbKeycodeToKeysym(EVDPY(e), (KeyCode)ev->keycode, 0, 0); struct keybind *k; screen_update_sel(); status_flush_surface(); SLIST_FOREACH(k, &W->h.keybind, next) if(k->keysym == keysym && KEYPRESS_MASK(k->mod) == KEYPRESS_MASK(ev->state)) if(k->func) k->func(k->cmd); } static void event_expose(XEvent *e) { XExposeEvent *ev = &e->xexpose; struct barwin *b; SLIST_FOREACH(b, &W->h.barwin, next) if(b->win == ev->window) { barwin_refresh(b); return; } } static void event_mapnotify(XEvent *e) { XMapEvent *ev = &e->xmap; struct client *c; struct _systray *s; if(ev->window != ev->event && !ev->send_event) return; if((c = client_gb_win(ev->window))) client_map(c); else if((s = systray_find(ev->window))) { ewmh_set_wm_state(s->win, NormalState); ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, 0, 0); } } static void event_selectionclearevent(XEvent *ev) { /* Getting selection if lost it */ if(ev->xselectionclear.window == W->systray.win) systray_acquire(); systray_update(); } static void event_dummy(XEvent *e) { /* printf("%d\n", e->type);*/ (void)e; } void event_init(void) { int i = MAX_EV; while(i--) event_handle[i] = event_dummy; event_handle[ButtonPress] = event_buttonpress; event_handle[ClientMessage] = event_clientmessageevent; event_handle[ConfigureRequest] = event_configureevent; event_handle[DestroyNotify] = event_destroynotify; event_handle[EnterNotify] = event_enternotify; event_handle[Expose] = event_expose; event_handle[FocusIn] = event_focusin; event_handle[KeyPress] = event_keypress; event_handle[MapNotify] = event_mapnotify; event_handle[MapRequest] = event_maprequest; event_handle[MappingNotify] = event_mappingnotify; event_handle[PropertyNotify] = event_propertynotify; /*event_handle[ReparentNotify] = event_reparentnotify;*/ event_handle[SelectionClear] = event_selectionclearevent; event_handle[UnmapNotify] = event_unmapnotify; }