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/>.
33 #include "window-table.h"
37 static enum _window_operation
{
38 OP_NONE
, OP_MOVE
, OP_RESIZE
40 static enum size_which
{
41 SIZE_LESSER
, SIZE_NONE
, SIZE_GREATER
43 static int dx
, dy
, init_x
, init_y
, moved
;
44 static struct gwm_window
*feedback
;
46 static struct h_edge
{
51 static struct v_edge
{
56 static int num_t_edges
, num_b_edges
, num_l_edges
, num_r_edges
;
58 static int h_edge_compare( const void *v0
, const void *v1
) {
60 const struct h_edge
*e0
= v0
, *e1
= v1
;
65 static int v_edge_compare( const void *v0
, const void *v1
) {
67 const struct v_edge
*e0
= v0
, *e1
= v1
;
72 static void build_edges( int screen
) {
74 struct gwm_window
*window
, **windowp
, **end
;
81 t_edges
= malloc( ( windows
.used
+ 1 ) * sizeof *t_edges
);
82 b_edges
= malloc( ( windows
.used
+ 1 ) * sizeof *b_edges
);
83 l_edges
= malloc( ( windows
.used
+ 1 ) * sizeof *l_edges
);
84 r_edges
= malloc( ( windows
.used
+ 1 ) * sizeof *r_edges
);
86 t_edges
[ 0 ].x_min
= b_edges
[ 0 ].x_min
= 0;
87 t_edges
[ 0 ].x_max
= b_edges
[ 0 ].x_max
=
88 screens
[ screen
]->width_in_pixels
;
89 t_edges
[ 0 ].y
= screens
[ screen
]->height_in_pixels
;
92 l_edges
[ 0 ].x
= screens
[ screen
]->width_in_pixels
;
94 l_edges
[ 0 ].y_min
= r_edges
[ 0 ].y_min
= 0;
95 l_edges
[ 0 ].y_max
= r_edges
[ 0 ].y_max
=
96 screens
[ screen
]->height_in_pixels
;
98 num_t_edges
= num_b_edges
= num_l_edges
= num_r_edges
= 1;
100 end
= windows
.values
+ windows
.used
;
101 for( windowp
= windows
.values
; windowp
< end
; windowp
++ )
102 if( ( window
= *windowp
)->type
== WINDOW_FRAME
&&
103 window
->screen
== screen
) {
104 int t
= window
->u
.frame
.y
,
105 b
= window
->u
.frame
.y
+ window
->u
.frame
.height
+
106 ( FRAME_X_BORDER
<< 1 ),
107 l
= window
->u
.frame
.x
,
108 r
= window
->u
.frame
.x
+ window
->u
.frame
.width
+
109 ( FRAME_X_BORDER
<< 1 );
111 if( t
>= screens
[ screen
]->height_in_pixels
|| b
<= 0 ||
112 l
>= screens
[ screen
]->width_in_pixels
|| r
<= 0 )
113 continue; /* window is entirely off screen; ignore */
116 t_edges
[ num_t_edges
].x_min
= l
;
117 t_edges
[ num_t_edges
].x_max
= r
;
118 t_edges
[ num_t_edges
].y
= t
;
122 if( b
<= screens
[ screen
]->height_in_pixels
) {
123 b_edges
[ num_b_edges
].x_min
= l
;
124 b_edges
[ num_b_edges
].x_max
= r
;
125 b_edges
[ num_b_edges
].y
= b
;
130 l_edges
[ num_l_edges
].x
= l
;
131 l_edges
[ num_l_edges
].y_min
= t
;
132 l_edges
[ num_l_edges
].y_max
= b
;
136 if( r
<= screens
[ screen
]->width_in_pixels
) {
137 r_edges
[ num_r_edges
].x
= r
;
138 r_edges
[ num_r_edges
].y_min
= t
;
139 r_edges
[ num_r_edges
].y_max
= b
;
144 qsort( t_edges
, num_t_edges
, sizeof *t_edges
, h_edge_compare
);
145 qsort( b_edges
, num_b_edges
, sizeof *b_edges
, h_edge_compare
);
146 qsort( l_edges
, num_l_edges
, sizeof *l_edges
, v_edge_compare
);
147 qsort( r_edges
, num_r_edges
, sizeof *r_edges
, v_edge_compare
);
150 static void free_edges( void ) {
167 static void edge_resist( int old_t
, int old_b
, int old_l
, int old_r
,
168 int new_t
, int new_b
, int new_l
, int new_r
,
173 if( new_t
< old_t
) {
174 /* Trying to move up; look for bottom edges with
175 new_t < y <= new_t + EDGE_RESIST. */
176 int i0
= 0, i1
= num_b_edges
- 1, i
;
178 while( i1
> i0
+ 1 ) {
179 int i_mid
= ( i0
+ i1
) >> 1;
181 if( b_edges
[ i_mid
].y
<= new_t
)
187 while( i0
< num_b_edges
&& b_edges
[ i0
].y
<= new_t
)
190 for( i
= i0
; i
< num_b_edges
&& b_edges
[ i
].y
<= new_t
+ EDGE_RESIST
;
192 if( b_edges
[ i
].x_min
< new_r
&& b_edges
[ i
].x_max
> new_l
)
193 *ey
= b_edges
[ i
].y
- new_t
;
194 } else if( new_b
> old_b
) {
195 /* Trying to move down; look for top edges with
196 new_b > y >= new_b - EDGE_RESIST. */
197 int i0
= 0, i1
= num_t_edges
- 1, i
;
199 while( i1
> i0
+ 1 ) {
200 int i_mid
= ( i0
+ i1
) >> 1;
202 if( t_edges
[ i_mid
].y
>= new_b
)
208 while( i1
>= 0 && t_edges
[ i1
].y
>= new_b
)
211 for( i
= i1
; i
>= 0 && t_edges
[ i
].y
>= new_b
- EDGE_RESIST
; i
-- )
212 if( t_edges
[ i
].x_min
< new_r
&& t_edges
[ i
].x_max
> new_l
)
213 *ey
= t_edges
[ i
].y
- new_b
;
216 if( new_l
< old_l
) {
217 /* Trying to move left; look for right edges with
218 new_l < x <= new_l + EDGE_RESIST. */
219 int i0
= 0, i1
= num_r_edges
- 1, i
;
221 while( i1
> i0
+ 1 ) {
222 int i_mid
= ( i0
+ i1
) >> 1;
224 if( r_edges
[ i_mid
].x
<= new_l
)
230 while( i0
< num_r_edges
&& r_edges
[ i0
].x
<= new_l
)
233 for( i
= i0
; i
< num_r_edges
&& r_edges
[ i
].x
<= new_l
+ EDGE_RESIST
;
235 if( r_edges
[ i
].y_min
< new_b
&& r_edges
[ i
].y_max
> new_t
)
236 *ex
= r_edges
[ i
].x
- new_l
;
237 } else if( new_r
> old_r
) {
238 /* Trying to move right; look for left edges with
239 new_r > x >= new_r - EDGE_RESIST. */
240 int i0
= 0, i1
= num_l_edges
- 1, i
;
242 while( i1
> i0
+ 1 ) {
243 int i_mid
= ( i0
+ i1
) >> 1;
245 if( l_edges
[ i_mid
].x
>= new_r
)
251 while( i1
>= 0 && l_edges
[ i1
].x
>= new_r
)
254 for( i
= i1
; i
>= 0 && l_edges
[ i
].x
>= new_r
- EDGE_RESIST
; i
-- )
255 if( l_edges
[ i
].y_min
< new_b
&& l_edges
[ i
].y_max
> new_t
)
256 *ex
= l_edges
[ i
].x
- new_r
;
260 static void recalc_size( struct gwm_window
*window
, int x
, int y
,
261 int apply_edge_resist
, xcb_timestamp_t t
) {
263 int new_width
, new_height
, child_width
, child_height
;
264 enum size_which old_size_x
= size_x
, old_size_y
= size_y
;
265 int old_t
, old_b
, old_l
, old_r
, new_t
, new_b
, new_l
, new_r
;
267 old_t
= window
->u
.frame
.y
;
268 old_b
= old_t
+ window
->u
.frame
.height
+ ( FRAME_X_BORDER
<< 1 );
269 old_l
= window
->u
.frame
.x
;
270 old_r
= old_l
+ window
->u
.frame
.width
+ ( FRAME_X_BORDER
<< 1 );
272 if( size_x
== SIZE_LESSER
) {
275 } else if( size_x
== SIZE_GREATER
) {
278 } else if( x
< window
->u
.frame
.x
+ ( window
->u
.frame
.width
>> 2 ) ) {
279 /* Start sizing left border. */
280 size_x
= SIZE_LESSER
;
284 } else if( x
> window
->u
.frame
.x
+ window
->u
.frame
.width
-
285 ( window
->u
.frame
.width
>> 2 ) ) {
286 /* Start sizing right border. */
287 size_x
= SIZE_GREATER
;
296 if( size_y
== SIZE_LESSER
) {
299 } else if( size_y
== SIZE_GREATER
) {
302 } else if( y
< window
->u
.frame
.y
+ ( window
->u
.frame
.height
>> 2 ) ) {
303 /* Start sizing top border. */
304 size_y
= SIZE_LESSER
;
308 } else if( y
> window
->u
.frame
.y
+ window
->u
.frame
.height
-
309 ( window
->u
.frame
.height
>> 2 ) ) {
310 /* Start sizing bottom border. */
311 size_y
= SIZE_GREATER
;
320 if( size_x
!= old_size_x
|| size_y
!= old_size_y
)
321 xcb_change_active_pointer_grab( c
, cursors
[ CURSOR_TL
+ size_y
* 3 +
323 XCB_EVENT_MASK_BUTTON_RELEASE
|
324 XCB_EVENT_MASK_POINTER_MOTION_HINT
|
325 XCB_EVENT_MASK_BUTTON_MOTION
);
327 if( apply_edge_resist
) {
330 edge_resist( old_t
, old_b
, old_l
, old_r
,
331 new_t
, new_b
, new_l
, new_r
, &ex
, &ey
);
344 new_width
= new_r
- new_l
- ( FRAME_X_BORDER
<< 1 );
345 new_height
= new_b
- new_t
- ( FRAME_X_BORDER
<< 1 );
347 child_width
= new_width
- ( FRAME_BORDER_WIDTH
<< 1 );
348 child_height
= new_height
- FRAME_TITLE_HEIGHT
- FRAME_BORDER_WIDTH
;
349 apply_size_constraints( window
->u
.frame
.child
, &child_width
,
351 new_width
= child_width
+ ( FRAME_BORDER_WIDTH
<< 1 );
352 new_height
= child_height
+ FRAME_TITLE_HEIGHT
+ FRAME_BORDER_WIDTH
;
354 if( size_x
== SIZE_LESSER
)
355 new_l
= new_r
- new_width
- ( FRAME_X_BORDER
<< 1 );
357 if( size_y
== SIZE_LESSER
)
358 new_t
= new_b
- new_height
- ( FRAME_X_BORDER
<< 1 );
360 if( new_l
!= window
->u
.frame
.x
|| new_t
!= window
->u
.frame
.y
||
361 new_width
!= window
->u
.frame
.width
||
362 new_height
!= window
->u
.frame
.height
) {
363 int new_fb_width
, new_fb_height
;
364 uint32_t values
[ 4 ] = { new_l
, new_t
, new_width
, new_height
};
366 xcb_configure_window( c
, window
->w
, XCB_CONFIG_WINDOW_X
|
367 XCB_CONFIG_WINDOW_Y
| XCB_CONFIG_WINDOW_WIDTH
|
368 XCB_CONFIG_WINDOW_HEIGHT
, values
);
370 values
[ 0 ] = new_width
- ( FRAME_BORDER_WIDTH
<< 1 );
371 values
[ 1 ] = new_height
- FRAME_TITLE_HEIGHT
- FRAME_BORDER_WIDTH
;
372 /* FIXME See _NET_WM_SYNC_REQUEST in the EWMH to avoid resizing the
373 window faster than the client can redraw it. */
374 xcb_configure_window( c
, window
->u
.frame
.child
->w
,
375 XCB_CONFIG_WINDOW_WIDTH
|
376 XCB_CONFIG_WINDOW_HEIGHT
, values
);
379 uint32_t values
[ 4 ];
381 feedback
= add_window( xcb_generate_id( c
) );
382 feedback
->screen
= window
->screen
;
383 feedback
->type
= WINDOW_FEEDBACK
;
385 values
[ 0 ] = gwm_screens
[ window
->screen
].pixels
[
386 COL_FEEDBACK_BACK
]; /* background pixel */
387 values
[ 1 ] = gwm_screens
[ window
->screen
].pixels
[
388 COL_BORDER
]; /* border pixel */
389 values
[ 2 ] = TRUE
; /* override redirect */
390 values
[ 3 ] = XCB_EVENT_MASK_EXPOSURE
;
391 xcb_create_window( c
, XCB_COPY_FROM_PARENT
, feedback
->w
,
392 screens
[ window
->screen
]->root
,
393 ( screens
[ window
->screen
]->width_in_pixels
-
394 FEEDBACK_WIDTH
- 2 ) >> 1,
395 ( screens
[ window
->screen
]->height_in_pixels
-
396 FEEDBACK_HEIGHT
- 2 ) >> 1,
397 FEEDBACK_WIDTH
, FEEDBACK_HEIGHT
, 1,
398 XCB_WINDOW_CLASS_INPUT_OUTPUT
,
399 XCB_COPY_FROM_PARENT
,
400 XCB_CW_BACK_PIXEL
| XCB_CW_BORDER_PIXEL
|
401 XCB_CW_OVERRIDE_REDIRECT
| XCB_CW_EVENT_MASK
,
404 xcb_map_window( c
, feedback
->w
);
408 ( values
[ 0 ] - window
->u
.frame
.child
->u
.managed
.base_width
) /
409 window
->u
.frame
.child
->u
.managed
.width_inc
;
411 ( values
[ 1 ] - window
->u
.frame
.child
->u
.managed
.base_height
) /
412 window
->u
.frame
.child
->u
.managed
.height_inc
;
414 if( new_fb_width
!= feedback
->u
.feedback
.fb_width
||
415 new_fb_height
!= feedback
->u
.feedback
.fb_height
) {
416 feedback
->u
.feedback
.fb_width
= new_fb_width
;
417 feedback
->u
.feedback
.fb_height
= new_fb_height
;
419 queue_window_update( feedback
, 0, 0, FEEDBACK_WIDTH
,
420 FEEDBACK_HEIGHT
, FALSE
);
425 static void frame_button_press( struct gwm_window
*window
,
426 xcb_button_press_event_t
*ev
) {
428 if( !initial_press( ev
) || ev
->child
)
431 window_op
= ( ev
->detail
> 1 ) == ( ev
->event_y
< FRAME_TITLE_HEIGHT
) ?
437 if( window_op
== OP_RESIZE
) {
438 size_x
= size_y
= SIZE_NONE
;
439 recalc_size( window
, ev
->root_x
, ev
->root_y
, FALSE
, ev
->time
);
444 xcb_change_active_pointer_grab( c
, cursors
[ CURSOR_C
], ev
->time
,
445 XCB_EVENT_MASK_BUTTON_RELEASE
|
446 XCB_EVENT_MASK_POINTER_MOTION_HINT
|
447 XCB_EVENT_MASK_BUTTON_MOTION
);
453 static void frame_motion_notify( struct gwm_window
*window
,
454 xcb_motion_notify_event_t
*ev
) {
456 uint32_t values
[ 2 ];
458 if( window
->w
!= passive_grab
)
461 /* Hint to the server that we're ready for further motion events. */
462 xcb_query_pointer_unchecked( c
, window
->w
);
464 if( !ev
->same_screen
)
468 /* Ignore single pixel movements. */
469 if( abs( ev
->root_x
- init_x
) > 1 || abs( ev
->root_y
- init_y
) > 1 ) {
472 build_edges( window
->screen
);
477 switch( window_op
) {
478 int old_t
, old_b
, old_l
, old_r
, new_t
, new_b
, new_l
, new_r
;
481 old_t
= window
->u
.frame
.y
;
482 old_b
= old_t
+ window
->u
.frame
.height
+ ( FRAME_X_BORDER
<< 1 );
483 old_l
= window
->u
.frame
.x
;
484 old_r
= old_l
+ window
->u
.frame
.width
+ ( FRAME_X_BORDER
<< 1 );
485 new_t
= ev
->root_y
- dy
- FRAME_X_BORDER
;
486 new_b
= new_t
+ window
->u
.frame
.height
+ ( FRAME_X_BORDER
<< 1 );
487 new_l
= ev
->root_x
- dx
- FRAME_X_BORDER
;
488 new_r
= new_l
+ window
->u
.frame
.width
+ ( FRAME_X_BORDER
<< 1 );
490 if( !( ev
->state
& XCB_MOD_MASK_CONTROL
) ) {
493 edge_resist( old_t
, old_b
, old_l
, old_r
,
494 new_t
, new_b
, new_l
, new_r
, &ex
, &ey
);
502 if( new_t
!= old_t
|| new_l
!= old_l
) {
505 xcb_configure_window( c
, window
->w
, XCB_CONFIG_WINDOW_X
|
506 XCB_CONFIG_WINDOW_Y
, values
);
508 /* We're supposed to send the client a synthetic ConfigureNotify,
509 but if we actually moved the window, then we'll do that from
510 our own ConfigureNotify handler. */
516 recalc_size( window
, ev
->root_x
, ev
->root_y
,
517 !( ev
->state
& XCB_MOD_MASK_CONTROL
) &&
518 window
->u
.frame
.child
->u
.managed
.width_inc
== 1 &&
519 window
->u
.frame
.child
->u
.managed
.height_inc
== 1,
528 static void frame_button_release( struct gwm_window
*window
,
529 xcb_button_release_event_t
*ev
) {
531 if( !final_release( ev
) )
536 else if( window_op
) {
537 uint32_t n
= XCB_STACK_MODE_OPPOSITE
;
539 xcb_configure_window( c
, window
->w
, XCB_CONFIG_WINDOW_STACK_MODE
,
545 xcb_destroy_window( c
, feedback
->w
);
546 forget_window( feedback
);
551 static void frame_enter_notify( struct gwm_window
*window
,
552 xcb_enter_notify_event_t
*ev
) {
555 if( focus_frame
== window
)
556 /* We have the focus already -- probably an inferior change or
560 deactivate_focus_frame();
562 focus_frame
= window
;
564 n
= gwm_screens
[ window
->screen
].pixels
[ COL_FRAME_ACTIVE
];
565 xcb_change_window_attributes( c
, window
->w
, XCB_CW_BACK_PIXEL
, &n
);
567 queue_window_update( window
, 0, 0, window
->u
.frame
.width
,
568 window
->u
.frame
.height
, FALSE
);
570 /* FIXME Defer all this focus stuff in case of multiple enter/leave
573 if( window
->u
.frame
.child
->u
.managed
.hints
& HINT_INPUT
)
574 /* Give the client the focus (ICCCM 2.0, section 4.1.7). */
575 /* Ignore Window errors (which can occur if the client destroys
576 the window before our request arrives) and Match errors (which
577 can occur if the window is unmapped first). */
578 handle_error_reply( xcb_set_input_focus_checked(
579 c
, XCB_INPUT_FOCUS_POINTER_ROOT
,
580 window
->u
.frame
.child
->w
, ev
->time
),
581 ERR_MASK_WINDOW
| ERR_MASK_MATCH
);
583 if( window
->u
.frame
.child
->u
.managed
.protocols
& PROTOCOL_TAKE_FOCUS
) {
584 /* Tell the client to take the focus (ICCCM 2.0, section 4.1.7). */
585 xcb_client_message_event_t msg
;
587 msg
.response_type
= XCB_CLIENT_MESSAGE
;
590 msg
.window
= window
->u
.frame
.child
->w
;
591 msg
.type
= atoms
[ ATOM_WM_PROTOCOLS
];
592 msg
.data
.data32
[ 0 ] = atoms
[ ATOM_WM_TAKE_FOCUS
];
593 msg
.data
.data32
[ 1 ] = ev
->time
;
594 msg
.data
.data32
[ 2 ] = 0;
595 msg
.data
.data32
[ 3 ] = 0;
596 msg
.data
.data32
[ 4 ] = 0;
598 handle_error_reply( xcb_send_event_checked(
599 c
, FALSE
, window
->u
.frame
.child
->w
,
600 0, (char *) &msg
), ERR_MASK_WINDOW
);
603 if( !( window
->u
.frame
.child
->u
.managed
.hints
& HINT_INPUT
) &&
604 !( window
->u
.frame
.child
->u
.managed
.protocols
& PROTOCOL_TAKE_FOCUS
) )
605 /* The client really doesn't want the focus. */
606 xcb_set_input_focus( c
, XCB_INPUT_FOCUS_NONE
,
607 XCB_INPUT_FOCUS_POINTER_ROOT
, ev
->time
);
609 install_window_colormap( window
->screen
, window
->u
.frame
.child
,
613 extern void synthetic_configure_notify( struct gwm_window
*window
) {
615 xcb_configure_notify_event_t msg
;
617 assert( window
->type
== WINDOW_FRAME
);
619 /* Send a synthetic ConfigureNotify (ICCCM 2.0, section 4.2.3). */
620 msg
.response_type
= XCB_CONFIGURE_NOTIFY
;
621 msg
.event
= msg
.window
= window
->u
.frame
.child
->w
;
622 msg
.above_sibling
= XCB_NONE
;
623 msg
.x
= window
->u
.frame
.x
+ FRAME_BORDER_WIDTH
+ FRAME_X_BORDER
-
624 window
->u
.frame
.child
->u
.managed
.border_width
;
625 msg
.y
= window
->u
.frame
.y
+ FRAME_TITLE_HEIGHT
+ FRAME_X_BORDER
-
626 window
->u
.frame
.child
->u
.managed
.border_width
;
627 msg
.width
= window
->u
.frame
.width
- ( FRAME_BORDER_WIDTH
<< 1 );
628 msg
.height
= window
->u
.frame
.height
- FRAME_TITLE_HEIGHT
-
630 msg
.border_width
= window
->u
.frame
.child
->u
.managed
.border_width
;
631 msg
.override_redirect
= FALSE
;
632 xcb_send_event( c
, FALSE
, window
->u
.frame
.child
->w
,
633 XCB_EVENT_MASK_STRUCTURE_NOTIFY
, (char *) &msg
);
636 static void frame_map_request( struct gwm_window
*window
,
637 xcb_map_request_event_t
*ev
) {
639 if( ev
->window
== window
->u
.frame
.child
->w
)
640 /* A transition to the Normal state (ICCCM 2.0, section 4.1.4). */
641 iconic_to_normal( window
->u
.frame
.child
);
644 static void frame_configure_notify( struct gwm_window
*window
,
645 xcb_configure_notify_event_t
*ev
) {
647 if( ev
->window
!= window
->w
)
650 window
->u
.frame
.x
= ev
->x
;
651 window
->u
.frame
.y
= ev
->y
;
652 window
->u
.frame
.width
= ev
->width
;
653 window
->u
.frame
.height
= ev
->height
;
655 synthetic_configure_notify( window
);
658 static void frame_configure_request( struct gwm_window
*window
,
659 xcb_configure_request_event_t
*ev
) {
661 int x
, y
, child_x
, child_y
, frame_x
, frame_y
, frame_width
, frame_height
;
662 uint32_t values
[ 5 ];
664 if( ev
->value_mask
& XCB_CONFIG_WINDOW_BORDER_WIDTH
)
665 /* Ignore border width request, but remember what was asked for. */
666 window
->u
.frame
.child
->u
.managed
.border_width
= ev
->border_width
;
668 translate_frame_to_child( &child_x
, &child_y
, window
->u
.frame
.x
,
670 window
->u
.frame
.child
->u
.managed
.border_width
,
671 window
->u
.frame
.child
->u
.managed
.win_gravity
);
673 x
= ev
->value_mask
& XCB_CONFIG_WINDOW_X
? ev
->x
: child_x
;
674 y
= ev
->value_mask
& XCB_CONFIG_WINDOW_Y
? ev
->y
: child_y
;
676 translate_child_to_frame( &frame_x
, &frame_y
, &frame_width
, &frame_height
,
677 x
, y
, ev
->width
, ev
->height
,
678 window
->u
.frame
.child
->u
.managed
.border_width
,
679 window
->u
.frame
.child
->u
.managed
.win_gravity
);
681 values
[ 0 ] = frame_x
;
682 values
[ 1 ] = frame_y
;
683 values
[ 2 ] = frame_width
;
684 values
[ 3 ] = frame_height
;
685 values
[ 4 ] = ev
->stack_mode
;
686 if( frame_x
!= window
->u
.frame
.x
|| frame_y
!= window
->u
.frame
.y
||
687 frame_width
!= window
->u
.frame
.width
||
688 frame_height
!= window
->u
.frame
.height
||
689 ( ev
->value_mask
& XCB_CONFIG_WINDOW_STACK_MODE
) ) {
690 /* We'll also notify the client of any changes, in the ConfigureNotify
691 handler for the event we expect to receive in response to this
693 xcb_configure_window( c
, window
->w
, XCB_CONFIG_WINDOW_X
|
694 XCB_CONFIG_WINDOW_Y
| XCB_CONFIG_WINDOW_WIDTH
|
695 XCB_CONFIG_WINDOW_HEIGHT
|
696 ( ev
->value_mask
& XCB_CONFIG_WINDOW_STACK_MODE
),
699 if( frame_width
!= window
->u
.frame
.width
||
700 frame_height
!= window
->u
.frame
.height
) {
701 values
[ 0 ] = frame_width
- ( FRAME_BORDER_WIDTH
<< 1 );
702 values
[ 1 ] = frame_height
- FRAME_TITLE_HEIGHT
-
704 xcb_configure_window( c
, ev
->window
, XCB_CONFIG_WINDOW_WIDTH
|
705 XCB_CONFIG_WINDOW_HEIGHT
, values
);
708 /* Send a synthetic ConfigureNotify indicating the client's
709 configuration in the root co-ordinate space (ICCCM 2.0,
711 synthetic_configure_notify( window
);
714 event_handler frame_handlers
[] = {
718 NULL
, /* KeyRelease */
719 (event_handler
) frame_button_press
,
720 (event_handler
) frame_button_release
,
721 (event_handler
) frame_motion_notify
,
722 (event_handler
) frame_enter_notify
,
723 NULL
, /* LeaveNotify */
726 NULL
, /* KeymapNotify */
727 (event_handler
) generic_expose
,
728 NULL
, /* GraphicsExpose */
729 NULL
, /* NoExposure */
730 NULL
, /* VisibilityNotify */
731 NULL
, /* CreateNotify */
732 NULL
, /* DestroyNotify */
733 NULL
, /* UnmapNotify */
734 NULL
, /* MapNotify */
735 (event_handler
) frame_map_request
,
736 NULL
, /* ReparentNotify */
737 (event_handler
) frame_configure_notify
,
738 (event_handler
) frame_configure_request
,
739 NULL
, /* GravityNotify */
740 NULL
, /* ResizeRequest */
741 NULL
, /* CirculateNotify */
742 NULL
, /* CirculateRequest */
743 NULL
, /* PropertyNotify */
744 NULL
, /* SelectionClear */
745 NULL
, /* SelectionRequest */
746 NULL
, /* SelectionNotify */
747 NULL
, /* ColormapNotify */
748 NULL
, /* ClientMessage */
749 NULL
, /* MappingNotify */
750 NULL
, /* (synthetic) */
751 NULL
/* ShapeNotify */