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, acf) (mask & ~(acf.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
, "DUMMY");
61 si
= get_screen_info(c
->display
, c
->screen
, &awesomeconf
->statusbar
);
65 if(XGrabPointer(c
->display
, RootWindow(c
->display
, c
->phys_screen
), False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
,
66 None
, awesomeconf
->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
[0 - awesomeconf
->screen
]);
82 handle_event_expose(&ev
, &awesomeconf
[0 - awesomeconf
->screen
]);
85 handle_event_maprequest(&ev
, &awesomeconf
[0 - awesomeconf
->screen
]);
88 XSync(c
->display
, False
);
89 nx
= ocx
+ (ev
.xmotion
.x
- x1
);
90 ny
= ocy
+ (ev
.xmotion
.y
- y1
);
91 if(abs(nx
) < awesomeconf
->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
->snap
)
94 nx
= si
[c
->screen
].x_org
+ si
[c
->screen
].width
- c
->w
- 2 * c
->border
;
95 if(abs(ny
) < awesomeconf
->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
, 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
);
123 if(XGrabPointer(c
->display
, RootWindow(c
->display
, c
->phys_screen
),
124 False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
,
125 None
, awesomeconf
->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
[0 - awesomeconf
->screen
]);
143 handle_event_expose(&ev
, &awesomeconf
[0 - awesomeconf
->screen
]);
146 handle_event_maprequest(&ev
, &awesomeconf
[0 - awesomeconf
->screen
]);
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
, True
, False
);
162 handle_mouse_button_press(awesome_config
*awesomeconf
,
163 unsigned int button
, unsigned int state
,
164 Button
*buttons
, char *arg
)
168 for(b
= buttons
; b
; b
= b
->next
)
169 if(button
== b
->button
&& CLEANMASK(state
, awesomeconf
[0]) == b
->mod
&& 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
], ev
->button
, ev
->state
,
202 awesomeconf
[screen
].buttons
.tag
, arg
);
206 x
+= awesomeconf
[screen
].statusbar
.txtlayoutwidth
;
207 if(((awesomeconf
[screen
].statusbar
.position
== BarTop
208 || awesomeconf
[screen
].statusbar
.position
== BarBot
)
210 || (awesomeconf
[screen
].statusbar
.position
== BarRight
&& ev
->y
< x
)
211 || (awesomeconf
[screen
].statusbar
.position
== BarLeft
&& ev
->y
> awesomeconf
[screen
].statusbar
.width
- x
))
212 handle_mouse_button_press(&awesomeconf
[screen
], ev
->button
, ev
->state
,
213 awesomeconf
[screen
].buttons
.layout
, NULL
);
215 handle_mouse_button_press(&awesomeconf
[screen
], ev
->button
, ev
->state
,
216 awesomeconf
[screen
].buttons
.title
, NULL
);
220 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
222 XAllowEvents(c
->display
, ReplayPointer
, CurrentTime
);
223 focus(c
, ev
->same_screen
, &awesomeconf
[c
->screen
]);
224 if(CLEANMASK(ev
->state
, awesomeconf
[c
->screen
]) != awesomeconf
[c
->screen
].modkey
)
226 if (ev
->button
== Button1
)
228 restack(&awesomeconf
[c
->screen
]);
229 window_grabbuttons(c
->display
, c
->phys_screen
, c
->win
,
230 True
, True
, awesomeconf
->buttons
.root
,
231 awesomeconf
->modkey
, awesomeconf
->numlockmask
);
234 else if(ev
->button
== Button1
)
235 uicb_movemouse(&awesomeconf
[c
->screen
], NULL
);
236 else if(ev
->button
== Button2
)
238 if((get_current_layout(awesomeconf
[c
->screen
].tags
,
239 awesomeconf
[c
->screen
].ntags
)->arrange
!= layout_floating
)
240 && !c
->isfixed
&& c
->isfloating
)
241 uicb_togglefloating(&awesomeconf
[c
->screen
], NULL
);
243 uicb_zoom(&awesomeconf
[c
->screen
], NULL
);
245 else if(ev
->button
== Button3
)
246 uicb_resizemouse(&awesomeconf
[c
->screen
], NULL
);
247 else if(ev
->button
== Button4
)
248 uicb_settrans(&awesomeconf
[c
->screen
], "+5");
249 else if(ev
->button
== Button5
)
250 uicb_settrans(&awesomeconf
[c
->screen
], "-5");
253 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
254 if(RootWindow(e
->xany
.display
, screen
) == ev
->window
255 && XQueryPointer(e
->xany
.display
, ev
->window
, &wdummy
, &wdummy
, &x
, &y
, &i
, &i
, &udummy
))
257 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
258 handle_mouse_button_press(&awesomeconf
[screen
], ev
->button
, ev
->state
,
259 awesomeconf
[screen
].buttons
.root
, NULL
);
265 handle_event_configurerequest(XEvent
* e
, awesome_config
*awesomeconf
)
268 XConfigureRequestEvent
*ev
= &e
->xconfigurerequest
;
271 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
274 if(ev
->value_mask
& CWBorderWidth
)
275 c
->border
= ev
->border_width
;
276 if(c
->isfixed
|| c
->isfloating
277 || get_current_layout(awesomeconf
[c
->screen
].tags
,
278 awesomeconf
[c
->screen
].ntags
)->arrange
== layout_floating
)
280 if(ev
->value_mask
& CWX
)
282 if(ev
->value_mask
& CWY
)
284 if(ev
->value_mask
& CWWidth
)
286 if(ev
->value_mask
& CWHeight
)
288 if((c
->x
+ c
->w
) > DisplayWidth(c
->display
, c
->phys_screen
) && c
->isfloating
)
289 c
->x
= DisplayWidth(c
->display
, c
->phys_screen
) / 2 - c
->w
/ 2; /* center in x direction */
290 if((c
->y
+ c
->h
) > DisplayHeight(c
->display
, c
->phys_screen
) && c
->isfloating
)
291 c
->y
= DisplayHeight(c
->display
, c
->phys_screen
) / 2 - c
->h
/ 2; /* center in y direction */
292 if((ev
->value_mask
& (CWX
| CWY
)) && !(ev
->value_mask
& (CWWidth
| CWHeight
)))
293 window_configure(c
->display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
, c
->border
);
294 if(isvisible(c
, c
->screen
, awesomeconf
[c
->screen
].tags
, awesomeconf
[c
->screen
].ntags
))
295 XMoveResizeWindow(e
->xany
.display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
);
298 window_configure(c
->display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
, c
->border
);
304 wc
.width
= ev
->width
;
305 wc
.height
= ev
->height
;
306 wc
.border_width
= ev
->border_width
;
307 wc
.sibling
= ev
->above
;
308 wc
.stack_mode
= ev
->detail
;
309 XConfigureWindow(e
->xany
.display
, ev
->window
, ev
->value_mask
, &wc
);
311 XSync(e
->xany
.display
, False
);
315 handle_event_configurenotify(XEvent
* e
, awesome_config
*awesomeconf
)
317 XConfigureEvent
*ev
= &e
->xconfigure
;
321 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
322 if(ev
->window
== RootWindow(e
->xany
.display
, screen
)
323 && (ev
->width
!= DisplayWidth(e
->xany
.display
, screen
)
324 || ev
->height
!= DisplayHeight(e
->xany
.display
, screen
)))
326 DisplayWidth(e
->xany
.display
, screen
) = ev
->width
;
327 DisplayHeight(e
->xany
.display
, screen
) = ev
->height
;
329 /* update statusbar */
330 si
= get_screen_info(e
->xany
.display
, screen
, NULL
);
331 awesomeconf
[screen
].statusbar
.width
= si
[screen
].width
;
334 XResizeWindow(e
->xany
.display
,
335 awesomeconf
[screen
].statusbar
.window
,
336 awesomeconf
[screen
].statusbar
.width
,
337 awesomeconf
[screen
].statusbar
.height
);
339 updatebarpos(e
->xany
.display
, awesomeconf
[screen
].statusbar
);
340 arrange(&awesomeconf
[screen
]);
345 handle_event_destroynotify(XEvent
* e
, awesome_config
*awesomeconf
)
348 XDestroyWindowEvent
*ev
= &e
->xdestroywindow
;
350 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
351 client_unmanage(c
, WithdrawnState
, &awesomeconf
[c
->screen
]);
355 handle_event_enternotify(XEvent
* e
, awesome_config
*awesomeconf
)
358 XCrossingEvent
*ev
= &e
->xcrossing
;
361 if(ev
->mode
!= NotifyNormal
|| ev
->detail
== NotifyInferior
)
363 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
365 focus(c
, ev
->same_screen
, &awesomeconf
[c
->screen
]);
367 || get_current_layout(awesomeconf
[c
->screen
].tags
,
368 awesomeconf
[c
->screen
].ntags
)->arrange
== layout_floating
)
369 window_grabbuttons(c
->display
, c
->phys_screen
, c
->win
,
370 True
, False
, awesomeconf
->buttons
.root
,
371 awesomeconf
->modkey
, awesomeconf
->numlockmask
);
374 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
375 if(ev
->window
== RootWindow(e
->xany
.display
, screen
))
376 focus(NULL
, True
, &awesomeconf
[screen
]);
380 handle_event_expose(XEvent
* e
, awesome_config
*awesomeconf
)
382 XExposeEvent
*ev
= &e
->xexpose
;
386 for(screen
= 0; screen
< get_screen_count(e
->xany
.display
); screen
++)
387 if(awesomeconf
[screen
].statusbar
.window
== ev
->window
)
388 drawstatusbar(&awesomeconf
[screen
]);
392 handle_event_keypress(XEvent
* e
, awesome_config
*awesomeconf
)
397 XKeyEvent
*ev
= &e
->xkey
;
401 keysym
= XKeycodeToKeysym(e
->xany
.display
, (KeyCode
) ev
->keycode
, 0);
403 /* find the right screen for this event */
404 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
405 if(XQueryPointer(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
), &dummy
, &dummy
, &x
, &y
, &d
, &d
, &m
))
407 /* if screen is 0, we are on first Zaphod screen or on the
408 * only screen in Xinerama, so we can ask for a better screen
409 * number with get_screen_bycoord: we'll get 0 in Zaphod mode
410 * so it's the same, or maybe the real Xinerama screen */
412 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
416 for(k
= awesomeconf
[screen
].keys
; k
; k
= k
->next
)
417 if(keysym
== k
->keysym
&& k
->func
418 && CLEANMASK(k
->mod
, awesomeconf
[screen
]) == CLEANMASK(ev
->state
, awesomeconf
[screen
]))
419 k
->func(&awesomeconf
[screen
], k
->arg
);
423 handle_event_leavenotify(XEvent
* e
, awesome_config
*awesomeconf
)
425 XCrossingEvent
*ev
= &e
->xcrossing
;
428 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
429 if((ev
->window
== RootWindow(e
->xany
.display
, screen
)) && !ev
->same_screen
)
430 focus(NULL
, ev
->same_screen
, &awesomeconf
[screen
]);
434 handle_event_mappingnotify(XEvent
* e
, awesome_config
*awesomeconf
)
436 XMappingEvent
*ev
= &e
->xmapping
;
439 XRefreshKeyboardMapping(ev
);
440 if(ev
->request
== MappingKeyboard
)
441 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
442 grabkeys(&awesomeconf
[screen
]);
446 handle_event_maprequest(XEvent
* e
, awesome_config
*awesomeconf
)
448 static XWindowAttributes wa
;
449 XMapRequestEvent
*ev
= &e
->xmaprequest
;
454 if(!XGetWindowAttributes(e
->xany
.display
, ev
->window
, &wa
))
456 if(wa
.override_redirect
)
458 if(!get_client_bywin(*awesomeconf
->clients
, ev
->window
))
460 for(screen
= 0; wa
.screen
!= ScreenOfDisplay(e
->xany
.display
, screen
); screen
++);
461 if(screen
== 0 && XQueryPointer(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
),
462 &dummy
, &dummy
, &x
, &y
, &d
, &d
, &m
))
463 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
464 client_manage(ev
->window
, &wa
, &awesomeconf
[screen
]);
469 handle_event_propertynotify(XEvent
* e
, awesome_config
*awesomeconf
)
473 XPropertyEvent
*ev
= &e
->xproperty
;
475 if(ev
->state
== PropertyDelete
)
477 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
481 case XA_WM_TRANSIENT_FOR
:
482 XGetTransientForHint(e
->xany
.display
, c
->win
, &trans
);
483 if(!c
->isfloating
&& (c
->isfloating
= (get_client_bywin(*awesomeconf
->clients
, trans
) != NULL
)))
484 arrange(&awesomeconf
[c
->screen
]);
486 case XA_WM_NORMAL_HINTS
:
490 if(ev
->atom
== XA_WM_NAME
|| ev
->atom
== XInternAtom(c
->display
, "_NET_WM_NAME", False
))
493 if(c
== get_current_tag(awesomeconf
->tags
, awesomeconf
->ntags
)->client_sel
)
494 drawstatusbar(&awesomeconf
[c
->screen
]);
500 handle_event_unmapnotify(XEvent
* e
, awesome_config
*awesomeconf
)
503 XUnmapEvent
*ev
= &e
->xunmap
;
505 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
))
506 && ev
->event
== RootWindow(e
->xany
.display
, c
->phys_screen
)
507 && ev
->send_event
&& window_getstate(c
->display
, c
->win
) == NormalState
)
508 client_unmanage(c
, WithdrawnState
, &awesomeconf
[c
->screen
]);
512 handle_event_shape(XEvent
* e
,
513 awesome_config
*awesomeconf
__attribute__ ((unused
)))
515 XShapeEvent
*ev
= (XShapeEvent
*) e
;
516 Client
*c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
);
519 window_setshape(c
->display
, c
->phys_screen
, c
->win
);
523 handle_event_randr_screen_change_notify(XEvent
*e
,
524 awesome_config
*awesomeconf
__attribute__ ((unused
)))
526 XRRUpdateConfiguration(e
);
530 grabkeys(awesome_config
*awesomeconf
)
535 XUngrabKey(awesomeconf
->display
, AnyKey
, AnyModifier
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
));
536 for(k
= awesomeconf
->keys
; k
; k
= k
->next
)
538 if((code
= XKeysymToKeycode(awesomeconf
->display
, k
->keysym
)) == NoSymbol
)
540 XGrabKey(awesomeconf
->display
, code
, k
->mod
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
541 XGrabKey(awesomeconf
->display
, code
, k
->mod
| LockMask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
542 XGrabKey(awesomeconf
->display
, code
, k
->mod
| awesomeconf
->numlockmask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
543 XGrabKey(awesomeconf
->display
, code
, k
->mod
| awesomeconf
->numlockmask
| LockMask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
546 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99