]> git.lizzy.rs Git - bspwm.git/blob - events.c
Fix "alternate" command, min width,height is 1,1
[bspwm.git] / events.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <xcb/xcb.h>
4 #include <xcb/xcb_icccm.h>
5 #include <xcb/xcb_event.h>
6 #include "helpers.h"
7 #include "types.h"
8 #include "bspwm.h"
9 #include "settings.h"
10 #include "utils.h"
11 #include "window.h"
12 #include "events.h"
13 #include "tree.h"
14 #include "rules.h"
15 #include "ewmh.h"
16
17 void handle_event(xcb_generic_event_t *evt)
18 {
19     switch (XCB_EVENT_RESPONSE_TYPE(evt)) {
20         case XCB_MAP_REQUEST:
21             PUTS("map request");
22             map_request(evt);
23             break;
24         case XCB_DESTROY_NOTIFY:
25             PUTS("destroy notify");
26             destroy_notify(evt);
27             break;
28         case XCB_UNMAP_NOTIFY:
29             PUTS("unmap notify");
30             unmap_notify(evt);
31             break;
32         case XCB_CLIENT_MESSAGE:
33             PUTS("client message");
34             client_message(evt);
35             break;
36         case XCB_CONFIGURE_REQUEST:
37             PUTS("configure request");
38             configure_request(evt);
39             break;
40         case XCB_BUTTON_PRESS:
41             PUTS("button press");
42             break;
43         default:
44             /* PRINTF("received event %i\n", XCB_EVENT_RESPONSE_TYPE(evt)); */
45             break;
46     }
47 }
48
49 void map_request(xcb_generic_event_t *evt)
50 {
51     xcb_map_request_event_t *e = (xcb_map_request_event_t *) evt;
52     xcb_get_window_attributes_reply_t  *wa;
53     xcb_window_t win = e->window;
54     window_location_t loc;
55     wa = xcb_get_window_attributes_reply(dpy, xcb_get_window_attributes(dpy, win), NULL);
56
57     if ((wa != NULL && wa->override_redirect) || locate_window(win, &loc))
58         return;
59
60     free(wa);
61
62     client_t *c = make_client(win);
63
64     xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, win), NULL);
65
66     if (geom) {
67         c->rectangle = (xcb_rectangle_t) {geom->x, geom->y, geom->width, geom->height};
68         free(geom);
69     } else {
70         c->rectangle = (xcb_rectangle_t) {0, 0, 320, 240};
71     }
72
73     bool floating = false, transient = false, fullscreen = false, takes_focus = true;
74
75     handle_rules(win, &floating, &transient, &fullscreen, &takes_focus);
76
77     if (c->transient)
78         floating = true;
79
80     node_t *birth = make_node();
81     birth->client = c;
82     insert_node(desk, birth);
83
84     if (floating)
85         toggle_floating(birth);
86
87     if (desk->focus != NULL && desk->focus->client->fullscreen)
88         toggle_fullscreen(desk->focus->client);
89
90     if (fullscreen)
91         toggle_fullscreen(birth->client);
92
93     c->transient = transient;
94
95     if (takes_focus)
96         focus_node(desk, birth, false);
97
98     apply_layout(desk, desk->root, root_rect);
99
100     xcb_map_window(dpy, c->window);
101     xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, win, XCB_CURRENT_TIME);
102
103     num_clients++;
104     ewmh_update_client_list();
105 }
106
107 void configure_request(xcb_generic_event_t *evt)
108 {
109     xcb_configure_request_event_t *e = (xcb_configure_request_event_t *) evt;
110     window_location_t loc;
111     bool is_managed = locate_window(e->window, &loc);
112
113     if (!is_managed || is_floating(loc.node->client)) {
114         uint16_t mask = 0;
115         uint32_t values[7];
116         unsigned short i = 0;
117
118         if (e->value_mask & XCB_CONFIG_WINDOW_X) {
119             mask |= XCB_CONFIG_WINDOW_X;
120             values[i++] = e->x;
121             if (is_managed)
122                 loc.node->client->rectangle.x = e->x;
123         }
124
125         if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
126             mask |= XCB_CONFIG_WINDOW_Y;
127             values[i++] = e->y;
128             if (is_managed)
129                 loc.node->client->rectangle.y = e->y;
130         }
131
132         if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
133             mask |= XCB_CONFIG_WINDOW_WIDTH;
134             values[i++] = e->width;
135             if (is_managed)
136                 loc.node->client->rectangle.width = e->width;
137         }
138
139         if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
140             mask |= XCB_CONFIG_WINDOW_HEIGHT;
141             values[i++] = e->height;
142             if (is_managed)
143                 loc.node->client->rectangle.height = e->height;
144         }
145
146         if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) {
147             mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
148             values[i++] = e->border_width;
149         }
150
151         if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
152             mask |= XCB_CONFIG_WINDOW_SIBLING;
153             values[i++] = e->sibling;
154         }
155
156         if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
157             mask |= XCB_CONFIG_WINDOW_STACK_MODE;
158             values[i++] = e->stack_mode;
159         }
160
161         xcb_configure_window(dpy, e->window, mask, values);
162     }
163
164     if (is_managed && is_floating(loc.node->client))
165         apply_layout(loc.desktop, loc.node, root_rect);
166 }
167
168 void destroy_notify(xcb_generic_event_t *evt)
169 {
170     xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *) evt;
171     window_location_t loc;
172
173     if (locate_window(e->window, &loc)) {
174         remove_node(loc.desktop, loc.node);
175         apply_layout(loc.desktop, loc.desktop->root, root_rect);
176     }
177 }
178
179 void unmap_notify(xcb_generic_event_t *evt)
180 {
181     xcb_unmap_notify_event_t *e = (xcb_unmap_notify_event_t *) evt;
182     if (e->event != screen->root) {
183         window_location_t loc;
184         if (locate_window(e->window, &loc)) {
185             remove_node(loc.desktop, loc.node);
186             apply_layout(loc.desktop, loc.desktop->root, root_rect);
187         }
188     }
189 }
190
191 void client_message(xcb_generic_event_t *evt)
192 {
193     xcb_client_message_event_t *e = (xcb_client_message_event_t *) evt;
194     window_location_t loc;
195
196     if (!locate_window(e->window, &loc))
197         return;
198
199     if (e->type == ewmh->_NET_WM_STATE) {
200         handle_state(loc.node, e->data.data32[1], e->data.data32[0]);
201         handle_state(loc.node, e->data.data32[2], e->data.data32[0]);
202     } else if (e->type == ewmh->_NET_ACTIVE_WINDOW) {
203         if (desk != loc.desktop)
204             select_desktop(loc.desktop);
205         focus_node(loc.desktop, loc.node, true);
206     }
207 }
208
209 void handle_state(node_t *n, xcb_atom_t state, unsigned int action)
210 {
211     if (state == ewmh->_NET_WM_STATE_FULLSCREEN) {
212         bool fs = n->client->fullscreen;
213         if (action == XCB_EWMH_WM_STATE_TOGGLE
214                 || (fs && action == XCB_EWMH_WM_STATE_REMOVE)
215                 || (!fs && action == XCB_EWMH_WM_STATE_ADD))
216             toggle_fullscreen(n->client);
217     }
218 }