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"
35 #include "layouts/tile.h"
36 #include "layouts/floating.h"
39 extern DC
*dc
; /* global draw context */
40 extern Client
*clients
, *sel
; /* global client list */
42 #define CLEANMASK(mask, screen) (mask & ~(awesomeconf[screen].numlockmask | LockMask))
43 #define MOUSEMASK (BUTTONMASK | PointerMotionMask)
50 for(c
= clients
; c
&& c
->win
!= w
; c
= c
->next
);
55 movemouse(Client
* c
, awesome_config
*awesomeconf
)
57 int x1
, y1
, ocx
, ocy
, di
, nx
, ny
, real_screen
;
63 real_screen
= get_real_screen(c
->display
, awesomeconf
->screen
);
65 si
= get_display_info(c
->display
, real_screen
, NULL
);
69 if(XGrabPointer(c
->display
, RootWindow(c
->display
, real_screen
), False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
,
70 None
, dc
[c
->screen
].cursor
[CurMove
], CurrentTime
) != GrabSuccess
)
72 XQueryPointer(c
->display
, RootWindow(c
->display
, real_screen
), &dummy
, &dummy
, &x1
, &y1
, &di
, &di
, &dui
);
75 XMaskEvent(c
->display
, MOUSEMASK
| ExposureMask
| SubstructureRedirectMask
, &ev
);
79 XUngrabPointer(c
->display
, CurrentTime
);
81 case ConfigureRequest
:
84 handle_event_maprequest(&ev
, awesomeconf
);
87 XSync(c
->display
, False
);
88 nx
= ocx
+ (ev
.xmotion
.x
- x1
);
89 ny
= ocy
+ (ev
.xmotion
.y
- y1
);
90 if(abs(si
->x_org
+ nx
) < awesomeconf
->snap
)
92 else if(abs((si
->x_org
+ si
->width
) - (nx
+ c
->w
+ 2 * c
->border
)) < awesomeconf
->snap
)
93 nx
= si
->x_org
+ si
->width
- c
->w
- 2 * c
->border
;
94 if(abs(si
->y_org
- ny
) < awesomeconf
->snap
)
96 else if(abs((si
->y_org
+ si
->height
) - (ny
+ c
->h
+ 2 * c
->border
)) < awesomeconf
->snap
)
97 ny
= si
->y_org
+ si
->height
- c
->h
- 2 * c
->border
;
98 resize(c
, nx
, ny
, c
->w
, c
->h
, awesomeconf
, False
);
106 resizemouse(Client
* c
, awesome_config
*awesomeconf
)
108 int ocx
, ocy
, nw
, nh
;
113 if(XGrabPointer(c
->display
, RootWindow(c
->display
, get_real_screen(c
->display
, awesomeconf
->screen
)),
114 False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
,
115 None
, dc
[c
->screen
].cursor
[CurResize
], CurrentTime
) != GrabSuccess
)
118 XWarpPointer(c
->display
, None
, c
->win
, 0, 0, 0, 0, c
->w
+ c
->border
- 1, c
->h
+ c
->border
- 1);
121 XMaskEvent(c
->display
, MOUSEMASK
| ExposureMask
| SubstructureRedirectMask
, &ev
);
125 XWarpPointer(c
->display
, None
, c
->win
, 0, 0, 0, 0, c
->w
+ c
->border
- 1, c
->h
+ c
->border
- 1);
126 XUngrabPointer(c
->display
, CurrentTime
);
127 while(XCheckMaskEvent(c
->display
, EnterWindowMask
, &ev
));
129 case ConfigureRequest
:
132 handle_event_maprequest(&ev
, awesomeconf
);
135 XSync(c
->display
, False
);
136 if((nw
= ev
.xmotion
.x
- ocx
- 2 * c
->border
+ 1) <= 0)
138 if((nh
= ev
.xmotion
.y
- ocy
- 2 * c
->border
+ 1) <= 0)
140 resize(c
, c
->x
, c
->y
, nw
, nh
, awesomeconf
, True
);
147 handle_event_buttonpress(XEvent
* e
, awesome_config
*awesomeconf
)
151 XButtonPressedEvent
*ev
= &e
->xbutton
;
153 for(screen
= 0; screen
< get_screen_count(e
->xany
.display
); screen
++)
154 if(awesomeconf
[screen
].statusbar
.window
== ev
->window
)
157 for(i
= 0; i
< awesomeconf
[screen
].ntags
; i
++)
159 x
+= textw(dc
[screen
].font
.set
, dc
[screen
].font
.xfont
, awesomeconf
[screen
].tags
[i
].name
, dc
[screen
].font
.height
);
162 if(ev
->button
== Button1
)
164 if(ev
->state
& awesomeconf
[screen
].modkey
)
165 uicb_tag(e
->xany
.display
, &dc
[screen
], &awesomeconf
[screen
], awesomeconf
[screen
].tags
[i
].name
);
167 uicb_view(e
->xany
.display
, &dc
[screen
], &awesomeconf
[screen
], awesomeconf
[screen
].tags
[i
].name
);
169 else if(ev
->button
== Button3
)
171 if(ev
->state
& awesomeconf
[screen
].modkey
)
172 uicb_toggletag(e
->xany
.display
, &dc
[screen
], &awesomeconf
[screen
], awesomeconf
[screen
].tags
[i
].name
);
174 uicb_toggleview(e
->xany
.display
, &dc
[screen
], &awesomeconf
[screen
], awesomeconf
[screen
].tags
[i
].name
);
179 if((ev
->x
< x
+ awesomeconf
[screen
].statusbar
.width
) && ev
->button
== Button1
)
180 uicb_setlayout(e
->xany
.display
, &dc
[screen
], &awesomeconf
[screen
], NULL
);
184 if((c
= getclient(ev
->window
)))
186 focus(c
->display
, &dc
[c
->screen
], c
, ev
->same_screen
, &awesomeconf
[c
->screen
]);
187 if(CLEANMASK(ev
->state
, c
->screen
) != awesomeconf
[c
->screen
].modkey
)
189 if(ev
->button
== Button1
)
191 if(!IS_ARRANGE(layout_floating
) && !c
->isfloating
)
192 uicb_togglefloating(e
->xany
.display
, &dc
[c
->screen
], &awesomeconf
[c
->screen
], NULL
);
194 restack(e
->xany
.display
, &dc
[c
->screen
], &awesomeconf
[c
->screen
]);
195 movemouse(c
, &awesomeconf
[c
->screen
]);
197 else if(ev
->button
== Button2
)
199 if(!IS_ARRANGE(layout_floating
) && !c
->isfixed
&& c
->isfloating
)
200 uicb_togglefloating(e
->xany
.display
, &dc
[c
->screen
], &awesomeconf
[c
->screen
], NULL
);
202 uicb_zoom(e
->xany
.display
, &dc
[c
->screen
], &awesomeconf
[c
->screen
], NULL
);
204 else if(ev
->button
== Button3
)
206 if(!IS_ARRANGE(layout_floating
) && !c
->isfloating
)
207 uicb_togglefloating(e
->xany
.display
, &dc
[c
->screen
], &awesomeconf
[c
->screen
], NULL
);
209 restack(e
->xany
.display
, &dc
[c
->screen
], &awesomeconf
[c
->screen
]);
210 resizemouse(c
, &awesomeconf
[c
->screen
]);
214 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
215 if(RootWindow(e
->xany
.display
, screen
) == ev
->window
)
217 if(ev
->button
== Button4
)
218 uicb_tag_viewnext(e
->xany
.display
, &dc
[screen
], &awesomeconf
[screen
], NULL
);
219 else if(ev
->button
== Button5
)
220 uicb_tag_viewprev(e
->xany
.display
, &dc
[screen
], &awesomeconf
[screen
], NULL
);
225 handle_event_configurerequest(XEvent
* e
, awesome_config
*awesomeconf
)
228 XConfigureRequestEvent
*ev
= &e
->xconfigurerequest
;
232 if((c
= getclient(ev
->window
)))
235 if(ev
->value_mask
& CWBorderWidth
)
236 c
->border
= ev
->border_width
;
237 if(c
->isfixed
|| c
->isfloating
|| IS_ARRANGE(layout_floating
))
239 real_screen
= get_real_screen(c
->display
, c
->screen
);
240 if(ev
->value_mask
& CWX
)
242 if(ev
->value_mask
& CWY
)
244 if(ev
->value_mask
& CWWidth
)
246 if(ev
->value_mask
& CWHeight
)
248 if((c
->x
+ c
->w
) > DisplayWidth(c
->display
, real_screen
) && c
->isfloating
)
249 c
->x
= DisplayWidth(c
->display
, real_screen
) / 2 - c
->w
/ 2; /* center in x direction */
250 if((c
->y
+ c
->h
) > DisplayHeight(c
->display
, real_screen
) && c
->isfloating
)
251 c
->y
= DisplayHeight(c
->display
, real_screen
) / 2 - c
->h
/ 2; /* center in y direction */
252 if((ev
->value_mask
& (CWX
| CWY
)) && !(ev
->value_mask
& (CWWidth
| CWHeight
)))
254 if(isvisible(c
, c
->screen
, awesomeconf
[c
->screen
].tags
, awesomeconf
[c
->screen
].ntags
))
255 XMoveResizeWindow(e
->xany
.display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
);
264 wc
.width
= ev
->width
;
265 wc
.height
= ev
->height
;
266 wc
.border_width
= ev
->border_width
;
267 wc
.sibling
= ev
->above
;
268 wc
.stack_mode
= ev
->detail
;
269 XConfigureWindow(e
->xany
.display
, ev
->window
, ev
->value_mask
, &wc
);
271 XSync(e
->xany
.display
, False
);
275 handle_event_configurenotify(XEvent
* e
, awesome_config
*awesomeconf
)
277 XConfigureEvent
*ev
= &e
->xconfigure
;
281 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
282 if(ev
->window
== RootWindow(e
->xany
.display
, screen
)
283 && (ev
->width
!= DisplayWidth(e
->xany
.display
, screen
)
284 || ev
->height
!= DisplayHeight(e
->xany
.display
, screen
)))
286 DisplayWidth(e
->xany
.display
, screen
) = ev
->width
;
287 DisplayHeight(e
->xany
.display
, screen
) = ev
->height
;
289 si
= get_screen_info(e
->xany
.display
, screen
, NULL
, &dummy
);
290 XFreePixmap(e
->xany
.display
, awesomeconf
[screen
].statusbar
.drawable
);
291 awesomeconf
[screen
].statusbar
.drawable
= XCreatePixmap(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
),
293 awesomeconf
[screen
].statusbar
.height
,
294 DefaultDepth(e
->xany
.display
, screen
));
295 XResizeWindow(e
->xany
.display
, awesomeconf
[screen
].statusbar
.window
,
296 si
[screen
].width
, awesomeconf
[screen
].statusbar
.height
);
298 updatebarpos(e
->xany
.display
, awesomeconf
[screen
].statusbar
);
299 arrange(e
->xany
.display
, &dc
[screen
], &awesomeconf
[screen
]);
304 handle_event_destroynotify(XEvent
* e
, awesome_config
*awesomeconf
)
307 XDestroyWindowEvent
*ev
= &e
->xdestroywindow
;
309 if((c
= getclient(ev
->window
)))
310 unmanage(c
, &dc
[c
->screen
], WithdrawnState
, &awesomeconf
[c
->screen
]);
314 handle_event_enternotify(XEvent
* e
, awesome_config
*awesomeconf
)
317 XCrossingEvent
*ev
= &e
->xcrossing
;
320 if(ev
->mode
!= NotifyNormal
|| ev
->detail
== NotifyInferior
)
322 if((c
= getclient(ev
->window
)))
323 focus(c
->display
, &dc
[c
->screen
], c
, ev
->same_screen
, &awesomeconf
[c
->screen
]);
325 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
326 if(ev
->window
== RootWindow(e
->xany
.display
, screen
))
327 focus(e
->xany
.display
, &dc
[screen
], NULL
, True
, &awesomeconf
[screen
]);
331 handle_event_expose(XEvent
* e
, awesome_config
*awesomeconf
)
333 XExposeEvent
*ev
= &e
->xexpose
;
337 for(screen
= 0; screen
< get_screen_count(e
->xany
.display
); screen
++)
338 if(awesomeconf
[screen
].statusbar
.window
== ev
->window
)
339 drawstatusbar(e
->xany
.display
, &dc
[screen
], &awesomeconf
[screen
]);
343 handle_event_keypress(XEvent
* e
, awesome_config
*awesomeconf
)
345 int i
, screen
, x
, y
, d
;
348 XKeyEvent
*ev
= &e
->xkey
;
351 keysym
= XKeycodeToKeysym(e
->xany
.display
, (KeyCode
) ev
->keycode
, 0);
353 /* find the right screen for this event */
354 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
355 if(XQueryPointer(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
), &dummy
, &dummy
, &x
, &y
, &d
, &d
, &m
))
357 /* if screen is 0, we are on first Zaphod screen or on the
358 * only screen in Xinerama, so we can ask for a better screen
359 * number with get_screen_bycoord: we'll get 0 in Zaphod mode
360 * so it's the same, or maybe the real Xinerama screen */
362 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
366 for(i
= 0; i
< awesomeconf
[screen
].nkeys
; i
++)
367 if(keysym
== awesomeconf
[screen
].keys
[i
].keysym
368 && CLEANMASK(awesomeconf
[screen
].keys
[i
].mod
, screen
) == CLEANMASK(ev
->state
, screen
) && awesomeconf
[screen
].keys
[i
].func
)
369 awesomeconf
[screen
].keys
[i
].func(e
->xany
.display
, &dc
[screen
], &awesomeconf
[screen
], awesomeconf
[screen
].keys
[i
].arg
);
373 handle_event_leavenotify(XEvent
* e
, awesome_config
*awesomeconf
)
375 XCrossingEvent
*ev
= &e
->xcrossing
;
378 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
379 if((ev
->window
== RootWindow(e
->xany
.display
, screen
)) && !ev
->same_screen
)
380 focus(e
->xany
.display
, &dc
[screen
], NULL
, ev
->same_screen
, &awesomeconf
[screen
]);
384 handle_event_mappingnotify(XEvent
* e
, awesome_config
*awesomeconf
)
386 XMappingEvent
*ev
= &e
->xmapping
;
389 XRefreshKeyboardMapping(ev
);
390 if(ev
->request
== MappingKeyboard
)
391 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
392 grabkeys(e
->xany
.display
, screen
, &awesomeconf
[screen
]);
396 handle_event_maprequest(XEvent
* e
, awesome_config
*awesomeconf
)
398 static XWindowAttributes wa
;
399 XMapRequestEvent
*ev
= &e
->xmaprequest
;
402 if(!XGetWindowAttributes(e
->xany
.display
, ev
->window
, &wa
))
404 if(wa
.override_redirect
)
406 if(!getclient(ev
->window
))
408 for(screen
= 0; wa
.screen
!= ScreenOfDisplay(e
->xany
.display
, screen
); screen
++);
410 screen
= get_screen_bycoord(e
->xany
.display
, wa
.x
, wa
.y
);
411 manage(e
->xany
.display
, &dc
[screen
], ev
->window
, &wa
, &awesomeconf
[screen
]);
416 handle_event_propertynotify(XEvent
* e
, awesome_config
*awesomeconf
)
420 XPropertyEvent
*ev
= &e
->xproperty
;
422 if(ev
->state
== PropertyDelete
)
424 if((c
= getclient(ev
->window
)))
428 case XA_WM_TRANSIENT_FOR
:
429 XGetTransientForHint(e
->xany
.display
, c
->win
, &trans
);
430 if(!c
->isfloating
&& (c
->isfloating
= (getclient(trans
) != NULL
)))
431 arrange(e
->xany
.display
, &dc
[c
->screen
], &awesomeconf
[c
->screen
]);
433 case XA_WM_NORMAL_HINTS
:
437 if(ev
->atom
== XA_WM_NAME
|| ev
->atom
== XInternAtom(c
->display
, "_NET_WM_NAME", False
))
441 drawstatusbar(e
->xany
.display
, &dc
[c
->screen
], &awesomeconf
[c
->screen
]);
447 handle_event_unmapnotify(XEvent
* e
, awesome_config
*awesomeconf
)
450 XUnmapEvent
*ev
= &e
->xunmap
;
452 if((c
= getclient(ev
->window
))
453 && ev
->event
== RootWindow(e
->xany
.display
, c
->screen
) && (ev
->send_event
|| !c
->unmapped
))
454 unmanage(c
, &dc
[c
->screen
], WithdrawnState
, &awesomeconf
[c
->screen
]);
458 handle_event_shape(XEvent
* e
,
459 awesome_config
*awesomeconf
__attribute__ ((unused
)))
461 XShapeEvent
*ev
= (XShapeEvent
*) e
;
462 Client
*c
= getclient(ev
->window
);
469 handle_event_randr_screen_change_notify(XEvent
*e
,
470 awesome_config
*awesomeconf
__attribute__ ((unused
)))
472 XRRUpdateConfiguration(e
);
476 grabkeys(Display
*disp
, int screen
, awesome_config
*awesomeconf
)
481 XUngrabKey(disp
, AnyKey
, AnyModifier
, RootWindow(disp
, screen
));
482 for(i
= 0; i
< awesomeconf
->nkeys
; i
++)
484 if((code
= XKeysymToKeycode(disp
, awesomeconf
->keys
[i
].keysym
)) == NoSymbol
)
486 XGrabKey(disp
, code
, awesomeconf
->keys
[i
].mod
, RootWindow(disp
, screen
), True
, GrabModeAsync
, GrabModeAsync
);
487 XGrabKey(disp
, code
, awesomeconf
->keys
[i
].mod
| LockMask
, RootWindow(disp
, screen
), True
, GrabModeAsync
, GrabModeAsync
);
488 XGrabKey(disp
, code
, awesomeconf
->keys
[i
].mod
| awesomeconf
->numlockmask
, RootWindow(disp
, screen
), True
, GrabModeAsync
, GrabModeAsync
);
489 XGrabKey(disp
, code
, awesomeconf
->keys
[i
].mod
| awesomeconf
->numlockmask
| LockMask
, RootWindow(disp
, screen
), True
,
490 GrabModeAsync
, GrabModeAsync
);