From ba40a52c6e39f578828f629c3d5fdc64f7c82036 Mon Sep 17 00:00:00 2001 From: Michael Cardell Widerkrantz Date: Tue, 21 Jun 2011 08:05:12 +0200 Subject: arrangewindows() rewritten. We already know the geometry of windows since we track it all the time now. Only call arrangewindows() when root window changes geometry if we don't have RANDR. Otherwise, we call getrandr() when we get a XCB_RANDR_SCREEN_CHANGE_NOTIFY event. Added comments. When a monitor gets a new mode in an RANDR scenario, we track the x,y position and width,height. If we lose a monitor, we add the windows on that monitor to another monitor. --- mcwm.c | 240 ++++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 135 insertions(+), 105 deletions(-) (limited to 'mcwm.c') diff --git a/mcwm.c b/mcwm.c index 2f8afc2..5f1bdbf 100644 --- a/mcwm.c +++ b/mcwm.c @@ -277,7 +277,7 @@ xcb_atom_t wm_protocols; /* WM_PROTOCOLS. */ static void finishtabbing(void); static struct modkeycodes getmodkeys(xcb_mod_mask_t modmask); static void cleanup(int code); -static void arrangewindows(uint16_t rootwidth, uint16_t rootheight); +static void arrangewindows(void); static void setwmdesktop(xcb_drawable_t win, uint32_t ws); static int32_t getwmdesktop(xcb_drawable_t win); static void addtoworkspace(struct client *client, uint32_t ws); @@ -298,6 +298,7 @@ static int setuprandr(void); static void getrandr(void); static void getoutputs(xcb_randr_output_t *outputs, int len, xcb_timestamp_t timestamp); +void arrbymon(struct monitor *monitor); static struct monitor *findmonitor(xcb_randr_output_t id); static struct monitor *findclones(xcb_randr_output_t id, int16_t x, int16_t y); static struct monitor *findmonbycoord(int16_t x, int16_t y); @@ -477,102 +478,21 @@ void cleanup(int code) } /* - * - * Rearrange windows to fit new screen size rootwidth x rootheight. + * Rearrange windows to fit new screen size. */ -void arrangewindows(uint16_t rootwidth, uint16_t rootheight) +void arrangewindows(void) { - uint32_t mask = 0; - uint32_t values[5]; - bool changed; - int16_t x; - int16_t y; - uint16_t width; - uint16_t height; struct item *item; struct client *client; - - PDEBUG("Rearranging all windows to fit new screen size %d x %d.\n", - rootwidth, rootheight); /* - * Go through all windows we care about and look at their - * coordinates and geometry. If they don't fit on the new screen, + * Go through all windows. If they don't fit on the new screen, * move them around and resize them as necessary. */ for (item = winlist; item != NULL; item = item->next) { client = item->data; - - changed = false; - - if (!getgeom(client->id, &x, &y, &width, &height)) - { - return; - } - - PDEBUG("Win %d at %d,%d %d x %d\n", client->id, x, y, width, height); - - if (width > rootwidth) - { - width = rootwidth - BORDERWIDTH * 2; - changed = true; - } - - if (height > rootheight) - { - height = rootheight - BORDERWIDTH * 2; - changed = true; - } - - /* If x or y + geometry is outside of screen, move window. */ - - if (x + width > rootwidth) - { - x = rootwidth - (width + BORDERWIDTH * 2); - changed = true; - } - - if (y + height > rootheight) - { - y = rootheight - (height + BORDERWIDTH * 2);; - changed = true; - } - - /* Reset sense of maximized. */ - client->vertmaxed = false; - - if (client->maxed) - { - client->maxed = false; - - /* Set borders again. */ - setborders(client, BORDERWIDTH); - } - - if (changed) - { - PDEBUG("--- Win %d going to %d,%d %d x %d\n", client->id, - x, y, width, height); - - client->x = x; - client->y = y; - client->width = width; - client->height = height; - - /* Find monitor for the client. */ - client->monitor = findmonbycoord(x, y); - - mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y - | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; - values[0] = x; - values[1] = y; - values[2] = width; - values[3] = height; - - xcb_configure_window(conn, client->id, mask, values); - xcb_flush(conn); - } + fitonscreen(client); } /* for */ } @@ -1479,6 +1399,10 @@ int setupscreen(void) return 0; } +/* + * Set up RANDR extension. Get the extension base and subscribe to + * events. + */ int setuprandr(void) { const xcb_query_extension_reply_t *extension; @@ -1509,6 +1433,9 @@ int setuprandr(void) return base; } +/* + * Get RANDR resources and figure out how many outputs there are. + */ void getrandr(void) { xcb_randr_get_screen_resources_current_cookie_t rcookie; @@ -1517,11 +1444,8 @@ void getrandr(void) int len; xcb_timestamp_t timestamp; - /* Get screen resources (crtcs, outputs, modes) */ rcookie = xcb_randr_get_screen_resources_current(conn, screen->root); - res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL); - if (NULL == res) { printf("No RANDR extension available.\n"); @@ -1540,6 +1464,10 @@ void getrandr(void) free(res); } +/* + * Walk through all the RANDR outputs (number of outputs == len) there + * was at time timestamp. + */ void getoutputs(xcb_randr_output_t *outputs, int len, xcb_timestamp_t timestamp) { char *name; @@ -1566,9 +1494,6 @@ void getoutputs(xcb_randr_output_t *outputs, int len, xcb_timestamp_t timestamp) continue; } -/* handle_output(conn, randr_outputs[i], output, cts, res); - free(output); -*/ asprintf(&name, "%.*s", xcb_randr_get_output_info_name_length(output), xcb_randr_get_output_info_name(output)); @@ -1647,20 +1572,90 @@ typedef struct xcb_randr_get_crtc_info_reply_t { addmonitor(outputs[i], name, crtc->x, crtc->y, crtc->width, crtc->height); } + else + { + bool changed = false; + + /* + * We know this monitor. Update information. If it's + * smaller than before, rearrange windows. + */ + PDEBUG("Known monitor. Updating info.\n"); + + if (crtc->x != mon->x) + { + mon->x = crtc->x; + changed = true; + } + if (crtc->y != mon->y) + { + mon->y = crtc->y; + changed = true; + } + + if (crtc->width != mon->width) + { + mon->width = crtc->width; + changed = true; + } + if (crtc->height != mon->height) + { + mon->height = crtc->height; + changed = true; + } + + if (changed) + { + arrbymon(mon); + } + } free(crtc); } else { - PDEBUG("Not used at the moment.\n"); - /* FIXME: Check if it was used before. If it was, do something. - * - * Done with arrangewindows() - * + PDEBUG("Monitor not used at the moment.\n"); + /* + * Check if it was used before. If it was, do something. */ - if ((mon = findmonitor(outputs[i]))) { + struct item *item; + struct client *client; + + /* Check all windows on this monitor and move them to + * the next or to the first monitor if there is no + * next. + * + * FIXME: Use per monitor workspace list instead of + * global window list. + */ + for (item = winlist; item != NULL; item = item->next) + { + client = item->data; + if (client->monitor == mon) + { + if (NULL == client->monitor->item->next) + { + if (NULL == monlist->data) + { + client->monitor = NULL; + } + else + { + client->monitor = monlist->data; + } + } + else + { + client->monitor = + client->monitor->item->next->data; + } + + fitonscreen(client); + } + } /* for */ + /* It's not active anymore. Forget about it. */ delmonitor(mon); } @@ -1670,6 +1665,30 @@ typedef struct xcb_randr_get_crtc_info_reply_t { } /* for */ } +void arrbymon(struct monitor *monitor) +{ + struct item *item; + struct client *client; + + PDEBUG("arrbymon\n"); + /* + * Go through all windows on this monitor. If they don't fit on + * the new screen, move them around and resize them as necessary. + * + * FIXME: Use a per monitor workspace list instead of global + * windows list. + */ + for (item = winlist; item != NULL; item = item->next) + { + client = item->data; + if (client->monitor == monitor) + { + fitonscreen(client); + } + } /* for */ + +} + struct monitor *findmonitor(xcb_randr_output_t id) { struct item *item; @@ -3734,15 +3753,14 @@ void events(void) if (e->window == screen->root) { /* - * When using RANDR, the root can change geometry when - * the user adds a new screen, tilts their screen 90 - * degrees or whatnot. We might need to rearrange - * windows to be visible. + * When using RANDR or Xinerama, the root can change + * geometry when the user adds a new screen, tilts + * their screen 90 degrees or whatnot. We might need + * to rearrange windows to be visible. * * We might get notified for several reasons, not just * if the geometry changed. If the geometry is - * unchanged, do nothing. - * + * unchanged we do nothing. */ PDEBUG("Notify event for root!\n"); PDEBUG("Possibly a new root geometry: %dx%d\n", @@ -3756,9 +3774,21 @@ void events(void) } else { - arrangewindows(e->width, e->height); screen->width_in_pixels = e->width; screen->height_in_pixels = e->height; + + /* Check for RANDR. */ + if (-1 == randrbase) + { + /* We have no RANDR so we rearrange windows to + * the new root geometry here. + * + * With RANDR enabled, we handle this per + * screen getrandr() when we receive an + * XCB_RANDR_SCREEN_CHANGE_NOTIFY event. + */ + arrangewindows(); + } } } } -- cgit v1.2.3