]> git.lizzy.rs Git - bspwm.git/blob - monitor.c
Remove a few useless header inclusion via deheader
[bspwm.git] / monitor.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include "bspwm.h"
4 #include "tree.h"
5 #include "monitor.h"
6 #include "desktop.h"
7 #include "window.h"
8 #include "ewmh.h"
9
10 monitor_t *make_monitor(xcb_rectangle_t rect)
11 {
12     monitor_t *m = malloc(sizeof(monitor_t));
13     snprintf(m->name, sizeof(m->name), "%s%02d", DEFAULT_MON_NAME, ++monitor_uid);
14     m->prev = m->next = NULL;
15     m->desk = m->last_desk = NULL;
16     m->rectangle = rect;
17     m->top_padding = m->right_padding = m->bottom_padding = m->left_padding = 0;
18     m->wired = true;
19     return m;
20 }
21
22 monitor_t *find_monitor(char *name)
23 {
24     for (monitor_t *m = mon_head; m != NULL; m = m->next)
25         if (streq(m->name, name))
26             return m;
27     return NULL;
28 }
29
30 monitor_t *get_monitor_by_id(xcb_randr_output_t id)
31 {
32     for (monitor_t *m = mon_head; m != NULL; m = m->next)
33         if (m->id == id)
34             return m;
35     return NULL;
36 }
37
38 monitor_t *add_monitor(xcb_rectangle_t rect)
39 {
40     monitor_t *m = make_monitor(rect);
41     if (mon == NULL) {
42         mon = m;
43         mon_head = m;
44         mon_tail = m;
45     } else {
46         mon_tail->next = m;
47         m->prev = mon_tail;
48         mon_tail = m;
49     }
50     num_monitors++;
51     return m;
52 }
53
54 void remove_monitor(monitor_t *m)
55 {
56     while (m->desk_head != NULL)
57         remove_desktop(m, m->desk_head);
58     monitor_t *prev = m->prev;
59     monitor_t *next = m->next;
60     if (prev != NULL)
61         prev->next = next;
62     if (next != NULL)
63         next->prev = prev;
64     if (mon_head == m)
65         mon_head = next;
66     if (mon_tail == m)
67         mon_tail = prev;
68     if (last_mon == m)
69         last_mon = NULL;
70     if (pri_mon == m)
71         pri_mon = NULL;
72     if (mon == m) {
73         monitor_t *mm = (last_mon == NULL ? (prev == NULL ? next : prev) : last_mon);
74         if (mm != NULL) {
75             focus_node(mm, mm->desk, mm->desk->focus);
76             last_mon = NULL;
77         } else {
78             mon = NULL;
79         }
80     }
81     free(m);
82     num_monitors--;
83     put_status();
84 }
85
86 void merge_monitors(monitor_t *ms, monitor_t *md)
87 {
88     PRINTF("merge %s into %s\n", ms->name, md->name);
89
90     desktop_t *d = ms->desk_head;
91     while (d != NULL) {
92         desktop_t *next = d->next;
93         transfer_desktop(ms, md, d);
94         d = next;
95     }
96 }
97
98 void swap_monitors(monitor_t *m1, monitor_t *m2)
99 {
100     if (m1 == NULL || m2 == NULL || m1 == m2)
101         return;
102
103     if (mon_head == m1)
104         mon_head = m2;
105     else if (mon_head == m2)
106         mon_head = m1;
107     if (mon_tail == m1)
108         mon_tail = m2;
109     else if (mon_tail == m2)
110         mon_tail = m1;
111
112     monitor_t *p1 = m1->prev;
113     monitor_t *n1 = m1->next;
114     monitor_t *p2 = m2->prev;
115     monitor_t *n2 = m2->next;
116
117     if (p1 != NULL && p1 != m2)
118         p1->next = m2;
119     if (n1 != NULL && n1 != m2)
120         n1->prev = m2;
121     if (p2 != NULL && p2 != m1)
122         p2->next = m1;
123     if (n2 != NULL && n2 != m1)
124         n2->prev = m1;
125
126     m1->prev = p2 == m1 ? m2 : p2;
127     m1->next = n2 == m1 ? m2 : n2;
128     m2->prev = p1 == m2 ? m1 : p1;
129     m2->next = n1 == m2 ? m1 : n1;
130
131     ewmh_update_wm_desktops();
132     ewmh_update_desktop_names();
133     ewmh_update_current_desktop();
134     put_status();
135 }
136
137 bool import_monitors(void)
138 {
139     PUTS("import monitors");
140     xcb_randr_get_screen_resources_current_reply_t *sres = xcb_randr_get_screen_resources_current_reply(dpy, xcb_randr_get_screen_resources_current(dpy, root), NULL);
141     if (sres == NULL)
142         return false;
143
144     int len = xcb_randr_get_screen_resources_current_outputs_length(sres);
145     xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(sres);
146
147     xcb_randr_get_output_info_cookie_t cookies[len];
148     for (int i = 0; i < len; i++)
149         cookies[i] = xcb_randr_get_output_info(dpy, outputs[i], XCB_CURRENT_TIME);
150
151     for (monitor_t *m = mon_head; m != NULL; m = m->next)
152         m->wired = false;
153
154     monitor_t *mm = NULL;
155     unsigned int num = 0;
156
157     for (int i = 0; i < len; i++) {
158         xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(dpy, cookies[i], NULL);
159         if (info != NULL && info->crtc != XCB_NONE) {
160
161             xcb_randr_get_crtc_info_reply_t *cir = xcb_randr_get_crtc_info_reply(dpy, xcb_randr_get_crtc_info(dpy, info->crtc, XCB_CURRENT_TIME), NULL);
162             if (cir != NULL) {
163                 xcb_rectangle_t rect = (xcb_rectangle_t) {cir->x, cir->y, cir->width, cir->height};
164                 mm = get_monitor_by_id(outputs[i]);
165                 if (mm != NULL) {
166                     mm->rectangle = rect;
167                     for (desktop_t *d = mm->desk_head; d != NULL; d = d->next)
168                         for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
169                             fit_monitor(mm, n->client);
170                     arrange(mm, mm->desk);
171                     mm->wired = true;
172                     PRINTF("update monitor %s (0x%X)\n", mm->name, mm->id);
173                 } else {
174                     mm = add_monitor(rect);
175                     char *name = (char *)xcb_randr_get_output_info_name(info);
176                     size_t name_len = MIN(sizeof(mm->name), (size_t)xcb_randr_get_output_info_name_length(info));
177                     strncpy(mm->name, name, name_len);
178                     mm->name[name_len] = '\0';
179                     mm->id = outputs[i];
180                     PRINTF("add monitor %s (0x%X)\n", mm->name, mm->id);
181                 }
182                 num++;
183             }
184             free(cir);
185         }
186         free(info);
187     }
188
189     /* initially focus the primary monitor and add the first desktop to it */
190     xcb_randr_get_output_primary_reply_t *gpo = xcb_randr_get_output_primary_reply(dpy, xcb_randr_get_output_primary(dpy, root), NULL);
191     if (gpo != NULL) {
192         pri_mon = get_monitor_by_id(gpo->output);
193         if (!running && pri_mon != NULL) {
194             if (mon != pri_mon)
195                 mon = pri_mon;
196             add_desktop(pri_mon, make_desktop(NULL));
197             ewmh_update_current_desktop();
198         }
199     }
200     free(gpo);
201
202     /* add one desktop to each new monitor */
203     for (monitor_t *m = mon_head; m != NULL; m = m->next)
204         if (m->desk == NULL && (running || pri_mon == NULL || m != pri_mon))
205             add_desktop(m, make_desktop(NULL));
206
207     /* merge and remove disconnected monitors */
208     monitor_t *m = mon_head;
209     while (m != NULL) {
210         monitor_t *next = m->next;
211         if (!m->wired) {
212             PRINTF("remove monitor %s (0x%X)\n", m->name, m->id);
213             merge_monitors(m, mm);
214             remove_monitor(m);
215         }
216         m = next;
217     }
218
219     free(sres);
220     update_motion_recorder();
221     return (num_monitors > 0);
222 }