/* * event.c * Copyright © 2008 Martin Duquesnoy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of the nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "wmfs.h" /* BUTTONPRESS * For make a code cleaner, i put * more {} (useless sometimes) * and BIG comment.*/ void buttonpress(XEvent ev) { Client *c; int i, j; char s[6]; if(conf.ttbarheight) { /* ******** */ /* TITLEBAR */ /* ******** */ { if((c = client_gettbar(ev.xbutton.window))) { raiseclient(c); /* BUTTON 1 */ { if(ev.xbutton.button == Button1) mouseaction(c, ev.xbutton.x_root, ev.xbutton.y_root, False); } /* BUTTON 2 */ { if(ev.xbutton.button == Button2) { if(tags[seltag].layout.func == tile) uicb_tile_switch(NULL); else uicb_togglemax(NULL); } } /* BUTTON 3 */ { if(ev.xbutton.button == Button3) mouseaction(c, ev.xbutton.x_root, ev.xbutton.y_root, True); } } } } /* ****** */ /* CLIENT */ /* ****** */ { if((c = getclient(ev.xbutton.window))) { raiseclient(c); /* BUTTON 1 */ { if(ev.xbutton.button == Button1) mouseaction(c, ev.xbutton.x_root, ev.xbutton.y_root, False); } /* BUTTON 2 */ { if(ev.xbutton.button == Button2) { if(tags[seltag].layout.func == tile) uicb_tile_switch(NULL); else uicb_togglemax(NULL); } } /* BUTTON 3 */ { if(ev.xbutton.button == Button3) mouseaction(c, ev.xbutton.x_root, ev.xbutton.y_root, True); } } } /* *** */ /* BAR */ /* *** */ { if(ev.xbutton.window == bar->win) { /* *** */ /* TAG */ /* *** */ { /* CLICK */ { for(i = 0; i < conf.ntag + 1; ++i) { if(ev.xbutton.x > taglen[i-1] - 3 && ev.xbutton.x < (taglen[i] - 3)) { ITOA(s, i); /* BUTTON 1 */ { if(ev.xbutton.button == Button1) uicb_tag(s); } /* BUTTON 2 */ { if(ev.xbutton.button == Button3) uicb_tagtransfert(s); } } } } /* SCROLL */ { if(ev.xbutton.x < taglen[conf.ntag]) { /* BUTTON 4 (UP) */ { if(ev.xbutton.button == Button4) uicb_tag("+1"); } /* BUTTON 5 (UP) */ { if (ev.xbutton.button == Button5) uicb_tag("-1"); } } } } /* ****** */ /* LAYOUT */ /* ****** */ { if(ev.xbutton.x >= taglen[conf.ntag] && ev.xbutton.x <= taglen[conf.ntag] + textw(tags[seltag].layout.symbol) + PAD/2) { /* BUTTON 1 / 4 */ { if(ev.xbutton.button == Button1 || ev.xbutton.button == Button4) layoutswitch(True); } /* BUTTON 3 / 5 */ { if(ev.xbutton.button == Button3 || ev.xbutton.button == Button5) layoutswitch(False); } } } } } /* **** */ /* ROOT */ /* **** */ { if(ev.xbutton.window == root) { /* BUTTON 4 */ { if(ev.xbutton.button == Button4) uicb_tag("+1"); } /* BUTTON 5 */ { if(ev.xbutton.button == Button5) uicb_tag("-1"); } } } /* *********** */ /* BAR BUTTONS */ /* *********** */ { for(i=0; iwin && ev.xbutton.button == conf.barbutton[i].mouse[j]) if(conf.barbutton[i].func[j]) conf.barbutton[i].func[j](conf.barbutton[i].cmd[j]); } return; } /* CONFIGUREREQUEST */ void configurerequest(XEvent ev) { Client *c; XWindowChanges wc; XRectangle geo; if((c = getclient(ev.xconfigurerequest.window))) if(c->tile || c->lmax) return; geo.x = wc.x = ev.xconfigurerequest.x; geo.y = wc.y = ev.xconfigurerequest.y; geo.width = wc.width = ev.xconfigurerequest.width; geo.height = wc.height = ev.xconfigurerequest.height; wc.border_width = ev.xconfigurerequest.border_width; wc.sibling = ev.xconfigurerequest.above; wc.stack_mode = ev.xconfigurerequest.detail; XConfigureWindow(dpy, ev.xconfigurerequest.window, ev.xconfigurerequest.value_mask, &wc); if((c = getclient(ev.xconfigurerequest.window))) if(wc.y < mw && wc.x < mh) { geo.y -= conf.ttbarheight; geo.height += conf.ttbarheight; client_moveresize(c, geo, True); } return; } /* DESTROYNOTIFY */ void destroynotify(XEvent ev) { Client *c; if((c = getclient(ev.xdestroywindow.window))) client_unmanage(c); return; } /* ENTERNOTIFY */ void enternotify(XEvent ev) { Client *c; if(ev.xcrossing.mode != NotifyNormal || ev.xcrossing.detail == NotifyInferior) return; if((c = getclient(ev.xcrossing.window)) || (c = client_gettbar(ev.xcrossing.window))) client_focus(c); else client_focus(NULL); return; } /* EXPOSE */ void expose(XEvent ev) { Client *c; if(ev.xexpose.count == 0 && (ev.xexpose.window == bar->win)) updatebar(); if(conf.ttbarheight) for(c = clients; c; c = c->next) if(ev.xexpose.window == c->tbar->win) updatetitlebar(c); return; } /* FOCUSIN */ void focusin(XEvent ev) { if(sel && ev.xfocus.window != sel->win) XSetInputFocus(dpy, sel->win, RevertToPointerRoot, CurrentTime); return; } void grabbuttons(Client *c, Bool focused) { XUngrabButton(dpy, AnyButton, AnyModifier, c->win); if(focused) { /* Window */ XGrabButton(dpy, Button1, ALT, c->win, False, ButtonMask, GrabModeAsync,GrabModeSync, None, None); XGrabButton(dpy, Button1, ALT|LockMask, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); XGrabButton(dpy, Button2, ALT, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); XGrabButton(dpy, Button2, ALT|LockMask, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); XGrabButton(dpy, Button3, ALT, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); XGrabButton(dpy, Button3, ALT|LockMask, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); } else XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); return; } void grabkeys(void) { uint i; KeyCode code; XUngrabKey(dpy, AnyKey, AnyModifier, root); for(i = 0; i < conf.nkeybind; i++) { code = XKeysymToKeycode(dpy, keys[i].keysym); XGrabKey(dpy, code, keys[i].mod, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(dpy, code, keys[i].mod|numlockmask, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(dpy, code, keys[i].mod|LockMask, root, True, GrabModeAsync, GrabModeAsync); XGrabKey(dpy, code, keys[i].mod|LockMask|numlockmask, root, True, GrabModeAsync, GrabModeAsync); } return; } /* KEYPRESS */ void keypress(XEvent ev) { uint i; KeySym keysym; keysym = XKeycodeToKeysym(dpy, (KeyCode)ev.xkey.keycode, 0); for(i = 0; i < conf.nkeybind; i++) if(keysym == keys[i].keysym && (keys[i].mod & ~(numlockmask | LockMask)) == (ev.xkey.state & ~(numlockmask | LockMask)) && keys[i].func) keys[i].func(keys[i].cmd); return; } /* MAPPINGNOTIFY */ void mapnotify(XEvent ev) { if(ev.xmapping.request == MappingKeyboard) grabkeys(); return; } /* MAPREQUEST */ void maprequest(XEvent ev) { XWindowAttributes at; if(!XGetWindowAttributes(dpy, ev.xmaprequest.window, &at)) return; if(at.override_redirect) return; if(!getclient(ev.xmaprequest.window)) { client_focus(NULL); client_manage(ev.xmaprequest.window, &at); } return; } /* If the type is 0, this function will move, else, * this will resize */ void mouseaction(Client *c, int x, int y, int type) { int ocx, ocy; XRectangle geo; XEvent ev; if(c->max || c->tile || c->lmax) return; ocx = c->geo.x; ocy = c->geo.y; if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync, None, cursor[((type) ?CurResize:CurMove)], CurrentTime) != GrabSuccess) return; if(type) XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->geo.width, c->geo.height); for(;;) { XMaskEvent(dpy, MouseMask | ExposureMask | SubstructureRedirectMask, &ev); if(ev.type == ButtonRelease) { if(type) XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->geo.width, c->geo.height); XUngrabPointer(dpy, CurrentTime); updatebar(); return; } else if(ev.type == MotionNotify) { XSync(dpy, False); /* Resize */ if(type) { geo.x = c->geo.x; geo.y = c->geo.y; geo.width = ((ev.xmotion.x - ocx <= 0) ? 1 : ev.xmotion.x - ocx); geo.height = ((ev.xmotion.y - ocy <= 0) ? 1 : ev.xmotion.y - ocy); client_moveresize(c, geo, True); } /* Move */ else { geo.x = (ocx + (ev.xmotion.x - x)); geo.y = (ocy + (ev.xmotion.y - y)); geo.width = c->geo.width; geo.height = c->geo.height; client_moveresize(c, geo, True); } } else if(ev.type == Expose) expose(ev); } return; } /* PROPERTYNOTIFY */ void propertynotify(XEvent ev) { Client *c; Window trans; if(event.xproperty.state == PropertyDelete) return; if((c = getclient(event.xproperty.window))) { switch(event.xproperty.atom) { default: break; case XA_WM_TRANSIENT_FOR: XGetTransientForHint(dpy, c->win, &trans); if((c->tile || c->max) && (c->hint = (getclient(trans) != NULL))) arrange(); break; case XA_WM_NORMAL_HINTS: client_size_hints(c); break; } if(ev.xproperty.atom == XA_WM_NAME || ev.xproperty.atom == net_atom[NetWMName]) updatetitlebar(c); } return; } /* UNMAPNOTIFY */ void unmapnotify(XEvent ev) { Client *c; if((c = getclient(ev.xunmap.window))) if(!c->hide) client_unmanage(c); return; } /* Handle */ void getevent(void) { switch (event.type) { case ButtonPress: buttonpress(event); break; case ConfigureRequest: configurerequest(event); break; case DestroyNotify: destroynotify(event); break; case EnterNotify: enternotify(event); break; case Expose: expose(event); break; case FocusIn: focusin(event); break; case KeyPress: keypress(event); break; case MapRequest: maprequest(event); break; case MappingNotify: mapnotify(event); break; case PropertyNotify: propertynotify(event); break; case UnmapNotify: unmapnotify(event); break; } return; }