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>
33 #include "statusbar.h"
36 #include "layouts/tile.h"
37 #include "layouts/floating.h"
39 #define CLEANMASK(mask, screen) (mask & ~(awesomeconf[screen].numlockmask | LockMask))
40 #define MOUSEMASK (BUTTONMASK | PointerMotionMask)
43 movemouse(Client
*c
, awesome_config
*awesomeconf
)
45 int x1
, y1
, ocx
, ocy
, di
, nx
, ny
;
51 si
= get_screen_info(c
->display
, c
->screen
, &awesomeconf
[c
->screen
].statusbar
);
55 if(XGrabPointer(c
->display
, RootWindow(c
->display
, c
->phys_screen
), False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
,
56 None
, awesomeconf
[c
->screen
].cursor
[CurMove
], CurrentTime
) != GrabSuccess
)
58 XWarpPointer(c
->display
, None
, c
->win
, 0, 0, 0, 0, c
->w
/ 2, c
->h
/ 2);
59 XQueryPointer(c
->display
, RootWindow(c
->display
, c
->phys_screen
), &dummy
, &dummy
, &x1
, &y1
, &di
, &di
, &dui
);
62 XMaskEvent(c
->display
, MOUSEMASK
| ExposureMask
| SubstructureRedirectMask
, &ev
);
66 XUngrabPointer(c
->display
, CurrentTime
);
69 case ConfigureRequest
:
70 handle_event_configurerequest(&ev
,awesomeconf
);
73 handle_event_expose(&ev
, awesomeconf
);
76 handle_event_maprequest(&ev
, awesomeconf
);
79 XSync(c
->display
, False
);
80 nx
= ocx
+ (ev
.xmotion
.x
- x1
);
81 ny
= ocy
+ (ev
.xmotion
.y
- y1
);
82 if(abs(nx
) < awesomeconf
[c
->screen
].snap
+ si
[c
->screen
].x_org
&& nx
> si
[c
->screen
].x_org
)
83 nx
= si
[c
->screen
].x_org
;
84 else if(abs((si
[c
->screen
].x_org
+ si
[c
->screen
].width
) - (nx
+ c
->w
+ 2 * c
->border
)) < awesomeconf
[c
->screen
].snap
)
85 nx
= si
[c
->screen
].x_org
+ si
[c
->screen
].width
- c
->w
- 2 * c
->border
;
86 if(abs(ny
) < awesomeconf
[c
->screen
].snap
+ si
[c
->screen
].y_org
&& ny
> si
[c
->screen
].y_org
)
87 ny
= si
[c
->screen
].y_org
;
88 else if(abs((si
[c
->screen
].y_org
+ si
[c
->screen
].height
) - (ny
+ c
->h
+ 2 * c
->border
)) < awesomeconf
[c
->screen
].snap
)
89 ny
= si
[c
->screen
].y_org
+ si
[c
->screen
].height
- c
->h
- 2 * c
->border
;
90 client_resize(c
, nx
, ny
, c
->w
, c
->h
, &awesomeconf
[c
->screen
], False
, False
);
97 resizemouse(Client
* c
, awesome_config
*awesomeconf
)
104 if(XGrabPointer(c
->display
, RootWindow(c
->display
, c
->phys_screen
),
105 False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
,
106 None
, awesomeconf
[c
->screen
].cursor
[CurResize
], CurrentTime
) != GrabSuccess
)
109 XWarpPointer(c
->display
, None
, c
->win
, 0, 0, 0, 0, c
->w
+ c
->border
- 1, c
->h
+ c
->border
- 1);
112 XMaskEvent(c
->display
, MOUSEMASK
| ExposureMask
| SubstructureRedirectMask
, &ev
);
116 XWarpPointer(c
->display
, None
, c
->win
, 0, 0, 0, 0, c
->w
+ c
->border
- 1, c
->h
+ c
->border
- 1);
117 XUngrabPointer(c
->display
, CurrentTime
);
118 while(XCheckMaskEvent(c
->display
, EnterWindowMask
, &ev
));
120 case ConfigureRequest
:
121 handle_event_configurerequest(&ev
,awesomeconf
);
124 handle_event_expose(&ev
, awesomeconf
);
127 handle_event_maprequest(&ev
, awesomeconf
);
130 XSync(c
->display
, False
);
131 if((nw
= ev
.xmotion
.x
- ocx
- 2 * c
->border
+ 1) <= 0)
133 if((nh
= ev
.xmotion
.y
- ocy
- 2 * c
->border
+ 1) <= 0)
135 client_resize(c
, c
->x
, c
->y
, nw
, nh
, &awesomeconf
[c
->screen
], True
, False
);
142 handle_event_buttonpress(XEvent
* e
, awesome_config
*awesomeconf
)
144 int i
, screen
, x
= 0, y
= 0;
148 XButtonPressedEvent
*ev
= &e
->xbutton
;
150 for(screen
= 0; screen
< get_screen_count(e
->xany
.display
); screen
++)
151 if(awesomeconf
[screen
].statusbar
.window
== ev
->window
)
153 for(i
= 0; i
< awesomeconf
[screen
].ntags
; i
++)
155 x
+= textwidth(e
->xany
.display
, awesomeconf
[screen
].font
, awesomeconf
[screen
].tags
[i
].name
);
158 if(ev
->button
== Button1
)
160 if(ev
->state
& awesomeconf
[screen
].modkey
)
161 uicb_tag(&awesomeconf
[screen
], awesomeconf
[screen
].tags
[i
].name
);
163 uicb_view(&awesomeconf
[screen
], awesomeconf
[screen
].tags
[i
].name
);
165 else if(ev
->button
== Button3
)
167 if(ev
->state
& awesomeconf
[screen
].modkey
)
168 uicb_toggletag(&awesomeconf
[screen
], awesomeconf
[screen
].tags
[i
].name
);
170 uicb_toggleview(&awesomeconf
[screen
], awesomeconf
[screen
].tags
[i
].name
);
172 else if(ev
->button
== Button4
)
173 uicb_tag_viewnext(&awesomeconf
[screen
], NULL
);
174 else if(ev
->button
== Button5
)
175 uicb_tag_viewprev(&awesomeconf
[screen
], NULL
);
179 x
+= awesomeconf
[screen
].statusbar
.txtlayoutwidth
;
180 if(ev
->x
< x
&& (ev
->button
== Button1
|| ev
->button
== Button4
))
181 uicb_setlayout(&awesomeconf
[screen
], "+1");
182 else if(ev
->x
< x
&& (ev
->button
== Button3
|| ev
->button
== Button5
))
183 uicb_setlayout(&awesomeconf
[screen
], "-1");
184 else if(ev
->button
== Button4
)
185 uicb_focusnext(&awesomeconf
[screen
], NULL
);
186 else if(ev
->button
== Button5
)
187 uicb_focusprev(&awesomeconf
[screen
], NULL
);
191 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
193 XAllowEvents(c
->display
, ReplayPointer
, CurrentTime
);
194 focus(c
, ev
->same_screen
, &awesomeconf
[c
->screen
]);
195 if(CLEANMASK(ev
->state
, c
->screen
) != awesomeconf
[c
->screen
].modkey
)
197 if (ev
->button
== Button1
)
199 restack(&awesomeconf
[c
->screen
]);
200 window_grabbuttons(c
->display
, c
->phys_screen
, c
->win
,
201 True
, True
, awesomeconf
->modkey
, awesomeconf
->numlockmask
);
204 else if(ev
->button
== Button1
)
206 if((get_current_layout(awesomeconf
[c
->screen
].tags
,
207 awesomeconf
[c
->screen
].ntags
)->arrange
!= layout_floating
)
209 uicb_togglefloating(&awesomeconf
[c
->screen
], NULL
);
211 restack(&awesomeconf
[c
->screen
]);
212 movemouse(c
, awesomeconf
);
214 else if(ev
->button
== Button2
)
216 if((get_current_layout(awesomeconf
[c
->screen
].tags
,
217 awesomeconf
[c
->screen
].ntags
)->arrange
!= layout_floating
)
218 && !c
->isfixed
&& c
->isfloating
)
219 uicb_togglefloating(&awesomeconf
[c
->screen
], NULL
);
221 uicb_zoom(&awesomeconf
[c
->screen
], NULL
);
223 else if(ev
->button
== Button3
)
225 if((get_current_layout(awesomeconf
[c
->screen
].tags
,
226 awesomeconf
[c
->screen
].ntags
)->arrange
!= layout_floating
)
228 uicb_togglefloating(&awesomeconf
[c
->screen
], NULL
);
230 restack(&awesomeconf
[c
->screen
]);
231 resizemouse(c
, awesomeconf
);
233 else if(ev
->button
== Button4
)
234 uicb_settrans(&awesomeconf
[c
->screen
], "+5");
235 else if(ev
->button
== Button5
)
236 uicb_settrans(&awesomeconf
[c
->screen
], "-5");
239 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
240 if(RootWindow(e
->xany
.display
, screen
) == ev
->window
241 && XQueryPointer(e
->xany
.display
, ev
->window
, &wdummy
, &wdummy
, &x
, &y
, &i
, &i
, &udummy
))
243 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
244 if(ev
->button
== Button4
)
245 uicb_tag_viewnext(&awesomeconf
[screen
], NULL
);
246 else if(ev
->button
== Button5
)
247 uicb_tag_viewprev(&awesomeconf
[screen
], NULL
);
253 handle_event_configurerequest(XEvent
* e
, awesome_config
*awesomeconf
)
256 XConfigureRequestEvent
*ev
= &e
->xconfigurerequest
;
259 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
262 if(ev
->value_mask
& CWBorderWidth
)
263 c
->border
= ev
->border_width
;
264 if(c
->isfixed
|| c
->isfloating
265 || get_current_layout(awesomeconf
[c
->screen
].tags
,
266 awesomeconf
[c
->screen
].ntags
)->arrange
== layout_floating
)
268 if(ev
->value_mask
& CWX
)
270 if(ev
->value_mask
& CWY
)
272 if(ev
->value_mask
& CWWidth
)
274 if(ev
->value_mask
& CWHeight
)
276 if((c
->x
+ c
->w
) > DisplayWidth(c
->display
, c
->phys_screen
) && c
->isfloating
)
277 c
->x
= DisplayWidth(c
->display
, c
->phys_screen
) / 2 - c
->w
/ 2; /* center in x direction */
278 if((c
->y
+ c
->h
) > DisplayHeight(c
->display
, c
->phys_screen
) && c
->isfloating
)
279 c
->y
= DisplayHeight(c
->display
, c
->phys_screen
) / 2 - c
->h
/ 2; /* center in y direction */
280 if((ev
->value_mask
& (CWX
| CWY
)) && !(ev
->value_mask
& (CWWidth
| CWHeight
)))
281 window_configure(c
->display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
, c
->border
);
282 if(isvisible(c
, c
->screen
, awesomeconf
[c
->screen
].tags
, awesomeconf
[c
->screen
].ntags
))
283 XMoveResizeWindow(e
->xany
.display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
);
286 window_configure(c
->display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
, c
->border
);
292 wc
.width
= ev
->width
;
293 wc
.height
= ev
->height
;
294 wc
.border_width
= ev
->border_width
;
295 wc
.sibling
= ev
->above
;
296 wc
.stack_mode
= ev
->detail
;
297 XConfigureWindow(e
->xany
.display
, ev
->window
, ev
->value_mask
, &wc
);
299 XSync(e
->xany
.display
, False
);
303 handle_event_configurenotify(XEvent
* e
, awesome_config
*awesomeconf
)
305 XConfigureEvent
*ev
= &e
->xconfigure
;
309 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
310 if(ev
->window
== RootWindow(e
->xany
.display
, screen
)
311 && (ev
->width
!= DisplayWidth(e
->xany
.display
, screen
)
312 || ev
->height
!= DisplayHeight(e
->xany
.display
, screen
)))
314 DisplayWidth(e
->xany
.display
, screen
) = ev
->width
;
315 DisplayHeight(e
->xany
.display
, screen
) = ev
->height
;
317 /* update statusbar */
318 XFreePixmap(e
->xany
.display
, awesomeconf
[screen
].statusbar
.drawable
);
320 si
= get_screen_info(e
->xany
.display
, screen
, NULL
);
321 awesomeconf
[screen
].statusbar
.width
= si
[screen
].width
;
324 awesomeconf
[screen
].statusbar
.drawable
= XCreatePixmap(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
),
325 awesomeconf
[screen
].statusbar
.width
,
326 awesomeconf
[screen
].statusbar
.height
,
327 DefaultDepth(e
->xany
.display
, screen
));
328 XResizeWindow(e
->xany
.display
,
329 awesomeconf
[screen
].statusbar
.window
,
330 awesomeconf
[screen
].statusbar
.width
,
331 awesomeconf
[screen
].statusbar
.height
);
333 updatebarpos(e
->xany
.display
, awesomeconf
[screen
].statusbar
);
334 arrange(&awesomeconf
[screen
]);
339 handle_event_destroynotify(XEvent
* e
, awesome_config
*awesomeconf
)
342 XDestroyWindowEvent
*ev
= &e
->xdestroywindow
;
344 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
345 client_unmanage(c
, WithdrawnState
, &awesomeconf
[c
->screen
]);
349 handle_event_enternotify(XEvent
* e
, awesome_config
*awesomeconf
)
352 XCrossingEvent
*ev
= &e
->xcrossing
;
355 if(ev
->mode
!= NotifyNormal
|| ev
->detail
== NotifyInferior
)
357 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
359 focus(c
, ev
->same_screen
, &awesomeconf
[c
->screen
]);
361 || get_current_layout(awesomeconf
[c
->screen
].tags
,
362 awesomeconf
[c
->screen
].ntags
)->arrange
== layout_floating
)
363 window_grabbuttons(c
->display
, c
->phys_screen
, c
->win
,
364 True
, False
, awesomeconf
->modkey
, awesomeconf
->numlockmask
);
367 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
368 if(ev
->window
== RootWindow(e
->xany
.display
, screen
))
369 focus(NULL
, True
, &awesomeconf
[screen
]);
373 handle_event_expose(XEvent
* e
, awesome_config
*awesomeconf
)
375 XExposeEvent
*ev
= &e
->xexpose
;
379 for(screen
= 0; screen
< get_screen_count(e
->xany
.display
); screen
++)
380 if(awesomeconf
[screen
].statusbar
.window
== ev
->window
)
381 drawstatusbar(&awesomeconf
[screen
]);
385 handle_event_keypress(XEvent
* e
, awesome_config
*awesomeconf
)
387 int i
, screen
, x
, y
, d
;
390 XKeyEvent
*ev
= &e
->xkey
;
393 keysym
= XKeycodeToKeysym(e
->xany
.display
, (KeyCode
) ev
->keycode
, 0);
395 /* find the right screen for this event */
396 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
397 if(XQueryPointer(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
), &dummy
, &dummy
, &x
, &y
, &d
, &d
, &m
))
399 /* if screen is 0, we are on first Zaphod screen or on the
400 * only screen in Xinerama, so we can ask for a better screen
401 * number with get_screen_bycoord: we'll get 0 in Zaphod mode
402 * so it's the same, or maybe the real Xinerama screen */
404 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
408 for(i
= 0; i
< awesomeconf
[screen
].nkeys
; i
++)
409 if(keysym
== awesomeconf
[screen
].keys
[i
].keysym
410 && CLEANMASK(awesomeconf
[screen
].keys
[i
].mod
, screen
) == CLEANMASK(ev
->state
, screen
) && awesomeconf
[screen
].keys
[i
].func
)
411 awesomeconf
[screen
].keys
[i
].func(&awesomeconf
[screen
], awesomeconf
[screen
].keys
[i
].arg
);
415 handle_event_leavenotify(XEvent
* e
, awesome_config
*awesomeconf
)
417 XCrossingEvent
*ev
= &e
->xcrossing
;
420 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
421 if((ev
->window
== RootWindow(e
->xany
.display
, screen
)) && !ev
->same_screen
)
422 focus(NULL
, ev
->same_screen
, &awesomeconf
[screen
]);
426 handle_event_mappingnotify(XEvent
* e
, awesome_config
*awesomeconf
)
428 XMappingEvent
*ev
= &e
->xmapping
;
431 XRefreshKeyboardMapping(ev
);
432 if(ev
->request
== MappingKeyboard
)
433 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
434 grabkeys(&awesomeconf
[screen
]);
438 handle_event_maprequest(XEvent
* e
, awesome_config
*awesomeconf
)
440 static XWindowAttributes wa
;
441 XMapRequestEvent
*ev
= &e
->xmaprequest
;
446 if(!XGetWindowAttributes(e
->xany
.display
, ev
->window
, &wa
))
448 if(wa
.override_redirect
)
450 if(!get_client_bywin(*awesomeconf
->clients
, ev
->window
))
452 for(screen
= 0; wa
.screen
!= ScreenOfDisplay(e
->xany
.display
, screen
); screen
++);
455 if(XQueryPointer(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
),
456 &dummy
, &dummy
, &x
, &y
, &d
, &d
, &m
))
457 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
460 client_manage(ev
->window
, &wa
, &awesomeconf
[screen
]);
465 handle_event_propertynotify(XEvent
* e
, awesome_config
*awesomeconf
)
469 XPropertyEvent
*ev
= &e
->xproperty
;
471 if(ev
->state
== PropertyDelete
)
473 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
477 case XA_WM_TRANSIENT_FOR
:
478 XGetTransientForHint(e
->xany
.display
, c
->win
, &trans
);
479 if(!c
->isfloating
&& (c
->isfloating
= (get_client_bywin(*awesomeconf
->clients
, trans
) != NULL
)))
480 arrange(&awesomeconf
[c
->screen
]);
482 case XA_WM_NORMAL_HINTS
:
486 if(ev
->atom
== XA_WM_NAME
|| ev
->atom
== XInternAtom(c
->display
, "_NET_WM_NAME", False
))
489 if(c
== get_current_tag(awesomeconf
->tags
, awesomeconf
->ntags
)->client_sel
)
490 drawstatusbar(&awesomeconf
[c
->screen
]);
496 handle_event_unmapnotify(XEvent
* e
, awesome_config
*awesomeconf
)
499 XUnmapEvent
*ev
= &e
->xunmap
;
501 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
))
502 && ev
->event
== RootWindow(e
->xany
.display
, c
->phys_screen
)
503 && ev
->send_event
&& window_getstate(c
->display
, c
->win
) == NormalState
)
504 client_unmanage(c
, WithdrawnState
, &awesomeconf
[c
->screen
]);
508 handle_event_shape(XEvent
* e
,
509 awesome_config
*awesomeconf
__attribute__ ((unused
)))
511 XShapeEvent
*ev
= (XShapeEvent
*) e
;
512 Client
*c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
);
515 window_setshape(c
->display
, c
->phys_screen
, c
->win
);
519 handle_event_randr_screen_change_notify(XEvent
*e
,
520 awesome_config
*awesomeconf
__attribute__ ((unused
)))
522 XRRUpdateConfiguration(e
);
526 grabkeys(awesome_config
*awesomeconf
)
531 XUngrabKey(awesomeconf
->display
, AnyKey
, AnyModifier
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
));
532 for(i
= 0; i
< awesomeconf
->nkeys
; i
++)
534 if((code
= XKeysymToKeycode(awesomeconf
->display
, awesomeconf
->keys
[i
].keysym
)) == NoSymbol
)
536 XGrabKey(awesomeconf
->display
, code
, awesomeconf
->keys
[i
].mod
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
537 XGrabKey(awesomeconf
->display
, code
, awesomeconf
->keys
[i
].mod
| LockMask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
538 XGrabKey(awesomeconf
->display
, code
, awesomeconf
->keys
[i
].mod
| awesomeconf
->numlockmask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
539 XGrabKey(awesomeconf
->display
, code
, awesomeconf
->keys
[i
].mod
| awesomeconf
->numlockmask
| LockMask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
,
540 GrabModeAsync
, GrabModeAsync
);
543 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99