4 * Part of gwm, the Gratuitous Window Manager,
5 * by Gary Wong, <gtw@gnu.org>.
7 * Copyright (C) 2009 Gary Wong
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of version 3 of the GNU General Public License as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 #include <xcb/shape.h>
39 #include "window-table.h"
41 extern void set_managed_state( struct gwm_window
*window
, int state
) {
45 assert( window
->type
== WINDOW_MANAGED
);
47 /* Place a WM_STATE property on the client window (ICCCM 2.0, section
49 values
[ 0 ] = window
->u
.managed
.state
= state
;
50 values
[ 1 ] = XCB_NONE
;
51 xcb_change_property( c
, XCB_PROP_MODE_REPLACE
, window
->w
,
52 atoms
[ ATOM_WM_STATE
], atoms
[ ATOM_WM_STATE
],
56 extern void iconic_to_normal( struct gwm_window
*window
) {
58 assert( window
->type
== WINDOW_MANAGED
);
60 set_managed_state( window
, STATE_NORMAL
);
61 xcb_map_window( c
, window
->w
);
62 xcb_map_window( c
, window
->u
.managed
.frame
->w
);
65 extern void normal_to_iconic( struct gwm_window
*window
) {
69 assert( window
->type
== WINDOW_MANAGED
);
71 set_managed_state( window
, STATE_ICONIC
);
73 /* We need to unmap our child without invoking the normal
74 UnmapNotify handler response. Unfortunately it's very
75 difficult to communicate to the handler the distinction between
76 the resultant UnmapNotify from an unmap here and an unrelated
77 event. Checking the request sequence is not robust, because
78 asynchronous events might not be assigned unique sequence
79 numbers. Instead, we grab the server and temporarily change
80 our event mask, which seems a heavyweight approach but does
81 guarantee that only this event will be ignored. */
84 n
= XCB_EVENT_MASK_PROPERTY_CHANGE
| XCB_EVENT_MASK_COLOR_MAP_CHANGE
;
85 xcb_change_window_attributes( c
, window
->w
, XCB_CW_EVENT_MASK
, &n
);
87 xcb_unmap_window( c
, window
->w
);
89 n
= XCB_EVENT_MASK_STRUCTURE_NOTIFY
| XCB_EVENT_MASK_PROPERTY_CHANGE
|
90 XCB_EVENT_MASK_COLOR_MAP_CHANGE
;
91 xcb_change_window_attributes( c
, window
->w
, XCB_CW_EVENT_MASK
, &n
);
93 xcb_ungrab_server( c
);
95 xcb_unmap_window( c
, window
->u
.managed
.frame
->w
);
98 static void managed_destroy_notify( struct gwm_window
*window
,
99 xcb_destroy_notify_event_t
*ev
) {
101 assert( window
->type
== WINDOW_MANAGED
);
103 /* This isn't the preferred notification mechanism, but it can
104 happen: if a client has a window in the Iconic state and either
105 terminates abnormally or doesn't send a synthetic UnmapNotify
106 (as specified in ICCCM 2.0, section 4.1.4), then we might not
107 find out about it until we receive a DestroyNotify. */
108 unmanage_window( window
);
111 static void managed_unmap_notify( struct gwm_window
*window
,
112 xcb_unmap_notify_event_t
*ev
) {
114 assert( window
->type
== WINDOW_MANAGED
);
116 /* A transition to the Withdrawn state (ICCCM 2.0, section 4.1.4). */
117 unmanage_window( window
);
120 static void managed_reparent_notify( struct gwm_window
*window
,
121 xcb_reparent_notify_event_t
*ev
) {
123 assert( window
->type
== WINDOW_MANAGED
);
125 if( ev
->parent
!= window
->u
.managed
.frame
->w
)
126 /* Handle an obscure case: a client window being reparented away from
127 our frame while iconified. Much like managed_destroy_notify. */
128 unmanage_window( window
->u
.frame
.child
);
131 struct managed_get_property
{
133 enum gwm_property_type prop
;
136 static void handle_managed_get_property( unsigned int sequence
, void *reply
,
137 xcb_generic_error_t
*error
,
138 union callback_param cp
) {
140 struct managed_get_property
*p
= cp
.p
;
143 /* Ignore Window errors, since the window might have been destroyed
145 if( error
->error_code
!= XCB_WINDOW
)
152 struct gwm_window
*window
= lookup_window( p
->w
);
154 /* Don't assume the window is valid: it might have been destroyed
155 or forgotten asynchronously. */
156 if( window
&& window
->type
== WINDOW_MANAGED
)
157 managed_property_change( window
, p
->prop
, reply
);
165 extern void async_get_property( struct gwm_window
*window
,
166 enum gwm_property_type prop
) {
168 struct managed_get_property
*p
= xmalloc( sizeof *p
);
169 union callback_param cp
;
175 handle_async_reply( xcb_get_property( c
, FALSE
, window
->w
,
177 prop_types
[ prop
], 0,
178 PROP_SIZE
).sequence
,
179 handle_managed_get_property
, cp
);
182 struct managed_get_geometry
{
183 struct gwm_window
*window
;
184 xcb_pixmap_t icon
, mask
;
187 static void handle_get_geometry( unsigned int sequence
, void *reply
,
188 xcb_generic_error_t
*error
,
189 union callback_param cp
) {
191 struct managed_get_geometry
*p
= cp
.p
;
194 /* Ignore Drawable errors, since it was specified by the client. */
195 if( error
->error_code
!= XCB_DRAWABLE
)
201 replace_icons( p
->window
, 0, NULL
, NULL
, NULL
, &p
->icon
);
205 xcb_get_geometry_reply_t
*r
= reply
;
207 xcb_pixmap_t icons
[ 2 ];
211 icons
[ 0 ] = p
->icon
;
212 icons
[ 1 ] = p
->mask
;
213 replace_icons( p
->window
, 1, &width
, &height
, NULL
, icons
);
221 #define MOTIF_WM_HINTS_DECORATIONS 0x2
223 #define MOTIF_WM_HINTS_FLAGS_OFF 0
224 #define MOTIF_WM_HINTS_DECORATIONS_OFF 2
225 #define MOTIF_WM_HINTS_MIN_SIZE 3 /* ignore hint properties smaller than this */
227 #define MOTIF_WM_HINTS_DEC_ALL 0x1
228 #define MOTIF_WM_HINTS_DEC_BORDER 0x2
229 #define MOTIF_WM_HINTS_DEC_TITLE 0x8
231 #define WM_HINTS_INPUT 0x01
232 #define WM_HINTS_STATE 0x02
233 #define WM_HINTS_ICON 0x04
234 #define WM_HINTS_ICON_MASK 0x20
236 #define WM_HINTS_FLAGS_OFF 0
237 #define WM_HINTS_INPUT_OFF 1
238 #define WM_HINTS_STATE_OFF 2
239 #define WM_HINTS_ICON_OFF 3
240 #define WM_HINTS_MASK_OFF 7
242 #define WM_HINTS_STATE_NORMAL 1
243 #define WM_HINTS_STATE_ICONIC 3
245 #define WM_NORMAL_HINTS_USER_POSITION 0x001
246 #define WM_NORMAL_HINTS_PROGRAM_POSITION 0x004
247 #define WM_NORMAL_HINTS_MIN_SIZE 0x010
248 #define WM_NORMAL_HINTS_MAX_SIZE 0x020
249 #define WM_NORMAL_HINTS_SIZE_INC 0x040
250 #define WM_NORMAL_HINTS_ASPECT 0x080
251 #define WM_NORMAL_HINTS_BASE_SIZE 0x100
252 #define WM_NORMAL_HINTS_WIN_GRAVITY 0x200
254 #define WM_NORMAL_HINTS_FLAGS_OFF 0
255 #define WM_NORMAL_HINTS_MIN_SIZE_OFF 5
256 #define WM_NORMAL_HINTS_MAX_SIZE_OFF 7
257 #define WM_NORMAL_HINTS_SIZE_INC_OFF 9
258 #define WM_NORMAL_HINTS_ASPECT_OFF 11
259 #define WM_NORMAL_HINTS_BASE_SIZE_OFF 15
260 #define WM_NORMAL_HINTS_WIN_GRAVITY_OFF 17
262 extern void managed_property_change( struct gwm_window
*window
, int prop
,
263 xcb_get_property_reply_t
*p
) {
267 struct xcb_screen_t
*screen
;
273 assert( window
->type
== WINDOW_MANAGED
);
276 case PROP__MOTIF_WM_HINTS
:
277 /* _MOTIF_WM_HINTS property. */
278 old_decoration
= window
->u
.managed
.frame
->u
.frame
.decoration
;
280 window
->u
.managed
.frame
->u
.frame
.decoration
= DEC_DEFAULT
;
282 if( p
->format
== 32 && p
->value_len
>= MOTIF_WM_HINTS_MIN_SIZE
) {
283 p32
= xcb_get_property_value( p
);
285 if( p32
[ MOTIF_WM_HINTS_FLAGS_OFF
] &
286 MOTIF_WM_HINTS_DECORATIONS
) {
287 if( p32
[ MOTIF_WM_HINTS_DECORATIONS_OFF
] &
288 MOTIF_WM_HINTS_DEC_ALL
) {
289 window
->u
.managed
.frame
->u
.frame
.decoration
=
290 DEC_BORDER
| DEC_TITLE
;
292 if( p32
[ MOTIF_WM_HINTS_DECORATIONS_OFF
] &
293 MOTIF_WM_HINTS_DEC_BORDER
)
294 window
->u
.managed
.frame
->u
.frame
.decoration
&=
297 if( p32
[ MOTIF_WM_HINTS_DECORATIONS_OFF
] &
298 MOTIF_WM_HINTS_DEC_TITLE
)
299 window
->u
.managed
.frame
->u
.frame
.decoration
&=
302 window
->u
.managed
.frame
->u
.frame
.decoration
= 0;
304 if( p32
[ MOTIF_WM_HINTS_DECORATIONS_OFF
] &
305 MOTIF_WM_HINTS_DEC_BORDER
)
306 window
->u
.managed
.frame
->u
.frame
.decoration
|=
309 if( p32
[ MOTIF_WM_HINTS_DECORATIONS_OFF
] &
310 MOTIF_WM_HINTS_DEC_TITLE
)
311 window
->u
.managed
.frame
->u
.frame
.decoration
|=
318 if( window
->u
.managed
.shaped
)
319 /* Never apply borders to shaped windows. */
320 window
->u
.managed
.frame
->u
.frame
.decoration
&= ~DEC_BORDER
;
323 if( window
->u
.managed
.state
== STATE_NORMAL
&&
324 window
->u
.managed
.frame
->u
.frame
.decoration
!= old_decoration
) {
325 int new_decoration
= window
->u
.managed
.frame
->u
.frame
.decoration
;
326 int x
, y
, width
, height
;
329 window
->u
.managed
.frame
->u
.frame
.decoration
= old_decoration
;
331 translate_frame_to_child( window
->u
.managed
.frame
, &x
, &y
,
332 window
->u
.managed
.frame
->u
.frame
.x
,
333 window
->u
.managed
.frame
->u
.frame
.y
,
334 window
->u
.managed
.border_width
,
335 window
->u
.managed
.win_gravity
);
337 window
->u
.managed
.frame
->u
.frame
.decoration
= new_decoration
;
339 translate_child_to_frame( window
->u
.managed
.frame
, &x
, &y
,
340 &width
, &height
, x
, y
,
341 window
->u
.managed
.frame
->u
.frame
.width
-
342 frame_l( window
->u
.managed
.frame
,
344 frame_r( window
->u
.managed
.frame
,
346 window
->u
.managed
.frame
->u
.frame
.height
-
347 frame_t( window
->u
.managed
.frame
,
349 frame_b( window
->u
.managed
.frame
,
351 window
->u
.managed
.border_width
,
352 window
->u
.managed
.win_gravity
);
354 if( new_decoration
& DEC_TITLE
)
356 window
->u
.managed
.frame
->u
.frame
.button
->w
);
359 window
->u
.managed
.frame
->u
.frame
.button
->w
);
361 n
[ 0 ] = frame_l( window
->u
.managed
.frame
, FALSE
);
362 n
[ 1 ] = frame_l( window
->u
.managed
.frame
, FALSE
);
363 xcb_configure_window( c
, window
->w
, XCB_CONFIG_WINDOW_X
|
364 XCB_CONFIG_WINDOW_Y
, n
);
370 n
[ 4 ] = frame_xb( window
->u
.managed
.frame
);
371 /* We'll also notify the client of any changes, in the
372 ConfigureNotify handler for the event we expect to receive in
373 response to this request. */
374 xcb_configure_window( c
, window
->u
.managed
.frame
->w
,
375 XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
|
376 XCB_CONFIG_WINDOW_WIDTH
|
377 XCB_CONFIG_WINDOW_HEIGHT
|
378 XCB_CONFIG_WINDOW_BORDER_WIDTH
, n
);
380 update_frame_extents( window
->u
.managed
.frame
);
385 case PROP__NET_WM_ICON
:
386 /* _NET_WM_ICON property (see EWMH "Application Window Properties". */
387 p32
= xcb_get_property_value( p
);
388 len
= p
->format
== 32 ? p
->value_len
: 0;
391 while( len
> i
+ 2 && len
>= i
+ 2 + p32
[ i
] * p32
[ i
+ 1 ] ) {
392 i
+= p32
[ i
] * p32
[ i
+ 1 ] + 2;
397 int *widths
, *heights
;
400 widths
= alloca( num_icons
* sizeof *widths
);
401 heights
= alloca( num_icons
* sizeof *heights
);
402 icons
= alloca( num_icons
* sizeof *icons
);
405 while( len
> i
+ 2 &&
406 len
>= i
+ 2 + ( widths
[ num_icons
] = p32
[ i
] ) *
407 ( heights
[ num_icons
] = p32
[ i
+ 1 ] ) ) {
408 icons
[ num_icons
] = p32
+ i
+ 2;
409 i
+= widths
[ num_icons
] * heights
[ num_icons
] + 2;
413 replace_icons( window
, num_icons
, widths
, heights
, icons
, NULL
);
415 replace_icons( window
, 0, NULL
, NULL
, NULL
, NULL
);
419 case PROP__NET_WM_NAME
:
420 /* _NET_WM_NAME property (see EWMH "Application Window Properties". */
421 if( window
->u
.managed
.name
)
422 free( window
->u
.managed
.name
);
424 if( p
->value_len
&& p
->format
== 8 ) {
425 window
->u
.managed
.name
= (char *) utf8_dup_valid_len(
426 xcb_get_property_value( p
), p
->value_len
);
427 window
->u
.managed
.net_wm_name
= TRUE
;
429 if( window
->u
.managed
.state
== STATE_NORMAL
&&
430 ( window
->u
.managed
.frame
->u
.frame
.decoration
& DEC_TITLE
) )
431 queue_window_update( window
->u
.managed
.frame
, 0, 0,
432 window
->u
.managed
.frame
->u
.frame
.width
,
433 frame_t( window
->u
.managed
.frame
, FALSE
),
436 window
->u
.managed
.name
= NULL
;
437 window
->u
.managed
.net_wm_name
= FALSE
;
438 /* We've lost the _NET_WM_NAME property. If the window still
439 has a plain WM_NAME, then fall back to that. */
440 async_get_property( window
, PROP_WM_NAME
);
445 case PROP_WM_COLORMAP_WINDOWS
:
446 /* WM_COLORMAP_WINDOWS property (see ICCCM 2.0, section 4.1.8). */
447 window
->u
.managed
.cmap_window
= XCB_NONE
;
449 if( p
->format
== 32 && p
->value_len
>= 2 ) {
450 p32
= xcb_get_property_value( p
);
452 if( p32
[ 0 ] == window
->w
)
453 /* The window itself is given the highest priority, which
454 is what we would do anyway -- ignore the list. */
457 for( i
= 1; i
< p
->value_len
; i
++ )
458 if( p32
[ i
] == window
->w
) {
459 /* The window is explicitly given a lower priority
460 than some other one. Remember whichever is
461 considered more important. */
462 window
->u
.managed
.cmap_window
= p32
[ i
];
471 /* WM_HINTS property (see ICCCM 2.0, section 4.1.2.4). */
472 window
->u
.managed
.hints
&= ~HINT_ICONIC
;
473 window
->u
.managed
.hints
|= HINT_INPUT
;
475 if( p
->format
== 32 ) {
476 xcb_pixmap_t icon
= XCB_NONE
, mask
= XCB_NONE
;
478 p32
= xcb_get_property_value( p
);
480 if( p
->value_len
> WM_HINTS_INPUT_OFF
&&
481 ( p32
[ WM_HINTS_FLAGS_OFF
] & WM_HINTS_INPUT
) &&
482 !p32
[ WM_HINTS_INPUT_OFF
] )
483 window
->u
.managed
.hints
&= ~HINT_INPUT
;
485 if( p
->value_len
> WM_HINTS_STATE_OFF
&&
486 ( p32
[ WM_HINTS_FLAGS_OFF
] & WM_HINTS_STATE
) &&
487 p32
[ WM_HINTS_STATE_OFF
] == WM_HINTS_STATE_ICONIC
)
488 window
->u
.managed
.hints
|= HINT_ICONIC
;
490 if( p
->value_len
> WM_HINTS_ICON_OFF
&&
491 ( p32
[ WM_HINTS_FLAGS_OFF
] & WM_HINTS_ICON
) )
492 icon
= p32
[ WM_HINTS_ICON_OFF
];
494 if( p
->value_len
> WM_HINTS_MASK_OFF
&&
495 ( p32
[ WM_HINTS_FLAGS_OFF
] & WM_HINTS_ICON_MASK
) )
496 mask
= p32
[ WM_HINTS_MASK_OFF
];
499 struct managed_get_geometry
*p
= xmalloc( sizeof *p
);
500 union callback_param cp
;
506 handle_async_reply( xcb_get_geometry( c
, icon
).sequence
,
507 handle_get_geometry
, cp
);
509 replace_icons( window
, 0, NULL
, NULL
, NULL
, &icon
);
515 /* WM_NAME property (see ICCCM 2.0, section 4.1.2.1). */
516 if( window
->u
.managed
.net_wm_name
)
517 /* Ignore WM_NAME if _NET_WM_NAME is set. */
520 if( window
->u
.managed
.name
)
521 free( window
->u
.managed
.name
);
523 if( p
->value_len
&& p
->format
== 8 )
524 window
->u
.managed
.name
= to_utf8(
525 p
->type
== atoms
[ ATOM_COMPOUND_TEXT
] ? ENCODING_COMPOUND
:
526 ENCODING_LATIN_1
, xcb_get_property_value( p
), p
->value_len
);
528 window
->u
.managed
.name
= NULL
;
530 if( window
->u
.managed
.state
== STATE_NORMAL
&&
531 ( window
->u
.managed
.frame
->u
.frame
.decoration
& DEC_TITLE
) )
532 queue_window_update( window
->u
.managed
.frame
, 0, 0,
533 window
->u
.managed
.frame
->u
.frame
.width
,
534 frame_t( window
->u
.managed
.frame
, FALSE
),
539 case PROP_WM_NORMAL_HINTS
:
540 /* WM_NORMAL_HINTS property (see ICCCM 2.0, section 4.1.2.3). */
541 window
->u
.managed
.hints
&= ~HINT_POSITION
;
542 window
->u
.managed
.min_width
= frame_t( window
->u
.managed
.frame
,
544 window
->u
.managed
.min_height
= frame_t( window
->u
.managed
.frame
,
546 window
->u
.managed
.max_width
= 0x7FFF;
547 window
->u
.managed
.max_height
= 0x7FFF;
548 window
->u
.managed
.width_inc
= 1;
549 window
->u
.managed
.height_inc
= 1;
550 window
->u
.managed
.min_aspect_x
= 0;
551 window
->u
.managed
.min_aspect_y
= 1;
552 window
->u
.managed
.max_aspect_x
= 1;
553 window
->u
.managed
.max_aspect_y
= 0;
554 window
->u
.managed
.base_width
= 0;
555 window
->u
.managed
.base_height
= 0;
556 window
->u
.managed
.win_gravity
= XCB_GRAVITY_NORTH_WEST
;
558 if( p
->value_len
< 1 || p
->format
!= 32 ) {
563 p32
= xcb_get_property_value( p
);
564 value_len
= p
->value_len
;
567 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_USER_POSITION
)
568 window
->u
.managed
.hints
|= HINT_USER_POSITION
;
569 else if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] &
570 WM_NORMAL_HINTS_PROGRAM_POSITION
)
571 window
->u
.managed
.hints
|= HINT_PROGRAM_POSITION
;
573 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_MIN_SIZE
&&
574 value_len
>= WM_NORMAL_HINTS_MIN_SIZE_OFF
+ 1 ) {
575 window
->u
.managed
.min_width
= p32
[ WM_NORMAL_HINTS_MIN_SIZE_OFF
];
576 window
->u
.managed
.min_height
=
577 p32
[ WM_NORMAL_HINTS_MIN_SIZE_OFF
+ 1 ];
580 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_MAX_SIZE
&&
581 value_len
>= WM_NORMAL_HINTS_MAX_SIZE_OFF
+ 1 ) {
582 window
->u
.managed
.max_width
= p32
[ WM_NORMAL_HINTS_MAX_SIZE_OFF
];
583 window
->u
.managed
.max_height
=
584 p32
[ WM_NORMAL_HINTS_MAX_SIZE_OFF
+ 1 ];
587 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_SIZE_INC
&&
588 value_len
>= WM_NORMAL_HINTS_SIZE_INC_OFF
+ 1 ) {
589 window
->u
.managed
.width_inc
= p32
[ WM_NORMAL_HINTS_SIZE_INC_OFF
];
590 window
->u
.managed
.height_inc
=
591 p32
[ WM_NORMAL_HINTS_SIZE_INC_OFF
+ 1 ];
594 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_ASPECT
&&
595 value_len
>= WM_NORMAL_HINTS_ASPECT_OFF
+ 3 ) {
596 window
->u
.managed
.min_aspect_x
= p32
[ WM_NORMAL_HINTS_ASPECT_OFF
];
597 window
->u
.managed
.min_aspect_y
=
598 p32
[ WM_NORMAL_HINTS_ASPECT_OFF
+ 1 ];
599 window
->u
.managed
.max_aspect_x
=
600 p32
[ WM_NORMAL_HINTS_ASPECT_OFF
+ 2 ];
601 window
->u
.managed
.max_aspect_y
=
602 p32
[ WM_NORMAL_HINTS_ASPECT_OFF
+ 3 ];
605 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_BASE_SIZE
&&
606 value_len
>= WM_NORMAL_HINTS_BASE_SIZE_OFF
+ 1 ) {
607 window
->u
.managed
.base_width
=
608 p32
[ WM_NORMAL_HINTS_BASE_SIZE_OFF
];
609 window
->u
.managed
.base_height
=
610 p32
[ WM_NORMAL_HINTS_BASE_SIZE_OFF
+ 1 ];
612 if( !( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] &
613 WM_NORMAL_HINTS_MIN_SIZE
) ) {
614 window
->u
.managed
.min_width
= window
->u
.managed
.base_width
;
615 window
->u
.managed
.min_width
= window
->u
.managed
.base_width
;
619 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_WIN_GRAVITY
&&
620 value_len
>= WM_NORMAL_HINTS_WIN_GRAVITY_OFF
)
621 window
->u
.managed
.win_gravity
=
622 p32
[ WM_NORMAL_HINTS_WIN_GRAVITY_OFF
];
625 screen
= screens
[ window
->screen
];
627 if( window
->u
.managed
.min_width
< frame_t( window
->u
.managed
.frame
,
629 window
->u
.managed
.min_width
= frame_t( window
->u
.managed
.frame
,
631 if( window
->u
.managed
.min_width
> screen
->width_in_pixels
)
632 window
->u
.managed
.min_width
= screen
->width_in_pixels
;
634 if( window
->u
.managed
.min_height
< frame_t( window
->u
.managed
.frame
,
636 window
->u
.managed
.min_height
= frame_t( window
->u
.managed
.frame
,
638 if( window
->u
.managed
.min_height
> screen
->height_in_pixels
)
639 window
->u
.managed
.min_height
= screen
->height_in_pixels
;
641 if( window
->u
.managed
.max_width
< window
->u
.managed
.min_width
)
642 window
->u
.managed
.max_width
= window
->u
.managed
.min_width
;
643 if( window
->u
.managed
.max_width
> 0x7FFF )
644 window
->u
.managed
.max_width
= 0x7FFF;
646 if( window
->u
.managed
.max_height
< window
->u
.managed
.min_height
)
647 window
->u
.managed
.max_height
= window
->u
.managed
.min_height
;
648 if( window
->u
.managed
.max_height
> 0x7FFF )
649 window
->u
.managed
.max_height
= 0x7FFF;
651 if( window
->u
.managed
.min_aspect_x
< 0 ||
652 window
->u
.managed
.min_aspect_y
< 1 ||
653 window
->u
.managed
.max_aspect_x
< 1 ||
654 window
->u
.managed
.max_aspect_x
< 0 ||
655 window
->u
.managed
.min_aspect_x
* window
->u
.managed
.max_aspect_y
>
656 window
->u
.managed
.min_aspect_y
* window
->u
.managed
.max_aspect_x
) {
657 window
->u
.managed
.min_aspect_x
= 0;
658 window
->u
.managed
.min_aspect_y
= 1;
659 window
->u
.managed
.max_aspect_x
= 1;
660 window
->u
.managed
.max_aspect_y
= 0;
663 if( window
->u
.managed
.base_width
< 0 ||
664 window
->u
.managed
.base_width
> window
->u
.managed
.min_width
||
665 window
->u
.managed
.base_height
< 0 ||
666 window
->u
.managed
.base_height
> window
->u
.managed
.min_height
) {
667 window
->u
.managed
.base_width
= 0;
668 window
->u
.managed
.base_height
= 0;
671 if( window
->u
.managed
.win_gravity
< XCB_GRAVITY_NORTH_WEST
||
672 window
->u
.managed
.win_gravity
> XCB_GRAVITY_STATIC
)
673 window
->u
.managed
.win_gravity
= XCB_GRAVITY_NORTH_WEST
;
675 if( window
->u
.managed
.state
== STATE_NORMAL
) {
676 /* Recalculate constraints. */
677 int width
= window
->u
.managed
.frame
->u
.frame
.width
-
678 frame_l( window
->u
.managed
.frame
, FALSE
) -
679 frame_r( window
->u
.managed
.frame
, FALSE
);
680 int height
= window
->u
.managed
.frame
->u
.frame
.height
-
681 frame_t( window
->u
.managed
.frame
, FALSE
) -
682 frame_b( window
->u
.managed
.frame
, FALSE
);
683 int old_width
, old_height
;
688 apply_size_constraints( window
, &width
, &height
);
690 if( width
!= old_width
|| height
!= old_height
) {
691 xcb_configure_request_event_t ev
;
693 ev
.response_type
= XCB_CONFIGURE_REQUEST
;
694 ev
.parent
= window
->u
.managed
.frame
->w
;
695 ev
.window
= window
->w
;
698 ev
.value_mask
= XCB_CONFIG_WINDOW_WIDTH
|
699 XCB_CONFIG_WINDOW_HEIGHT
;
701 frame_handlers
[ XCB_CONFIGURE_REQUEST
](
702 window
->u
.managed
.frame
, (xcb_generic_event_t
*) &ev
);
708 case PROP_WM_PROTOCOLS
:
709 /* WM_PROTOCOLS property (see ICCCM 2.0, section 4.1.2.7). */
710 /* FIXME Look for _NET_WM_SYNC_REQUEST. */
711 window
->u
.managed
.protocols
= 0;
713 if( p
->format
== 32 ) {
714 p32
= xcb_get_property_value( p
);
716 for( i
= 0; i
< p
->value_len
; i
++ )
717 if( p32
[ i
] == atoms
[ ATOM_WM_DELETE_WINDOW
] )
718 window
->u
.managed
.protocols
|= PROTOCOL_DELETE_WINDOW
;
719 else if( p32
[ i
] == atoms
[ ATOM_WM_TAKE_FOCUS
] )
720 window
->u
.managed
.protocols
|= PROTOCOL_TAKE_FOCUS
;
723 if( window
->u
.managed
.state
== STATE_NORMAL
) {
724 uint32_t n
= window
->u
.managed
.protocols
& PROTOCOL_DELETE_WINDOW
?
725 XCB_NONE
: cursors
[ CURSOR_DESTROY
];
726 xcb_change_window_attributes( c
, window
->u
.managed
.frame
->
727 u
.frame
.button
->w
, XCB_CW_CURSOR
,
735 static void managed_property_notify( struct gwm_window
*window
,
736 xcb_property_notify_event_t
*ev
) {
738 enum gwm_property_type i
;
740 for( i
= 0; i
< NUM_PROPS
; i
++ )
741 if( ev
->atom
== prop_atoms
[ i
] ) {
742 async_get_property( window
, i
);
747 static void managed_colormap_notify( struct gwm_window
*window
,
748 xcb_colormap_notify_event_t
*ev
) {
751 window
->u
.managed
.cmap
= ev
->colormap
;
753 if( window
->u
.managed
.frame
== focus_frame
)
754 /* Gah... the protocol doesn't specify a timestamp on
755 ColormapNotify events. We'll have to make do with the
756 most recent timestamp we've received instead. */
757 install_window_colormap( window
->screen
, window
, latest_timestamp
);
762 extern void match_managed_shape( struct gwm_window
*window
) {
764 if( window
->u
.managed
.shaped
) {
765 xcb_rectangle_t rect
;
768 rect
.width
= window
->u
.managed
.frame
->u
.frame
.width
;
769 rect
.height
= frame_t( window
->u
.managed
.frame
, FALSE
);
770 xcb_shape_rectangles( c
, XCB_SHAPE_SO_SET
, XCB_SHAPE_SK_BOUNDING
, 0,
771 window
->u
.managed
.frame
->w
, 0, 0, 1, &rect
);
773 xcb_shape_combine( c
, XCB_SHAPE_SO_UNION
, XCB_SHAPE_SK_BOUNDING
,
774 XCB_SHAPE_SK_BOUNDING
, window
->u
.managed
.frame
->w
,
775 frame_l( window
->u
.managed
.frame
, FALSE
),
776 frame_t( window
->u
.managed
.frame
, FALSE
),
779 xcb_shape_mask( c
, XCB_SHAPE_SO_SET
, XCB_SHAPE_SK_BOUNDING
,
780 window
->u
.managed
.frame
->w
, 0, 0, XCB_NONE
);
783 static void managed_shape_notify( struct gwm_window
*window
,
784 xcb_shape_notify_event_t
*ev
) {
786 if( ev
->shape_kind
== XCB_SHAPE_SK_BOUNDING
) {
787 if( window
->u
.managed
.shaped
!= ev
->shaped
&&
788 !( window
->u
.managed
.shaped
= ev
->shaped
) )
789 /* The client is no longer shaped. Retrieve its original
790 _MOTIF_WM_HINTS, since we might now want to apply a border. */
791 async_get_property( window
, PROP__MOTIF_WM_HINTS
);
793 match_managed_shape( window
);
798 const event_handler managed_handlers
[] = {
802 NULL
, /* KeyRelease */
803 NULL
, /* ButtonPress */
804 NULL
, /* ButtonRelease */
805 NULL
, /* MotionNotify */
806 NULL
, /* EnterNotify */
807 NULL
, /* LeaveNotify */
810 NULL
, /* KeymapNotify */
812 NULL
, /* GraphicsExpose */
813 NULL
, /* NoExposure */
814 NULL
, /* VisibilityNotify */
815 NULL
, /* CreateNotify */
816 (event_handler
) managed_destroy_notify
,
817 (event_handler
) managed_unmap_notify
,
818 NULL
, /* MapNotify */
819 NULL
, /* MapRequest */
820 (event_handler
) managed_reparent_notify
,
821 NULL
, /* ConfigureNotify */
822 NULL
, /* ConfigureRequest */
823 NULL
, /* GravityNotify */
824 NULL
, /* ResizeRequest */
825 NULL
, /* CirculateNotify */
826 NULL
, /* CirculateRequest */
827 (event_handler
) managed_property_notify
,
828 NULL
, /* SelectionClear */
829 NULL
, /* SelectionRequest */
830 NULL
, /* SelectionNotify */
831 (event_handler
) managed_colormap_notify
,
832 NULL
, /* ClientMessage */
833 NULL
, /* MappingNotify */
834 NULL
, /* (synthetic) */
836 (event_handler
) managed_shape_notify
838 NULL
/* ShapeNotify */
842 extern void withdrawn_map_request( struct gwm_window
*window
,
843 xcb_map_request_event_t
*ev
) {
845 manage_window( ev
->window
, TRUE
);
848 extern void withdrawn_configure_request( struct gwm_window
*window
,
849 xcb_configure_request_event_t
*ev
) {
852 uint32_t values
[ 7 ];
854 /* Configuring an unmanaged window -- just honour the request as is. */
855 if( ev
->value_mask
& XCB_CONFIG_WINDOW_X
)
856 values
[ i
++ ] = ev
->x
;
857 if( ev
->value_mask
& XCB_CONFIG_WINDOW_Y
)
858 values
[ i
++ ] = ev
->y
;
859 if( ev
->value_mask
& XCB_CONFIG_WINDOW_WIDTH
)
860 values
[ i
++ ] = ev
->width
;
861 if( ev
->value_mask
& XCB_CONFIG_WINDOW_HEIGHT
)
862 values
[ i
++ ] = ev
->height
;
863 if( ev
->value_mask
& XCB_CONFIG_WINDOW_BORDER_WIDTH
)
864 values
[ i
++ ] = ev
->border_width
;
865 if( ev
->value_mask
& XCB_CONFIG_WINDOW_SIBLING
)
866 values
[ i
++ ] = ev
->sibling
;
867 if( ev
->value_mask
& XCB_CONFIG_WINDOW_STACK_MODE
)
868 values
[ i
++ ] = ev
->stack_mode
;
870 xcb_configure_window( c
, ev
->window
, ev
->value_mask
, values
);