Add support for the zoomed state to managed windows.
[gwm.git] / button.c
blob07cb9d5ef5aa2c5823a923a12fc140a5a32bcde9
1 /*
2 * button.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 <xcb/xcb.h>
29 #include "gwm.h"
31 #include "button.h"
32 #include "window-table.h"
34 #define BUTTON_SIZE 12 /* size of buttons in title bar; excludes X border */
35 #define BUTTON_X_BORDER 1
37 extern int button_size( struct gwm_window *window, int include_x_border ) {
39 assert( window->type == WINDOW_BUTTON );
41 return BUTTON_SIZE + ( include_x_border ? BUTTON_X_BORDER << 1 : 0 );
44 extern int button_xb( struct gwm_window *window ) {
46 assert( window->type == WINDOW_BUTTON );
48 return BUTTON_X_BORDER;
51 static int button_active;
53 static void set_button_active( struct gwm_window *window, int new ) {
55 uint32_t n;
57 if( new == button_active )
58 return;
60 n = gwm_screens[ window->screen ].pixels[ ( button_active = new ) ?
61 COL_BUTTON_ACTIVE :
62 COL_BUTTON_INACTIVE ];
63 xcb_change_window_attributes( c, window->w, XCB_CW_BACK_PIXEL, &n );
65 queue_window_update( window, 0, 0, button_size( window, FALSE ),
66 button_size( window, FALSE ), FALSE );
69 static void button_button_press( struct gwm_window *window,
70 xcb_button_press_event_t *ev ) {
72 if( !pointer_demux ) {
73 /* Initiate grab. */
74 pointer_demux = window->w;
76 set_button_active( window, TRUE );
79 if( ( window->u.button.frame->u.frame.child->u.managed.protocols &
80 PROTOCOL_DELETE_WINDOW ) && ( ev->detail == 3 ||
81 ( ev->state & XCB_BUTTON_MASK_3 ) ) )
82 /* Button 3 will kill the client, even if it supports WM_DELETE_WINDOW.
83 Change to CURSOR_DESTROY to indicate the distinction. */
84 xcb_change_active_pointer_grab( c, cursors[ CURSOR_DESTROY ],
85 ev->time, XCB_EVENT_MASK_BUTTON_PRESS |
86 XCB_EVENT_MASK_BUTTON_RELEASE |
87 XCB_EVENT_MASK_ENTER_WINDOW |
88 XCB_EVENT_MASK_LEAVE_WINDOW );
91 static void button_button_release( struct gwm_window *window,
92 xcb_button_release_event_t *ev ) {
94 if( !pointer_demux )
95 return;
97 if( final_release( ev ) ) {
98 /* Final button released; grab terminates. */
99 if( button_active ) {
100 if( ev->detail == 3 || !( window->u.button.frame->u.frame.child->
101 u.managed.protocols &
102 PROTOCOL_DELETE_WINDOW ) )
103 xcb_kill_client( c, window->u.button.frame->u.frame.child->w );
104 else {
105 xcb_client_message_event_t msg;
106 struct gwm_window *frame = window->u.button.frame;
108 msg.response_type = XCB_CLIENT_MESSAGE;
109 msg.format = 32;
110 msg.sequence = 0;
111 msg.window = frame->u.frame.child->w;
112 msg.type = atoms[ ATOM_WM_PROTOCOLS ];
113 msg.data.data32[ 0 ] = atoms[ ATOM_WM_DELETE_WINDOW ];
114 msg.data.data32[ 1 ] = ev->time;
115 msg.data.data32[ 2 ] = 0;
116 msg.data.data32[ 3 ] = 0;
117 msg.data.data32[ 4 ] = 0;
119 xcb_send_event( c, FALSE, frame->u.frame.child->w, 0,
120 (char *) &msg );
123 set_button_active( window, FALSE );
126 pointer_demux = XCB_NONE;
127 } else if( ev->detail == 3 && ( window->u.button.frame->u.frame.child->
128 u.managed.protocols &
129 PROTOCOL_DELETE_WINDOW ) )
130 /* Button 3 released; we'll no longer kill the client. Remove
131 the temporary CURSOR_DESTROY. */
132 xcb_change_active_pointer_grab( c, XCB_NONE, ev->time,
133 XCB_EVENT_MASK_BUTTON_PRESS |
134 XCB_EVENT_MASK_BUTTON_RELEASE |
135 XCB_EVENT_MASK_ENTER_WINDOW |
136 XCB_EVENT_MASK_LEAVE_WINDOW );
139 static void button_enter_notify( struct gwm_window *window,
140 xcb_enter_notify_event_t *ev ) {
142 if( !pointer_demux )
143 return;
145 if( ev->event == window->w )
146 set_button_active( window, TRUE );
149 static void button_leave_notify( struct gwm_window *window,
150 xcb_leave_notify_event_t *ev ) {
152 if( !pointer_demux )
153 return;
155 if( ev->event == window->w )
156 set_button_active( window, FALSE );
159 const event_handler button_handlers[ NUM_EXTENDED_EVENTS ] = {
160 NULL, /* Error */
161 NULL, /* Reply */
162 NULL, /* KeyPress */
163 NULL, /* KeyRelease */
164 (event_handler) button_button_press,
165 (event_handler) button_button_release,
166 NULL, /* MotionNotify */
167 (event_handler) button_enter_notify,
168 (event_handler) button_leave_notify,
169 NULL, /* FocusIn */
170 NULL, /* FocusOut */
171 NULL, /* KeymapNotify */
172 NULL, /* Expose */
173 NULL, /* GraphicsExpose */
174 NULL, /* NoExposure */
175 NULL, /* VisibilityNotify */
176 NULL, /* CreateNotify */
177 NULL, /* DestroyNotify */
178 NULL, /* UnmapNotify */
179 NULL, /* MapNotify */
180 NULL, /* MapRequest */
181 NULL, /* ReparentNotify */
182 NULL, /* ConfigureNotify */
183 NULL, /* ConfigureRequest */
184 NULL, /* GravityNotify */
185 NULL, /* ResizeRequest */
186 NULL, /* CirculateNotify */
187 NULL, /* CirculateRequest */
188 NULL, /* PropertyNotify */
189 NULL, /* SelectionClear */
190 NULL, /* SelectionRequest */
191 NULL, /* SelectionNotify */
192 NULL, /* ColormapNotify */
193 NULL, /* ClientMessage */
194 NULL, /* MappingNotify */
195 NULL, /* (synthetic) */
196 NULL, /* RRScreenChangeNotify */
197 NULL /* ShapeNotify */