2 * event.c - event handlers
4 * Copyright © 2007-2008 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>
31 #include "statusbar.h"
39 #include "layouts/tile.h"
40 #include "layouts/floating.h"
41 #include "common/xscreen.h"
43 extern AwesomeConf globalconf
;
45 /** Handle mouse button click
46 * \param screen screen number
47 * \param button button number
48 * \param state modkeys state
49 * \param buttons buttons list to check for
50 * \param arg optional arg passed to uicb, otherwise buttons' arg are used
53 event_handle_mouse_button_press(int screen
, unsigned int button
, unsigned int state
,
54 Button
*buttons
, char *arg
)
58 for(b
= buttons
; b
; b
= b
->next
)
59 if(button
== b
->button
&& CLEANMASK(state
) == b
->mod
&& b
->func
)
64 b
->func(screen
, b
->arg
);
69 /** Handle XButtonPressed events
73 event_handle_buttonpress(XEvent
*e
)
75 int i
, screen
, x
= 0, y
= 0;
81 XButtonPressedEvent
*ev
= &e
->xbutton
;
83 for(screen
= 0; screen
< globalconf
.screens_info
->nscreen
; screen
++)
84 for(statusbar
= globalconf
.screens
[screen
].statusbar
; statusbar
; statusbar
= statusbar
->next
)
85 if(statusbar
->sw
->window
== ev
->window
|| statusbar
->sw
->window
== ev
->subwindow
)
87 switch(statusbar
->position
)
91 for(widget
= statusbar
->widgets
; widget
; widget
= widget
->next
)
92 if(ev
->x
>= widget
->area
.x
&& ev
->x
< widget
->area
.x
+ widget
->area
.width
93 && ev
->y
>= widget
->area
.y
&& ev
->y
< widget
->area
.y
+ widget
->area
.height
)
95 widget
->button_press(widget
, ev
);
100 for(widget
= statusbar
->widgets
; widget
; widget
= widget
->next
)
101 if(ev
->y
>= widget
->area
.x
&& ev
->y
< widget
->area
.x
+ widget
->area
.width
102 && statusbar
->sw
->geometry
.width
- ev
->x
>= widget
->area
.y
103 && statusbar
->sw
->geometry
.width
- ev
->x
104 < widget
->area
.y
+ widget
->area
.height
)
106 widget
->button_press(widget
, ev
);
111 for(widget
= statusbar
->widgets
; widget
; widget
= widget
->next
)
112 if(statusbar
->sw
->geometry
.height
- ev
->y
>= widget
->area
.x
113 && statusbar
->sw
->geometry
.height
- ev
->y
114 < widget
->area
.x
+ widget
->area
.width
115 && ev
->x
>= widget
->area
.y
&& ev
->x
< widget
->area
.y
+ widget
->area
.height
)
117 widget
->button_press(widget
, ev
);
124 /* return if no widget match */
128 if((c
= client_get_bywin(globalconf
.clients
, ev
->window
)))
130 if(!client_focus(c
, c
->screen
, True
))
132 if(CLEANMASK(ev
->state
) == NoSymbol
133 && ev
->button
== Button1
)
135 XAllowEvents(globalconf
.display
, ReplayPointer
, CurrentTime
);
136 window_grabbuttons(c
->win
, c
->phys_screen
);
139 event_handle_mouse_button_press(c
->screen
, ev
->button
, ev
->state
, globalconf
.buttons
.client
, NULL
);
143 for(c
= globalconf
.clients
; c
; c
= c
->next
)
144 if(c
->titlebar
.sw
&& c
->titlebar
.sw
->window
== ev
->window
)
145 event_handle_mouse_button_press(c
->screen
, ev
->button
, ev
->state
, globalconf
.buttons
.titlebar
, NULL
);
146 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
147 if(RootWindow(e
->xany
.display
, screen
) == ev
->window
148 && XQueryPointer(e
->xany
.display
,
153 screen
= screen_get_bycoord(globalconf
.screens_info
, screen
, x
, y
);
154 event_handle_mouse_button_press(screen
, ev
->button
, ev
->state
,
155 globalconf
.buttons
.root
, NULL
);
161 /** Handle XConfigureRequest events
165 event_handle_configurerequest(XEvent
* e
)
168 XConfigureRequestEvent
*ev
= &e
->xconfigurerequest
;
172 if((c
= client_get_bywin(globalconf
.clients
, ev
->window
)))
174 geometry
= c
->geometry
;
176 if(ev
->value_mask
& CWX
)
178 if(ev
->value_mask
& CWY
)
180 if(ev
->value_mask
& CWWidth
)
181 geometry
.width
= ev
->width
;
182 if(ev
->value_mask
& CWHeight
)
183 geometry
.height
= ev
->height
;
185 if(geometry
.x
!= c
->geometry
.x
|| geometry
.y
!= c
->geometry
.y
186 || geometry
.width
!= c
->geometry
.width
|| geometry
.height
!= c
->geometry
.height
)
188 if(c
->isfloating
|| layout_get_current(c
->screen
)->arrange
== layout_floating
)
189 client_resize(c
, geometry
, False
);
192 globalconf
.screens
[c
->screen
].need_arrange
= True
;
193 /* If we do not resize the client, at least tell it that it
194 * has its new configuration. That fixes at least
196 window_configure(c
->win
, c
->geometry
, c
->border
);
201 titlebar_update_geometry_floating(c
);
202 window_configure(c
->win
, geometry
, c
->border
);
209 wc
.width
= ev
->width
;
210 wc
.height
= ev
->height
;
211 wc
.border_width
= ev
->border_width
;
212 wc
.sibling
= ev
->above
;
213 wc
.stack_mode
= ev
->detail
;
214 XConfigureWindow(e
->xany
.display
, ev
->window
, ev
->value_mask
, &wc
);
218 /** Handle XConfigure events
222 event_handle_configurenotify(XEvent
* e
)
224 XConfigureEvent
*ev
= &e
->xconfigure
;
227 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
228 if(ev
->window
== RootWindow(e
->xany
.display
, screen
)
229 && (ev
->width
!= DisplayWidth(e
->xany
.display
, screen
)
230 || ev
->height
!= DisplayHeight(e
->xany
.display
, screen
)))
231 /* it's not that we panic, but restart */
232 uicb_restart(0, NULL
);
235 /** Handle XDestroyWindow events
239 event_handle_destroynotify(XEvent
*e
)
242 XDestroyWindowEvent
*ev
= &e
->xdestroywindow
;
244 if((c
= client_get_bywin(globalconf
.clients
, ev
->window
)))
248 /** Handle XCrossing events on enter
252 event_handle_enternotify(XEvent
*e
)
255 XCrossingEvent
*ev
= &e
->xcrossing
;
258 if(ev
->mode
!= NotifyNormal
259 || (ev
->x_root
== globalconf
.pointer_x
260 && ev
->y_root
== globalconf
.pointer_y
))
263 /* the idea behind saving pointer_x and pointer_y is Bob Marley powered
264 * this will allow us top drop some EnterNotify events and thus not giving
265 * focus to windows appering under the cursor without a cursor move */
266 globalconf
.pointer_x
= ev
->x_root
;
267 globalconf
.pointer_y
= ev
->y_root
;
269 for(c
= globalconf
.clients
; c
; c
= c
->next
)
270 if(c
->titlebar
.sw
&& c
->titlebar
.sw
->window
== ev
->window
)
273 if(c
|| (c
= client_get_bywin(globalconf
.clients
, ev
->window
)))
275 window_grabbuttons(c
->win
, c
->phys_screen
);
276 if(globalconf
.screens
[c
->screen
].sloppy_focus
)
277 client_focus(c
, c
->screen
,
278 globalconf
.screens
[c
->screen
].sloppy_focus_raise
);
281 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
282 if(ev
->window
== RootWindow(e
->xany
.display
, screen
))
284 window_root_grabbuttons(screen
);
289 /** Handle XMotion events
293 event_handle_motionnotify(XEvent
*e
)
295 XMotionEvent
*ev
= &e
->xmotion
;
297 globalconf
.pointer_x
= ev
->x_root
;
298 globalconf
.pointer_y
= ev
->y_root
;
301 /** Handle XExpose events
305 event_handle_expose(XEvent
*e
)
307 XExposeEvent
*ev
= &e
->xexpose
;
309 Statusbar
*statusbar
;
314 for(screen
= 0; screen
< globalconf
.screens_info
->nscreen
; screen
++)
315 for(statusbar
= globalconf
.screens
[screen
].statusbar
; statusbar
; statusbar
= statusbar
->next
)
316 if(statusbar
->sw
->window
== ev
->window
)
318 statusbar_display(statusbar
);
322 for(c
= globalconf
.clients
; c
; c
= c
->next
)
323 if(c
->titlebar
.sw
&& c
->titlebar
.sw
->window
== ev
->window
)
325 simplewindow_refresh_drawable(c
->titlebar
.sw
, c
->phys_screen
);
331 /** Handle XKey events
335 event_handle_keypress(XEvent
*e
)
339 XKeyEvent
*ev
= &e
->xkey
;
343 /* find the right screen for this event */
344 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
345 if(XQueryPointer(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
), &dummy
, &dummy
, &x
, &y
, &d
, &d
, &m
))
347 /* if screen is 0, we are on first Zaphod screen or on the
348 * only screen in Xinerama, so we can ask for a better screen
349 * number with screen_get_bycoord: we'll get 0 in Zaphod mode
350 * so it's the same, or maybe the real Xinerama screen */
351 screen
= screen_get_bycoord(globalconf
.screens_info
, screen
, x
, y
);
355 for(k
= globalconf
.keys
; k
; k
= k
->next
)
356 if(ev
->keycode
== k
->keycode
&&
357 k
->func
&& CLEANMASK(k
->mod
) == CLEANMASK(ev
->state
))
358 k
->func(screen
, k
->arg
);
361 /** Handle XCrossing events on leave
365 event_handle_leavenotify(XEvent
* e
)
367 XCrossingEvent
*ev
= &e
->xcrossing
;
370 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
371 if((ev
->window
== RootWindow(e
->xany
.display
, screen
)) && !ev
->same_screen
)
372 client_focus(NULL
, screen
, True
);
375 /** Handle XMapping events
379 event_handle_mappingnotify(XEvent
*e
)
381 XMappingEvent
*ev
= &e
->xmapping
;
384 XRefreshKeyboardMapping(ev
);
385 if(ev
->request
== MappingKeyboard
)
386 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
387 window_root_grabkeys(screen
);
390 /** Handle XMapRequest events
394 event_handle_maprequest(XEvent
*e
)
396 static XWindowAttributes wa
;
397 XMapRequestEvent
*ev
= &e
->xmaprequest
;
398 int screen
= 0, x
, y
, d
;
402 if(!XGetWindowAttributes(e
->xany
.display
, ev
->window
, &wa
))
404 if(wa
.override_redirect
)
406 if(!client_get_bywin(globalconf
.clients
, ev
->window
))
408 if(globalconf
.screens_info
->xinerama_is_active
409 && XQueryPointer(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
),
410 &dummy
, &dummy
, &x
, &y
, &d
, &d
, &m
))
411 screen
= screen_get_bycoord(globalconf
.screens_info
, screen
, x
, y
);
413 for(screen
= 0; wa
.screen
!= ScreenOfDisplay(e
->xany
.display
, screen
); screen
++);
415 client_manage(ev
->window
, &wa
, screen
);
419 /** Handle XProperty events
423 event_handle_propertynotify(XEvent
* e
)
427 XPropertyEvent
*ev
= &e
->xproperty
;
429 if(ev
->state
== PropertyDelete
)
431 if((c
= client_get_bywin(globalconf
.clients
, ev
->window
)))
435 case XA_WM_TRANSIENT_FOR
:
436 XGetTransientForHint(e
->xany
.display
, c
->win
, &trans
);
438 && (c
->isfloating
= (client_get_bywin(globalconf
.clients
, trans
) != NULL
)))
439 globalconf
.screens
[c
->screen
].need_arrange
= True
;
441 case XA_WM_NORMAL_HINTS
:
442 client_updatesizehints(c
);
445 client_updatewmhints(c
);
448 if(ev
->atom
== XA_WM_NAME
|| ev
->atom
== XInternAtom(globalconf
.display
, "_NET_WM_NAME", False
))
449 client_updatetitle(c
);
453 /** Handle XUnmap events
457 event_handle_unmapnotify(XEvent
* e
)
460 XUnmapEvent
*ev
= &e
->xunmap
;
462 if((c
= client_get_bywin(globalconf
.clients
, ev
->window
))
463 && ev
->event
== RootWindow(e
->xany
.display
, c
->phys_screen
)
464 && ev
->send_event
&& window_getstate(c
->win
) == NormalState
)
468 /** Handle XShape events
472 event_handle_shape(XEvent
* e
)
474 XShapeEvent
*ev
= (XShapeEvent
*) e
;
475 Client
*c
= client_get_bywin(globalconf
.clients
, ev
->window
);
478 window_setshape(c
->win
, c
->phys_screen
);
481 /** Handle XRandR events
485 event_handle_randr_screen_change_notify(XEvent
*e
)
487 XRRUpdateConfiguration(e
);
488 uicb_restart(0, NULL
);
491 /** Handle XClientMessage events
495 event_handle_clientmessage(XEvent
*e
)
497 ewmh_process_client_message(&e
->xclient
);
500 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80