]> git.lizzy.rs Git - bspwm.git/blob - types.c
New setting: `history_aware_focus`
[bspwm.git] / types.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <xcb/xcb.h>
4 #include <xcb/xcb_event.h>
5 #include "bspwm.h"
6 #include "window.h"
7 #include "rules.h"
8 #include "ewmh.h"
9 #include "settings.h"
10 #include "types.h"
11 #include "tree.h"
12
13 node_t *make_node(void)
14 {
15     node_t *n = malloc(sizeof(node_t));
16     n->parent = n->first_child = n->second_child = NULL;
17     n->split_ratio = split_ratio;
18     n->split_type = TYPE_VERTICAL;
19     n->birth_rotation = ROTATE_IDENTITY;
20     n->client = NULL;
21     n->vacant = false;
22     return n;
23 }
24
25 monitor_t *make_monitor(xcb_rectangle_t *rect)
26 {
27     monitor_t *m = malloc(sizeof(monitor_t));
28     snprintf(m->name, sizeof(m->name), "%s%02d", DEFAULT_MON_NAME, ++monitor_uid);
29     m->prev = m->next = NULL;
30     m->desk = m->last_desk = NULL;
31     if (rect != NULL)
32         m->rectangle = *rect;
33     else
34         warn("no rectangle was given for monitor '%s'\n", m->name);
35     m->top_padding = m->right_padding = m->bottom_padding = m->left_padding = 0;
36     m->wired = true;
37     return m;
38 }
39
40 monitor_t *find_monitor(char *name)
41 {
42     for (monitor_t *m = mon_head; m != NULL; m = m->next)
43         if (strcmp(m->name, name) == 0)
44             return m;
45     return NULL;
46 }
47
48 monitor_t *get_monitor_by_id(xcb_randr_output_t id)
49 {
50     for (monitor_t *m = mon_head; m != NULL; m = m->next)
51         if (m->id == id)
52             return m;
53     return NULL;
54 }
55
56 monitor_t *add_monitor(xcb_rectangle_t *rect)
57 {
58     monitor_t *m = make_monitor(rect);
59     if (mon == NULL) {
60         mon = m;
61         mon_head = m;
62         mon_tail = m;
63     } else {
64         mon_tail->next = m;
65         m->prev = mon_tail;
66         mon_tail = m;
67     }
68     num_monitors++;
69     return m;
70 }
71
72 void remove_monitor(monitor_t *m)
73 {
74     while (m->desk_head != NULL)
75         remove_desktop(m, m->desk_head);
76     monitor_t *prev = m->prev;
77     monitor_t *next = m->next;
78     if (prev != NULL)
79         prev->next = next;
80     if (next != NULL)
81         next->prev = prev;
82     if (mon_head == m)
83         mon_head = next;
84     if (mon_tail == m)
85         mon_tail = prev;
86     if (last_mon == m)
87         last_mon = NULL;
88     if (mon == m) {
89         monitor_t *mm = (last_mon == NULL ? (prev == NULL ? next : prev) : last_mon);
90         if (mm != NULL) {
91             focus_node(mm, mm->desk, mm->desk->focus);
92             last_mon = NULL;
93         } else {
94             mon = NULL;
95         }
96     }
97     free(m);
98     num_monitors--;
99     put_status();
100 }
101
102 void transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d)
103 {
104     desktop_t *dd = ms->desk;
105     unlink_desktop(ms, d);
106     insert_desktop(md, d);
107     if (d == dd) {
108         if (ms->desk != NULL)
109             desktop_show(ms->desk);
110         if (md->desk != d)
111             desktop_hide(d);
112     }
113     for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
114         fit_monitor(md, n->client);
115     arrange(md, d);
116     if (d != dd && md->desk == d) {
117         desktop_show(d);
118     }
119     put_status();
120     ewmh_update_desktop_names();
121 }
122
123 void merge_monitors(monitor_t *ms, monitor_t *md)
124 {
125     PRINTF("merge %s into %s\n", ms->name, md->name);
126
127     desktop_t *d = ms->desk_head;
128     while (d != NULL) {
129         desktop_t *next = d->next;
130         transfer_desktop(ms, md, d);
131         d = next;
132     }
133 }
134
135 desktop_t *make_desktop(const char *name)
136 {
137     desktop_t *d = malloc(sizeof(desktop_t));
138     if (name == NULL)
139         snprintf(d->name, sizeof(d->name), "%s%02d", DEFAULT_DESK_NAME, ++desktop_uid);
140     else
141         strncpy(d->name, name, sizeof(d->name));
142     d->layout = LAYOUT_TILED;
143     d->prev = d->next = NULL;
144     d->root = d->focus = NULL;
145     d->history = make_focus_history();
146     return d;
147 }
148
149 void insert_desktop(monitor_t *m, desktop_t *d)
150 {
151     if (m->desk == NULL) {
152         m->desk = d;
153         m->desk_head = d;
154         m->desk_tail = d;
155     } else {
156         m->desk_tail->next = d;
157         d->prev = m->desk_tail;
158         m->desk_tail = d;
159     }
160 }
161
162 void add_desktop(monitor_t *m, desktop_t *d)
163 {
164     PRINTF("add desktop %s\n", d->name);
165
166     insert_desktop(m, d);
167     num_desktops++;
168     ewmh_update_number_of_desktops();
169     ewmh_update_desktop_names();
170     put_status();
171 }
172
173 void empty_desktop(desktop_t *d)
174 {
175     destroy_tree(d->root);
176     d->root = d->focus = NULL;
177     empty_history(d->history);
178 }
179
180 void unlink_desktop(monitor_t *m, desktop_t *d)
181 {
182     desktop_t *prev = d->prev;
183     desktop_t *next = d->next;
184     if (prev != NULL)
185         prev->next = next;
186     if (next != NULL)
187         next->prev = prev;
188     if (m->desk_head == d)
189         m->desk_head = next;
190     if (m->desk_tail == d)
191         m->desk_tail = prev;
192     if (m->last_desk == d)
193         m->last_desk = NULL;
194     if (m->desk == d)
195         m->desk = (m->last_desk == NULL ? (prev == NULL ? next : prev) : m->last_desk);
196     d->prev = d->next = NULL;
197 }
198
199 void remove_desktop(monitor_t *m, desktop_t *d)
200 {
201     PRINTF("remove desktop %s\n", d->name);
202
203     prune_rules(d);
204     unlink_desktop(m, d);
205     empty_desktop(d);
206     free(d);
207     num_desktops--;
208     ewmh_update_number_of_desktops();
209     ewmh_update_desktop_names();
210     put_status();
211 }
212
213 client_t *make_client(xcb_window_t win)
214 {
215     client_t *c = malloc(sizeof(client_t));
216     strncpy(c->class_name, MISSING_VALUE, sizeof(c->class_name));
217     c->uid = ++client_uid;
218     c->border_width = border_width;
219     c->window = win;
220     c->floating = c->transient = c->fullscreen = c->locked = c->urgent = false;
221     return c;
222 }
223
224 rule_t *make_rule(void)
225 {
226     rule_t *r = malloc(sizeof(rule_t));
227     r->uid = ++rule_uid;
228     r->effect.floating = false;
229     r->effect.follow = false;
230     r->effect.monitor = NULL;
231     r->effect.desktop = NULL;
232     r->prev = NULL;
233     r->next = NULL;
234     return r;
235 }
236
237 pointer_state_t *make_pointer_state(void)
238 {
239     pointer_state_t *p = malloc(sizeof(pointer_state_t));
240     p->monitor = NULL;
241     p->desktop = NULL;
242     p->node = p->vertical_fence = p->horizontal_fence = NULL;
243     p->client = NULL;
244     p->window = XCB_NONE;
245     return p;
246 }
247
248 focus_history_t *make_focus_history(void)
249 {
250     focus_history_t *f = malloc(sizeof(focus_history_t));
251     f->head = f->tail = NULL;
252     return f;
253 }
254
255 node_list_t *make_node_list(void)
256 {
257     node_list_t *n = malloc(sizeof(node_list_t));
258     n->node = NULL;
259     n->prev = n->next = NULL;
260     n->latest = true;
261     return n;
262 }
263
264 void history_add(focus_history_t *f, node_t *n)
265 {
266     node_list_t *a = make_node_list();
267     a->node = n;
268     if (f->head == NULL) {
269         f->head = f->tail = a;
270     } else if (f->head->node != n) {
271         for (node_list_t *b = f->head; b != NULL; b = b->next)
272             if (b->node == n)
273                 b->latest = false;
274         f->head->prev = a;
275         a->next = f->head;
276         f->head = a;
277     } else {
278         free(a);
279     }
280 }
281
282 void history_remove(focus_history_t *f, node_t *n)
283 {
284     /* in order to maintain the `latest` node list state,
285        we remove node lists from head to tail */
286     node_list_t *b = f->head;
287     while (b != NULL) {
288         if (b->node == n) {
289             node_list_t *a = b->prev;
290             node_list_t *c = b->next;
291             if (a != NULL) {
292                 /* remove duplicate entries */
293                 while (c != NULL && c->node == a->node) {
294                     node_list_t *d = c->next;
295                     if (f->tail == c)
296                         f->tail = f->head;
297                     free(c);
298                     c = d;
299                 }
300                 a->next = c;
301             }
302             if (c != NULL)
303                 c->prev = a;
304             if (f->head == b)
305                 f->head = c;
306             if (f->tail == b)
307                 f->tail = a;
308             free(b);
309             b = c;
310         } else {
311             b = b->next;
312         }
313     }
314 }
315
316 void empty_history(focus_history_t *f)
317 {
318     node_list_t *a = f->head;
319     while (a != NULL) {
320         node_list_t *b = a->next;
321         free(a);
322         a = b;
323     }
324     f->head = f->tail = NULL;
325 }
326
327 node_t *history_get(focus_history_t *f, int i)
328 {
329     node_list_t *a = f->head;
330     while (a != NULL && i > 0) {
331         a = a->next;
332         i--;
333     }
334     if (a == NULL)
335         return NULL;
336     else
337         return a->node;
338 }
339
340 int history_rank(focus_history_t *f, node_t *n)
341 {
342     int i = 0;
343     node_list_t *a = f->head;
344     while (a != NULL && (!a->latest || a->node != n)) {
345         a = a->next;
346         i++;
347     }
348     if (a == NULL)
349         return -1;
350     else
351         return i;
352 }