1 /* evilwm - Minimalist Window Manager for X
2 * Copyright (C) 1999-2009 Ciaran Anscomb <evilwm@6809.org.uk>
3 * see README for license and other details. */
12 Window info_window
= None
;
14 static void create_info_window(Client
*c
);
15 static void update_info_window(Client
*c
);
16 static void remove_info_window(void);
17 static void grab_keysym(Window w
, unsigned int mask
, KeySym keysym
);
19 static void create_info_window(Client
*c
) {
20 info_window
= XCreateSimpleWindow(dpy
, c
->screen
->root
, -4, -4, 2, 2,
21 0, c
->screen
->fg
.pixel
, c
->screen
->fg
.pixel
);
22 XMapRaised(dpy
, info_window
);
23 update_info_window(c
);
26 static void update_info_window(Client
*c
) {
29 int namew
, iwinx
, iwiny
, iwinw
, iwinh
;
30 int width_inc
= c
->width_inc
, height_inc
= c
->height_inc
;
34 snprintf(buf
, sizeof(buf
), "%dx%d+%d+%d", (c
->width
-c
->base_width
)/width_inc
,
35 (c
->height
-c
->base_height
)/height_inc
, c
->x
, c
->y
);
36 iwinw
= XTextWidth(font
, buf
, strlen(buf
)) + 2;
37 iwinh
= font
->max_bounds
.ascent
+ font
->max_bounds
.descent
;
38 XFetchName(dpy
, c
->window
, &name
);
40 namew
= XTextWidth(font
, name
, strlen(name
));
45 iwinx
= c
->x
+ c
->border
+ c
->width
- iwinw
;
46 iwiny
= c
->y
- c
->border
;
47 if (iwinx
+ iwinw
> DisplayWidth(dpy
, c
->screen
->screen
))
48 iwinx
= DisplayWidth(dpy
, c
->screen
->screen
) - iwinw
;
51 if (iwiny
+ iwinh
> DisplayHeight(dpy
, c
->screen
->screen
))
52 iwiny
= DisplayHeight(dpy
, c
->screen
->screen
) - iwinh
;
55 XMoveResizeWindow(dpy
, info_window
, iwinx
, iwiny
, iwinw
, iwinh
);
56 XClearWindow(dpy
, info_window
);
58 XDrawString(dpy
, info_window
, c
->screen
->invert_gc
,
59 1, iwinh
/ 2 - 1, name
, strlen(name
));
62 XDrawString(dpy
, info_window
, c
->screen
->invert_gc
, 1, iwinh
- 1,
66 static void remove_info_window(void) {
68 XDestroyWindow(dpy
, info_window
);
71 #endif /* INFOBANNER */
73 #if defined(MOUSE) || !defined(INFOBANNER)
74 static void draw_outline(Client
*c
) {
75 #ifndef INFOBANNER_MOVERESIZE
77 int width_inc
= c
->width_inc
, height_inc
= c
->height_inc
;
78 #endif /* ndef INFOBANNER_MOVERESIZE */
80 XDrawRectangle(dpy
, c
->screen
->root
, c
->screen
->invert_gc
,
81 c
->x
- c
->border
, c
->y
- c
->border
,
82 c
->width
+ c
->border
, c
->height
+ c
->border
);
84 #ifndef INFOBANNER_MOVERESIZE
85 snprintf(buf
, sizeof(buf
), "%dx%d+%d+%d", (c
->width
-c
->base_width
)/width_inc
,
86 (c
->height
-c
->base_height
)/height_inc
, c
->x
, c
->y
);
87 XDrawString(dpy
, c
->screen
->root
, c
->screen
->invert_gc
,
88 c
->x
+ c
->width
- XTextWidth(font
, buf
, strlen(buf
)) - SPACE
,
89 c
->y
+ c
->height
- SPACE
,
91 #endif /* ndef INFOBANNER_MOVERESIZE */
96 static void recalculate_sweep(Client
*c
, int x1
, int y1
, int x2
, int y2
) {
98 c
->width
= abs(x1
- x2
);
99 c
->width
-= (c
->width
- c
->base_width
) % c
->width_inc
;
100 if (c
->min_width
&& c
->width
< c
->min_width
)
101 c
->width
= c
->min_width
;
102 if (c
->max_width
&& c
->width
> c
->max_width
)
103 c
->width
= c
->max_width
;
104 c
->x
= (x1
<= x2
) ? x1
: x1
- c
->width
;
107 c
->height
= abs(y1
- y2
);
108 c
->height
-= (c
->height
- c
->base_height
) % c
->height_inc
;
109 if (c
->min_height
&& c
->height
< c
->min_height
)
110 c
->height
= c
->min_height
;
111 if (c
->max_height
&& c
->height
> c
->max_height
)
112 c
->height
= c
->max_height
;
113 c
->y
= (y1
<= y2
) ? y1
: y1
- c
->height
;
117 void sweep(Client
*c
) {
122 if (!grab_pointer(c
->screen
->root
, MouseMask
, resize_curs
)) return;
125 #ifdef INFOBANNER_MOVERESIZE
126 create_info_window(c
);
131 setmouse(c
->window
, c
->width
, c
->height
);
133 XMaskEvent(dpy
, MouseMask
, &ev
);
136 if (ev
.xmotion
.root
!= c
->screen
->root
)
138 draw_outline(c
); /* clear */
140 recalculate_sweep(c
, old_cx
, old_cy
, ev
.xmotion
.x
, ev
.xmotion
.y
);
141 #ifdef INFOBANNER_MOVERESIZE
142 update_info_window(c
);
149 draw_outline(c
); /* clear */
151 #ifdef INFOBANNER_MOVERESIZE
152 remove_info_window();
154 XUngrabPointer(dpy
, CurrentTime
);
163 void show_info(Client
*c
, unsigned int keycode
) {
165 XKeyboardState keyboard
;
167 XGetKeyboardControl(dpy
, &keyboard
);
170 create_info_window(c
);
176 XMaskEvent(dpy
, KeyReleaseMask
, &ev
);
177 } while (ev
.xkey
.keycode
!= keycode
);
179 remove_info_window();
184 if (keyboard
.global_auto_repeat
== AutoRepeatModeOn
)
189 static int absmin(int a
, int b
) {
195 static void snap_client(Client
*c
) {
197 int dpy_width
= DisplayWidth(dpy
, c
->screen
->screen
);
198 int dpy_height
= DisplayHeight(dpy
, c
->screen
->screen
);
202 /* snap to other windows */
204 for (iter
= clients_tab_order
; iter
; iter
= iter
->next
) {
206 if (ci
== c
) continue;
207 if (ci
->screen
!= ci
->screen
) continue;
209 if (!is_fixed(ci
) && ci
->vdesk
!= c
->vdesk
) continue;
211 if (ci
->is_dock
&& !c
->screen
->docks_visible
) continue;
212 if (ci
->y
- ci
->border
- c
->border
- c
->height
- c
->y
<= opt_snap
&& c
->y
- c
->border
- ci
->border
- ci
->height
- ci
->y
<= opt_snap
) {
213 dx
= absmin(dx
, ci
->x
+ ci
->width
- c
->x
+ c
->border
+ ci
->border
);
214 dx
= absmin(dx
, ci
->x
+ ci
->width
- c
->x
- c
->width
);
215 dx
= absmin(dx
, ci
->x
- c
->x
- c
->width
- c
->border
- ci
->border
);
216 dx
= absmin(dx
, ci
->x
- c
->x
);
218 if (ci
->x
- ci
->border
- c
->border
- c
->width
- c
->x
<= opt_snap
&& c
->x
- c
->border
- ci
->border
- ci
->width
- ci
->x
<= opt_snap
) {
219 dy
= absmin(dy
, ci
->y
+ ci
->height
- c
->y
+ c
->border
+ ci
->border
);
220 dy
= absmin(dy
, ci
->y
+ ci
->height
- c
->y
- c
->height
);
221 dy
= absmin(dy
, ci
->y
- c
->y
- c
->height
- c
->border
- ci
->border
);
222 dy
= absmin(dy
, ci
->y
- c
->y
);
225 if (abs(dx
) < opt_snap
)
227 if (abs(dy
) < opt_snap
)
230 /* snap to screen border */
231 if (abs(c
->x
- c
->border
) < opt_snap
) c
->x
= c
->border
;
232 if (abs(c
->y
- c
->border
) < opt_snap
) c
->y
= c
->border
;
233 if (abs(c
->x
+ c
->width
+ c
->border
- dpy_width
) < opt_snap
)
234 c
->x
= dpy_width
- c
->width
- c
->border
;
235 if (abs(c
->y
+ c
->height
+ c
->border
- dpy_height
) < opt_snap
)
236 c
->y
= dpy_height
- c
->height
- c
->border
;
238 if (abs(c
->x
) == c
->border
&& c
->width
== dpy_width
)
240 if (abs(c
->y
) == c
->border
&& c
->height
== dpy_height
)
244 void drag(Client
*c
) {
250 if (!grab_pointer(c
->screen
->root
, MouseMask
, move_curs
)) return;
252 get_mouse_position(&x1
, &y1
, c
->screen
->root
);
253 #ifdef INFOBANNER_MOVERESIZE
254 create_info_window(c
);
261 XMaskEvent(dpy
, MouseMask
, &ev
);
264 if (ev
.xmotion
.root
!= c
->screen
->root
)
267 draw_outline(c
); /* clear */
270 c
->x
= old_cx
+ (ev
.xmotion
.x
- x1
);
271 c
->y
= old_cy
+ (ev
.xmotion
.y
- y1
);
275 #ifdef INFOBANNER_MOVERESIZE
276 update_info_window(c
);
283 XMoveWindow(dpy
, c
->parent
,
291 draw_outline(c
); /* clear */
294 #ifdef INFOBANNER_MOVERESIZE
295 remove_info_window();
297 XUngrabPointer(dpy
, CurrentTime
);
306 #endif /* def MOUSE */
308 void moveresize(Client
*c
) {
310 XMoveResizeWindow(dpy
, c
->parent
, c
->x
- c
->border
, c
->y
- c
->border
,
311 c
->width
, c
->height
);
312 XMoveResizeWindow(dpy
, c
->window
, 0, 0, c
->width
, c
->height
);
316 void maximise_client(Client
*c
, int action
, int hv
) {
317 if (hv
& MAXIMISE_HORZ
) {
319 if (action
== NET_WM_STATE_REMOVE
320 || action
== NET_WM_STATE_TOGGLE
) {
324 XDeleteProperty(dpy
, c
->window
, xa_evilwm_unmaximised_horz
);
327 if (action
== NET_WM_STATE_ADD
328 || action
== NET_WM_STATE_TOGGLE
) {
329 unsigned long props
[2];
333 c
->width
= DisplayWidth(dpy
, c
->screen
->screen
);
336 XChangeProperty(dpy
, c
->window
, xa_evilwm_unmaximised_horz
,
337 XA_CARDINAL
, 32, PropModeReplace
,
338 (unsigned char *)&props
, 2);
342 if (hv
& MAXIMISE_VERT
) {
344 if (action
== NET_WM_STATE_REMOVE
345 || action
== NET_WM_STATE_TOGGLE
) {
349 XDeleteProperty(dpy
, c
->window
, xa_evilwm_unmaximised_vert
);
352 if (action
== NET_WM_STATE_ADD
353 || action
== NET_WM_STATE_TOGGLE
) {
354 unsigned long props
[2];
358 c
->height
= DisplayHeight(dpy
, c
->screen
->screen
);
361 XChangeProperty(dpy
, c
->window
, xa_evilwm_unmaximised_vert
,
362 XA_CARDINAL
, 32, PropModeReplace
,
363 (unsigned char *)&props
, 2);
367 ewmh_set_net_wm_state(c
);
369 discard_enter_events();
373 struct list
*newl
= list_find(clients_tab_order
, current
);
374 Client
*newc
= current
;
378 if (!newl
&& !current
)
382 newl
= clients_tab_order
;
390 /* NOTE: Checking against newc->screen->vdesk implies we can Alt+Tab
391 * across screen boundaries. Is this what we want? */
392 while ((!is_fixed(newc
) && (newc
->vdesk
!= newc
->screen
->vdesk
)) || (newc
->is_dock
&& !newc
->screen
->docks_visible
));
402 setmouse(newc
->window
, newc
->width
+ newc
->border
- 1,
403 newc
->height
+ newc
->border
- 1);
405 discard_enter_events();
409 void switch_vdesk(ScreenInfo
*s
, unsigned int v
) {
412 int hidden
= 0, raised
= 0;
417 LOG_ENTER("switch_vdesk(screen=%d, from=%d, to=%d)", s
->screen
, s
->vdesk
, v
);
418 if (current
&& !is_fixed(current
)) {
421 for (iter
= clients_tab_order
; iter
; iter
= iter
->next
) {
422 Client
*c
= iter
->data
;
425 if (c
->vdesk
== s
->vdesk
) {
430 } else if (c
->vdesk
== v
) {
431 if (!c
->is_dock
|| s
->docks_visible
)
439 ewmh_set_net_current_desktop(s
);
440 LOG_DEBUG("%d hidden, %d raised\n", hidden
, raised
);
445 void set_docks_visible(ScreenInfo
*s
, int is_visible
) {
448 LOG_ENTER("set_docks_visible(screen=%d, is_visible=%d)", s
->screen
, is_visible
);
449 s
->docks_visible
= is_visible
;
450 for (iter
= clients_tab_order
; iter
; iter
= iter
->next
) {
451 Client
*c
= iter
->data
;
457 if (is_fixed(c
) || (c
->vdesk
== s
->vdesk
)) {
472 ScreenInfo
*find_screen(Window root
) {
474 for (i
= 0; i
< num_screens
; i
++) {
475 if (screens
[i
].root
== root
)
481 ScreenInfo
*find_current_screen(void) {
486 /* XQueryPointer is useful for getting the current pointer root */
487 XQueryPointer(dpy
, screens
[0].root
, &cur_root
, &dw
, &di
, &di
, &di
, &di
, &dui
);
488 return find_screen(cur_root
);
491 static void grab_keysym(Window w
, unsigned int mask
, KeySym keysym
) {
492 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
493 XGrabKey(dpy
, keycode
, mask
, w
, True
,
494 GrabModeAsync
, GrabModeAsync
);
495 XGrabKey(dpy
, keycode
, mask
|LockMask
, w
, True
,
496 GrabModeAsync
, GrabModeAsync
);
498 XGrabKey(dpy
, keycode
, mask
|numlockmask
, w
, True
,
499 GrabModeAsync
, GrabModeAsync
);
500 XGrabKey(dpy
, keycode
, mask
|numlockmask
|LockMask
, w
, True
,
501 GrabModeAsync
, GrabModeAsync
);
505 static KeySym keys_to_grab
[] = {
507 KEY_FIX
, KEY_PREVDESK
, KEY_NEXTDESK
,
508 XK_1
, XK_2
, XK_3
, XK_4
, XK_5
, XK_6
, XK_7
, XK_8
,
511 KEY_TOPLEFT
, KEY_TOPRIGHT
, KEY_BOTTOMLEFT
, KEY_BOTTOMRIGHT
,
512 KEY_LEFT
, KEY_RIGHT
, KEY_DOWN
, KEY_UP
,
513 KEY_LOWER
, KEY_ALTLOWER
, KEY_INFO
, KEY_MAXVERT
, KEY_MAX
,
516 #define NUM_GRABS (int)(sizeof(keys_to_grab) / sizeof(KeySym))
518 static KeySym alt_keys_to_grab
[] = {
519 KEY_KILL
, KEY_LEFT
, KEY_RIGHT
, KEY_DOWN
, KEY_UP
521 #define NUM_ALT_GRABS (int)(sizeof(alt_keys_to_grab) / sizeof(KeySym))
523 void grab_keys_for_screen(ScreenInfo
*s
) {
525 /* Release any previous grabs */
526 XUngrabKey(dpy
, AnyKey
, AnyModifier
, s
->root
);
527 /* Grab key combinations we're interested in */
528 for (i
= 0; i
< NUM_GRABS
; i
++) {
529 grab_keysym(s
->root
, grabmask1
, keys_to_grab
[i
]);
531 for (i
= 0; i
< NUM_ALT_GRABS
; i
++) {
532 grab_keysym(s
->root
, grabmask1
| altmask
, alt_keys_to_grab
[i
]);
534 grab_keysym(s
->root
, grabmask2
, KEY_NEXT
);