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/>.
27 #include <xcb/randr.h>
38 #include "window-table.h"
40 static void root_key_press( struct gwm_window
*window
,
41 xcb_key_press_event_t
*ev
) {
45 for( i
= 0; i
< num_key_actions
; i
++ )
46 if( keyboard_map
[ ev
->detail
][ 0 ] == key_actions
[ i
].keysym
&&
47 ( ev
->state
& 0xFF & key_actions
[ i
].modifiers
) ==
48 key_actions
[ i
].modifiers
) {
49 union callback_param cp
;
52 key_actions
[ i
].handler( focus_frame
? focus_frame
: window
,
53 (xcb_generic_event_t
*) ev
, cp
);
59 static const struct button_action
{
61 xcb_mod_mask_t modifiers
;
62 void ( *handler
)( struct gwm_window
*window
, xcb_generic_event_t
*ev
,
63 union callback_param cp
);
64 } button_actions
[] = {
65 /* FIXME This table should be configurable, of course. */
66 { 1, 0, action_root_menu
},
67 { 2, 0, action_window_list_menu
},
68 { 3, 0, action_start_xterm
}
71 #define NUM_BUTTON_ACTIONS ( sizeof button_actions / sizeof *button_actions )
73 static void root_button_press( struct gwm_window
*window
,
74 xcb_button_press_event_t
*ev
) {
81 for( i
= 0; i
< NUM_BUTTON_ACTIONS
; i
++ )
82 if( ev
->detail
== button_actions
[ i
].button
&&
83 ( ev
->state
& 0xFF & button_actions
[ i
].modifiers
) ==
84 button_actions
[ i
].modifiers
) {
85 union callback_param cp
;
88 button_actions
[ i
].handler( window
, (xcb_generic_event_t
*) ev
,
95 static void root_enter_notify( struct gwm_window
*window
,
96 xcb_enter_notify_event_t
*ev
) {
98 if( focus_frame
&& ( ev
->detail
== XCB_NOTIFY_DETAIL_INFERIOR
||
99 ev
->detail
== XCB_NOTIFY_DETAIL_NONLINEAR
) ) {
100 deactivate_focus_frame();
102 xcb_set_input_focus( c
, XCB_INPUT_FOCUS_NONE
,
103 XCB_INPUT_FOCUS_POINTER_ROOT
, ev
->time
);
108 install_window_colormap( window
->screen
, NULL
, ev
->time
);
111 static void root_create_notify( struct gwm_window
*window
,
112 xcb_create_notify_event_t
*ev
) {
114 /* We only ever update the window stack in response to notify
115 events from the server. The drawback to this approach is that
116 our stack can become slightly stale (recently transmitted requests
117 might not be reflected in our state). However, this policy has
118 the critical advantage that the window stack is always internally
119 consistent: if we updated it eagerly instead, that would introduce
120 the possibility of non-causal ordering of events. */
121 stack_insert_above( &window_stack
, ev
->window
,
122 stack_lookup( &window_stack
,
123 window
->w
| STACK_END
)->lower_window
);
126 static void root_destroy_notify( struct gwm_window
*window
,
127 xcb_destroy_notify_event_t
*ev
) {
129 stack_remove( &window_stack
, ev
->window
);
132 static void root_reparent_notify( struct gwm_window
*window
,
133 xcb_reparent_notify_event_t
*ev
) {
135 if( ev
->parent
== window
->w
) {
136 /* It's possible to reparent a window to its current parent,
137 so we can't assume the window is not already in the stack. */
138 if( stack_lookup( &window_stack
, ev
->window
) )
139 stack_move_above( &window_stack
, ev
->window
,
140 stack_lookup( &window_stack
, window
->w
|
141 STACK_END
)->lower_window
);
143 stack_insert_above( &window_stack
, ev
->window
,
144 stack_lookup( &window_stack
, window
->w
|
145 STACK_END
)->lower_window
);
147 stack_remove( &window_stack
, ev
->window
);
150 static void root_configure_notify( struct gwm_window
*window
,
151 xcb_configure_notify_event_t
*ev
) {
153 if( ev
->event
== ev
->window
) {
154 /* The root window itself was configured. */
155 if( screens
[ window
->screen
]->width_in_pixels
!=
157 screens
[ window
->screen
]->height_in_pixels
!=
159 uint32_t values
[ 4 ];
161 screens
[ window
->screen
]->width_in_pixels
= ev
->width
;
162 screens
[ window
->screen
]->height_in_pixels
= ev
->height
;
164 values
[ 0 ] = ev
->width
;
165 values
[ 1 ] = ev
->height
;
166 xcb_change_property( c
, XCB_PROP_MODE_REPLACE
, ev
->window
,
167 atoms
[ ATOM__NET_DESKTOP_GEOMETRY
], CARDINAL
,
172 values
[ 2 ] = ev
->width
;
173 values
[ 3 ] = ev
->height
;
174 xcb_change_property( c
, XCB_PROP_MODE_REPLACE
, ev
->window
,
175 atoms
[ ATOM__NET_WORKAREA
], CARDINAL
, 32, 4,
179 /* A child of the root was configured. */
180 stack_move_above( &window_stack
, ev
->window
, ev
->above_sibling
?
181 ev
->above_sibling
: window
->w
| STACK_END
);
184 extern void root_circulate_request( struct gwm_window
*window
,
185 xcb_circulate_request_event_t
*ev
) {
187 uint32_t value
= ev
->place
== XCB_PLACE_ON_TOP
? XCB_STACK_MODE_ABOVE
:
188 XCB_STACK_MODE_BELOW
;
190 /* Circulating children of the root -- honour the request as is. */
191 xcb_configure_window( c
, ev
->window
, XCB_CONFIG_WINDOW_STACK_MODE
,
195 static void root_synthetic( struct gwm_window
*root
,
196 xcb_generic_event_t
*ev
) {
198 xcb_unmap_notify_event_t
*unmap
= (xcb_unmap_notify_event_t
*) ev
;
199 xcb_configure_request_event_t
*config
=
200 (xcb_configure_request_event_t
*) ev
;
201 struct gwm_window
*window
;
203 switch( ev
->response_type
& ~SEND_EVENT_MASK
) {
204 case XCB_UNMAP_NOTIFY
:
205 /* Handle a synthetic UnmapNotify request to move a window to
206 the Withdrawn state (see ICCCM 2.0, section 4.1.4). */
207 if( ( window
= lookup_window( unmap
->window
) ) &&
208 window
->type
== WINDOW_MANAGED
)
209 unmanage_window( window
);
213 case XCB_CONFIGURE_REQUEST
:
214 /* Handle a synthetic ConfigureRequest, which should be used
215 only to restack managed windows relative to windows which
216 were originally siblings (see ICCCM 4.1.5). */
217 if( ( config
->value_mask
& XCB_CONFIG_WINDOW_STACK_MODE
) &&
218 ( window
= lookup_window( config
->window
) ) &&
219 window
->type
== WINDOW_MANAGED
) {
220 struct gwm_window
*sibling
;
221 uint32_t values
[ 2 ];
223 if( ( sibling
= lookup_window( config
->sibling
) ) &&
224 sibling
->type
== WINDOW_MANAGED
)
225 sibling
= sibling
->u
.managed
.frame
;
227 values
[ 0 ] = sibling
? sibling
->w
: config
->sibling
;
228 values
[ 1 ] = config
->stack_mode
;
230 handle_error_reply( xcb_configure_window_checked(
231 c
, window
->u
.managed
.frame
->w
,
232 XCB_CONFIG_WINDOW_SIBLING
|
233 XCB_CONFIG_WINDOW_STACK_MODE
,
235 ERR_MASK_VALUE
| ERR_MASK_WINDOW
|
244 static void root_rr_crtc_change_notify( struct gwm_window
*window
,
245 xcb_randr_notify_event_t
*ev
) {
247 int rotated
= ev
->u
.cc
.rotation
& ( XCB_RANDR_ROTATION_ROTATE_90
|
248 XCB_RANDR_ROTATION_ROTATE_270
);
250 update_crtc( window
->screen
, ev
->u
.cc
.crtc
,
251 rotated
? ev
->u
.cc
.height
: ev
->u
.cc
.width
,
252 rotated
? ev
->u
.cc
.width
: ev
->u
.cc
.height
,
253 ev
->u
.cc
.x
, ev
->u
.cc
.y
);
257 const event_handler root_handlers
[ NUM_EXTENDED_EVENTS
] = {
260 (event_handler
) root_key_press
,
261 NULL
, /* KeyRelease */
262 (event_handler
) root_button_press
,
263 NULL
, /* ButtonRelease */
264 NULL
, /* MotionNotify */
265 (event_handler
) root_enter_notify
,
266 NULL
, /* LeaveNotify */
269 NULL
, /* KeymapNotify */
271 NULL
, /* GraphicsExpose */
272 NULL
, /* NoExposure */
273 NULL
, /* VisibilityNotify */
274 (event_handler
) root_create_notify
,
275 (event_handler
) root_destroy_notify
,
276 NULL
, /* UnmapNotify */
277 NULL
, /* MapNotify */
278 (event_handler
) withdrawn_map_request
,
279 (event_handler
) root_reparent_notify
,
280 (event_handler
) root_configure_notify
,
281 (event_handler
) withdrawn_configure_request
,
282 NULL
, /* GravityNotify */
283 NULL
, /* ResizeRequest */
284 NULL
, /* CirculateNotify */
285 (event_handler
) root_circulate_request
,
286 NULL
, /* PropertyNotify */
287 NULL
, /* SelectionClear */
288 NULL
, /* SelectionRequest */
289 NULL
, /* SelectionNotify */
290 NULL
, /* ColormapNotify */
291 NULL
, /* ClientMessage */
292 NULL
, /* MappingNotify */
293 (event_handler
) root_synthetic
,
295 (event_handler
) root_rr_crtc_change_notify
, /* RRCrtcChangeNotify */
297 NULL
, /* RRCrtcChangeNotify */
299 NULL
/* ShapeNotify */