Clean up UTF-8 processing.
[gwm.git] / managed.c
blob7a74b601f13ccbb52f2295af140e43a67dec777c
1 /*
2 * managed.c
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/>.
21 * $Id$
24 #include <config.h>
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <xcb/xcb.h>
30 #if USE_SHAPE
31 #include <xcb/shape.h>
32 #endif
34 #include "gwm.h"
36 #include "frame.h"
37 #include "managed.h"
38 #include "utf8.h"
39 #include "window-table.h"
41 extern void set_managed_state( struct gwm_window *window, int state ) {
43 uint32_t values[ 2 ];
45 assert( window->type == WINDOW_MANAGED );
47 /* Place a WM_STATE property on the client window (ICCCM 2.0, section
48 4.1.3.1). */
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 ],
53 32, 2, values );
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 ) {
67 uint32_t n;
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. */
82 xcb_grab_server( c );
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 {
132 struct gwm_window *window;
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;
142 if( error ) {
143 /* Ignore Window errors, since the window might have been destroyed
144 in the meantime. */
145 if( error->error_code != XCB_WINDOW )
146 show_error( error );
148 free( error );
151 if( reply ) {
152 managed_property_change( p->window, p->prop, reply );
154 free( reply );
157 free( p );
160 static void async_get_property( struct gwm_window *window,
161 enum gwm_property_type prop ) {
163 struct managed_get_property *p = xmalloc( sizeof *p );
164 union callback_param cp;
166 p->window = window;
167 p->prop = prop;
169 cp.p = p;
170 handle_async_reply( xcb_get_property( c, FALSE, window->w,
171 prop_atoms[ prop ],
172 prop_types[ prop ], 0,
173 PROP_SIZE ).sequence,
174 handle_managed_get_property, cp );
177 #define MOTIF_WM_HINTS_DECORATIONS 0x2
179 #define MOTIF_WM_HINTS_FLAGS_OFF 0
180 #define MOTIF_WM_HINTS_DECORATIONS_OFF 2
181 #define MOTIF_WM_HINTS_MIN_SIZE 3 /* ignore hint properties smaller than this */
183 #define MOTIF_WM_HINTS_DEC_ALL 0x1
184 #define MOTIF_WM_HINTS_DEC_BORDER 0x2
185 #define MOTIF_WM_HINTS_DEC_TITLE 0x8
187 #define WM_HINTS_INPUT 0x1
188 #define WM_HINTS_STATE 0x2
190 #define WM_HINTS_FLAGS_OFF 0
191 #define WM_HINTS_INPUT_OFF 1
192 #define WM_HINTS_STATE_OFF 2
193 #define WM_HINTS_MIN_SIZE 3 /* ignore hint properties smaller than this */
195 #define WM_HINTS_STATE_NORMAL 1
196 #define WM_HINTS_STATE_ICONIC 3
198 #define WM_NORMAL_HINTS_USER_POSITION 0x001
199 #define WM_NORMAL_HINTS_PROGRAM_POSITION 0x004
200 #define WM_NORMAL_HINTS_MIN_SIZE 0x010
201 #define WM_NORMAL_HINTS_MAX_SIZE 0x020
202 #define WM_NORMAL_HINTS_SIZE_INC 0x040
203 #define WM_NORMAL_HINTS_ASPECT 0x080
204 #define WM_NORMAL_HINTS_BASE_SIZE 0x100
205 #define WM_NORMAL_HINTS_WIN_GRAVITY 0x200
207 #define WM_NORMAL_HINTS_FLAGS_OFF 0
208 #define WM_NORMAL_HINTS_MIN_SIZE_OFF 5
209 #define WM_NORMAL_HINTS_MAX_SIZE_OFF 7
210 #define WM_NORMAL_HINTS_SIZE_INC_OFF 9
211 #define WM_NORMAL_HINTS_ASPECT_OFF 11
212 #define WM_NORMAL_HINTS_BASE_SIZE_OFF 15
213 #define WM_NORMAL_HINTS_WIN_GRAVITY_OFF 17
215 extern void managed_property_change( struct gwm_window *window, int prop,
216 xcb_get_property_reply_t *p ) {
218 uint32_t *p32, n32;
219 int i;
220 struct xcb_screen_t *screen;
221 int value_len;
222 int old_decoration;
224 assert( window->type == WINDOW_MANAGED );
226 switch( prop ) {
227 case PROP__MOTIF_WM_HINTS:
228 /* _MOTIF_WM_HINTS property. */
229 old_decoration = window->u.managed.frame->u.frame.decoration;
231 window->u.managed.frame->u.frame.decoration = DEC_DEFAULT;
233 if( p->format == 32 && p->value_len >= MOTIF_WM_HINTS_MIN_SIZE ) {
234 p32 = xcb_get_property_value( p );
236 if( p32[ MOTIF_WM_HINTS_FLAGS_OFF ] &
237 MOTIF_WM_HINTS_DECORATIONS ) {
238 if( p32[ MOTIF_WM_HINTS_DECORATIONS_OFF ] &
239 MOTIF_WM_HINTS_DEC_ALL ) {
240 window->u.managed.frame->u.frame.decoration =
241 DEC_BORDER | DEC_TITLE;
243 if( p32[ MOTIF_WM_HINTS_DECORATIONS_OFF ] &
244 MOTIF_WM_HINTS_DEC_BORDER )
245 window->u.managed.frame->u.frame.decoration &=
246 ~DEC_BORDER;
248 if( p32[ MOTIF_WM_HINTS_DECORATIONS_OFF ] &
249 MOTIF_WM_HINTS_DEC_TITLE )
250 window->u.managed.frame->u.frame.decoration &=
251 ~DEC_TITLE;
252 } else {
253 window->u.managed.frame->u.frame.decoration = 0;
255 if( p32[ MOTIF_WM_HINTS_DECORATIONS_OFF ] &
256 MOTIF_WM_HINTS_DEC_BORDER )
257 window->u.managed.frame->u.frame.decoration |=
258 DEC_BORDER;
260 if( p32[ MOTIF_WM_HINTS_DECORATIONS_OFF ] &
261 MOTIF_WM_HINTS_DEC_TITLE )
262 window->u.managed.frame->u.frame.decoration |=
263 DEC_TITLE;
268 #if USE_SHAPE
269 if( window->u.managed.shaped )
270 /* Never apply borders to shaped windows. */
271 window->u.managed.frame->u.frame.decoration &= ~DEC_BORDER;
272 #endif
274 if( window->u.managed.state == STATE_NORMAL &&
275 window->u.managed.frame->u.frame.decoration != old_decoration ) {
276 int new_decoration = window->u.managed.frame->u.frame.decoration;
277 int x, y, width, height;
278 uint32_t n[ 5 ];
280 window->u.managed.frame->u.frame.decoration = old_decoration;
282 translate_frame_to_child( window->u.managed.frame, &x, &y,
283 window->u.managed.frame->u.frame.x,
284 window->u.managed.frame->u.frame.y,
285 window->u.managed.border_width,
286 window->u.managed.win_gravity );
288 window->u.managed.frame->u.frame.decoration = new_decoration;
290 translate_child_to_frame( window->u.managed.frame, &x, &y,
291 &width, &height, x, y,
292 window->u.managed.frame->u.frame.width -
293 frame_l( window->u.managed.frame,
294 FALSE ) -
295 frame_r( window->u.managed.frame,
296 FALSE ),
297 window->u.managed.frame->u.frame.height -
298 frame_t( window->u.managed.frame,
299 FALSE ) -
300 frame_b( window->u.managed.frame,
301 FALSE ),
302 window->u.managed.border_width,
303 window->u.managed.win_gravity );
305 if( new_decoration & DEC_TITLE )
306 xcb_map_window( c,
307 window->u.managed.frame->u.frame.button->w );
308 else
309 xcb_unmap_window( c,
310 window->u.managed.frame->u.frame.button->w );
312 n[ 0 ] = frame_l( window->u.managed.frame, FALSE );
313 n[ 1 ] = frame_l( window->u.managed.frame, FALSE );
314 xcb_configure_window( c, window->w, XCB_CONFIG_WINDOW_X |
315 XCB_CONFIG_WINDOW_Y, n );
317 n[ 0 ] = x;
318 n[ 1 ] = y;
319 n[ 2 ] = width;
320 n[ 3 ] = height;
321 n[ 4 ] = frame_xb( window->u.managed.frame );
322 /* We'll also notify the client of any changes, in the
323 ConfigureNotify handler for the event we expect to receive in
324 response to this request. */
325 xcb_configure_window( c, window->u.managed.frame->w,
326 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
327 XCB_CONFIG_WINDOW_WIDTH |
328 XCB_CONFIG_WINDOW_HEIGHT |
329 XCB_CONFIG_WINDOW_BORDER_WIDTH, n );
332 break;
334 case PROP__NET_WM_NAME:
335 /* _NET_WM_NAME property (see EMWH "Application Window Properties". */
336 if( window->u.managed.name )
337 free( window->u.managed.name );
339 if( p->value_len && p->format == 8 ) {
340 window->u.managed.name = (char *) utf8_dup_valid_len(
341 xcb_get_property_value( p ), p->value_len );
342 window->u.managed.net_wm_name = 1;
344 if( window->u.managed.state == STATE_NORMAL &&
345 ( window->u.managed.frame->u.frame.decoration & DEC_TITLE ) )
346 queue_window_update( window->u.managed.frame, 0, 0,
347 window->u.managed.frame->u.frame.width,
348 frame_t( window->u.managed.frame, FALSE ),
349 FALSE );
350 } else {
351 window->u.managed.name = NULL;
352 window->u.managed.net_wm_name = 0;
353 /* We've lost the _NET_WM_NAME property. If the window still
354 has a plain WM_NAME, then fall back to that. */
355 async_get_property( window, PROP_WM_NAME );
358 break;
360 case PROP_WM_COLORMAP_WINDOWS:
361 /* WM_COLORMAP_WINDOWS property (see ICCCM 2.0, section 4.1.8). */
362 window->u.managed.cmap_window = XCB_NONE;
364 if( p->format == 32 && p->value_len >= 2 ) {
365 p32 = xcb_get_property_value( p );
367 if( p32[ 0 ] == window->w )
368 /* The window itself is given the highest priority, which
369 is what we would do anyway -- ignore the list. */
370 break;
372 for( i = 1; i < p->value_len; i++ )
373 if( p32[ i ] == window->w ) {
374 /* The window is explicitly given a lower priority
375 than some other one. Remember whichever is
376 considered more important. */
377 window->u.managed.cmap_window = p32[ i ];
379 break;
383 break;
385 case PROP_WM_HINTS:
386 /* WM_HINTS property (see ICCCM 2.0, section 4.1.2.4). */
387 window->u.managed.hints &= ~HINT_ICONIC;
388 window->u.managed.hints |= HINT_INPUT;
390 if( p->value_len < WM_HINTS_MIN_SIZE || p->format != 32 )
391 break;
393 p32 = xcb_get_property_value( p );
395 if( ( p32[ WM_HINTS_FLAGS_OFF ] & WM_HINTS_INPUT ) &&
396 !p32[ WM_HINTS_INPUT_OFF ] )
397 window->u.managed.hints &= ~HINT_INPUT;
399 if( ( p32[ WM_HINTS_FLAGS_OFF ] & WM_HINTS_STATE ) &&
400 p32[ WM_HINTS_STATE_OFF ] == WM_HINTS_STATE_ICONIC )
401 window->u.managed.hints |= HINT_ICONIC;
403 break;
405 case PROP_WM_NAME:
406 /* WM_NAME property (see ICCCM 2.0, section 4.1.2.1). */
407 if( window->u.managed.net_wm_name )
408 /* Ignore WM_NAME if _NET_WM_NAME is set. */
409 break;
411 if( window->u.managed.name )
412 free( window->u.managed.name );
414 if( p->value_len && p->format == 8 )
415 window->u.managed.name = to_utf8(
416 p->type == atoms[ ATOM_COMPOUND_TEXT ] ? ENCODING_COMPOUND :
417 ENCODING_LATIN_1, xcb_get_property_value( p ), p->value_len );
418 else
419 window->u.managed.name = NULL;
421 if( window->u.managed.state == STATE_NORMAL &&
422 ( window->u.managed.frame->u.frame.decoration & DEC_TITLE ) )
423 queue_window_update( window->u.managed.frame, 0, 0,
424 window->u.managed.frame->u.frame.width,
425 frame_t( window->u.managed.frame, FALSE ),
426 FALSE );
428 break;
430 case PROP_WM_NORMAL_HINTS:
431 /* WM_NORMAL_HINTS property (see ICCCM 2.0, section 4.1.2.3). */
432 window->u.managed.hints &= ~HINT_POSITION;
433 window->u.managed.min_width = frame_t( window->u.managed.frame,
434 FALSE );
435 window->u.managed.min_height = frame_t( window->u.managed.frame,
436 FALSE ) >> 1;
437 window->u.managed.max_width = 0x7FFF;
438 window->u.managed.max_height = 0x7FFF;
439 window->u.managed.width_inc = 1;
440 window->u.managed.height_inc = 1;
441 window->u.managed.min_aspect_x = 0;
442 window->u.managed.min_aspect_y = 1;
443 window->u.managed.max_aspect_x = 1;
444 window->u.managed.max_aspect_y = 0;
445 window->u.managed.base_width = 0;
446 window->u.managed.base_height = 0;
447 window->u.managed.win_gravity = XCB_GRAVITY_NORTH_WEST;
449 if( p->value_len < 1 || p->format != 32 ) {
450 n32 = 0;
451 p32 = &n32;
452 value_len = 1;
453 } else {
454 p32 = xcb_get_property_value( p );
455 value_len = p->value_len;
458 if( p32[ WM_NORMAL_HINTS_FLAGS_OFF ] & WM_NORMAL_HINTS_USER_POSITION )
459 window->u.managed.hints |= HINT_USER_POSITION;
460 else if( p32[ WM_NORMAL_HINTS_FLAGS_OFF ] &
461 WM_NORMAL_HINTS_PROGRAM_POSITION )
462 window->u.managed.hints |= HINT_PROGRAM_POSITION;
464 if( p32[ WM_NORMAL_HINTS_FLAGS_OFF ] & WM_NORMAL_HINTS_MIN_SIZE &&
465 value_len >= WM_NORMAL_HINTS_MIN_SIZE_OFF + 1 ) {
466 window->u.managed.min_width = p32[ WM_NORMAL_HINTS_MIN_SIZE_OFF ];
467 window->u.managed.min_height =
468 p32[ WM_NORMAL_HINTS_MIN_SIZE_OFF + 1 ];
471 if( p32[ WM_NORMAL_HINTS_FLAGS_OFF ] & WM_NORMAL_HINTS_MAX_SIZE &&
472 value_len >= WM_NORMAL_HINTS_MAX_SIZE_OFF + 1 ) {
473 window->u.managed.max_width = p32[ WM_NORMAL_HINTS_MAX_SIZE_OFF ];
474 window->u.managed.max_height =
475 p32[ WM_NORMAL_HINTS_MAX_SIZE_OFF + 1 ];
478 if( p32[ WM_NORMAL_HINTS_FLAGS_OFF ] & WM_NORMAL_HINTS_SIZE_INC &&
479 value_len >= WM_NORMAL_HINTS_SIZE_INC_OFF + 1 ) {
480 window->u.managed.width_inc = p32[ WM_NORMAL_HINTS_SIZE_INC_OFF ];
481 window->u.managed.height_inc =
482 p32[ WM_NORMAL_HINTS_SIZE_INC_OFF + 1 ];
485 if( p32[ WM_NORMAL_HINTS_FLAGS_OFF ] & WM_NORMAL_HINTS_ASPECT &&
486 value_len >= WM_NORMAL_HINTS_ASPECT_OFF + 3 ) {
487 window->u.managed.min_aspect_x = p32[ WM_NORMAL_HINTS_ASPECT_OFF ];
488 window->u.managed.min_aspect_y =
489 p32[ WM_NORMAL_HINTS_ASPECT_OFF + 1 ];
490 window->u.managed.max_aspect_x =
491 p32[ WM_NORMAL_HINTS_ASPECT_OFF + 2 ];
492 window->u.managed.max_aspect_y =
493 p32[ WM_NORMAL_HINTS_ASPECT_OFF + 3 ];
496 if( p32[ WM_NORMAL_HINTS_FLAGS_OFF ] & WM_NORMAL_HINTS_BASE_SIZE &&
497 value_len >= WM_NORMAL_HINTS_BASE_SIZE_OFF + 1 ) {
498 window->u.managed.base_width =
499 p32[ WM_NORMAL_HINTS_BASE_SIZE_OFF ];
500 window->u.managed.base_height =
501 p32[ WM_NORMAL_HINTS_BASE_SIZE_OFF + 1 ];
503 if( !( p32[ WM_NORMAL_HINTS_FLAGS_OFF ] &
504 WM_NORMAL_HINTS_MIN_SIZE ) ) {
505 window->u.managed.min_width = window->u.managed.base_width;
506 window->u.managed.min_width = window->u.managed.base_width;
510 if( p32[ WM_NORMAL_HINTS_FLAGS_OFF ] & WM_NORMAL_HINTS_WIN_GRAVITY &&
511 value_len >= WM_NORMAL_HINTS_WIN_GRAVITY_OFF )
512 window->u.managed.win_gravity =
513 p32[ WM_NORMAL_HINTS_WIN_GRAVITY_OFF ];
515 /* Sanity check. */
516 screen = screens[ window->screen ];
518 if( window->u.managed.min_width < frame_t( window->u.managed.frame,
519 FALSE ) )
520 window->u.managed.min_width = frame_t( window->u.managed.frame,
521 FALSE );
522 if( window->u.managed.min_width > screen->width_in_pixels )
523 window->u.managed.min_width = screen->width_in_pixels;
525 if( window->u.managed.min_height < frame_t( window->u.managed.frame,
526 FALSE ) >> 1 )
527 window->u.managed.min_height = frame_t( window->u.managed.frame,
528 FALSE ) >> 1;
529 if( window->u.managed.min_height > screen->height_in_pixels )
530 window->u.managed.min_height = screen->height_in_pixels;
532 if( window->u.managed.max_width < window->u.managed.min_width )
533 window->u.managed.max_width = window->u.managed.min_width;
534 if( window->u.managed.max_width > 0x7FFF )
535 window->u.managed.max_width = 0x7FFF;
537 if( window->u.managed.max_height < window->u.managed.min_height )
538 window->u.managed.max_height = window->u.managed.min_height;
539 if( window->u.managed.max_height > 0x7FFF )
540 window->u.managed.max_height = 0x7FFF;
542 if( window->u.managed.min_aspect_x < 0 ||
543 window->u.managed.min_aspect_y < 1 ||
544 window->u.managed.max_aspect_x < 1 ||
545 window->u.managed.max_aspect_x < 0 ||
546 window->u.managed.min_aspect_x * window->u.managed.max_aspect_y >
547 window->u.managed.min_aspect_y * window->u.managed.max_aspect_x ) {
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;
554 if( window->u.managed.base_width < 0 ||
555 window->u.managed.base_width > window->u.managed.min_width ||
556 window->u.managed.base_height < 0 ||
557 window->u.managed.base_height > window->u.managed.min_height ) {
558 window->u.managed.base_width = 0;
559 window->u.managed.base_height = 0;
562 if( window->u.managed.win_gravity < XCB_GRAVITY_NORTH_WEST ||
563 window->u.managed.win_gravity > XCB_GRAVITY_STATIC )
564 window->u.managed.win_gravity = XCB_GRAVITY_NORTH_WEST;
566 if( window->u.managed.state == STATE_NORMAL ) {
567 /* Recalculate constraints. */
568 int width = window->u.managed.frame->u.frame.width -
569 frame_l( window->u.managed.frame, FALSE ) -
570 frame_r( window->u.managed.frame, FALSE );
571 int height = window->u.managed.frame->u.frame.height -
572 frame_t( window->u.managed.frame, FALSE ) -
573 frame_b( window->u.managed.frame, FALSE );
574 int old_width, old_height;
576 old_width = width;
577 old_height = height;
579 apply_size_constraints( window, &width, &height );
581 if( width != old_width || height != old_height ) {
582 xcb_configure_request_event_t ev;
584 ev.response_type = XCB_CONFIGURE_REQUEST;
585 ev.parent = window->u.managed.frame->w;
586 ev.window = window->w;
587 ev.width = width;
588 ev.height = height;
589 ev.value_mask = XCB_CONFIG_WINDOW_WIDTH |
590 XCB_CONFIG_WINDOW_HEIGHT;
592 frame_handlers[ XCB_CONFIGURE_REQUEST ](
593 window->u.managed.frame, (xcb_generic_event_t *) &ev );
597 break;
599 case PROP_WM_PROTOCOLS:
600 /* WM_PROTOCOLS property (see ICCCM 2.0, section 4.1.2.7). */
601 /* FIXME Look for _NET_WM_SYNC_REQUEST. */
602 window->u.managed.protocols = 0;
604 if( p->format == 32 ) {
605 p32 = xcb_get_property_value( p );
607 for( i = 0; i < p->value_len; i++ )
608 if( p32[ i ] == atoms[ ATOM_WM_DELETE_WINDOW ] )
609 window->u.managed.protocols |= PROTOCOL_DELETE_WINDOW;
610 else if( p32[ i ] == atoms[ ATOM_WM_TAKE_FOCUS ] )
611 window->u.managed.protocols |= PROTOCOL_TAKE_FOCUS;
614 if( window->u.managed.state == STATE_NORMAL ) {
615 uint32_t n = window->u.managed.protocols & PROTOCOL_DELETE_WINDOW ?
616 XCB_NONE : cursors[ CURSOR_DESTROY ];
617 xcb_change_window_attributes( c, window->u.managed.frame->
618 u.frame.button->w, XCB_CW_CURSOR,
619 &n );
622 break;
626 static void managed_property_notify( struct gwm_window *window,
627 xcb_property_notify_event_t *ev ) {
629 enum gwm_property_type i;
631 for( i = 0; i < NUM_PROPS; i++ )
632 if( ev->atom == prop_atoms[ i ] ) {
633 async_get_property( window, i );
634 return;
638 static void managed_colormap_notify( struct gwm_window *window,
639 xcb_colormap_notify_event_t *ev ) {
641 if( ev->_new ) {
642 window->u.managed.cmap = ev->colormap;
644 if( window->u.managed.frame == focus_frame )
645 /* Gah... the protocol doesn't specify a timestamp on
646 ColormapNotify events. We'll have to make do with the
647 most recent timestamp we've received instead. */
648 install_window_colormap( window->screen, window, latest_timestamp );
652 #if USE_SHAPE
653 extern void match_managed_shape( struct gwm_window *window ) {
655 if( window->u.managed.shaped ) {
656 xcb_rectangle_t rect;
658 rect.x = rect.y = 0;
659 rect.width = window->u.managed.frame->u.frame.width;
660 rect.height = frame_t( window->u.managed.frame, FALSE );
661 xcb_shape_rectangles( c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, 0,
662 window->u.managed.frame->w, 0, 0, 1, &rect );
664 xcb_shape_combine( c, XCB_SHAPE_SO_UNION, XCB_SHAPE_SK_BOUNDING,
665 XCB_SHAPE_SK_BOUNDING, window->u.managed.frame->w,
666 frame_l( window->u.managed.frame, FALSE ),
667 frame_t( window->u.managed.frame, FALSE ),
668 window->w );
669 } else
670 xcb_shape_mask( c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING,
671 window->u.managed.frame->w, 0, 0, XCB_NONE );
674 static void managed_shape_notify( struct gwm_window *window,
675 xcb_shape_notify_event_t *ev ) {
677 if( ev->shape_kind == XCB_SHAPE_SK_BOUNDING ) {
678 if( window->u.managed.shaped != ev->shaped &&
679 !( window->u.managed.shaped = ev->shaped ) )
680 /* The client is no longer shaped. Retrieve its original
681 _MOTIF_WM_HINTS, since we might now want to apply a border. */
682 async_get_property( window, PROP__MOTIF_WM_HINTS );
684 match_managed_shape( window );
687 #endif
689 const event_handler managed_handlers[] = {
690 NULL, /* Error */
691 NULL, /* Reply */
692 NULL, /* KeyPress */
693 NULL, /* KeyRelease */
694 NULL, /* ButtonPress */
695 NULL, /* ButtonRelease */
696 NULL, /* MotionNotify */
697 NULL, /* EnterNotify */
698 NULL, /* LeaveNotify */
699 NULL, /* FocusIn */
700 NULL, /* FocusOut */
701 NULL, /* KeymapNotify */
702 NULL, /* Expose */
703 NULL, /* GraphicsExpose */
704 NULL, /* NoExposure */
705 NULL, /* VisibilityNotify */
706 NULL, /* CreateNotify */
707 (event_handler) managed_destroy_notify,
708 (event_handler) managed_unmap_notify,
709 NULL, /* MapNotify */
710 NULL, /* MapRequest */
711 (event_handler) managed_reparent_notify,
712 NULL, /* ConfigureNotify */
713 NULL, /* ConfigureRequest */
714 NULL, /* GravityNotify */
715 NULL, /* ResizeRequest */
716 NULL, /* CirculateNotify */
717 NULL, /* CirculateRequest */
718 (event_handler) managed_property_notify,
719 NULL, /* SelectionClear */
720 NULL, /* SelectionRequest */
721 NULL, /* SelectionNotify */
722 (event_handler) managed_colormap_notify,
723 NULL, /* ClientMessage */
724 NULL, /* MappingNotify */
725 NULL, /* (synthetic) */
726 #if USE_SHAPE
727 (event_handler) managed_shape_notify
728 #else
729 NULL /* ShapeNotify */
730 #endif
733 extern void withdrawn_map_request( struct gwm_window *window,
734 xcb_map_request_event_t *ev ) {
736 manage_window( ev->window, TRUE );
739 extern void withdrawn_configure_request( struct gwm_window *window,
740 xcb_configure_request_event_t *ev ) {
742 int i = 0;
743 uint32_t values[ 7 ];
745 /* Configuring an unmanaged window -- just honour the request as is. */
746 if( ev->value_mask & XCB_CONFIG_WINDOW_X )
747 values[ i++ ] = ev->x;
748 if( ev->value_mask & XCB_CONFIG_WINDOW_Y )
749 values[ i++ ] = ev->y;
750 if( ev->value_mask & XCB_CONFIG_WINDOW_WIDTH )
751 values[ i++ ] = ev->width;
752 if( ev->value_mask & XCB_CONFIG_WINDOW_HEIGHT )
753 values[ i++ ] = ev->height;
754 if( ev->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH )
755 values[ i++ ] = ev->border_width;
756 if( ev->value_mask & XCB_CONFIG_WINDOW_SIBLING )
757 values[ i++ ] = ev->sibling;
758 if( ev->value_mask & XCB_CONFIG_WINDOW_STACK_MODE )
759 values[ i++ ] = ev->stack_mode;
761 xcb_configure_window( c, ev->window, ev->value_mask, values );