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 uicb_movemouse(awesome_config
*awesomeconf
, const char *arg
__attribute__ ((unused
)))
45 int x1
, y1
, ocx
, ocy
, di
, nx
, ny
;
50 Client
*c
= get_current_tag(awesomeconf
->tags
, awesomeconf
->ntags
)->client_sel
;
55 if((get_current_layout(awesomeconf
->tags
, awesomeconf
->ntags
)->arrange
!= layout_floating
)
57 uicb_togglefloating(&awesomeconf
[c
->screen
], "DUMMY");
61 si
= get_screen_info(c
->display
, c
->screen
, &awesomeconf
[c
->screen
].statusbar
);
65 if(XGrabPointer(c
->display
, RootWindow(c
->display
, c
->phys_screen
), False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
,
66 None
, awesomeconf
[c
->screen
].cursor
[CurMove
], CurrentTime
) != GrabSuccess
)
68 XQueryPointer(c
->display
, RootWindow(c
->display
, c
->phys_screen
), &dummy
, &dummy
, &x1
, &y1
, &di
, &di
, &dui
);
71 XMaskEvent(c
->display
, MOUSEMASK
| ExposureMask
| SubstructureRedirectMask
, &ev
);
75 XUngrabPointer(c
->display
, CurrentTime
);
78 case ConfigureRequest
:
79 handle_event_configurerequest(&ev
,awesomeconf
);
82 handle_event_expose(&ev
, awesomeconf
);
85 handle_event_maprequest(&ev
, awesomeconf
);
88 XSync(c
->display
, False
);
89 nx
= ocx
+ (ev
.xmotion
.x
- x1
);
90 ny
= ocy
+ (ev
.xmotion
.y
- y1
);
91 if(abs(nx
) < awesomeconf
[c
->screen
].snap
+ si
[c
->screen
].x_org
&& nx
> si
[c
->screen
].x_org
)
92 nx
= si
[c
->screen
].x_org
;
93 else if(abs((si
[c
->screen
].x_org
+ si
[c
->screen
].width
) - (nx
+ c
->w
+ 2 * c
->border
)) < awesomeconf
[c
->screen
].snap
)
94 nx
= si
[c
->screen
].x_org
+ si
[c
->screen
].width
- c
->w
- 2 * c
->border
;
95 if(abs(ny
) < awesomeconf
[c
->screen
].snap
+ si
[c
->screen
].y_org
&& ny
> si
[c
->screen
].y_org
)
96 ny
= si
[c
->screen
].y_org
;
97 else if(abs((si
[c
->screen
].y_org
+ si
[c
->screen
].height
) - (ny
+ c
->h
+ 2 * c
->border
)) < awesomeconf
[c
->screen
].snap
)
98 ny
= si
[c
->screen
].y_org
+ si
[c
->screen
].height
- c
->h
- 2 * c
->border
;
99 client_resize(c
, nx
, ny
, c
->w
, c
->h
, &awesomeconf
[c
->screen
], False
, False
);
106 uicb_resizemouse(awesome_config
*awesomeconf
, const char *arg
__attribute__ ((unused
)))
108 int ocx
, ocy
, nw
, nh
;
110 Client
*c
= get_current_tag(awesomeconf
->tags
, awesomeconf
->ntags
)->client_sel
;
115 if((get_current_layout(awesomeconf
->tags
, awesomeconf
->ntags
)->arrange
!= layout_floating
)
117 uicb_togglefloating(awesomeconf
, "DUMMY");
119 restack(&awesomeconf
[c
->screen
]);
123 if(XGrabPointer(c
->display
, RootWindow(c
->display
, c
->phys_screen
),
124 False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
,
125 None
, awesomeconf
[c
->screen
].cursor
[CurResize
], CurrentTime
) != GrabSuccess
)
128 XWarpPointer(c
->display
, None
, c
->win
, 0, 0, 0, 0, c
->w
+ c
->border
- 1, c
->h
+ c
->border
- 1);
131 XMaskEvent(c
->display
, MOUSEMASK
| ExposureMask
| SubstructureRedirectMask
, &ev
);
135 XWarpPointer(c
->display
, None
, c
->win
, 0, 0, 0, 0, c
->w
+ c
->border
- 1, c
->h
+ c
->border
- 1);
136 XUngrabPointer(c
->display
, CurrentTime
);
137 while(XCheckMaskEvent(c
->display
, EnterWindowMask
, &ev
));
139 case ConfigureRequest
:
140 handle_event_configurerequest(&ev
,awesomeconf
);
143 handle_event_expose(&ev
, awesomeconf
);
146 handle_event_maprequest(&ev
, awesomeconf
);
149 XSync(c
->display
, False
);
150 if((nw
= ev
.xmotion
.x
- ocx
- 2 * c
->border
+ 1) <= 0)
152 if((nh
= ev
.xmotion
.y
- ocy
- 2 * c
->border
+ 1) <= 0)
154 client_resize(c
, c
->x
, c
->y
, nw
, nh
, &awesomeconf
[c
->screen
], True
, False
);
162 handle_mouse_button_press(awesome_config
*awesomeconf
,
163 unsigned int button
, unsigned int state
, unsigned int numlockmask
,
164 Button
*buttons
, char *arg
)
168 for(b
= buttons
; b
; b
= b
->next
)
169 if(button
== b
->button
&& (state
== b
->mod
|| state
== (b
->mod
| numlockmask
)) && b
->func
)
172 b
->func(awesomeconf
, arg
);
174 b
->func(awesomeconf
, b
->arg
);
179 handle_event_buttonpress(XEvent
* e
, awesome_config
*awesomeconf
)
181 int i
, screen
, x
= 0, y
= 0;
186 XButtonPressedEvent
*ev
= &e
->xbutton
;
188 for(screen
= 0; screen
< get_screen_count(e
->xany
.display
); screen
++)
189 if(awesomeconf
[screen
].statusbar
.window
== ev
->window
)
191 for(i
= 0; i
< awesomeconf
[screen
].ntags
; i
++)
193 x
+= textwidth(e
->xany
.display
, awesomeconf
[screen
].font
, awesomeconf
[screen
].tags
[i
].name
);
194 if(((awesomeconf
[screen
].statusbar
.position
== BarTop
195 || awesomeconf
[screen
].statusbar
.position
== BarBot
)
197 || (awesomeconf
[screen
].statusbar
.position
== BarRight
&& ev
->y
< x
)
198 || (awesomeconf
[screen
].statusbar
.position
== BarLeft
&& ev
->y
> awesomeconf
[screen
].statusbar
.width
- x
))
200 snprintf(arg
, sizeof(arg
), "%d", i
+ 1);
201 handle_mouse_button_press(&awesomeconf
[screen
],
202 ev
->button
, ev
->state
, awesomeconf
->numlockmask
,
203 awesomeconf
[screen
].buttons
.tag
, arg
);
207 x
+= awesomeconf
[screen
].statusbar
.txtlayoutwidth
;
208 if(((awesomeconf
[screen
].statusbar
.position
== BarTop
209 || awesomeconf
[screen
].statusbar
.position
== BarBot
)
211 || (awesomeconf
[screen
].statusbar
.position
== BarRight
&& ev
->y
< x
)
212 || (awesomeconf
[screen
].statusbar
.position
== BarLeft
&& ev
->y
> awesomeconf
[screen
].statusbar
.width
- x
))
213 handle_mouse_button_press(&awesomeconf
[screen
],
214 ev
->button
, ev
->state
, awesomeconf
->numlockmask
,
215 awesomeconf
[screen
].buttons
.layout
, NULL
);
217 handle_mouse_button_press(&awesomeconf
[screen
],
218 ev
->button
, ev
->state
, awesomeconf
->numlockmask
,
219 awesomeconf
[screen
].buttons
.title
, NULL
);
223 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
225 XAllowEvents(c
->display
, ReplayPointer
, CurrentTime
);
226 focus(c
, ev
->same_screen
, &awesomeconf
[c
->screen
]);
227 if(CLEANMASK(ev
->state
, c
->screen
) != awesomeconf
[c
->screen
].modkey
)
229 if (ev
->button
== Button1
)
231 restack(&awesomeconf
[c
->screen
]);
232 window_grabbuttons(c
->display
, c
->phys_screen
, c
->win
,
233 True
, True
, awesomeconf
->buttons
.root
,
234 awesomeconf
->modkey
, awesomeconf
->numlockmask
);
237 else if(ev
->button
== Button1
)
238 uicb_movemouse(&awesomeconf
[c
->screen
], NULL
);
239 else if(ev
->button
== Button2
)
241 if((get_current_layout(awesomeconf
[c
->screen
].tags
,
242 awesomeconf
[c
->screen
].ntags
)->arrange
!= layout_floating
)
243 && !c
->isfixed
&& c
->isfloating
)
244 uicb_togglefloating(&awesomeconf
[c
->screen
], NULL
);
246 uicb_zoom(&awesomeconf
[c
->screen
], NULL
);
248 else if(ev
->button
== Button3
)
249 uicb_resizemouse(&awesomeconf
[c
->screen
], NULL
);
250 else if(ev
->button
== Button4
)
251 uicb_settrans(&awesomeconf
[c
->screen
], "+5");
252 else if(ev
->button
== Button5
)
253 uicb_settrans(&awesomeconf
[c
->screen
], "-5");
256 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
257 if(RootWindow(e
->xany
.display
, screen
) == ev
->window
258 && XQueryPointer(e
->xany
.display
, ev
->window
, &wdummy
, &wdummy
, &x
, &y
, &i
, &i
, &udummy
))
260 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
261 handle_mouse_button_press(&awesomeconf
[screen
],
262 ev
->button
, ev
->state
, awesomeconf
->numlockmask
,
263 awesomeconf
[screen
].buttons
.root
, NULL
);
269 handle_event_configurerequest(XEvent
* e
, awesome_config
*awesomeconf
)
272 XConfigureRequestEvent
*ev
= &e
->xconfigurerequest
;
275 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
278 if(ev
->value_mask
& CWBorderWidth
)
279 c
->border
= ev
->border_width
;
280 if(c
->isfixed
|| c
->isfloating
281 || get_current_layout(awesomeconf
[c
->screen
].tags
,
282 awesomeconf
[c
->screen
].ntags
)->arrange
== layout_floating
)
284 if(ev
->value_mask
& CWX
)
286 if(ev
->value_mask
& CWY
)
288 if(ev
->value_mask
& CWWidth
)
290 if(ev
->value_mask
& CWHeight
)
292 if((c
->x
+ c
->w
) > DisplayWidth(c
->display
, c
->phys_screen
) && c
->isfloating
)
293 c
->x
= DisplayWidth(c
->display
, c
->phys_screen
) / 2 - c
->w
/ 2; /* center in x direction */
294 if((c
->y
+ c
->h
) > DisplayHeight(c
->display
, c
->phys_screen
) && c
->isfloating
)
295 c
->y
= DisplayHeight(c
->display
, c
->phys_screen
) / 2 - c
->h
/ 2; /* center in y direction */
296 if((ev
->value_mask
& (CWX
| CWY
)) && !(ev
->value_mask
& (CWWidth
| CWHeight
)))
297 window_configure(c
->display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
, c
->border
);
298 if(isvisible(c
, c
->screen
, awesomeconf
[c
->screen
].tags
, awesomeconf
[c
->screen
].ntags
))
299 XMoveResizeWindow(e
->xany
.display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
);
302 window_configure(c
->display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
, c
->border
);
308 wc
.width
= ev
->width
;
309 wc
.height
= ev
->height
;
310 wc
.border_width
= ev
->border_width
;
311 wc
.sibling
= ev
->above
;
312 wc
.stack_mode
= ev
->detail
;
313 XConfigureWindow(e
->xany
.display
, ev
->window
, ev
->value_mask
, &wc
);
315 XSync(e
->xany
.display
, False
);
319 handle_event_configurenotify(XEvent
* e
, awesome_config
*awesomeconf
)
321 XConfigureEvent
*ev
= &e
->xconfigure
;
325 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
326 if(ev
->window
== RootWindow(e
->xany
.display
, screen
)
327 && (ev
->width
!= DisplayWidth(e
->xany
.display
, screen
)
328 || ev
->height
!= DisplayHeight(e
->xany
.display
, screen
)))
330 DisplayWidth(e
->xany
.display
, screen
) = ev
->width
;
331 DisplayHeight(e
->xany
.display
, screen
) = ev
->height
;
333 /* update statusbar */
334 si
= get_screen_info(e
->xany
.display
, screen
, NULL
);
335 awesomeconf
[screen
].statusbar
.width
= si
[screen
].width
;
338 XResizeWindow(e
->xany
.display
,
339 awesomeconf
[screen
].statusbar
.window
,
340 awesomeconf
[screen
].statusbar
.width
,
341 awesomeconf
[screen
].statusbar
.height
);
343 updatebarpos(e
->xany
.display
, awesomeconf
[screen
].statusbar
);
344 arrange(&awesomeconf
[screen
]);
349 handle_event_destroynotify(XEvent
* e
, awesome_config
*awesomeconf
)
352 XDestroyWindowEvent
*ev
= &e
->xdestroywindow
;
354 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
355 client_unmanage(c
, WithdrawnState
, &awesomeconf
[c
->screen
]);
359 handle_event_enternotify(XEvent
* e
, awesome_config
*awesomeconf
)
362 XCrossingEvent
*ev
= &e
->xcrossing
;
365 if(ev
->mode
!= NotifyNormal
|| ev
->detail
== NotifyInferior
)
367 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
369 focus(c
, ev
->same_screen
, &awesomeconf
[c
->screen
]);
371 || get_current_layout(awesomeconf
[c
->screen
].tags
,
372 awesomeconf
[c
->screen
].ntags
)->arrange
== layout_floating
)
373 window_grabbuttons(c
->display
, c
->phys_screen
, c
->win
,
374 True
, False
, awesomeconf
->buttons
.root
,
375 awesomeconf
->modkey
, awesomeconf
->numlockmask
);
378 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
379 if(ev
->window
== RootWindow(e
->xany
.display
, screen
))
380 focus(NULL
, True
, &awesomeconf
[screen
]);
384 handle_event_expose(XEvent
* e
, awesome_config
*awesomeconf
)
386 XExposeEvent
*ev
= &e
->xexpose
;
390 for(screen
= 0; screen
< get_screen_count(e
->xany
.display
); screen
++)
391 if(awesomeconf
[screen
].statusbar
.window
== ev
->window
)
392 drawstatusbar(&awesomeconf
[screen
]);
396 handle_event_keypress(XEvent
* e
, awesome_config
*awesomeconf
)
398 int i
, screen
, x
, y
, d
;
401 XKeyEvent
*ev
= &e
->xkey
;
404 keysym
= XKeycodeToKeysym(e
->xany
.display
, (KeyCode
) ev
->keycode
, 0);
406 /* find the right screen for this event */
407 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
408 if(XQueryPointer(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
), &dummy
, &dummy
, &x
, &y
, &d
, &d
, &m
))
410 /* if screen is 0, we are on first Zaphod screen or on the
411 * only screen in Xinerama, so we can ask for a better screen
412 * number with get_screen_bycoord: we'll get 0 in Zaphod mode
413 * so it's the same, or maybe the real Xinerama screen */
415 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
419 for(i
= 0; i
< awesomeconf
[screen
].nkeys
; i
++)
420 if(keysym
== awesomeconf
[screen
].keys
[i
].keysym
421 && CLEANMASK(awesomeconf
[screen
].keys
[i
].mod
, screen
) == CLEANMASK(ev
->state
, screen
) && awesomeconf
[screen
].keys
[i
].func
)
422 awesomeconf
[screen
].keys
[i
].func(&awesomeconf
[screen
], awesomeconf
[screen
].keys
[i
].arg
);
426 handle_event_leavenotify(XEvent
* e
, awesome_config
*awesomeconf
)
428 XCrossingEvent
*ev
= &e
->xcrossing
;
431 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
432 if((ev
->window
== RootWindow(e
->xany
.display
, screen
)) && !ev
->same_screen
)
433 focus(NULL
, ev
->same_screen
, &awesomeconf
[screen
]);
437 handle_event_mappingnotify(XEvent
* e
, awesome_config
*awesomeconf
)
439 XMappingEvent
*ev
= &e
->xmapping
;
442 XRefreshKeyboardMapping(ev
);
443 if(ev
->request
== MappingKeyboard
)
444 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
445 grabkeys(&awesomeconf
[screen
]);
449 handle_event_maprequest(XEvent
* e
, awesome_config
*awesomeconf
)
451 static XWindowAttributes wa
;
452 XMapRequestEvent
*ev
= &e
->xmaprequest
;
457 if(!XGetWindowAttributes(e
->xany
.display
, ev
->window
, &wa
))
459 if(wa
.override_redirect
)
461 if(!get_client_bywin(*awesomeconf
->clients
, ev
->window
))
463 for(screen
= 0; wa
.screen
!= ScreenOfDisplay(e
->xany
.display
, screen
); screen
++);
464 if(screen
== 0 && XQueryPointer(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
),
465 &dummy
, &dummy
, &x
, &y
, &d
, &d
, &m
))
466 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
467 client_manage(ev
->window
, &wa
, &awesomeconf
[screen
]);
472 handle_event_propertynotify(XEvent
* e
, awesome_config
*awesomeconf
)
476 XPropertyEvent
*ev
= &e
->xproperty
;
478 if(ev
->state
== PropertyDelete
)
480 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
484 case XA_WM_TRANSIENT_FOR
:
485 XGetTransientForHint(e
->xany
.display
, c
->win
, &trans
);
486 if(!c
->isfloating
&& (c
->isfloating
= (get_client_bywin(*awesomeconf
->clients
, trans
) != NULL
)))
487 arrange(&awesomeconf
[c
->screen
]);
489 case XA_WM_NORMAL_HINTS
:
493 if(ev
->atom
== XA_WM_NAME
|| ev
->atom
== XInternAtom(c
->display
, "_NET_WM_NAME", False
))
496 if(c
== get_current_tag(awesomeconf
->tags
, awesomeconf
->ntags
)->client_sel
)
497 drawstatusbar(&awesomeconf
[c
->screen
]);
503 handle_event_unmapnotify(XEvent
* e
, awesome_config
*awesomeconf
)
506 XUnmapEvent
*ev
= &e
->xunmap
;
508 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
))
509 && ev
->event
== RootWindow(e
->xany
.display
, c
->phys_screen
)
510 && ev
->send_event
&& window_getstate(c
->display
, c
->win
) == NormalState
)
511 client_unmanage(c
, WithdrawnState
, &awesomeconf
[c
->screen
]);
515 handle_event_shape(XEvent
* e
,
516 awesome_config
*awesomeconf
__attribute__ ((unused
)))
518 XShapeEvent
*ev
= (XShapeEvent
*) e
;
519 Client
*c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
);
522 window_setshape(c
->display
, c
->phys_screen
, c
->win
);
526 handle_event_randr_screen_change_notify(XEvent
*e
,
527 awesome_config
*awesomeconf
__attribute__ ((unused
)))
529 XRRUpdateConfiguration(e
);
533 grabkeys(awesome_config
*awesomeconf
)
538 XUngrabKey(awesomeconf
->display
, AnyKey
, AnyModifier
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
));
539 for(i
= 0; i
< awesomeconf
->nkeys
; i
++)
541 if((code
= XKeysymToKeycode(awesomeconf
->display
, awesomeconf
->keys
[i
].keysym
)) == NoSymbol
)
543 XGrabKey(awesomeconf
->display
, code
, awesomeconf
->keys
[i
].mod
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
544 XGrabKey(awesomeconf
->display
, code
, awesomeconf
->keys
[i
].mod
| LockMask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
545 XGrabKey(awesomeconf
->display
, code
, awesomeconf
->keys
[i
].mod
| awesomeconf
->numlockmask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
546 XGrabKey(awesomeconf
->display
, code
, awesomeconf
->keys
[i
].mod
| awesomeconf
->numlockmask
| LockMask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
,
547 GrabModeAsync
, GrabModeAsync
);
550 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99