diff options
Diffstat (limited to 'src/xevent.c')
-rw-r--r-- | src/xevent.c | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/src/xevent.c b/src/xevent.c new file mode 100644 index 0000000..1955ee3 --- /dev/null +++ b/src/xevent.c @@ -0,0 +1,269 @@ +/* + * \/\/\ + * + * Copyright (C) 2012-2016 Vito Caputo - <vcaputo@gnugeneration.com> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "X11/Xlib.h" + +#include "key.h" +#include "clickety.h" +#include "composite.h" +#include "desktop.h" +#include "screen.h" +#include "vwm.h" +#include "window.h" +#include "xwindow.h" + +/* this forms the glue between the X event loop in vwm.c and the rest of the + * code making up vwm */ + +void vwm_xevent_handle_key_press(vwm_t *vwm, XKeyPressedEvent *ev) +{ + vwm_key_pressed(vwm, ev->window, ev); +} + + +void vwm_xevent_handle_key_release(vwm_t *vwm, XKeyReleasedEvent *ev) +{ + vwm_key_released(vwm, ev->window, ev); +} + + +void vwm_xevent_handle_button_press(vwm_t *vwm, XButtonPressedEvent *ev) +{ + vwm_clickety_pressed(vwm, ev->window, ev); +} + + +void vwm_xevent_handle_motion_notify(vwm_t *vwm, XMotionEvent *ev) +{ + vwm_clickety_motion(vwm, ev->window, ev); +} + + +void vwm_xevent_handle_button_release(vwm_t *vwm, XButtonReleasedEvent *ev) +{ + vwm_clickety_released(vwm, ev->window, ev); +} + + +void vwm_xevent_handle_create_notify(vwm_t *vwm, XCreateWindowEvent *ev) +{ + vwm_xwin_create(vwm, ev->window, VWM_NOT_GRABBED); +} + + +void vwm_xevent_handle_destroy_notify(vwm_t *vwm, XDestroyWindowEvent *ev) +{ + vwm_xwindow_t *xwin; + + if ((xwin = vwm_xwin_lookup(vwm, ev->window))) { + vwm_xwin_destroy(vwm, xwin); + } +} + + +void vwm_xevent_handle_configure_request(vwm_t *vwm, XConfigureRequestEvent *ev) +{ + XWindowChanges changes = { + .x = ev->x, /* TODO: for now I don't manipulate anything */ + .y = ev->y, + .width = ev->width, + .height = ev->height, + .border_width = WINDOW_BORDER_WIDTH /* except I do override whatever the border width may be */ + }; + unsigned long change_mask = (ev->value_mask & (CWX | CWY | CWWidth | CWHeight)) | CWBorderWidth; + vwm_xwindow_t *xwin; + + /* XXX: windows raising themselves is annoying, so discard CWSibling and CWStackMode. */ + + if ((xwin = vwm_xwin_lookup(vwm, ev->window)) && + xwin->managed && + xwin->managed->autoconfigured == VWM_WIN_AUTOCONF_ALL) { + /* this is to allow auto-allscreen to succeed in getting a borderless window configured */ + change_mask &= ~CWBorderWidth; + } + + XConfigureWindow(vwm->display, ev->window, change_mask, &changes); +} + + +void vwm_xevent_handle_configure_notify(vwm_t *vwm, XConfigureEvent *ev) +{ + vwm_xwindow_t *xwin; + + if ((xwin = vwm_xwin_lookup(vwm, ev->window))) { + XWindowAttributes attrs; + vwm_xwin_restack(vwm, xwin, ev->above); + XGetWindowAttributes(vwm->display, ev->window, &attrs); + vwm_composite_handle_configure(vwm, xwin, &attrs); + VWM_TRACE("pre x=%i y=%i w=%i h=%i\n", xwin->attrs.x, xwin->attrs.y, xwin->attrs.width, xwin->attrs.height); + xwin->attrs = attrs; + VWM_TRACE("post x=%i y=%i w=%i h=%i\n", xwin->attrs.x, xwin->attrs.y, xwin->attrs.width, xwin->attrs.height); + } +} + + +void vwm_xevent_handle_unmap_notify(vwm_t *vwm, XUnmapEvent *ev) +{ + vwm_xwindow_t *xwin; + + /* unlike MapRequest, we simply are notified when a window is unmapped. */ + if ((xwin = vwm_xwin_lookup(vwm, ev->window))) { + if (xwin->managed) { + if (xwin->managed->unmapping) { + VWM_TRACE("swallowed vwm-induced UnmapNotify"); + xwin->managed->unmapping = 0; + } else { + /* client requested unmap, demote the window and note the unmapped state */ + vwm_win_unmanage(vwm, xwin->managed); + xwin->mapped = 0; + } + } else { + /* if it's not managed, we can't have caused the map */ + xwin->mapped = 0; + } + + vwm_composite_damage_win(vwm, xwin); + } +} + + +void vwm_xevent_handle_map_notify(vwm_t *vwm, XMapEvent *ev) +{ + vwm_xwindow_t *xwin; + + if ((xwin = vwm_xwin_lookup(vwm, ev->window))) { + if (xwin->managed && xwin->managed->mapping) { + VWM_TRACE("swallowed vwm-induced MapNotify"); + xwin->managed->mapping = 0; + } else { + /* some windows like popup dialog boxes bypass MapRequest */ + xwin->mapped = 1; + } + + vwm_composite_handle_map(vwm, xwin); + } +} + + +void vwm_xevent_handle_map_request(vwm_t *vwm, XMapRequestEvent *ev) +{ + vwm_xwindow_t *xwin; + vwm_window_t *vwin = NULL; + int domap = 1; + + /* FIXME TODO: this is a fairly spuriously open-coded mess, this stuff + * needs to be factored and moved elsewhere */ + + if ((xwin = vwm_xwin_lookup(vwm, ev->window)) && + ((vwin = xwin->managed) || (vwin = vwm_win_manage_xwin(vwm, xwin)))) { + XWindowAttributes attrs; + XWindowChanges changes = {.x = 0, .y = 0}; + unsigned changes_mask = (CWX | CWY); + XClassHint *classhint; + const vwm_screen_t *scr = NULL; + + xwin->mapped = 1; /* note that the client mapped the window */ + + /* figure out if the window is the console */ + if ((classhint = XAllocClassHint())) { + if (XGetClassHint(vwm->display, ev->window, classhint) && !strcmp(classhint->res_class, CONSOLE_WM_CLASS)) { + vwm->console = vwin; + vwm_win_shelve(vwm, vwin); + vwm_win_autoconf(vwm, vwin, VWM_SCREEN_REL_XWIN, VWM_WIN_AUTOCONF_FULL); + domap = 0; + } + + if (classhint->res_class) XFree(classhint->res_class); + if (classhint->res_name) XFree(classhint->res_name); + XFree(classhint); + } + + /* TODO: this is a good place to hook in a window placement algo */ + + /* on client-requested mapping we place the window */ + if (!vwin->shelved) { + /* we place the window on the screen containing the the pointer only if that screen is empty, + * otherwise we place windows on the screen containing the currently focused window */ + /* since we query the geometry of windows in determining where to place them, a configuring + * flag is used to exclude the window being configured from those queries */ + scr = vwm_screen_find(vwm, VWM_SCREEN_REL_POINTER); + vwin->configuring = 1; + if (vwm_screen_is_empty(vwm, scr)) { + /* focus the new window if it isn't already focused when it's going to an empty screen */ + VWM_TRACE("window \"%s\" is alone on screen \"%i\", focusing", vwin->xwindow->name, scr->screen_number); + vwm_win_focus(vwm, vwin); + } else { + scr = vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, vwm->focused_desktop->focused_window->xwindow); + } + vwin->configuring = 0; + + changes.x = scr->x_org; + changes.y = scr->y_org; + } else if (vwm->focused_context == VWM_CONTEXT_SHELF) { + scr = vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, vwm->focused_shelf->xwindow); + changes.x = scr->x_org; + changes.y = scr->y_org; + } + + /* XXX TODO: does this belong here? */ + XGetWMNormalHints(vwm->display, ev->window, vwin->hints, &vwin->hints_supplied); + XGetWindowAttributes(vwm->display, ev->window, &attrs); + + + /* if the window size is precisely the screen size then directly "allscreen" the window right here */ + if (!vwin->shelved && scr && + attrs.width == scr->width && + attrs.height == scr->height) { + VWM_TRACE("auto-allscreened window \"%s\"", vwin->xwindow->name); + changes.border_width = 0; + changes_mask |= CWBorderWidth; + vwin->autoconfigured = VWM_WIN_AUTOCONF_ALL; + } + + vwin->client.x = changes.x; + vwin->client.y = changes.y; + vwin->client.height = attrs.height; + vwin->client.width = attrs.width; + + XConfigureWindow(vwm->display, ev->window, changes_mask, &changes); + } + + if (domap) { + XMapWindow(vwm->display, ev->window); + if (vwin && vwin->desktop->focused_window == vwin) { + XSync(vwm->display, False); + XSetInputFocus(vwm->display, vwin->xwindow->id, RevertToPointerRoot, CurrentTime); + } + } +} + + +void vwm_xevent_handle_property_notify(vwm_t *vwm, XPropertyEvent *ev) +{ + vwm_xwindow_t *xwin; + + if ((xwin = vwm_xwin_lookup(vwm, ev->window)) && + ev->atom == vwm->wm_pid_atom && + ev->state == PropertyNewValue) vwm_overlay_xwin_create(vwm, xwin); +} + + +void vwm_xevent_handle_mapping_notify(vwm_t *vwm, XMappingEvent *ev) +{ + XRefreshKeyboardMapping(ev); +} |