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
);
383 case PROP__NET_WM_ICON
:
384 /* _NET_WM_ICON property (see EWMH "Application Window Properties". */
385 p32
= xcb_get_property_value( p
);
386 len
= p
->format
== 32 ? p
->value_len
: 0;
389 while( len
> i
+ 2 && len
>= i
+ 2 + p32
[ i
] * p32
[ i
+ 1 ] ) {
390 i
+= p32
[ i
] * p32
[ i
+ 1 ] + 2;
395 int *widths
, *heights
;
398 widths
= alloca( num_icons
* sizeof *widths
);
399 heights
= alloca( num_icons
* sizeof *heights
);
400 icons
= alloca( num_icons
* sizeof *icons
);
403 while( len
> i
+ 2 &&
404 len
>= i
+ 2 + ( widths
[ num_icons
] = p32
[ i
] ) *
405 ( heights
[ num_icons
] = p32
[ i
+ 1 ] ) ) {
406 icons
[ num_icons
] = p32
+ i
+ 2;
407 i
+= widths
[ num_icons
] * heights
[ num_icons
] + 2;
411 replace_icons( window
, num_icons
, widths
, heights
, icons
, NULL
);
413 replace_icons( window
, 0, NULL
, NULL
, NULL
, NULL
);
417 case PROP__NET_WM_NAME
:
418 /* _NET_WM_NAME property (see EWMH "Application Window Properties". */
419 if( window
->u
.managed
.name
)
420 free( window
->u
.managed
.name
);
422 if( p
->value_len
&& p
->format
== 8 ) {
423 window
->u
.managed
.name
= (char *) utf8_dup_valid_len(
424 xcb_get_property_value( p
), p
->value_len
);
425 window
->u
.managed
.net_wm_name
= TRUE
;
427 if( window
->u
.managed
.state
== STATE_NORMAL
&&
428 ( window
->u
.managed
.frame
->u
.frame
.decoration
& DEC_TITLE
) )
429 queue_window_update( window
->u
.managed
.frame
, 0, 0,
430 window
->u
.managed
.frame
->u
.frame
.width
,
431 frame_t( window
->u
.managed
.frame
, FALSE
),
434 window
->u
.managed
.name
= NULL
;
435 window
->u
.managed
.net_wm_name
= FALSE
;
436 /* We've lost the _NET_WM_NAME property. If the window still
437 has a plain WM_NAME, then fall back to that. */
438 async_get_property( window
, PROP_WM_NAME
);
443 case PROP_WM_COLORMAP_WINDOWS
:
444 /* WM_COLORMAP_WINDOWS property (see ICCCM 2.0, section 4.1.8). */
445 window
->u
.managed
.cmap_window
= XCB_NONE
;
447 if( p
->format
== 32 && p
->value_len
>= 2 ) {
448 p32
= xcb_get_property_value( p
);
450 if( p32
[ 0 ] == window
->w
)
451 /* The window itself is given the highest priority, which
452 is what we would do anyway -- ignore the list. */
455 for( i
= 1; i
< p
->value_len
; i
++ )
456 if( p32
[ i
] == window
->w
) {
457 /* The window is explicitly given a lower priority
458 than some other one. Remember whichever is
459 considered more important. */
460 window
->u
.managed
.cmap_window
= p32
[ i
];
469 /* WM_HINTS property (see ICCCM 2.0, section 4.1.2.4). */
470 window
->u
.managed
.hints
&= ~HINT_ICONIC
;
471 window
->u
.managed
.hints
|= HINT_INPUT
;
473 if( p
->format
== 32 ) {
474 xcb_pixmap_t icon
= XCB_NONE
, mask
= XCB_NONE
;
476 p32
= xcb_get_property_value( p
);
478 if( p
->value_len
> WM_HINTS_INPUT_OFF
&&
479 ( p32
[ WM_HINTS_FLAGS_OFF
] & WM_HINTS_INPUT
) &&
480 !p32
[ WM_HINTS_INPUT_OFF
] )
481 window
->u
.managed
.hints
&= ~HINT_INPUT
;
483 if( p
->value_len
> WM_HINTS_STATE_OFF
&&
484 ( p32
[ WM_HINTS_FLAGS_OFF
] & WM_HINTS_STATE
) &&
485 p32
[ WM_HINTS_STATE_OFF
] == WM_HINTS_STATE_ICONIC
)
486 window
->u
.managed
.hints
|= HINT_ICONIC
;
488 if( p
->value_len
> WM_HINTS_ICON_OFF
&&
489 ( p32
[ WM_HINTS_FLAGS_OFF
] & WM_HINTS_ICON
) )
490 icon
= p32
[ WM_HINTS_ICON_OFF
];
492 if( p
->value_len
> WM_HINTS_MASK_OFF
&&
493 ( p32
[ WM_HINTS_FLAGS_OFF
] & WM_HINTS_ICON_MASK
) )
494 mask
= p32
[ WM_HINTS_MASK_OFF
];
497 struct managed_get_geometry
*p
= xmalloc( sizeof *p
);
498 union callback_param cp
;
504 handle_async_reply( xcb_get_geometry( c
, icon
).sequence
,
505 handle_get_geometry
, cp
);
507 replace_icons( window
, 0, NULL
, NULL
, NULL
, &icon
);
513 /* WM_NAME property (see ICCCM 2.0, section 4.1.2.1). */
514 if( window
->u
.managed
.net_wm_name
)
515 /* Ignore WM_NAME if _NET_WM_NAME is set. */
518 if( window
->u
.managed
.name
)
519 free( window
->u
.managed
.name
);
521 if( p
->value_len
&& p
->format
== 8 )
522 window
->u
.managed
.name
= to_utf8(
523 p
->type
== atoms
[ ATOM_COMPOUND_TEXT
] ? ENCODING_COMPOUND
:
524 ENCODING_LATIN_1
, xcb_get_property_value( p
), p
->value_len
);
526 window
->u
.managed
.name
= NULL
;
528 if( window
->u
.managed
.state
== STATE_NORMAL
&&
529 ( window
->u
.managed
.frame
->u
.frame
.decoration
& DEC_TITLE
) )
530 queue_window_update( window
->u
.managed
.frame
, 0, 0,
531 window
->u
.managed
.frame
->u
.frame
.width
,
532 frame_t( window
->u
.managed
.frame
, FALSE
),
537 case PROP_WM_NORMAL_HINTS
:
538 /* WM_NORMAL_HINTS property (see ICCCM 2.0, section 4.1.2.3). */
539 window
->u
.managed
.hints
&= ~HINT_POSITION
;
540 window
->u
.managed
.min_width
= frame_t( window
->u
.managed
.frame
,
542 window
->u
.managed
.min_height
= frame_t( window
->u
.managed
.frame
,
544 window
->u
.managed
.max_width
= 0x7FFF;
545 window
->u
.managed
.max_height
= 0x7FFF;
546 window
->u
.managed
.width_inc
= 1;
547 window
->u
.managed
.height_inc
= 1;
548 window
->u
.managed
.min_aspect_x
= 0;
549 window
->u
.managed
.min_aspect_y
= 1;
550 window
->u
.managed
.max_aspect_x
= 1;
551 window
->u
.managed
.max_aspect_y
= 0;
552 window
->u
.managed
.base_width
= 0;
553 window
->u
.managed
.base_height
= 0;
554 window
->u
.managed
.win_gravity
= XCB_GRAVITY_NORTH_WEST
;
556 if( p
->value_len
< 1 || p
->format
!= 32 ) {
561 p32
= xcb_get_property_value( p
);
562 value_len
= p
->value_len
;
565 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_USER_POSITION
)
566 window
->u
.managed
.hints
|= HINT_USER_POSITION
;
567 else if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] &
568 WM_NORMAL_HINTS_PROGRAM_POSITION
)
569 window
->u
.managed
.hints
|= HINT_PROGRAM_POSITION
;
571 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_MIN_SIZE
&&
572 value_len
>= WM_NORMAL_HINTS_MIN_SIZE_OFF
+ 1 ) {
573 window
->u
.managed
.min_width
= p32
[ WM_NORMAL_HINTS_MIN_SIZE_OFF
];
574 window
->u
.managed
.min_height
=
575 p32
[ WM_NORMAL_HINTS_MIN_SIZE_OFF
+ 1 ];
578 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_MAX_SIZE
&&
579 value_len
>= WM_NORMAL_HINTS_MAX_SIZE_OFF
+ 1 ) {
580 window
->u
.managed
.max_width
= p32
[ WM_NORMAL_HINTS_MAX_SIZE_OFF
];
581 window
->u
.managed
.max_height
=
582 p32
[ WM_NORMAL_HINTS_MAX_SIZE_OFF
+ 1 ];
585 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_SIZE_INC
&&
586 value_len
>= WM_NORMAL_HINTS_SIZE_INC_OFF
+ 1 ) {
587 window
->u
.managed
.width_inc
= p32
[ WM_NORMAL_HINTS_SIZE_INC_OFF
];
588 window
->u
.managed
.height_inc
=
589 p32
[ WM_NORMAL_HINTS_SIZE_INC_OFF
+ 1 ];
592 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_ASPECT
&&
593 value_len
>= WM_NORMAL_HINTS_ASPECT_OFF
+ 3 ) {
594 window
->u
.managed
.min_aspect_x
= p32
[ WM_NORMAL_HINTS_ASPECT_OFF
];
595 window
->u
.managed
.min_aspect_y
=
596 p32
[ WM_NORMAL_HINTS_ASPECT_OFF
+ 1 ];
597 window
->u
.managed
.max_aspect_x
=
598 p32
[ WM_NORMAL_HINTS_ASPECT_OFF
+ 2 ];
599 window
->u
.managed
.max_aspect_y
=
600 p32
[ WM_NORMAL_HINTS_ASPECT_OFF
+ 3 ];
603 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_BASE_SIZE
&&
604 value_len
>= WM_NORMAL_HINTS_BASE_SIZE_OFF
+ 1 ) {
605 window
->u
.managed
.base_width
=
606 p32
[ WM_NORMAL_HINTS_BASE_SIZE_OFF
];
607 window
->u
.managed
.base_height
=
608 p32
[ WM_NORMAL_HINTS_BASE_SIZE_OFF
+ 1 ];
610 if( !( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] &
611 WM_NORMAL_HINTS_MIN_SIZE
) ) {
612 window
->u
.managed
.min_width
= window
->u
.managed
.base_width
;
613 window
->u
.managed
.min_width
= window
->u
.managed
.base_width
;
617 if( p32
[ WM_NORMAL_HINTS_FLAGS_OFF
] & WM_NORMAL_HINTS_WIN_GRAVITY
&&
618 value_len
>= WM_NORMAL_HINTS_WIN_GRAVITY_OFF
)
619 window
->u
.managed
.win_gravity
=
620 p32
[ WM_NORMAL_HINTS_WIN_GRAVITY_OFF
];
623 screen
= screens
[ window
->screen
];
625 if( window
->u
.managed
.min_width
< frame_t( window
->u
.managed
.frame
,
627 window
->u
.managed
.min_width
= frame_t( window
->u
.managed
.frame
,
629 if( window
->u
.managed
.min_width
> screen
->width_in_pixels
)
630 window
->u
.managed
.min_width
= screen
->width_in_pixels
;
632 if( window
->u
.managed
.min_height
< frame_t( window
->u
.managed
.frame
,
634 window
->u
.managed
.min_height
= frame_t( window
->u
.managed
.frame
,
636 if( window
->u
.managed
.min_height
> screen
->height_in_pixels
)
637 window
->u
.managed
.min_height
= screen
->height_in_pixels
;
639 if( window
->u
.managed
.max_width
< window
->u
.managed
.min_width
)
640 window
->u
.managed
.max_width
= window
->u
.managed
.min_width
;
641 if( window
->u
.managed
.max_width
> 0x7FFF )
642 window
->u
.managed
.max_width
= 0x7FFF;
644 if( window
->u
.managed
.max_height
< window
->u
.managed
.min_height
)
645 window
->u
.managed
.max_height
= window
->u
.managed
.min_height
;
646 if( window
->u
.managed
.max_height
> 0x7FFF )
647 window
->u
.managed
.max_height
= 0x7FFF;
649 if( window
->u
.managed
.min_aspect_x
< 0 ||
650 window
->u
.managed
.min_aspect_y
< 1 ||
651 window
->u
.managed
.max_aspect_x
< 1 ||
652 window
->u
.managed
.max_aspect_x
< 0 ||
653 window
->u
.managed
.min_aspect_x
* window
->u
.managed
.max_aspect_y
>
654 window
->u
.managed
.min_aspect_y
* window
->u
.managed
.max_aspect_x
) {
655 window
->u
.managed
.min_aspect_x
= 0;
656 window
->u
.managed
.min_aspect_y
= 1;
657 window
->u
.managed
.max_aspect_x
= 1;
658 window
->u
.managed
.max_aspect_y
= 0;
661 if( window
->u
.managed
.base_width
< 0 ||
662 window
->u
.managed
.base_width
> window
->u
.managed
.min_width
||
663 window
->u
.managed
.base_height
< 0 ||
664 window
->u
.managed
.base_height
> window
->u
.managed
.min_height
) {
665 window
->u
.managed
.base_width
= 0;
666 window
->u
.managed
.base_height
= 0;
669 if( window
->u
.managed
.win_gravity
< XCB_GRAVITY_NORTH_WEST
||
670 window
->u
.managed
.win_gravity
> XCB_GRAVITY_STATIC
)
671 window
->u
.managed
.win_gravity
= XCB_GRAVITY_NORTH_WEST
;
673 if( window
->u
.managed
.state
== STATE_NORMAL
) {
674 /* Recalculate constraints. */
675 int width
= window
->u
.managed
.frame
->u
.frame
.width
-
676 frame_l( window
->u
.managed
.frame
, FALSE
) -
677 frame_r( window
->u
.managed
.frame
, FALSE
);
678 int height
= window
->u
.managed
.frame
->u
.frame
.height
-
679 frame_t( window
->u
.managed
.frame
, FALSE
) -
680 frame_b( window
->u
.managed
.frame
, FALSE
);
681 int old_width
, old_height
;
686 apply_size_constraints( window
, &width
, &height
);
688 if( width
!= old_width
|| height
!= old_height
) {
689 xcb_configure_request_event_t ev
;
691 ev
.response_type
= XCB_CONFIGURE_REQUEST
;
692 ev
.parent
= window
->u
.managed
.frame
->w
;
693 ev
.window
= window
->w
;
696 ev
.value_mask
= XCB_CONFIG_WINDOW_WIDTH
|
697 XCB_CONFIG_WINDOW_HEIGHT
;
699 frame_handlers
[ XCB_CONFIGURE_REQUEST
](
700 window
->u
.managed
.frame
, (xcb_generic_event_t
*) &ev
);
706 case PROP_WM_PROTOCOLS
:
707 /* WM_PROTOCOLS property (see ICCCM 2.0, section 4.1.2.7). */
708 /* FIXME Look for _NET_WM_SYNC_REQUEST. */
709 window
->u
.managed
.protocols
= 0;
711 if( p
->format
== 32 ) {
712 p32
= xcb_get_property_value( p
);
714 for( i
= 0; i
< p
->value_len
; i
++ )
715 if( p32
[ i
] == atoms
[ ATOM_WM_DELETE_WINDOW
] )
716 window
->u
.managed
.protocols
|= PROTOCOL_DELETE_WINDOW
;
717 else if( p32
[ i
] == atoms
[ ATOM_WM_TAKE_FOCUS
] )
718 window
->u
.managed
.protocols
|= PROTOCOL_TAKE_FOCUS
;
721 if( window
->u
.managed
.state
== STATE_NORMAL
) {
722 uint32_t n
= window
->u
.managed
.protocols
& PROTOCOL_DELETE_WINDOW
?
723 XCB_NONE
: cursors
[ CURSOR_DESTROY
];
724 xcb_change_window_attributes( c
, window
->u
.managed
.frame
->
725 u
.frame
.button
->w
, XCB_CW_CURSOR
,
733 static void managed_property_notify( struct gwm_window
*window
,
734 xcb_property_notify_event_t
*ev
) {
736 enum gwm_property_type i
;
738 for( i
= 0; i
< NUM_PROPS
; i
++ )
739 if( ev
->atom
== prop_atoms
[ i
] ) {
740 async_get_property( window
, i
);
745 static void managed_colormap_notify( struct gwm_window
*window
,
746 xcb_colormap_notify_event_t
*ev
) {
749 window
->u
.managed
.cmap
= ev
->colormap
;
751 if( window
->u
.managed
.frame
== focus_frame
)
752 /* Gah... the protocol doesn't specify a timestamp on
753 ColormapNotify events. We'll have to make do with the
754 most recent timestamp we've received instead. */
755 install_window_colormap( window
->screen
, window
, latest_timestamp
);
760 extern void match_managed_shape( struct gwm_window
*window
) {
762 if( window
->u
.managed
.shaped
) {
763 xcb_rectangle_t rect
;
766 rect
.width
= window
->u
.managed
.frame
->u
.frame
.width
;
767 rect
.height
= frame_t( window
->u
.managed
.frame
, FALSE
);
768 xcb_shape_rectangles( c
, XCB_SHAPE_SO_SET
, XCB_SHAPE_SK_BOUNDING
, 0,
769 window
->u
.managed
.frame
->w
, 0, 0, 1, &rect
);
771 xcb_shape_combine( c
, XCB_SHAPE_SO_UNION
, XCB_SHAPE_SK_BOUNDING
,
772 XCB_SHAPE_SK_BOUNDING
, window
->u
.managed
.frame
->w
,
773 frame_l( window
->u
.managed
.frame
, FALSE
),
774 frame_t( window
->u
.managed
.frame
, FALSE
),
777 xcb_shape_mask( c
, XCB_SHAPE_SO_SET
, XCB_SHAPE_SK_BOUNDING
,
778 window
->u
.managed
.frame
->w
, 0, 0, XCB_NONE
);
781 static void managed_shape_notify( struct gwm_window
*window
,
782 xcb_shape_notify_event_t
*ev
) {
784 if( ev
->shape_kind
== XCB_SHAPE_SK_BOUNDING
) {
785 if( window
->u
.managed
.shaped
!= ev
->shaped
&&
786 !( window
->u
.managed
.shaped
= ev
->shaped
) )
787 /* The client is no longer shaped. Retrieve its original
788 _MOTIF_WM_HINTS, since we might now want to apply a border. */
789 async_get_property( window
, PROP__MOTIF_WM_HINTS
);
791 match_managed_shape( window
);
796 const event_handler managed_handlers
[] = {
800 NULL
, /* KeyRelease */
801 NULL
, /* ButtonPress */
802 NULL
, /* ButtonRelease */
803 NULL
, /* MotionNotify */
804 NULL
, /* EnterNotify */
805 NULL
, /* LeaveNotify */
808 NULL
, /* KeymapNotify */
810 NULL
, /* GraphicsExpose */
811 NULL
, /* NoExposure */
812 NULL
, /* VisibilityNotify */
813 NULL
, /* CreateNotify */
814 (event_handler
) managed_destroy_notify
,
815 (event_handler
) managed_unmap_notify
,
816 NULL
, /* MapNotify */
817 NULL
, /* MapRequest */
818 (event_handler
) managed_reparent_notify
,
819 NULL
, /* ConfigureNotify */
820 NULL
, /* ConfigureRequest */
821 NULL
, /* GravityNotify */
822 NULL
, /* ResizeRequest */
823 NULL
, /* CirculateNotify */
824 NULL
, /* CirculateRequest */
825 (event_handler
) managed_property_notify
,
826 NULL
, /* SelectionClear */
827 NULL
, /* SelectionRequest */
828 NULL
, /* SelectionNotify */
829 (event_handler
) managed_colormap_notify
,
830 NULL
, /* ClientMessage */
831 NULL
, /* MappingNotify */
832 NULL
, /* (synthetic) */
834 (event_handler
) managed_shape_notify
836 NULL
/* ShapeNotify */
840 extern void withdrawn_map_request( struct gwm_window
*window
,
841 xcb_map_request_event_t
*ev
) {
843 manage_window( ev
->window
, TRUE
);
846 extern void withdrawn_configure_request( struct gwm_window
*window
,
847 xcb_configure_request_event_t
*ev
) {
850 uint32_t values
[ 7 ];
852 /* Configuring an unmanaged window -- just honour the request as is. */
853 if( ev
->value_mask
& XCB_CONFIG_WINDOW_X
)
854 values
[ i
++ ] = ev
->x
;
855 if( ev
->value_mask
& XCB_CONFIG_WINDOW_Y
)
856 values
[ i
++ ] = ev
->y
;
857 if( ev
->value_mask
& XCB_CONFIG_WINDOW_WIDTH
)
858 values
[ i
++ ] = ev
->width
;
859 if( ev
->value_mask
& XCB_CONFIG_WINDOW_HEIGHT
)
860 values
[ i
++ ] = ev
->height
;
861 if( ev
->value_mask
& XCB_CONFIG_WINDOW_BORDER_WIDTH
)
862 values
[ i
++ ] = ev
->border_width
;
863 if( ev
->value_mask
& XCB_CONFIG_WINDOW_SIBLING
)
864 values
[ i
++ ] = ev
->sibling
;
865 if( ev
->value_mask
& XCB_CONFIG_WINDOW_STACK_MODE
)
866 values
[ i
++ ] = ev
->stack_mode
;
868 xcb_configure_window( c
, ev
->window
, ev
->value_mask
, values
);