]> git.lizzy.rs Git - bspwm.git/blob - events.c
5d221fce426239041c306f1d5307c2d26ce55d07
[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\n");
22             map_request(evt);
23             break;
24         case XCB_DESTROY_NOTIFY:
25             PUTS("destroy notify\n");
26             destroy_notify(evt);
27             break;
28         case XCB_UNMAP_NOTIFY:
29             PUTS("unmap notify\n");
30             unmap_notify(evt);
31             break;
32         case XCB_CLIENT_MESSAGE:
33             PUTS("client message\n");
34             client_message(evt);
35             break;
36         case XCB_CONFIGURE_REQUEST:
37             PUTS("configure request\n");
38             configure_request(evt);
39             break;
40         case XCB_BUTTON_PRESS:
41             PUTS("button press\n");
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, takes_focus = true;
74
75     handle_rules(win, &floating, &transient, &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     c->transient = transient;
91
92     if (takes_focus)
93         focus_node(desk, birth, false);
94
95     apply_layout(desk, desk->root, root_rect);
96
97     xcb_map_window(dpy, c->window);
98     xcb_flush(dpy);
99     xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, win, XCB_CURRENT_TIME);
100 }
101
102 void configure_request(xcb_generic_event_t *evt)
103 {
104     xcb_configure_request_event_t *e = (xcb_configure_request_event_t *) evt;
105     window_location_t loc;
106     bool is_managed = locate_window(e->window, &loc);
107
108     if (!is_managed || (is_managed && !is_tiled(loc.node->client))) {
109         uint16_t mask = 0;
110         uint32_t values[7];
111         unsigned short i = 0;
112
113         if (e->value_mask & XCB_CONFIG_WINDOW_X) {
114             mask |= XCB_CONFIG_WINDOW_X;
115             values[i++] = e->x;
116             if (is_managed)
117                 loc.node->client->rectangle.x = e->x;
118         }
119
120         if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
121             mask |= XCB_CONFIG_WINDOW_Y;
122             values[i++] = e->y;
123             if (is_managed)
124                 loc.node->client->rectangle.y = e->y;
125         }
126
127         if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
128             mask |= XCB_CONFIG_WINDOW_WIDTH;
129             values[i++] = e->width;
130             if (is_managed)
131                 loc.node->client->rectangle.width = e->width;
132         }
133
134         if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
135             mask |= XCB_CONFIG_WINDOW_HEIGHT;
136             values[i++] = e->height;
137             if (is_managed)
138                 loc.node->client->rectangle.height = e->height;
139         }
140
141         if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) {
142             mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
143             values[i++] = e->border_width;
144         }
145
146         if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
147             mask |= XCB_CONFIG_WINDOW_SIBLING;
148             values[i++] = e->sibling;
149         }
150
151         if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
152             mask |= XCB_CONFIG_WINDOW_STACK_MODE;
153             values[i++] = e->stack_mode;
154         }
155
156         xcb_configure_window(dpy, e->window, mask, values);
157     }
158
159     if (is_managed && is_floating(loc.node->client))
160         apply_layout(loc.desktop, loc.node, root_rect);
161 }
162
163 void destroy_notify(xcb_generic_event_t *evt)
164 {
165     xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *) evt;
166     window_location_t loc;
167
168     if (locate_window(e->window, &loc)) {
169         remove_node(loc.desktop, loc.node);
170         apply_layout(loc.desktop, loc.desktop->root, root_rect);
171     }
172 }
173
174 void unmap_notify(xcb_generic_event_t *evt)
175 {
176     xcb_unmap_notify_event_t *e = (xcb_unmap_notify_event_t *) evt;
177     if (e->event != screen->root) {
178         window_location_t loc;
179         if (locate_window(e->window, &loc)) {
180             remove_node(loc.desktop, loc.node);
181             apply_layout(loc.desktop, loc.desktop->root, root_rect);
182         }
183     }
184 }
185
186 void client_message(xcb_generic_event_t *evt)
187 {
188     xcb_client_message_event_t *e = (xcb_client_message_event_t *) evt;
189     window_location_t loc;
190
191     if (!locate_window(e->window, &loc))
192         return;
193
194     if (e->type == ewmh->_NET_WM_STATE) {
195         handle_state(loc.node, e->data.data32[1], e->data.data32[0]);
196         handle_state(loc.node, e->data.data32[2], e->data.data32[0]);
197     } else if (e->type == ewmh->_NET_ACTIVE_WINDOW) {
198         focus_node(loc.desktop, loc.node, true);
199     }
200 }
201
202 void handle_state(node_t *n, xcb_atom_t state, unsigned int action)
203 {
204     if (state == ewmh->_NET_WM_STATE_FULLSCREEN) {
205         bool fs = n->client->fullscreen;
206         if (action == XCB_EWMH_WM_STATE_TOGGLE
207                 || (fs && action == XCB_EWMH_WM_STATE_REMOVE)
208                 || (!fs && action == XCB_EWMH_WM_STATE_ADD))
209             toggle_fullscreen(n->client);
210     }
211 }