13 monitor_t *make_monitor(xcb_rectangle_t rect)
15 monitor_t *m = malloc(sizeof(monitor_t));
16 snprintf(m->name, sizeof(m->name), "%s%02d", DEFAULT_MON_NAME, ++monitor_uid);
17 m->prev = m->next = NULL;
18 m->desk = m->last_desk = NULL;
20 m->top_padding = m->right_padding = m->bottom_padding = m->left_padding = 0;
25 monitor_t *find_monitor(char *name)
27 for (monitor_t *m = mon_head; m != NULL; m = m->next)
28 if (streq(m->name, name))
33 monitor_t *get_monitor_by_id(xcb_randr_output_t id)
35 for (monitor_t *m = mon_head; m != NULL; m = m->next)
41 void fit_monitor(monitor_t *m, client_t *c)
43 xcb_rectangle_t crect = c->floating_rectangle;
44 xcb_rectangle_t mrect = m->rectangle;
45 while (crect.x < mrect.x)
46 crect.x += mrect.width;
47 while (crect.x > (mrect.x + mrect.width - 1))
48 crect.x -= mrect.width;
49 while (crect.y < mrect.y)
50 crect.y += mrect.height;
51 while (crect.y > (mrect.y + mrect.height - 1))
52 crect.y -= mrect.height;
53 c->floating_rectangle = crect;
56 void select_monitor(monitor_t *m)
61 PRINTF("select monitor %s\n", m->name);
66 if (pointer_follows_monitor)
69 ewmh_update_current_desktop();
73 monitor_t *add_monitor(xcb_rectangle_t rect)
75 monitor_t *m = make_monitor(rect);
89 void remove_monitor(monitor_t *m)
91 PRINTF("remove monitor %s (0x%X)\n", m->name, m->id);
93 while (m->desk_head != NULL)
94 remove_desktop(m, m->desk_head);
95 monitor_t *prev = m->prev;
96 monitor_t *next = m->next;
110 monitor_t *mm = (last_mon == NULL ? (prev == NULL ? next : prev) : last_mon);
112 focus_node(mm, mm->desk, mm->desk->focus);
123 void merge_monitors(monitor_t *ms, monitor_t *md)
125 PRINTF("merge %s into %s\n", ms->name, md->name);
127 desktop_t *d = ms->desk_head;
129 desktop_t *next = d->next;
130 transfer_desktop(ms, md, d);
135 void swap_monitors(monitor_t *m1, monitor_t *m2)
137 if (m1 == NULL || m2 == NULL || m1 == m2)
142 else if (mon_head == m2)
146 else if (mon_tail == m2)
149 monitor_t *p1 = m1->prev;
150 monitor_t *n1 = m1->next;
151 monitor_t *p2 = m2->prev;
152 monitor_t *n2 = m2->next;
154 if (p1 != NULL && p1 != m2)
156 if (n1 != NULL && n1 != m2)
158 if (p2 != NULL && p2 != m1)
160 if (n2 != NULL && n2 != m1)
163 m1->prev = p2 == m1 ? m2 : p2;
164 m1->next = n2 == m1 ? m2 : n2;
165 m2->prev = p1 == m2 ? m1 : p1;
166 m2->next = n1 == m2 ? m1 : n1;
168 ewmh_update_wm_desktops();
169 ewmh_update_desktop_names();
170 ewmh_update_current_desktop();
174 monitor_t *closest_monitor(monitor_t *m, cycle_dir_t dir, desktop_select_t sel)
176 monitor_t *f = (dir == CYCLE_PREV ? m->prev : m->next);
178 f = (dir == CYCLE_PREV ? mon_tail : mon_head);
181 if (desktop_matches(f->desk, sel))
183 f = (dir == CYCLE_PREV ? m->prev : m->next);
185 f = (dir == CYCLE_PREV ? mon_tail : mon_head);
191 monitor_t *nearest_monitor(monitor_t *m, direction_t dir, desktop_select_t sel)
194 monitor_t *nearest = NULL;
195 xcb_rectangle_t rect = m->rectangle;
196 for (monitor_t *f = mon_head; f != NULL; f = f->next) {
199 if (!desktop_matches(f->desk, sel))
201 xcb_rectangle_t r = f->rectangle;
202 if ((dir == DIR_LEFT && r.x < rect.x) ||
203 (dir == DIR_RIGHT && r.x >= (rect.x + rect.width)) ||
204 (dir == DIR_UP && r.y < rect.y) ||
205 (dir == DIR_DOWN && r.y >= (rect.y + rect.height))) {
206 int d = abs((r.x + r.width / 2) - (rect.x + rect.width / 2)) +
207 abs((r.y + r.height / 2) - (rect.y + rect.height / 2));
217 bool import_monitors(void)
219 PUTS("import monitors");
220 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);
224 monitor_t *m, *mm = NULL;
225 unsigned int num = 0;
227 int len = xcb_randr_get_screen_resources_current_outputs_length(sres);
228 xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(sres);
230 xcb_randr_get_output_info_cookie_t cookies[len];
231 for (int i = 0; i < len; i++)
232 cookies[i] = xcb_randr_get_output_info(dpy, outputs[i], XCB_CURRENT_TIME);
234 for (m = mon_head; m != NULL; m = m->next)
237 for (int i = 0; i < len; i++) {
238 xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(dpy, cookies[i], NULL);
239 if (info != NULL && info->crtc != XCB_NONE) {
241 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);
243 xcb_rectangle_t rect = (xcb_rectangle_t) {cir->x, cir->y, cir->width, cir->height};
244 mm = get_monitor_by_id(outputs[i]);
246 mm->rectangle = rect;
247 for (desktop_t *d = mm->desk_head; d != NULL; d = d->next)
248 for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
249 fit_monitor(mm, n->client);
250 arrange(mm, mm->desk);
252 PRINTF("update monitor %s (0x%X)\n", mm->name, mm->id);
254 mm = add_monitor(rect);
255 char *name = (char *)xcb_randr_get_output_info_name(info);
256 size_t name_len = MIN(sizeof(mm->name), (size_t)xcb_randr_get_output_info_name_length(info));
257 snprintf(mm->name, name_len, "%s", name);
259 PRINTF("add monitor %s (0x%X)\n", mm->name, mm->id);
268 /* initially focus the primary monitor and add the first desktop to it */
269 xcb_randr_get_output_primary_reply_t *gpo = xcb_randr_get_output_primary_reply(dpy, xcb_randr_get_output_primary(dpy, root), NULL);
271 pri_mon = get_monitor_by_id(gpo->output);
272 if (!running && pri_mon != NULL) {
275 add_desktop(pri_mon, make_desktop(NULL));
276 ewmh_update_current_desktop();
281 /* handle overlapping monitors */
284 monitor_t *next = m->next;
286 for (monitor_t *mb = mon_head; mb != NULL; mb = mb->next)
287 if (mb != m && mb->wired && contains(mb->rectangle, m->rectangle)) {
290 merge_monitors(m, mb);
298 /* add one desktop to each new monitor */
299 for (m = mon_head; m != NULL; m = m->next)
300 if (m->desk == NULL && (running || pri_mon == NULL || m != pri_mon))
301 add_desktop(m, make_desktop(NULL));
303 /* merge and remove disconnected monitors */
306 monitor_t *next = m->next;
308 merge_monitors(m, mm);
315 update_motion_recorder();
316 return (num_monitors > 0);