rename uicb_*mouse to uicb_client_*mouse
[awesome.git] / event.c
blob7f3ce30958c0b76479f47045ea5b4b1e341b6a52
1 /*
2 * event.c - event handlers
4 * Copyright © 2007 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <X11/keysym.h>
23 #include <X11/Xatom.h>
24 #include <X11/Xutil.h>
25 #include <X11/extensions/shape.h>
26 #include <X11/extensions/Xrandr.h>
28 #include "screen.h"
29 #include "event.h"
30 #include "layout.h"
31 #include "tag.h"
32 #include "draw.h"
33 #include "statusbar.h"
34 #include "util.h"
35 #include "window.h"
36 #include "mouse.h"
37 #include "layouts/tile.h"
38 #include "layouts/floating.h"
40 #define CLEANMASK(mask, acf) (mask & ~(acf.numlockmask | LockMask))
42 static void
43 handle_mouse_button_press(awesome_config *awesomeconf,
44 unsigned int button, unsigned int state,
45 Button *buttons, char *arg)
47 Button *b;
49 for(b = buttons; b; b = b->next)
50 if(button == b->button && CLEANMASK(state, awesomeconf[0]) == b->mod && b->func)
52 if(arg)
53 b->func(awesomeconf, arg);
54 else
55 b->func(awesomeconf, b->arg);
56 return;
60 void
61 handle_event_buttonpress(XEvent * e, awesome_config *awesomeconf)
63 int i, screen, x = 0, y = 0;
64 unsigned int udummy;
65 Client *c;
66 Window wdummy;
67 char arg[256];
68 XButtonPressedEvent *ev = &e->xbutton;
70 for(screen = 0; screen < get_screen_count(e->xany.display); screen++)
71 if(awesomeconf[screen].statusbar.window == ev->window)
73 for(i = 0; i < awesomeconf[screen].ntags; i++)
75 x += textwidth(e->xany.display, awesomeconf[screen].font, awesomeconf[screen].tags[i].name);
76 if(((awesomeconf[screen].statusbar.position == BarTop
77 || awesomeconf[screen].statusbar.position == BarBot)
78 && ev->x < x)
79 || (awesomeconf[screen].statusbar.position == BarRight && ev->y < x)
80 || (awesomeconf[screen].statusbar.position == BarLeft && ev->y > awesomeconf[screen].statusbar.width - x))
82 snprintf(arg, sizeof(arg), "%d", i + 1);
83 handle_mouse_button_press(&awesomeconf[screen], ev->button, ev->state,
84 awesomeconf[screen].buttons.tag, arg);
85 return;
88 x += awesomeconf[screen].statusbar.txtlayoutwidth;
89 if(((awesomeconf[screen].statusbar.position == BarTop
90 || awesomeconf[screen].statusbar.position == BarBot)
91 && ev->x < x)
92 || (awesomeconf[screen].statusbar.position == BarRight && ev->y < x)
93 || (awesomeconf[screen].statusbar.position == BarLeft && ev->y > awesomeconf[screen].statusbar.width - x))
94 handle_mouse_button_press(&awesomeconf[screen], ev->button, ev->state,
95 awesomeconf[screen].buttons.layout, NULL);
96 else
97 handle_mouse_button_press(&awesomeconf[screen], ev->button, ev->state,
98 awesomeconf[screen].buttons.title, NULL);
99 return;
102 if((c = get_client_bywin(*awesomeconf->clients, ev->window)))
104 XAllowEvents(c->display, ReplayPointer, CurrentTime);
105 focus(c, ev->same_screen, &awesomeconf[c->screen]);
106 if(CLEANMASK(ev->state, awesomeconf[c->screen]) == NoSymbol
107 && ev->button == Button1)
109 restack(&awesomeconf[c->screen]);
110 window_grabbuttons(c->display, c->phys_screen, c->win,
111 True, True, awesomeconf->buttons.root,
112 awesomeconf->buttons.client, awesomeconf->numlockmask);
114 else
115 handle_mouse_button_press(&awesomeconf[c->screen], ev->button, ev->state,
116 awesomeconf[c->screen].buttons.client, NULL);
118 else
119 for(screen = 0; screen < ScreenCount(e->xany.display); screen++)
120 if(RootWindow(e->xany.display, screen) == ev->window
121 && XQueryPointer(e->xany.display, ev->window, &wdummy, &wdummy, &x, &y, &i, &i, &udummy))
123 screen = get_screen_bycoord(e->xany.display, x, y);
124 handle_mouse_button_press(&awesomeconf[screen], ev->button, ev->state,
125 awesomeconf[screen].buttons.root, NULL);
126 return;
130 void
131 handle_event_configurerequest(XEvent * e, awesome_config *awesomeconf)
133 Client *c;
134 XConfigureRequestEvent *ev = &e->xconfigurerequest;
135 XWindowChanges wc;
137 if((c = get_client_bywin(*awesomeconf->clients, ev->window)))
139 c->ismax = False;
140 if(ev->value_mask & CWBorderWidth)
141 c->border = ev->border_width;
142 if(c->isfixed || c->isfloating
143 || get_current_layout(awesomeconf[c->screen].tags,
144 awesomeconf[c->screen].ntags)->arrange == layout_floating)
146 if(ev->value_mask & CWX)
147 c->x = ev->x;
148 if(ev->value_mask & CWY)
149 c->y = ev->y;
150 if(ev->value_mask & CWWidth)
151 c->w = ev->width;
152 if(ev->value_mask & CWHeight)
153 c->h = ev->height;
154 if((c->x + c->w) > DisplayWidth(c->display, c->phys_screen) && c->isfloating)
155 c->x = DisplayWidth(c->display, c->phys_screen) / 2 - c->w / 2; /* center in x direction */
156 if((c->y + c->h) > DisplayHeight(c->display, c->phys_screen) && c->isfloating)
157 c->y = DisplayHeight(c->display, c->phys_screen) / 2 - c->h / 2; /* center in y direction */
158 if((ev->value_mask & (CWX | CWY)) && !(ev->value_mask & (CWWidth | CWHeight)))
159 window_configure(c->display, c->win, c->x, c->y, c->w, c->h, c->border);
160 if(isvisible(c, c->screen, awesomeconf[c->screen].tags, awesomeconf[c->screen].ntags))
161 XMoveResizeWindow(e->xany.display, c->win, c->x, c->y, c->w, c->h);
163 else
164 window_configure(c->display, c->win, c->x, c->y, c->w, c->h, c->border);
166 else
168 wc.x = ev->x;
169 wc.y = ev->y;
170 wc.width = ev->width;
171 wc.height = ev->height;
172 wc.border_width = ev->border_width;
173 wc.sibling = ev->above;
174 wc.stack_mode = ev->detail;
175 XConfigureWindow(e->xany.display, ev->window, ev->value_mask, &wc);
177 XSync(e->xany.display, False);
180 void
181 handle_event_configurenotify(XEvent * e, awesome_config *awesomeconf)
183 XConfigureEvent *ev = &e->xconfigure;
184 int screen;
185 ScreenInfo *si;
187 for(screen = 0; screen < ScreenCount(e->xany.display); screen++)
188 if(ev->window == RootWindow(e->xany.display, screen)
189 && (ev->width != DisplayWidth(e->xany.display, screen)
190 || ev->height != DisplayHeight(e->xany.display, screen)))
192 DisplayWidth(e->xany.display, screen) = ev->width;
193 DisplayHeight(e->xany.display, screen) = ev->height;
195 /* update statusbar */
196 si = get_screen_info(e->xany.display, screen, NULL);
197 awesomeconf[screen].statusbar.width = si[screen].width;
198 p_delete(&si);
200 XResizeWindow(e->xany.display,
201 awesomeconf[screen].statusbar.window,
202 awesomeconf[screen].statusbar.width,
203 awesomeconf[screen].statusbar.height);
205 updatebarpos(e->xany.display, awesomeconf[screen].statusbar);
206 arrange(&awesomeconf[screen]);
210 void
211 handle_event_destroynotify(XEvent * e, awesome_config *awesomeconf)
213 Client *c;
214 XDestroyWindowEvent *ev = &e->xdestroywindow;
216 if((c = get_client_bywin(*awesomeconf->clients, ev->window)))
217 client_unmanage(c, WithdrawnState, &awesomeconf[c->screen]);
220 void
221 handle_event_enternotify(XEvent * e, awesome_config *awesomeconf)
223 Client *c;
224 XCrossingEvent *ev = &e->xcrossing;
225 int screen;
227 if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
228 return;
229 if((c = get_client_bywin(*awesomeconf->clients, ev->window)))
231 focus(c, ev->same_screen, &awesomeconf[c->screen]);
232 if (c->isfloating
233 || get_current_layout(awesomeconf[c->screen].tags,
234 awesomeconf[c->screen].ntags)->arrange == layout_floating)
235 window_grabbuttons(c->display, c->phys_screen, c->win,
236 True, False, awesomeconf->buttons.root,
237 awesomeconf->buttons.client, awesomeconf->numlockmask);
239 else
240 for(screen = 0; screen < ScreenCount(e->xany.display); screen++)
241 if(ev->window == RootWindow(e->xany.display, screen))
242 focus(NULL, True, &awesomeconf[screen]);
245 void
246 handle_event_expose(XEvent * e, awesome_config *awesomeconf)
248 XExposeEvent *ev = &e->xexpose;
249 int screen;
251 if(!ev->count)
252 for(screen = 0; screen < get_screen_count(e->xany.display); screen++)
253 if(awesomeconf[screen].statusbar.window == ev->window)
254 drawstatusbar(&awesomeconf[screen]);
257 void
258 handle_event_keypress(XEvent * e, awesome_config *awesomeconf)
260 int screen, x, y, d;
261 unsigned int m;
262 KeySym keysym;
263 XKeyEvent *ev = &e->xkey;
264 Window dummy;
265 Key *k;
267 keysym = XKeycodeToKeysym(e->xany.display, (KeyCode) ev->keycode, 0);
269 /* find the right screen for this event */
270 for(screen = 0; screen < ScreenCount(e->xany.display); screen++)
271 if(XQueryPointer(e->xany.display, RootWindow(e->xany.display, screen), &dummy, &dummy, &x, &y, &d, &d, &m))
273 /* if screen is 0, we are on first Zaphod screen or on the
274 * only screen in Xinerama, so we can ask for a better screen
275 * number with get_screen_bycoord: we'll get 0 in Zaphod mode
276 * so it's the same, or maybe the real Xinerama screen */
277 if(screen == 0)
278 screen = get_screen_bycoord(e->xany.display, x, y);
279 break;
282 for(k = awesomeconf[screen].keys; k; k = k->next)
283 if(keysym == k->keysym && k->func
284 && CLEANMASK(k->mod, awesomeconf[screen]) == CLEANMASK(ev->state, awesomeconf[screen]))
285 k->func(&awesomeconf[screen], k->arg);
288 void
289 handle_event_leavenotify(XEvent * e, awesome_config *awesomeconf)
291 XCrossingEvent *ev = &e->xcrossing;
292 int screen;
294 for(screen = 0; screen < ScreenCount(e->xany.display); screen++)
295 if((ev->window == RootWindow(e->xany.display, screen)) && !ev->same_screen)
296 focus(NULL, ev->same_screen, &awesomeconf[screen]);
299 void
300 handle_event_mappingnotify(XEvent * e, awesome_config *awesomeconf)
302 XMappingEvent *ev = &e->xmapping;
303 int screen;
305 XRefreshKeyboardMapping(ev);
306 if(ev->request == MappingKeyboard)
307 for(screen = 0; screen < ScreenCount(e->xany.display); screen++)
308 grabkeys(&awesomeconf[screen]);
311 void
312 handle_event_maprequest(XEvent * e, awesome_config *awesomeconf)
314 static XWindowAttributes wa;
315 XMapRequestEvent *ev = &e->xmaprequest;
316 int screen, x, y, d;
317 unsigned int m;
318 Window dummy;
320 if(!XGetWindowAttributes(e->xany.display, ev->window, &wa))
321 return;
322 if(wa.override_redirect)
323 return;
324 if(!get_client_bywin(*awesomeconf->clients, ev->window))
326 for(screen = 0; wa.screen != ScreenOfDisplay(e->xany.display, screen); screen++);
327 if(screen == 0 && XQueryPointer(e->xany.display, RootWindow(e->xany.display, screen),
328 &dummy, &dummy, &x, &y, &d, &d, &m))
329 screen = get_screen_bycoord(e->xany.display, x, y);
330 client_manage(ev->window, &wa, &awesomeconf[screen]);
334 void
335 handle_event_propertynotify(XEvent * e, awesome_config *awesomeconf)
337 Client *c;
338 Window trans;
339 XPropertyEvent *ev = &e->xproperty;
341 if(ev->state == PropertyDelete)
342 return; /* ignore */
343 if((c = get_client_bywin(*awesomeconf->clients, ev->window)))
345 switch (ev->atom)
347 case XA_WM_TRANSIENT_FOR:
348 XGetTransientForHint(e->xany.display, c->win, &trans);
349 if(!c->isfloating && (c->isfloating = (get_client_bywin(*awesomeconf->clients, trans) != NULL)))
350 arrange(&awesomeconf[c->screen]);
351 break;
352 case XA_WM_NORMAL_HINTS:
353 updatesizehints(c);
354 break;
356 if(ev->atom == XA_WM_NAME || ev->atom == XInternAtom(c->display, "_NET_WM_NAME", False))
358 updatetitle(c);
359 if(c == get_current_tag(awesomeconf->tags, awesomeconf->ntags)->client_sel)
360 drawstatusbar(&awesomeconf[c->screen]);
365 void
366 handle_event_unmapnotify(XEvent * e, awesome_config *awesomeconf)
368 Client *c;
369 XUnmapEvent *ev = &e->xunmap;
371 if((c = get_client_bywin(*awesomeconf->clients, ev->window))
372 && ev->event == RootWindow(e->xany.display, c->phys_screen)
373 && ev->send_event && window_getstate(c->display, c->win) == NormalState)
374 client_unmanage(c, WithdrawnState, &awesomeconf[c->screen]);
377 void
378 handle_event_shape(XEvent * e,
379 awesome_config *awesomeconf __attribute__ ((unused)))
381 XShapeEvent *ev = (XShapeEvent *) e;
382 Client *c = get_client_bywin(*awesomeconf->clients, ev->window);
384 if(c)
385 window_setshape(c->display, c->phys_screen, c->win);
388 void
389 handle_event_randr_screen_change_notify(XEvent *e,
390 awesome_config *awesomeconf __attribute__ ((unused)))
392 XRRUpdateConfiguration(e);
395 void
396 grabkeys(awesome_config *awesomeconf)
398 Key *k;
399 KeyCode code;
401 XUngrabKey(awesomeconf->display, AnyKey, AnyModifier, RootWindow(awesomeconf->display, awesomeconf->phys_screen));
402 for(k = awesomeconf->keys; k; k = k->next)
404 if((code = XKeysymToKeycode(awesomeconf->display, k->keysym)) == NoSymbol)
405 continue;
406 XGrabKey(awesomeconf->display, code, k->mod, RootWindow(awesomeconf->display, awesomeconf->phys_screen), True, GrabModeAsync, GrabModeAsync);
407 XGrabKey(awesomeconf->display, code, k->mod | LockMask, RootWindow(awesomeconf->display, awesomeconf->phys_screen), True, GrabModeAsync, GrabModeAsync);
408 XGrabKey(awesomeconf->display, code, k->mod | awesomeconf->numlockmask, RootWindow(awesomeconf->display, awesomeconf->phys_screen), True, GrabModeAsync, GrabModeAsync);
409 XGrabKey(awesomeconf->display, code, k->mod | awesomeconf->numlockmask | LockMask, RootWindow(awesomeconf->display, awesomeconf->phys_screen), True, GrabModeAsync, GrabModeAsync);
412 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99