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"
37 #include "layouts/tile.h"
38 #include "layouts/floating.h"
40 #define CLEANMASK(mask, acf) (mask & ~(acf.numlockmask | LockMask))
43 handle_mouse_button_press(awesome_config
*awesomeconf
,
44 unsigned int button
, unsigned int state
,
45 Button
*buttons
, char *arg
)
49 for(b
= buttons
; b
; b
= b
->next
)
50 if(button
== b
->button
&& CLEANMASK(state
, awesomeconf
[0]) == b
->mod
&& b
->func
)
53 b
->func(awesomeconf
, arg
);
55 b
->func(awesomeconf
, b
->arg
);
61 handle_event_buttonpress(XEvent
* e
, awesome_config
*awesomeconf
)
63 int i
, screen
, x
= 0, y
= 0;
68 XButtonPressedEvent
*ev
= &e
->xbutton
;
70 for(screen
= 0; screen
< get_screen_count(e
->xany
.display
); screen
++)
71 if(awesomeconf
[screen
].statusbar
.window
== ev
->window
)
73 for(i
= 0; i
< awesomeconf
[screen
].ntags
; i
++)
75 x
+= textwidth(e
->xany
.display
, awesomeconf
[screen
].font
, awesomeconf
[screen
].tags
[i
].name
);
76 if(((awesomeconf
[screen
].statusbar
.position
== BarTop
77 || awesomeconf
[screen
].statusbar
.position
== BarBot
)
79 || (awesomeconf
[screen
].statusbar
.position
== BarRight
&& ev
->y
< x
)
80 || (awesomeconf
[screen
].statusbar
.position
== BarLeft
&& ev
->y
> awesomeconf
[screen
].statusbar
.width
- x
))
82 snprintf(arg
, sizeof(arg
), "%d", i
+ 1);
83 handle_mouse_button_press(&awesomeconf
[screen
], ev
->button
, ev
->state
,
84 awesomeconf
[screen
].buttons
.tag
, arg
);
88 x
+= awesomeconf
[screen
].statusbar
.txtlayoutwidth
;
89 if(((awesomeconf
[screen
].statusbar
.position
== BarTop
90 || awesomeconf
[screen
].statusbar
.position
== BarBot
)
92 || (awesomeconf
[screen
].statusbar
.position
== BarRight
&& ev
->y
< x
)
93 || (awesomeconf
[screen
].statusbar
.position
== BarLeft
&& ev
->y
> awesomeconf
[screen
].statusbar
.width
- x
))
94 handle_mouse_button_press(&awesomeconf
[screen
], ev
->button
, ev
->state
,
95 awesomeconf
[screen
].buttons
.layout
, NULL
);
97 handle_mouse_button_press(&awesomeconf
[screen
], ev
->button
, ev
->state
,
98 awesomeconf
[screen
].buttons
.title
, NULL
);
102 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
104 XAllowEvents(c
->display
, ReplayPointer
, CurrentTime
);
105 focus(c
, ev
->same_screen
, &awesomeconf
[c
->screen
]);
106 if(CLEANMASK(ev
->state
, awesomeconf
[c
->screen
]) == NoSymbol
107 && ev
->button
== Button1
)
109 restack(&awesomeconf
[c
->screen
]);
110 window_grabbuttons(c
->display
, c
->phys_screen
, c
->win
,
111 True
, True
, awesomeconf
->buttons
.root
,
112 awesomeconf
->buttons
.client
, awesomeconf
->numlockmask
);
115 handle_mouse_button_press(&awesomeconf
[c
->screen
], ev
->button
, ev
->state
,
116 awesomeconf
[c
->screen
].buttons
.client
, NULL
);
119 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
120 if(RootWindow(e
->xany
.display
, screen
) == ev
->window
121 && XQueryPointer(e
->xany
.display
, ev
->window
, &wdummy
, &wdummy
, &x
, &y
, &i
, &i
, &udummy
))
123 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
124 handle_mouse_button_press(&awesomeconf
[screen
], ev
->button
, ev
->state
,
125 awesomeconf
[screen
].buttons
.root
, NULL
);
131 handle_event_configurerequest(XEvent
* e
, awesome_config
*awesomeconf
)
134 XConfigureRequestEvent
*ev
= &e
->xconfigurerequest
;
137 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
140 if(ev
->value_mask
& CWBorderWidth
)
141 c
->border
= ev
->border_width
;
142 if(c
->isfixed
|| c
->isfloating
143 || get_current_layout(awesomeconf
[c
->screen
].tags
,
144 awesomeconf
[c
->screen
].ntags
)->arrange
== layout_floating
)
146 if(ev
->value_mask
& CWX
)
148 if(ev
->value_mask
& CWY
)
150 if(ev
->value_mask
& CWWidth
)
152 if(ev
->value_mask
& CWHeight
)
154 if((c
->x
+ c
->w
) > DisplayWidth(c
->display
, c
->phys_screen
) && c
->isfloating
)
155 c
->x
= DisplayWidth(c
->display
, c
->phys_screen
) / 2 - c
->w
/ 2; /* center in x direction */
156 if((c
->y
+ c
->h
) > DisplayHeight(c
->display
, c
->phys_screen
) && c
->isfloating
)
157 c
->y
= DisplayHeight(c
->display
, c
->phys_screen
) / 2 - c
->h
/ 2; /* center in y direction */
158 if((ev
->value_mask
& (CWX
| CWY
)) && !(ev
->value_mask
& (CWWidth
| CWHeight
)))
159 window_configure(c
->display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
, c
->border
);
160 if(isvisible(c
, c
->screen
, awesomeconf
[c
->screen
].tags
, awesomeconf
[c
->screen
].ntags
))
161 XMoveResizeWindow(e
->xany
.display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
);
164 window_configure(c
->display
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
, c
->border
);
170 wc
.width
= ev
->width
;
171 wc
.height
= ev
->height
;
172 wc
.border_width
= ev
->border_width
;
173 wc
.sibling
= ev
->above
;
174 wc
.stack_mode
= ev
->detail
;
175 XConfigureWindow(e
->xany
.display
, ev
->window
, ev
->value_mask
, &wc
);
177 XSync(e
->xany
.display
, False
);
181 handle_event_configurenotify(XEvent
* e
, awesome_config
*awesomeconf
)
183 XConfigureEvent
*ev
= &e
->xconfigure
;
187 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
188 if(ev
->window
== RootWindow(e
->xany
.display
, screen
)
189 && (ev
->width
!= DisplayWidth(e
->xany
.display
, screen
)
190 || ev
->height
!= DisplayHeight(e
->xany
.display
, screen
)))
192 DisplayWidth(e
->xany
.display
, screen
) = ev
->width
;
193 DisplayHeight(e
->xany
.display
, screen
) = ev
->height
;
195 /* update statusbar */
196 si
= get_screen_info(e
->xany
.display
, screen
, NULL
);
197 awesomeconf
[screen
].statusbar
.width
= si
[screen
].width
;
200 XResizeWindow(e
->xany
.display
,
201 awesomeconf
[screen
].statusbar
.window
,
202 awesomeconf
[screen
].statusbar
.width
,
203 awesomeconf
[screen
].statusbar
.height
);
205 updatebarpos(e
->xany
.display
, awesomeconf
[screen
].statusbar
);
206 arrange(&awesomeconf
[screen
]);
211 handle_event_destroynotify(XEvent
* e
, awesome_config
*awesomeconf
)
214 XDestroyWindowEvent
*ev
= &e
->xdestroywindow
;
216 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
217 client_unmanage(c
, WithdrawnState
, &awesomeconf
[c
->screen
]);
221 handle_event_enternotify(XEvent
* e
, awesome_config
*awesomeconf
)
224 XCrossingEvent
*ev
= &e
->xcrossing
;
227 if(ev
->mode
!= NotifyNormal
|| ev
->detail
== NotifyInferior
)
229 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
231 focus(c
, ev
->same_screen
, &awesomeconf
[c
->screen
]);
233 || get_current_layout(awesomeconf
[c
->screen
].tags
,
234 awesomeconf
[c
->screen
].ntags
)->arrange
== layout_floating
)
235 window_grabbuttons(c
->display
, c
->phys_screen
, c
->win
,
236 True
, False
, awesomeconf
->buttons
.root
,
237 awesomeconf
->buttons
.client
, awesomeconf
->numlockmask
);
240 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
241 if(ev
->window
== RootWindow(e
->xany
.display
, screen
))
242 focus(NULL
, True
, &awesomeconf
[screen
]);
246 handle_event_expose(XEvent
* e
, awesome_config
*awesomeconf
)
248 XExposeEvent
*ev
= &e
->xexpose
;
252 for(screen
= 0; screen
< get_screen_count(e
->xany
.display
); screen
++)
253 if(awesomeconf
[screen
].statusbar
.window
== ev
->window
)
254 drawstatusbar(&awesomeconf
[screen
]);
258 handle_event_keypress(XEvent
* e
, awesome_config
*awesomeconf
)
263 XKeyEvent
*ev
= &e
->xkey
;
267 keysym
= XKeycodeToKeysym(e
->xany
.display
, (KeyCode
) ev
->keycode
, 0);
269 /* find the right screen for this event */
270 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
271 if(XQueryPointer(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
), &dummy
, &dummy
, &x
, &y
, &d
, &d
, &m
))
273 /* if screen is 0, we are on first Zaphod screen or on the
274 * only screen in Xinerama, so we can ask for a better screen
275 * number with get_screen_bycoord: we'll get 0 in Zaphod mode
276 * so it's the same, or maybe the real Xinerama screen */
278 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
282 for(k
= awesomeconf
[screen
].keys
; k
; k
= k
->next
)
283 if(keysym
== k
->keysym
&& k
->func
284 && CLEANMASK(k
->mod
, awesomeconf
[screen
]) == CLEANMASK(ev
->state
, awesomeconf
[screen
]))
285 k
->func(&awesomeconf
[screen
], k
->arg
);
289 handle_event_leavenotify(XEvent
* e
, awesome_config
*awesomeconf
)
291 XCrossingEvent
*ev
= &e
->xcrossing
;
294 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
295 if((ev
->window
== RootWindow(e
->xany
.display
, screen
)) && !ev
->same_screen
)
296 focus(NULL
, ev
->same_screen
, &awesomeconf
[screen
]);
300 handle_event_mappingnotify(XEvent
* e
, awesome_config
*awesomeconf
)
302 XMappingEvent
*ev
= &e
->xmapping
;
305 XRefreshKeyboardMapping(ev
);
306 if(ev
->request
== MappingKeyboard
)
307 for(screen
= 0; screen
< ScreenCount(e
->xany
.display
); screen
++)
308 grabkeys(&awesomeconf
[screen
]);
312 handle_event_maprequest(XEvent
* e
, awesome_config
*awesomeconf
)
314 static XWindowAttributes wa
;
315 XMapRequestEvent
*ev
= &e
->xmaprequest
;
320 if(!XGetWindowAttributes(e
->xany
.display
, ev
->window
, &wa
))
322 if(wa
.override_redirect
)
324 if(!get_client_bywin(*awesomeconf
->clients
, ev
->window
))
326 for(screen
= 0; wa
.screen
!= ScreenOfDisplay(e
->xany
.display
, screen
); screen
++);
327 if(screen
== 0 && XQueryPointer(e
->xany
.display
, RootWindow(e
->xany
.display
, screen
),
328 &dummy
, &dummy
, &x
, &y
, &d
, &d
, &m
))
329 screen
= get_screen_bycoord(e
->xany
.display
, x
, y
);
330 client_manage(ev
->window
, &wa
, &awesomeconf
[screen
]);
335 handle_event_propertynotify(XEvent
* e
, awesome_config
*awesomeconf
)
339 XPropertyEvent
*ev
= &e
->xproperty
;
341 if(ev
->state
== PropertyDelete
)
343 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
)))
347 case XA_WM_TRANSIENT_FOR
:
348 XGetTransientForHint(e
->xany
.display
, c
->win
, &trans
);
349 if(!c
->isfloating
&& (c
->isfloating
= (get_client_bywin(*awesomeconf
->clients
, trans
) != NULL
)))
350 arrange(&awesomeconf
[c
->screen
]);
352 case XA_WM_NORMAL_HINTS
:
356 if(ev
->atom
== XA_WM_NAME
|| ev
->atom
== XInternAtom(c
->display
, "_NET_WM_NAME", False
))
359 if(c
== get_current_tag(awesomeconf
->tags
, awesomeconf
->ntags
)->client_sel
)
360 drawstatusbar(&awesomeconf
[c
->screen
]);
366 handle_event_unmapnotify(XEvent
* e
, awesome_config
*awesomeconf
)
369 XUnmapEvent
*ev
= &e
->xunmap
;
371 if((c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
))
372 && ev
->event
== RootWindow(e
->xany
.display
, c
->phys_screen
)
373 && ev
->send_event
&& window_getstate(c
->display
, c
->win
) == NormalState
)
374 client_unmanage(c
, WithdrawnState
, &awesomeconf
[c
->screen
]);
378 handle_event_shape(XEvent
* e
,
379 awesome_config
*awesomeconf
__attribute__ ((unused
)))
381 XShapeEvent
*ev
= (XShapeEvent
*) e
;
382 Client
*c
= get_client_bywin(*awesomeconf
->clients
, ev
->window
);
385 window_setshape(c
->display
, c
->phys_screen
, c
->win
);
389 handle_event_randr_screen_change_notify(XEvent
*e
,
390 awesome_config
*awesomeconf
__attribute__ ((unused
)))
392 XRRUpdateConfiguration(e
);
396 grabkeys(awesome_config
*awesomeconf
)
401 XUngrabKey(awesomeconf
->display
, AnyKey
, AnyModifier
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
));
402 for(k
= awesomeconf
->keys
; k
; k
= k
->next
)
404 if((code
= XKeysymToKeycode(awesomeconf
->display
, k
->keysym
)) == NoSymbol
)
406 XGrabKey(awesomeconf
->display
, code
, k
->mod
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
407 XGrabKey(awesomeconf
->display
, code
, k
->mod
| LockMask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
408 XGrabKey(awesomeconf
->display
, code
, k
->mod
| awesomeconf
->numlockmask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
409 XGrabKey(awesomeconf
->display
, code
, k
->mod
| awesomeconf
->numlockmask
| LockMask
, RootWindow(awesomeconf
->display
, awesomeconf
->phys_screen
), True
, GrabModeAsync
, GrabModeAsync
);
412 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99