]> git.lizzy.rs Git - bspwm.git/blob - window.c
Fix hang related to SIGCHLD
[bspwm.git] / window.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <string.h>
5 #include <xcb/xcb.h>
6 #include <xcb/xcb_event.h>
7 #include "helpers.h"
8 #include "types.h"
9 #include "tree.h"
10 #include "bspwm.h"
11 #include "settings.h"
12 #include "ewmh.h"
13 #include "window.h"
14
15 #define p_clear(p, count)       ((void)memset((p), 0, sizeof(*(p)) * (count)))
16
17 bool locate_window(xcb_window_t win, window_location_t *loc)
18 {
19     node_t *n;
20     desktop_t *d = desk_head;
21
22     if (d == NULL)
23         return false;
24
25     while (d != NULL) {
26         n = first_extrema(d->root);
27         while (n != NULL) {
28             if (n->client->window == win) {
29                 loc->desktop = d;
30                 loc->node = n;
31                 return true;
32             }
33             n = next_leaf(n);
34         }
35         d = d->next;
36     }
37
38     return false;
39 }
40
41 void draw_triple_border(node_t *n, uint32_t main_border_color_pxl)
42 {
43     if (n == NULL)
44         return;
45
46     if (border_width < 1)
47         return;
48
49     xcb_window_t win = n->client->window;
50     xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, win), NULL);
51
52     if (geom == NULL)
53         return;
54
55     uint16_t width = geom->width;
56     uint16_t height = geom->height;
57     uint8_t depth = geom->depth;
58
59     free(geom);
60
61     uint16_t full_width = width + 2 * border_width;
62     uint16_t full_height = height + 2 * border_width;
63
64     xcb_rectangle_t inner_rectangles[] =
65     {
66         { width, 0, 2 * border_width, height + 2 * border_width },
67         { 0, height, width + 2 * border_width, 2 * border_width }
68     };
69
70     xcb_rectangle_t main_rectangles[] =
71     {
72         { width + inner_border_width, 0, 2 * (main_border_width + outer_border_width), height + 2 * border_width },
73         { 0, height + inner_border_width, width + 2 * border_width, 2 * (main_border_width + outer_border_width) }
74     };
75
76     xcb_rectangle_t outer_rectangles[] =
77     {
78         { width + inner_border_width + main_border_width, 0, 2 * outer_border_width, height + 2 * border_width },
79         { 0, height + inner_border_width + main_border_width, width + 2 * border_width, 2 * outer_border_width }
80     };
81
82     xcb_rectangle_t *presel_rectangles;
83
84     xcb_pixmap_t pix = xcb_generate_id(dpy);
85     xcb_create_pixmap(dpy, depth, pix, win, full_width, full_height);
86
87     xcb_gcontext_t gc = xcb_generate_id(dpy);
88     xcb_create_gc(dpy, gc, pix, 0, NULL);
89
90     /* inner border */
91     if (inner_border_width > 0) {
92         xcb_change_gc(dpy, gc, XCB_GC_FOREGROUND, &inner_border_color_pxl);
93         xcb_poly_fill_rectangle(dpy, pix, gc, LENGTH(inner_rectangles), inner_rectangles);
94     }
95
96     /* main border */
97     if (main_border_width > 0) {
98         xcb_change_gc(dpy, gc, XCB_GC_FOREGROUND, &main_border_color_pxl);
99         xcb_poly_fill_rectangle(dpy, pix, gc, LENGTH(main_rectangles), main_rectangles);
100     }
101
102     /* outer border */
103     if (outer_border_width > 0) {
104         xcb_change_gc(dpy, gc, XCB_GC_FOREGROUND, &outer_border_color_pxl);
105         xcb_poly_fill_rectangle(dpy, pix, gc, LENGTH(outer_rectangles), outer_rectangles);
106     }
107
108     if (split_mode == MODE_MANUAL && main_border_color_pxl == active_border_color_pxl) {
109         uint16_t fence = (int16_t) (n->split_ratio * ((split_dir == DIR_UP || split_dir == DIR_DOWN) ? height : width));
110         presel_rectangles = malloc(2 * sizeof(xcb_rectangle_t));
111         switch (split_dir) {
112             case DIR_UP:
113                 presel_rectangles[0] = (xcb_rectangle_t) {width, 0, 2 * border_width, fence};
114                 presel_rectangles[1] = (xcb_rectangle_t) {0, height + border_width, full_width, border_width};
115                 break;
116             case DIR_DOWN:
117                 presel_rectangles[0] = (xcb_rectangle_t) {width, fence + 1, 2 * border_width, height + border_width - (fence + 1)};
118                 presel_rectangles[1] = (xcb_rectangle_t) {0, height, full_width, border_width};
119                 break;
120             case DIR_LEFT:
121                 presel_rectangles[0] = (xcb_rectangle_t) {0, height, fence, 2 * border_width};
122                 presel_rectangles[1] = (xcb_rectangle_t) {width + border_width, 0, border_width, full_height};
123                 break;
124             case DIR_RIGHT:
125                 presel_rectangles[0] = (xcb_rectangle_t) {fence + 1, height, width + border_width - (fence + 1), 2 * border_width};
126                 presel_rectangles[1] = (xcb_rectangle_t) {width, 0, border_width, full_height};
127                 break;
128         }
129         xcb_change_gc(dpy, gc, XCB_GC_FOREGROUND, &presel_border_color_pxl);
130         xcb_poly_fill_rectangle(dpy, pix, gc, 2, presel_rectangles);
131         free(presel_rectangles);
132     }
133
134     /* apply border pixmap */
135     xcb_change_window_attributes(dpy, win, XCB_CW_BORDER_PIXMAP, &pix);
136
137     xcb_free_gc(dpy, gc);
138     xcb_free_pixmap(dpy, pix);
139 }
140
141 void close_window(desktop_t *d, node_t *n)
142 {
143     if (n == NULL || n->client->locked)
144         return;
145
146     PUTS("close window\n");
147
148     xcb_atom_t WM_DELETE_WINDOW;
149     xcb_window_t win = n->client->window;
150     xcb_client_message_event_t e;
151
152     xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(dpy, xcb_intern_atom(dpy, 0, strlen("WM_DELETE_WINDOW"), "WM_DELETE_WINDOW"), NULL);
153     if (reply) {
154         WM_DELETE_WINDOW = reply->atom;
155         free(reply);
156     } else {
157         PUTS("could not acquire WM_DELETE_WINDOW atom\n");
158         return;
159     }
160
161     e.response_type = XCB_CLIENT_MESSAGE;
162     e.window = win;
163     e.format = 32;
164     e.sequence = 0;
165     e.type = ewmh->WM_PROTOCOLS;
166     e.data.data32[0] = WM_DELETE_WINDOW;
167     e.data.data32[1] = XCB_CURRENT_TIME;
168
169     xcb_send_event(dpy, false, win, XCB_EVENT_MASK_NO_EVENT, (char *) &e);
170     remove_node(d, n);
171 }
172
173 void toggle_fullscreen(client_t *c)
174 {
175     if (c->fullscreen) {
176         c->fullscreen = false;
177         xcb_atom_t values[] = {XCB_NONE};
178         xcb_ewmh_set_wm_state(ewmh, c->window, LENGTH(values), values);
179         xcb_rectangle_t rect = c->rectangle;
180         window_border_width(c->window, border_width);
181         window_move_resize(c->window, rect.x, rect.y, rect.width, rect.height);
182     } else {
183         c->fullscreen = true;
184         xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, c->window), NULL);
185         if (geom != NULL) {
186             c->rectangle = (xcb_rectangle_t) {geom->x, geom->y, geom->width, geom->height};
187             free(geom);
188         }
189         xcb_atom_t values[] = {ewmh->_NET_WM_STATE_FULLSCREEN};
190         xcb_ewmh_set_wm_state(ewmh, c->window, LENGTH(values), values);
191         window_raise(c->window);
192         window_border_width(c->window, 0);
193         window_move_resize(c->window, 0, 0, screen_width, screen_height);
194     }
195 }
196
197 void list_windows(char *rsp)
198 {
199     char line[MAXLEN];
200
201     desktop_t *d = desk_head;
202
203     while (d != NULL) {
204         node_t *n = first_extrema(d->root);
205         while (n != NULL) {
206             sprintf(line, "0x%X\n", n->client->window);
207             strcat(rsp, line);
208             n = next_leaf(n);
209         }
210         d = d->next;
211     }
212 }
213
214 void window_border_width(xcb_window_t win, uint32_t bw)
215 {
216     uint32_t values[] = {bw};
217     xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_BORDER_WIDTH, values);
218 }
219
220 void window_move_resize(xcb_window_t win, int16_t x, int16_t y, uint16_t w, uint16_t h)
221 {
222     uint32_t values[] = {x, y, w, h};
223     xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_X_Y_WIDTH_HEIGHT, values);
224 }
225
226 void window_raise(xcb_window_t win)
227 {
228     uint32_t values[] = {XCB_STACK_MODE_ABOVE};
229     xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_STACK_MODE, values);
230 }