summaryrefslogtreecommitdiff
path: root/mcwm.c
diff options
context:
space:
mode:
Diffstat (limited to 'mcwm.c')
-rw-r--r--mcwm.c1954
1 files changed, 1296 insertions, 658 deletions
diff --git a/mcwm.c b/mcwm.c
index 24abe6e..efba40e 100644
--- a/mcwm.c
+++ b/mcwm.c
@@ -38,6 +38,7 @@
#include <sys/select.h>
#include <xcb/xcb.h>
+#include <xcb/randr.h>
#include <xcb/xcb_keysyms.h>
#include <xcb/xcb_atom.h>
#include <xcb/xcb_icccm.h>
@@ -81,8 +82,8 @@
*/
#define MCWM_TABBING 4
-/* Our highest workspace. */
-#define WORKSPACE_MAX 9
+/* Number of workspaces. */
+#define WORKSPACES 10
/* Value in WM hint which means this window is fixed on all workspaces. */
#define NET_WM_FIXED 0xffffffff
@@ -120,18 +121,41 @@ typedef enum {
KEY_B,
KEY_N,
KEY_END,
+ KEY_PREVSCR,
+ KEY_NEXTSCR,
KEY_MAX
} key_enum_t;
+
+struct monitor
+{
+ xcb_randr_output_t id;
+ char *name;
+ int16_t x; /* X and Y. */
+ int16_t y;
+ uint16_t width; /* Width in pixels. */
+ uint16_t height; /* Height in pixels. */
+ struct item *item; /* Pointer to our place in output list. */
+};
+
+struct sizepos
+{
+ int16_t x;
+ int16_t y;
+ uint16_t width;
+ uint16_t height;
+};
+
/* Everything we know about a window. */
struct client
{
xcb_drawable_t id; /* ID of this window. */
bool usercoord; /* X,Y was set by -geom. */
- uint32_t x; /* X coordinate. Only updated when maxed. */
- uint32_t y; /* Y coordinate. Ditto. */
- uint16_t width; /* Width in pixels. Ditto. */
- uint16_t height; /* Height in pixels. Ditto. */
+ int16_t x; /* X coordinate. */
+ int16_t y; /* Y coordinate. */
+ uint16_t width; /* Width in pixels. */
+ uint16_t height; /* Height in pixels. */
+ struct sizepos origsize; /* Original size if we're currently maxed. */
uint16_t min_width, min_height; /* Hints from application. */
uint16_t max_width, max_height;
int32_t width_inc, height_inc;
@@ -139,8 +163,9 @@ struct client
bool vertmaxed; /* Vertically maximized? */
bool maxed; /* Totally maximized? */
bool fixed; /* Visible on all workspaces? */
+ struct monitor *monitor; /* The physical output this window is on. */
struct item *winitem; /* Pointer to our place in global windows list. */
- struct item *wsitem[WORKSPACE_MAX + 1]; /* Pointer to our place in every
+ struct item *wsitem[WORKSPACES]; /* Pointer to our place in every
* workspace window list. */
};
@@ -151,6 +176,7 @@ int sigcode; /* Signal code. Non-zero if we've been
* interruped by a signal. */
xcb_connection_t *conn; /* Connection to X server. */
xcb_screen_t *screen; /* Our current screen. */
+int randrbase; /* Beginning of RANDR extension events. */
uint32_t curws = 0; /* Current workspace. */
struct client *focuswin; /* Current focus window. */
struct client *lastfocuswin; /* Last focused window. NOTE! Only
@@ -158,13 +184,14 @@ struct client *lastfocuswin; /* Last focused window. NOTE! Only
* start and end of tabbing
* mode. */
struct item *winlist = NULL; /* Global list of all client windows. */
+struct item *monlist = NULL; /* List of all physical monitor outputs. */
int mode = 0; /* Internal mode, such as move or resize */
/*
* Workspace list: Every workspace has a list of all visible
* windows.
*/
-struct item *wslist[WORKSPACE_MAX + 1] =
+struct item *wslist[WORKSPACES] =
{
NULL,
NULL,
@@ -210,6 +237,8 @@ struct keys
{ USERKEY_BOTLEFT, 0 },
{ USERKEY_BOTRIGHT, 0 },
{ USERKEY_DELETE, 0 },
+ { USERKEY_PREVSCREEN, 0 },
+ { USERKEY_NEXTSCREEN, 0 },
};
/* All keycodes generating our MODKEY mask. */
@@ -245,51 +274,72 @@ xcb_atom_t wm_protocols; /* WM_PROTOCOLS. */
/* Functions declerations. */
-void finishtabbing(void);
-struct modkeycodes getmodkeys(xcb_mod_mask_t modmask);
-void cleanup(int code);
-void arrangewindows(uint16_t rootwidth, uint16_t rootheight);
-void setwmdesktop(xcb_drawable_t win, uint32_t ws);
-int32_t getwmdesktop(xcb_drawable_t win);
-void addtoworkspace(struct client *client, uint32_t ws);
-void delfromworkspace(struct client *client, uint32_t ws);
-void changeworkspace(uint32_t ws);
-void fixwindow(struct client *client, bool setcolour);
-uint32_t getcolor(const char *colstr);
-void forgetclient(struct client *client);
-void forgetwin(xcb_window_t win);
-void newwin(xcb_window_t win);
-struct client *setupwin(xcb_window_t win);
-xcb_keycode_t keysymtokeycode(xcb_keysym_t keysym, xcb_key_symbols_t *keysyms);
-int setupkeys(void);
-int setupscreen(void);
-void raisewindow(xcb_drawable_t win);
-void raiseorlower(struct client *client);
-void movewindow(xcb_drawable_t win, uint16_t x, uint16_t y);
-struct client *findclient(xcb_drawable_t win);
-void focusnext(void);
-void setunfocus(xcb_drawable_t win);
-void setfocus(struct client *client);
-int start_terminal(void);
-void resize(xcb_drawable_t win, uint16_t width, uint16_t height);
-void resizestep(struct client *client, char direction);
-void mousemove(xcb_drawable_t win, int rel_x, int rel_y);
-void mouseresize(struct client *client, int rel_x, int rel_y);
-void movestep(struct client *client, char direction);
-void unmax(struct client *client);
-void maximize(struct client *client);
-void maxvert(struct client *client);
-bool getpointer(xcb_drawable_t win, int16_t *x, int16_t *y);
-bool getgeom(xcb_drawable_t win, int16_t *x, int16_t *y, uint16_t *width,
- uint16_t *height);
-void topleft(void);
-void topright(void);
-void botleft(void);
-void botright(void);
-void deletewin(void);
-void handle_keypress(xcb_key_press_event_t *ev);
-void printhelp(void);
-void sigcatch(int sig);
+static void finishtabbing(void);
+static struct modkeycodes getmodkeys(xcb_mod_mask_t modmask);
+static void cleanup(int code);
+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);
+static void delfromworkspace(struct client *client, uint32_t ws);
+static void changeworkspace(uint32_t ws);
+static void fixwindow(struct client *client, bool setcolour);
+static uint32_t getcolor(const char *colstr);
+static void forgetclient(struct client *client);
+static void forgetwin(xcb_window_t win);
+static void fitonscreen(struct client *client);
+static void newwin(xcb_window_t win);
+static struct client *setupwin(xcb_window_t win);
+static xcb_keycode_t keysymtokeycode(xcb_keysym_t keysym,
+ xcb_key_symbols_t *keysyms);
+static int setupkeys(void);
+static int setupscreen(void);
+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);
+static void delmonitor(struct monitor *mon);
+static struct monitor *addmonitor(xcb_randr_output_t id, char *name,
+ uint32_t x, uint32_t y, uint16_t width,
+ uint16_t height);
+static void raisewindow(xcb_drawable_t win);
+static void raiseorlower(struct client *client);
+static void movelim(struct client *client);
+static void movewindow(xcb_drawable_t win, uint16_t x, uint16_t y);
+static struct client *findclient(xcb_drawable_t win);
+static void focusnext(void);
+static void setunfocus(xcb_drawable_t win);
+static void setfocus(struct client *client);
+static int start_terminal(void);
+static void resizelim(struct client *client);
+static void resize(xcb_drawable_t win, uint16_t width, uint16_t height);
+static void resizestep(struct client *client, char direction);
+static void mousemove(struct client *client, int rel_x, int rel_y);
+static void mouseresize(struct client *client, int rel_x, int rel_y);
+static void movestep(struct client *client, char direction);
+static void setborders(struct client *client, int width);
+static void unmax(struct client *client);
+static void maximize(struct client *client);
+static void maxvert(struct client *client);
+static bool getpointer(xcb_drawable_t win, int16_t *x, int16_t *y);
+static bool getgeom(xcb_drawable_t win, int16_t *x, int16_t *y, uint16_t *width,
+ uint16_t *height);
+static void topleft(void);
+static void topright(void);
+static void botleft(void);
+static void botright(void);
+static void deletewin(void);
+static void prevscreen(void);
+static void nextscreen(void);
+static void handle_keypress(xcb_key_press_event_t *ev);
+static void configurerequest(xcb_configure_request_event_t *e);
+static void events(void);
+static void printhelp(void);
+static void sigcatch(int sig);
/* Function bodies. */
@@ -428,99 +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. */
- values[0] = BORDERWIDTH;
-
- mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
-
- xcb_configure_window(conn, client->id, mask, &values[0]);
- xcb_flush(conn);
- }
-
- if (changed)
- {
- PDEBUG("--- Win %d going to %d,%d %d x %d\n", client->id,
- x, y, width, height);
-
- 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 */
}
@@ -644,31 +616,14 @@ void changeworkspace(uint32_t ws)
}
/* Go through list of current ws. Unmap everything that isn't fixed. */
- for (item = wslist[curws]; item != NULL; )
+ for (item = wslist[curws]; item != NULL; item = item->next)
{
client = item->data;
PDEBUG("changeworkspace. unmap phase. ws #%d, client-fixed: %d\n",
curws, client->fixed);
-
- if (client->fixed)
- {
- /* Add the fixed window to the new workspace window list. */
- addtoworkspace(client, ws);
- /*
- * Remove the fixed window from the current workspace
- * list.
- *
- * NB! Before deleting this item, we need to save the
- * address to next item so we can continue through the
- * list.
- */
- item = item->next;
-
- delfromworkspace(client, curws);
- }
- else
+ if (!client->fixed)
{
/*
* This is an ordinary window. Just unmap it. Note that
@@ -676,10 +631,7 @@ void changeworkspace(uint32_t ws)
* which we will try to handle later.
*/
xcb_unmap_window(conn, client->id);
-
- item = item->next;
}
-
} /* for */
/* Go through list of new ws. Map everything that isn't fixed. */
@@ -709,7 +661,8 @@ void changeworkspace(uint32_t ws)
void fixwindow(struct client *client, bool setcolour)
{
uint32_t values[1];
-
+ uint32_t ws;
+
if (NULL == client)
{
return;
@@ -727,7 +680,15 @@ void fixwindow(struct client *client, bool setcolour)
xcb_change_window_attributes(conn, client->id, XCB_CW_BORDER_PIXEL,
values);
}
-
+
+ /* Delete from all workspace lists except current. */
+ for (ws = 0; ws < WORKSPACES; ws ++)
+ {
+ if (ws != curws)
+ {
+ delfromworkspace(client, ws);
+ }
+ }
}
else
{
@@ -741,6 +702,15 @@ void fixwindow(struct client *client, bool setcolour)
client->fixed = true;
setwmdesktop(client->id, NET_WM_FIXED);
+ /* Add window to all workspace lists. */
+ for (ws = 0; ws < WORKSPACES; ws ++)
+ {
+ if (ws != curws)
+ {
+ addtoworkspace(client, ws);
+ }
+ }
+
if (setcolour)
{
/* Set border color to fixed colour. */
@@ -785,18 +755,29 @@ uint32_t getcolor(const char *colstr)
/* Forget everything about client client. */
void forgetclient(struct client *client)
{
+ uint32_t ws;
+
if (NULL == client)
{
PDEBUG("forgetclient: client was NULL\n");
return;
}
-
- /* Delete window from workspace list. */
- delfromworkspace(client, curws);
- free(client->winitem->data);
+ /*
+ * Delete this client from whatever workspace lists it belongs to.
+ * Note that it's OK to be on several workspaces at once even if
+ * you're not fixed.
+ */
+ for (ws = 0; ws < WORKSPACES; ws ++)
+ {
+ if (NULL != client->wsitem[ws])
+ {
+ delfromworkspace(client, ws);
+ }
+ }
- delitem(&winlist, client->winitem);
+ /* Remove from global window list. */
+ freeitem(&winlist, NULL, client->winitem);
}
/* Forget everything about a client with client->id win. */
@@ -829,7 +810,7 @@ void forgetwin(xcb_window_t win)
* to. Note that it's OK to be on several workspaces at
* once.
*/
- for (ws = 0; ws != WORKSPACE_MAX; ws ++)
+ for (ws = 0; ws < WORKSPACES; ws ++)
{
PDEBUG("Looking in ws #%d.\n", ws);
if (NULL == client->wsitem[ws])
@@ -853,6 +834,109 @@ void forgetwin(xcb_window_t win)
}
/*
+ * Fit client on physical screen, moving and resizing as necessary.
+ */
+void fitonscreen(struct client *client)
+{
+ int16_t mon_x;
+ int16_t mon_y;
+ uint16_t mon_width;
+ uint16_t mon_height;
+ bool willmove = false;
+ bool willresize = false;
+
+ client->vertmaxed = false;
+
+ if (client->maxed)
+ {
+ client->maxed = false;
+ setborders(client, BORDERWIDTH);
+ }
+
+ if (NULL == client->monitor)
+ {
+ mon_x = 0;
+ mon_y = 0;
+ mon_width = screen->width_in_pixels;
+ mon_height = screen->height_in_pixels;
+ }
+ else
+ {
+ mon_x = client->monitor->x;
+ mon_y = client->monitor->y;
+ mon_width = client->monitor->width;
+ mon_height = client->monitor->height;
+ }
+
+ /* Is it outside the physical monitor? */
+ if (client->x < mon_x)
+ {
+ client->x = mon_x;
+ willmove = true;
+ }
+ if (client->y < mon_y)
+ {
+ client->y = mon_y;
+ willmove = true;
+ }
+
+ /* Is it smaller than it wants to be? */
+ if (0 != client->min_height && client->height < client->min_height)
+ {
+ client->height = client->min_height;
+ willresize = true;
+ }
+
+ if (0 != client->min_width && client->width < client->min_width)
+ {
+ client->width = client->min_width;
+ willresize = true;
+ }
+
+ /*
+ * If the window is larger than our screen, just place it in the
+ * corner and resize.
+ */
+ if (client->width + BORDERWIDTH * 2 > mon_width)
+ {
+ client->x = mon_x;
+ client->width = mon_width - BORDERWIDTH * 2;;
+ willmove = true;
+ willresize = true;
+ }
+ else if (client->x + client->width + BORDERWIDTH * 2 > mon_x + mon_width)
+ {
+ client->x = mon_x + mon_width - (client->width + BORDERWIDTH * 2);
+ willmove = true;
+ }
+
+ if (client->height + BORDERWIDTH * 2 > mon_height)
+ {
+ client->y = mon_y;
+ client->height = mon_height - BORDERWIDTH * 2;
+ willmove = true;
+ willresize = true;
+ }
+ else if (client->y + client->height + BORDERWIDTH * 2 > mon_y + mon_height)
+ {
+ client->y = mon_y + mon_height - (client->height + BORDERWIDTH * 2);
+ willmove = true;
+ }
+
+ if (willmove)
+ {
+ PDEBUG("Moving to %d,%d.\n", client->x, client->y);
+ movewindow(client->id, client->x, client->y);
+ }
+
+ if (willresize)
+ {
+ PDEBUG("Resizing to %d x %d.\n", client->width, client->height);
+ resize(client->id, client->width, client->height);
+ }
+}
+
+/*
* Set position, geometry and attributes of a new window and show it
* on the screen.
*/
@@ -860,10 +944,6 @@ void newwin(xcb_window_t win)
{
int16_t pointx;
int16_t pointy;
- int16_t x;
- int16_t y;
- uint16_t width;
- uint16_t height;
struct client *client;
if (NULL != findclient(win))
@@ -876,11 +956,11 @@ void newwin(xcb_window_t win)
*/
return;
}
-
+
/* Get pointer position so we can move the window to the cursor. */
-
if (!getpointer(screen->root, &pointx, &pointy))
{
+ PDEBUG("Failed to get pointer coords!\n");
pointx = 0;
pointy = 0;
}
@@ -889,7 +969,6 @@ void newwin(xcb_window_t win)
* Set up stuff, like borders, add the window to the client list,
* et cetera.
*/
-
client = setupwin(win);
if (NULL == client)
{
@@ -900,63 +979,43 @@ void newwin(xcb_window_t win)
/* Add this window to the current workspace. */
addtoworkspace(client, curws);
- if (!getgeom(win, &x, &y, &width, &height))
- {
- PDEBUG("Couldn't get geometry\n");
- return;
- }
-
- /*
- * If the client says the user specified the coordinates, we
- * override the pointer position and place the window where the
- * client specifies instead.
- */
- if (client->usercoord)
- {
- pointx = x;
- pointy = y;
- }
-
/*
- * If the window is larger than our screen, just place it in the
- * corner and resize.
+ * If the client doesn't say the user specified the coordinates
+ * for the window we store it where our pointer is instead.
*/
- if (width > screen->width_in_pixels)
+ if (!client->usercoord)
{
- pointx = 0;
- width = screen->width_in_pixels - BORDERWIDTH * 2;;
- resize(win, width, height);
- }
- else if (pointx + width + BORDERWIDTH * 2 > screen->width_in_pixels)
- {
- pointx = screen->width_in_pixels - (width + BORDERWIDTH * 2);
- }
+ PDEBUG("Coordinates not set by user. Using pointer: %d,%d.\n",
+ pointx, pointy);
+ client->x = pointx;
+ client->y = pointy;
- if (height > screen->height_in_pixels)
+ movewindow(client->id, client->x, client->y);
+ }
+ else
{
- pointy = 0;
- height = screen->height_in_pixels - BORDERWIDTH * 2;
- resize(win, width, height);
+ PDEBUG("User set coordinates.\n");
}
- else if (pointy + height + BORDERWIDTH * 2 > screen->height_in_pixels)
+
+ /* Find the physical output this window will be on if RANDR is active. */
+ if (-1 != randrbase)
{
- pointy = screen->height_in_pixels - (height + BORDERWIDTH * 2);
+ client->monitor = findmonbycoord(pointx, pointy);
}
- /* Move the window to cursor position. */
- movewindow(win, pointx, pointy);
+ fitonscreen(client);
/* Show window on screen. */
- xcb_map_window(conn, win);
+ xcb_map_window(conn, client->id);
/*
* Move cursor into the middle of the window so we don't lose the
* pointer to another window.
*/
xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0,
- width / 2, height / 2);
-
- xcb_flush(conn);
+ client->width / 2, client->height / 2);
+
+ xcb_flush(conn);
}
/* Set border colour, width and event mask for window. */
@@ -1005,7 +1064,7 @@ struct client *setupwin(xcb_window_t win)
}
item->data = client;
-
+
/* Initialize client. */
client->id = win;
client->usercoord = false;
@@ -1024,15 +1083,24 @@ struct client *setupwin(xcb_window_t win)
client->vertmaxed = false;
client->maxed = false;
client->fixed = false;
+ client->monitor = NULL;
+
client->winitem = item;
- for (ws = 0; ws != WORKSPACE_MAX; ws ++)
+ for (ws = 0; ws < WORKSPACES; ws ++)
{
client->wsitem[ws] = NULL;
}
PDEBUG("Adding window %d\n", client->id);
+ /* Get window geometry. */
+ if (!getgeom(client->id, &client->x, &client->y, &client->width,
+ &client->height))
+ {
+ fprintf(stderr, "Couldn't get geometry in initial setup of window.\n");
+ }
+
/*
* Get the window's incremental size step, if any.
*/
@@ -1040,7 +1108,7 @@ struct client *setupwin(xcb_window_t win)
conn, xcb_get_wm_normal_hints_unchecked(
conn, win), &hints, NULL))
{
- PDEBUG("Couldn't get size hints.");
+ PDEBUG("Couldn't get size hints.\n");
}
/*
@@ -1242,6 +1310,31 @@ int setupscreen(void)
if (NULL != client)
{
/*
+ * Find the physical output this window will be on if
+ * RANDR is active.
+ */
+ if (-1 != randrbase)
+ {
+ PDEBUG("Looking for monitor on %d x %d.\n", client->x,
+ client->y);
+ client->monitor = findmonbycoord(client->x, client->y);
+#if DEBUG
+ if (NULL != client->monitor)
+ {
+ PDEBUG("Found client on monitor %s.\n",
+ client->monitor->name);
+ }
+ else
+ {
+ PDEBUG("Couldn't find client on any monitor.\n");
+ }
+#endif
+ }
+
+ /* Fit window on physical screen. */
+ fitonscreen(client);
+
+ /*
* Check if this window has a workspace set already as
* a WM hint.
*
@@ -1250,10 +1343,12 @@ int setupscreen(void)
if (ws == NET_WM_FIXED)
{
+ /* Add to current workspace. */
+ addtoworkspace(client, curws);
+ /* Add to all other workspaces. */
fixwindow(client, false);
- addtoworkspace(client, curws);
}
- else if (MCWM_NOWS != ws && ws < WORKSPACE_MAX)
+ else if (MCWM_NOWS != ws && ws < WORKSPACES)
{
addtoworkspace(client, ws);
/* If it's not our current workspace, hide it. */
@@ -1302,6 +1397,407 @@ 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;
+ int base;
+
+ extension = xcb_get_extension_data(conn, &xcb_randr_id);
+ if (!extension->present)
+ {
+ printf("No RANDR.\n");
+ return -1;
+ }
+ else
+ {
+ getrandr();
+ }
+
+ base = extension->first_event;
+ PDEBUG("randrbase is %d.\n", base);
+
+ xcb_randr_select_input(conn, screen->root,
+ XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE |
+ XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE |
+ XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE |
+ XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY);
+
+ xcb_flush(conn);
+
+ 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;
+ xcb_randr_get_screen_resources_current_reply_t *res;
+ xcb_randr_output_t *outputs;
+ int len;
+ xcb_timestamp_t timestamp;
+
+ 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");
+ return;
+ }
+ timestamp = res->config_timestamp;
+
+ len = xcb_randr_get_screen_resources_current_outputs_length(res);
+ outputs = xcb_randr_get_screen_resources_current_outputs(res);
+
+ PDEBUG("Found %d outputs.\n", len);
+
+ /* Request information for all outputs. */
+ getoutputs(outputs, len, timestamp);
+
+ 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;
+ xcb_randr_get_crtc_info_cookie_t icookie;
+ xcb_randr_get_crtc_info_reply_t *crtc = NULL;
+ xcb_randr_get_output_info_reply_t *output;
+ struct monitor *mon;
+ struct monitor *clonemon;
+ xcb_randr_get_output_info_cookie_t ocookie[len];
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ ocookie[i] = xcb_randr_get_output_info(conn, outputs[i], timestamp);
+ }
+
+ /* Loop through all outputs. */
+ for (i = 0; i < len; i ++)
+ {
+ output = xcb_randr_get_output_info_reply(conn, ocookie[i], NULL);
+
+ if (output == NULL)
+ {
+ continue;
+ }
+
+ asprintf(&name, "%.*s",
+ xcb_randr_get_output_info_name_length(output),
+ xcb_randr_get_output_info_name(output));
+
+#if 0
+
+ output:
+
+ uint8_t response_type; /**< */
+ uint8_t status; /**< */
+ uint16_t sequence; /**< */
+ uint32_t length; /**< */
+ xcb_timestamp_t timestamp; /**< */
+ xcb_randr_crtc_t crtc; /**< */
+ uint32_t mm_width; /**< */
+ uint32_t mm_height; /**< */
+ uint8_t connection; /**< */
+ uint8_t subpixel_order; /**< */
+ uint16_t num_crtcs; /**< */
+ uint16_t num_modes; /**< */
+ uint16_t num_preferred; /**< */
+ uint16_t num_clones; /**< */
+ uint16_t name_len; /**< */
+#endif
+
+ PDEBUG("Name: %s\n", name);
+ PDEBUG("id: %d\n" , outputs[i]);
+ PDEBUG("Size: %d x %d mm.\n", output->mm_width, output->mm_height);
+
+ if (XCB_NONE != output->crtc)
+ {
+ icookie = xcb_randr_get_crtc_info(conn, output->crtc, timestamp);
+ crtc = xcb_randr_get_crtc_info_reply(conn, icookie, NULL);
+ if (NULL == crtc)
+ {
+ return;
+ }
+
+#if 0
+typedef struct xcb_randr_get_crtc_info_reply_t {
+ uint8_t response_type; /**< */
+ uint8_t status; /**< */
+ uint16_t sequence; /**< */
+ uint32_t length; /**< */
+ xcb_timestamp_t timestamp; /**< */
+ int16_t x; /**< */
+ int16_t y; /**< */
+ uint16_t width; /**< */
+ uint16_t height; /**< */
+ xcb_randr_mode_t mode; /**< */
+ uint16_t rotation; /**< */
+ uint16_t rotations; /**< */
+ uint16_t num_outputs; /**< */
+ uint16_t num_possible_outputs; /**< */
+} xcb_randr_get_crtc_info_reply_t;
+
+#endif
+
+ PDEBUG("CRTC: at %d, %d, size: %d x %d.\n", crtc->x, crtc->y,
+ crtc->width, crtc->height);
+
+ /* Check if it's a clone. */
+ clonemon = findclones(outputs[i], crtc->x, crtc->y);
+ if (NULL != clonemon)
+ {
+ PDEBUG("Monitor %s, id %d is a clone of %s, id %d. Skipping.\n",
+ name, outputs[i],
+ clonemon->name, clonemon->id);
+ continue;
+ }
+
+ /* Do we know this monitor already? */
+ if (NULL == (mon = findmonitor(outputs[i])))
+ {
+ PDEBUG("Monitor not known, adding to list.\n");
+ 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("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);
+ }
+ }
+
+ free(output);
+ } /* 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;
+ struct monitor *mon;
+
+ for (item = monlist; item != NULL; item = item->next)
+ {
+ mon = item->data;
+ if (id == mon->id)
+ {
+ PDEBUG("findmonitor: Found it. Output ID: %d\n", mon->id);
+ return mon;
+ }
+ PDEBUG("findmonitor: Goint to %p.\n", item->next);
+ }
+
+ return NULL;
+}
+
+struct monitor *findclones(xcb_randr_output_t id, int16_t x, int16_t y)
+{
+ struct monitor *clonemon;
+ struct item *item;
+
+ for (item = monlist; item != NULL; item = item->next)
+ {
+ clonemon = item->data;
+
+ PDEBUG("Monitor %s: x, y: %d--%d, %d--%d.\n",
+ clonemon->name,
+ clonemon->x, clonemon->x + clonemon->width,
+ clonemon->y, clonemon->y + clonemon->height);
+
+ /* Check for same position. */
+ if (id != clonemon->id && clonemon->x == x && clonemon->y == y)
+ {
+ return clonemon;
+ }
+ }
+
+ return NULL;
+}
+
+struct monitor *findmonbycoord(int16_t x, int16_t y)
+{
+ struct item *item;
+ struct monitor *mon;
+
+ for (item = monlist; item != NULL; item = item->next)
+ {
+ mon = item->data;
+
+ PDEBUG("Monitor %s: x, y: %d--%d, %d--%d.\n",
+ mon->name,
+ mon->x, mon->x + mon->width,
+ mon->y, mon->y + mon->height);
+
+ PDEBUG("Is %d,%d between them?\n", x, y);
+
+ if (x >= mon->x && x <= mon->x + mon->width
+ && y >= mon->y && y <= mon->y + mon->height)
+ {
+ PDEBUG("findmonbycoord: Found it. Output ID: %d, name %s\n",
+ mon->id, mon->name);
+ return mon;
+ }
+ }
+
+ return NULL;
+}
+
+void delmonitor(struct monitor *mon)
+{
+ PDEBUG("Deleting output %s.\n", mon->name);
+ free(mon->name);
+ freeitem(&monlist, NULL, mon->item);
+}
+
+struct monitor *addmonitor(xcb_randr_output_t id, char *name,
+ uint32_t x, uint32_t y, uint16_t width,
+ uint16_t height)
+{
+ struct item *item;
+ struct monitor *mon;
+
+ if (NULL == (item = additem(&monlist)))
+ {
+ fprintf(stderr, "Out of memory.\n");
+ return NULL;
+ }
+
+ mon = malloc(sizeof (struct monitor));
+ if (NULL == mon)
+ {
+ fprintf(stderr, "Out of memory.\n");
+ return NULL;
+ }
+
+ item->data = mon;
+
+ mon->id = id;
+ mon->name = name;
+ mon->x = x;
+ mon->y = y;
+ mon->width = width;
+ mon->height = height;
+ mon->item = item;
+
+ return mon;
+}
+
/* Raise window win to top of stack. */
void raisewindow(xcb_drawable_t win)
{
@@ -1340,6 +1836,51 @@ void raiseorlower(struct client *client)
xcb_flush(conn);
}
+void movelim(struct client *client)
+{
+ int16_t mon_x;
+ int16_t mon_y;
+ uint16_t mon_width;
+ uint16_t mon_height;
+
+ if (NULL == client->monitor)
+ {
+ mon_x = 0;
+ mon_y = 0;
+ mon_width = screen->width_in_pixels;
+ mon_height = screen->height_in_pixels;
+ }
+ else
+ {
+ mon_x = client->monitor->x;
+ mon_y = client->monitor->y;
+ mon_width = client->monitor->width;
+ mon_height = client->monitor->height;
+ }
+
+ /* Is it outside the physical monitor? */
+ if (client->x < mon_x)
+ {
+ client->x = mon_x;
+ }
+ if (client->y < mon_y)
+ {
+ client->y = mon_y;
+ }
+
+ if (client->x + client->width > mon_x + mon_width - BORDERWIDTH * 2)
+ {
+ client->x = (mon_x + mon_width - BORDERWIDTH * 2) - client->width;
+ }
+
+ if (client->y + client->height > mon_y + mon_height - BORDERWIDTH * 2)
+ {
+ client->y = (mon_y + mon_height - BORDERWIDTH * 2) - client->height;
+ }
+
+ movewindow(client->id, client->x, client->y);
+}
+
/* Move window win to root coordinates x,y. */
void movewindow(xcb_drawable_t win, uint16_t x, uint16_t y)
{
@@ -1625,6 +2166,53 @@ int start_terminal(void)
return 0;
}
+/* Resize with limit. */
+void resizelim(struct client *client)
+{
+ int16_t mon_x;
+ int16_t mon_y;
+ uint16_t mon_width;
+ uint16_t mon_height;
+
+ if (NULL == client->monitor)
+ {
+ mon_x = 0;
+ mon_y = 0;
+ mon_width = screen->width_in_pixels;
+ mon_height = screen->height_in_pixels;
+ }
+ else
+ {
+ mon_x = client->monitor->x;
+ mon_y = client->monitor->y;
+ mon_width = client->monitor->width;
+ mon_height = client->monitor->height;
+ }
+
+ /* Is it smaller than it wants to be? */
+ if (0 != client->min_height && client->height < client->min_height)
+ {
+ client->height = client->min_height;
+ }
+
+ if (0 != client->min_width && client->width < client->min_width)
+ {
+ client->width = client->min_width;
+ }
+
+ if (client->x + client->width + BORDERWIDTH * 2 > mon_x + mon_width)
+ {
+ client->width = mon_width - ((client->x - mon_x) + BORDERWIDTH * 2);
+ }
+
+ if (client->y + client->height + BORDERWIDTH * 2 > mon_y + mon_height)
+ {
+ client->height = mon_height - ((client->y - mon_y) + BORDERWIDTH * 2);
+ }
+
+ resize(client->id, client->width, client->height);
+}
+
/* Resize window win to width,height. */
void resize(xcb_drawable_t win, uint16_t width, uint16_t height)
{
@@ -1635,6 +2223,8 @@ void resize(xcb_drawable_t win, uint16_t width, uint16_t height)
/* Can't resize root. */
return;
}
+
+ PDEBUG("Resizing to %d x %d.\n", width, height);
values[0] = width;
values[1] = height;
@@ -1658,18 +2248,8 @@ void resize(xcb_drawable_t win, uint16_t width, uint16_t height)
*/
void resizestep(struct client *client, char direction)
{
- int16_t start_x;
- int16_t start_y;
- int16_t x;
- int16_t y;
- uint16_t width;
- uint16_t height;
- uint16_t origwidth;
- uint16_t origheight;
int step_x = MOVE_STEP;
int step_y = MOVE_STEP;
- xcb_drawable_t win;
- bool warp = false;
if (NULL == client)
{
@@ -1682,25 +2262,8 @@ void resizestep(struct client *client, char direction)
return;
}
- win = client->id;
-
- /* Save pointer position so we can warp back later, if necessary. */
- if (!getpointer(win, &start_x, &start_y))
- {
- return;
- }
+ raisewindow(client->id);
- raisewindow(win);
-
- /* Get window geometry. */
- if (!getgeom(client->id, &x, &y, &width, &height))
- {
- return;
- }
-
- origwidth = width;
- origheight = height;
-
if (client->width_inc > 1)
{
step_x = client->width_inc;
@@ -1718,44 +2281,23 @@ void resizestep(struct client *client, char direction)
{
step_y = MOVE_STEP;
}
-
+
switch (direction)
{
case 'h':
- if (step_x >= width)
- {
- return;
- }
-
- width = width - step_x;
- height = height;
-
+ client->width = client->width - step_x;
break;
case 'j':
- width = width;
- height = height + step_y;
- if (height + y > screen->height_in_pixels)
- {
- return;
- }
+ client->height = client->height + step_y;
break;
case 'k':
- if (step_y >= height)
- {
- return;
- }
- height = height - step_y;
+ client->height = client->height - step_y;
break;
case 'l':
- width = width + step_x;
- height = height;
- if (width + x > screen->width_in_pixels)
- {
- return;
- }
+ client->width = client->width + step_x;
break;
default:
@@ -1763,174 +2305,46 @@ void resizestep(struct client *client, char direction)
break;
} /* switch direction */
- /* Is it smaller than it wants to be? */
- if (0 != client->min_height && height < client->min_height)
- {
- height = client->min_height;
- }
-
- if (0 != client->min_width && width < client->min_width)
- {
- width = client->min_width;
- }
+ resizelim(client);
- PDEBUG("Resizing to %dx%d\n", width, height);
- resize(win, width, height);
-
/* If this window was vertically maximized, remember that it isn't now. */
if (client->vertmaxed)
{
client->vertmaxed = false;
}
-
- /*
- * We might need to warp the pointer to keep the focus.
- *
- * Don't do anything if the pointer was outside the window when we
- * began resizing.
- *
- * If the pointer was inside the window when we began and it still
- * is, don't do anything. However, if we're about to lose the
- * pointer, move in.
- */
- if (start_x > 0 - BORDERWIDTH && start_x < origwidth + BORDERWIDTH
- && start_y > 0 - BORDERWIDTH && start_y < origheight + BORDERWIDTH )
- {
- x = start_x;
- y = start_y;
-
- if (start_x > width - step_x)
- {
- x = width / 2;
- if (0 == x)
- {
- x = 1;
- }
- warp = true;
- }
-
- if (start_y > height - step_y)
- {
- y = height / 2;
- if (0 == y)
- {
- y = 1;
- }
- warp = true;
- }
- if (warp)
- {
- xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0,
- x, y);
- xcb_flush(conn);
- }
- }
+ xcb_warp_pointer(conn, XCB_NONE, client->id, 0, 0, 0, 0,
+ client->width / 2, client->height / 2);
+ xcb_flush(conn);
}
/*
* Move window win as a result of pointer motion to coordinates
* rel_x,rel_y.
*/
-void mousemove(xcb_drawable_t win, int rel_x, int rel_y)
+void mousemove(struct client *client, int rel_x, int rel_y)
{
- xcb_get_geometry_reply_t *geom;
- int x;
- int y;
-
- /* Get window geometry. */
-
- geom = xcb_get_geometry_reply(conn,
- xcb_get_geometry(conn, win),
- NULL);
- if (NULL == geom)
- {
- return;
- }
-
- x = rel_x;
- y = rel_y;
-
- if (x < 0)
- {
- x = 0;
- }
- if (y < 0)
- {
- y = 0;
- }
- if (y + geom->height + BORDERWIDTH * 2 > screen->height_in_pixels)
- {
- y = screen->height_in_pixels - (geom->height + BORDERWIDTH * 2);
- }
- if (x + geom->width + BORDERWIDTH * 2 > screen->width_in_pixels)
- {
- x = screen->width_in_pixels - (geom->width + BORDERWIDTH * 2);
- }
+ client->x = rel_x;
+ client->y = rel_y;
- movewindow(win, x, y);
-
- free(geom);
+ movelim(client);
}
void mouseresize(struct client *client, int rel_x, int rel_y)
{
- uint16_t width;
- uint16_t height;
- int16_t x;
- int16_t y;
-
- /* Get window geometry. We throw away width and height values. */
- if (!getgeom(client->id, &x, &y, &width, &height))
- {
- return;
- }
+ client->width = abs(rel_x - client->x);
+ client->height = abs(rel_y - client->y);
- /*
- * Calculate new width and height. If we have WM hints, we use
- * them. Otherwise these are set to 1 pixel when initializing
- * client.
- *
- * Note that we need to take the absolute of the difference since
- * we're dealing with unsigned integers. This has the interesting
- * side effect that we resize the window even if the mouse pointer
- * is at the other side of the window.
- */
-
- width = abs(rel_x - x);
- height = abs(rel_y - y);
-
- width -= (width - client->base_width) % client->width_inc;
- height -= (height - client->base_height) % client->height_inc;
+ client->width -= (client->width - client->base_width) % client->width_inc;
+ client->height -= (client->height - client->base_height)
+ % client->height_inc;
- /* Is it smaller than it wants to be? */
- if (0 != client->min_height && height < client->min_height)
- {
- height = client->min_height;
- }
+ PDEBUG("Trying to resize to %dx%d (%dx%d)\n", client->width, client->height,
+ (client->width - client->base_width) / client->width_inc,
+ (client->height - client->base_height) / client->height_inc);
- if (0 != client->min_width && width < client->min_width)
- {
- width = client->min_width;
- }
-
- /* Check if the window fits on screen. */
- if (x + width > screen->width_in_pixels - BORDERWIDTH * 2)
- {
- width = screen->width_in_pixels - (x + BORDERWIDTH * 2);
- }
-
- if (y + height > screen->height_in_pixels - BORDERWIDTH * 2)
- {
- height = screen->height_in_pixels - (y + BORDERWIDTH * 2);
- }
+ resizelim(client);
- PDEBUG("Resizing to %dx%d (%dx%d)\n", width, height,
- (width - client->base_width) / client->width_inc,
- (height - client->base_height) / client->height_inc);
-
- resize(client->id, width, height);
-
/* If this window was vertically maximized, remember that it isn't now. */
if (client->vertmaxed)
{
@@ -1942,11 +2356,6 @@ void movestep(struct client *client, char direction)
{
int16_t start_x;
int16_t start_y;
- int16_t x;
- int16_t y;
- uint16_t width;
- uint16_t height;
- xcb_drawable_t win;
if (NULL == client)
{
@@ -1959,63 +2368,29 @@ void movestep(struct client *client, char direction)
return;
}
- win = client->id;
-
/* Save pointer position so we can warp pointer here later. */
- if (!getpointer(win, &start_x, &start_y))
- {
- return;
- }
-
- if (!getgeom(win, &x, &y, &width, &height))
+ if (!getpointer(client->id, &start_x, &start_y))
{
return;
}
- width = width + BORDERWIDTH * 2;
- height = height + BORDERWIDTH * 2;
-
- raisewindow(win);
-
+ raisewindow(client->id);
switch (direction)
{
case 'h':
- x = x - MOVE_STEP;
- if (x < 0)
- {
- x = 0;
- }
-
- movewindow(win, x, y);
+ client->x = client->x - MOVE_STEP;
break;
case 'j':
- y = y + MOVE_STEP;
- if (y + height > screen->height_in_pixels)
- {
- y = screen->height_in_pixels - height;
- }
- movewindow(win, x, y);
+ client->y = client->y + MOVE_STEP;
break;
case 'k':
- y = y - MOVE_STEP;
- if (y < 0)
- {
- y = 0;
- }
-
- movewindow(win, x, y);
+ client->y = client->y - MOVE_STEP;
break;
case 'l':
- x = x + MOVE_STEP;
- if (x + width > screen->width_in_pixels)
- {
- x = screen->width_in_pixels - width;
- }
-
- movewindow(win, x, y);
+ client->x = client->x + MOVE_STEP;
break;
default:
@@ -2023,19 +2398,33 @@ void movestep(struct client *client, char direction)
break;
} /* switch direction */
+ movelim(client);
+
/*
* If the pointer was inside the window to begin with, move
* pointer back to where it was, relative to the window.
*/
- if (start_x > 0 - BORDERWIDTH && start_x < width + BORDERWIDTH
- && start_y > 0 - BORDERWIDTH && start_y < height + BORDERWIDTH )
+ if (start_x > 0 - BORDERWIDTH && start_x < client->width + BORDERWIDTH
+ && start_y > 0 - BORDERWIDTH && start_y < client->height + BORDERWIDTH )
{
- xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0,
+ xcb_warp_pointer(conn, XCB_NONE, client->id, 0, 0, 0, 0,
start_x, start_y);
xcb_flush(conn);
}
}
+void setborders(struct client *client, int width)
+{
+ uint32_t values[1];
+ uint32_t mask = 0;
+
+ values[0] = width;
+
+ mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
+ xcb_configure_window(conn, client->id, mask, &values[0]);
+ xcb_flush(conn);
+}
+
void unmax(struct client *client)
{
uint32_t values[5];
@@ -2046,13 +2435,17 @@ void unmax(struct client *client)
PDEBUG("unmax: client was NULL!\n");
return;
}
+
+ client->x = client->origsize.x;
+ client->y = client->origsize.y;
+ client->width = client->origsize.width;
+ client->height = client->origsize.height;
/* Restore geometry. */
if (client->maxed)
{
-
values[0] = client->x;
- values[1] = client->y;
+ values[1] = client->y;
values[2] = client->width;
values[3] = client->height;
@@ -2081,16 +2474,19 @@ void unmax(struct client *client)
/* Warp pointer to window or we might lose it. */
xcb_warp_pointer(conn, XCB_NONE, client->id, 0, 0, 0, 0,
- 1, 1);
+ client->width / 2, client->height / 2);
xcb_flush(conn);
}
void maximize(struct client *client)
{
- xcb_get_geometry_reply_t *geom;
uint32_t values[4];
- uint32_t mask = 0;
+ uint32_t mask = 0;
+ int16_t mon_x;
+ int16_t mon_y;
+ uint16_t mon_width;
+ uint16_t mon_height;
if (NULL == client)
{
@@ -2098,6 +2494,21 @@ void maximize(struct client *client)
return;
}
+ if (NULL == client->monitor)
+ {
+ mon_x = 0;
+ mon_y = 0;
+ mon_width = screen->width_in_pixels;
+ mon_height = screen->height_in_pixels;
+ }
+ else
+ {
+ mon_x = client->monitor->x;
+ mon_y = client->monitor->y;
+ mon_width = client->monitor->width;
+ mon_height = client->monitor->height;
+ }
+
/*
* Check if maximized already. If so, revert to stored
* geometry.
@@ -2108,35 +2519,31 @@ void maximize(struct client *client)
client->maxed = false;
return;
}
-
- /* Get window geometry. */
- geom = xcb_get_geometry_reply(conn,
- xcb_get_geometry(conn, client->id),
- NULL);
- if (NULL == geom)
- {
- return;
- }
/* Raise first. Pretty silly to maximize below something else. */
raisewindow(client->id);
/* FIXME: Store original geom in property as well? */
- client->x = geom->x;
- client->y = geom->y;
- client->width = geom->width;
- client->height = geom->height;
-
+ client->origsize.x = client->x;
+ client->origsize.y = client->y;
+ client->origsize.width = client->width;
+ client->origsize.height = client->height;
+
/* Remove borders. */
values[0] = 0;
mask = XCB_CONFIG_WINDOW_BORDER_WIDTH;
xcb_configure_window(conn, client->id, mask, values);
/* Move to top left and resize. */
- values[0] = 0;
- values[1] = 0;
- values[2] = screen->width_in_pixels;
- values[3] = screen->height_in_pixels;
+ client->x = mon_x;
+ client->y = mon_y;
+ client->width = mon_width;
+ client->height = mon_height;
+
+ values[0] = client->x;
+ values[1] = client->y;
+ values[2] = client->width;
+ values[3] = client->height;
xcb_configure_window(conn, client->id, XCB_CONFIG_WINDOW_X
| XCB_CONFIG_WINDOW_Y
| XCB_CONFIG_WINDOW_WIDTH
@@ -2145,17 +2552,15 @@ void maximize(struct client *client)
xcb_flush(conn);
client->maxed = true;
-
- free(geom);
}
void maxvert(struct client *client)
{
uint32_t values[2];
- uint16_t width;
- uint16_t height;
- int16_t x;
- int16_t y;
+ int16_t mon_x;
+ int16_t mon_y;
+ uint16_t mon_width;
+ uint16_t mon_height;
if (NULL == client)
{
@@ -2163,6 +2568,21 @@ void maxvert(struct client *client)
return;
}
+ if (NULL == client->monitor)
+ {
+ mon_x = 0;
+ mon_y = 0;
+ mon_width = screen->width_in_pixels;
+ mon_height = screen->height_in_pixels;
+ }
+ else
+ {
+ mon_x = client->monitor->x;
+ mon_y = client->monitor->y;
+ mon_width = client->monitor->width;
+ mon_height = client->monitor->height;
+ }
+
/*
* Check if maximized already. If so, revert to stored geometry.
*/
@@ -2175,29 +2595,25 @@ void maxvert(struct client *client)
/* Raise first. Pretty silly to maximize below something else. */
raisewindow(client->id);
-
- /* Get window geometry. */
- if (!getgeom(client->id, &x, &y, &width, &height))
- {
- return;
- }
/*
* Store original coordinates and geometry.
* FIXME: Store in property as well?
*/
- client->x = x;
- client->y = y;
- client->width = width;
- client->height = height;
+ client->origsize.x = client->x;
+ client->origsize.y = client->y;
+ client->origsize.width = client->width;
+ client->origsize.height = client->height;
+ client->y = mon_y;
/* Compute new height considering height increments and screen height. */
- height = screen->height_in_pixels - BORDERWIDTH * 2;
- height -= (height - client->base_height) % client->height_inc;
+ client->height = mon_height - BORDERWIDTH * 2;
+ client->height -= (client->height - client->base_height)
+ % client->height_inc;
/* Move to top of screen and resize. */
- values[0] = 0;
- values[1] = height;
+ values[0] = client->y;
+ values[1] = client->height;
xcb_configure_window(conn, client->id, XCB_CONFIG_WINDOW_Y
| XCB_CONFIG_WINDOW_HEIGHT, values);
@@ -2254,20 +2670,35 @@ void topleft(void)
{
int16_t pointx;
int16_t pointy;
-
+ int16_t mon_x;
+ int16_t mon_y;
+
if (NULL == focuswin)
{
return;
}
+ if (NULL == focuswin->monitor)
+ {
+ mon_x = 0;
+ mon_y = 0;
+ }
+ else
+ {
+ mon_x = focuswin->monitor->x;
+ mon_y = focuswin->monitor->y;
+ }
+
raisewindow(focuswin->id);
if (!getpointer(focuswin->id, &pointx, &pointy))
{
return;
}
-
- movewindow(focuswin->id, 0, 0);
+
+ focuswin->x = mon_x;
+ focuswin->y = mon_y;
+ movewindow(focuswin->id, focuswin->x, focuswin->y);
xcb_warp_pointer(conn, XCB_NONE, focuswin->id, 0, 0, 0, 0,
pointx, pointy);
xcb_flush(conn);
@@ -2275,32 +2706,38 @@ void topleft(void)
void topright(void)
{
- int16_t x;
- int16_t y;
- uint16_t width;
- uint16_t height;
int16_t pointx;
int16_t pointy;
-
+ uint16_t mon_y;
+ uint16_t mon_width;
+
if (NULL == focuswin)
{
return;
}
- raisewindow(focuswin->id);
-
- if (!getpointer(focuswin->id, &pointx, &pointy))
+ if (NULL == focuswin->monitor)
{
- return;
+ mon_width = screen->width_in_pixels;
+ mon_y = 0;
+ }
+ else
+ {
+ mon_width = focuswin->monitor->width;
+ mon_y = focuswin->monitor->y;
}
+
+ raisewindow(focuswin->id);
- if (!getgeom(focuswin->id, &x, &y, &width, &height))
+ if (!getpointer(focuswin->id, &pointx, &pointy))
{
return;
}
- movewindow(focuswin->id, screen->width_in_pixels
- - (width + BORDERWIDTH * 2), 0);
+ focuswin->x = mon_width - (focuswin->width + BORDERWIDTH * 2);
+ focuswin->y = mon_y;
+
+ movewindow(focuswin->id, focuswin->x, focuswin->y);
xcb_warp_pointer(conn, XCB_NONE, focuswin->id, 0, 0, 0, 0,
pointx, pointy);
@@ -2310,32 +2747,41 @@ void topright(void)
void botleft(void)
{
- int16_t x;
- int16_t y;
- uint16_t width;
- uint16_t height;
int16_t pointx;
int16_t pointy;
-
+ int16_t mon_x;
+ int16_t mon_y;
+ uint16_t mon_height;
+
if (NULL == focuswin)
{
return;
}
- raisewindow(focuswin->id);
-
- if (!getpointer(focuswin->id, &pointx, &pointy))
+ if (NULL == focuswin->monitor)
{
- return;
+ mon_x = 0;
+ mon_y = 0;
+ mon_height = screen->height_in_pixels;
+ }
+ else
+ {
+ mon_x = focuswin->monitor->x;
+ mon_y = focuswin->monitor->y;
+ mon_height = focuswin->monitor->height;
}
- if (!getgeom(focuswin->id, &x, &y, &width, &height))
+ raisewindow(focuswin->id);
+
+ if (!getpointer(focuswin->id, &pointx, &pointy))
{
return;
}
-
- movewindow(focuswin->id, 0, screen->height_in_pixels
- - (height + BORDERWIDTH * 2));
+
+ focuswin->x = mon_x;
+ focuswin->y = mon_y + mon_height - (focuswin->height + BORDERWIDTH * 2);
+
+ movewindow(focuswin->id, focuswin->x, focuswin->y);
xcb_warp_pointer(conn, XCB_NONE, focuswin->id, 0, 0, 0, 0,
pointx, pointy);
@@ -2344,35 +2790,45 @@ void botleft(void)
void botright(void)
{
- int16_t x;
- int16_t y;
- uint16_t width;
- uint16_t height;
int16_t pointx;
int16_t pointy;
+ int16_t mon_x;
+ int16_t mon_y;
+ uint16_t mon_width;
+ uint16_t mon_height;
if (NULL == focuswin)
{
return;
}
- raisewindow(focuswin->id);
-
- if (!getpointer(focuswin->id, &pointx, &pointy))
+ if (NULL == focuswin->monitor)
{
- return;
+ mon_x = 0;
+ mon_y = 0;
+ mon_width = screen->width_in_pixels;;
+ mon_height = screen->height_in_pixels;
}
+ else
+ {
+ mon_x = focuswin->monitor->x;
+ mon_y = focuswin->monitor->y;
+ mon_width = focuswin->monitor->width;
+ mon_height = focuswin->monitor->height;
+ }
+
+ raisewindow(focuswin->id);
- if (!getgeom(focuswin->id, &x, &y, &width, &height))
+ if (!getpointer(focuswin->id, &pointx, &pointy))
{
return;
}
+
+ focuswin->x = mon_x + mon_width - (focuswin->width + BORDERWIDTH * 2);
+
+ focuswin->y = mon_y + mon_height - (focuswin->height + BORDERWIDTH * 2);
- movewindow(focuswin->id,
- screen->width_in_pixels
- - (width + BORDERWIDTH * 2),
- screen->height_in_pixels
- - (height + BORDERWIDTH * 2));
+ movewindow(focuswin->id, focuswin->x, focuswin->y);
xcb_warp_pointer(conn, XCB_NONE, focuswin->id, 0, 0, 0, 0,
pointx, pointy);
@@ -2423,6 +2879,60 @@ void deletewin(void)
xcb_flush(conn);
}
+void prevscreen(void)
+{
+ struct item *item;
+
+ if (NULL == focuswin || NULL == focuswin->monitor)
+ {
+ return;
+ }
+
+ item = focuswin->monitor->item->prev;
+
+ if (NULL == item)
+ {
+ return;
+ }
+
+ focuswin->monitor = item->data;
+
+ raisewindow(focuswin->id);
+ fitonscreen(focuswin);
+ movelim(focuswin);
+
+ xcb_warp_pointer(conn, XCB_NONE, focuswin->id, 0, 0, 0, 0,
+ 0, 0);
+ xcb_flush(conn);
+}
+
+void nextscreen(void)
+{
+ struct item *item;
+
+ if (NULL == focuswin || NULL == focuswin->monitor)
+ {
+ return;
+ }
+
+ item = focuswin->monitor->item->next;
+
+ if (NULL == item)
+ {
+ return;
+ }
+
+ focuswin->monitor = item->data;
+
+ raisewindow(focuswin->id);
+ fitonscreen(focuswin);
+ movelim(focuswin);
+
+ xcb_warp_pointer(conn, XCB_NONE, focuswin->id, 0, 0, 0, 0,
+ 0, 0);
+ xcb_flush(conn);
+}
+
void handle_keypress(xcb_key_press_event_t *ev)
{
int i;
@@ -2584,7 +3094,15 @@ void handle_keypress(xcb_key_press_event_t *ev)
case KEY_END:
deletewin();
break;
-
+
+ case KEY_PREVSCR:
+ prevscreen();
+ break;
+
+ case KEY_NEXTSCR:
+ nextscreen();
+ break;
+
default:
/* Ignore other keys. */
break;
@@ -2592,6 +3110,165 @@ void handle_keypress(xcb_key_press_event_t *ev)
}
} /* handle_keypress() */
+void configurerequest(xcb_configure_request_event_t *e)
+{
+ uint32_t mask = 0;
+ uint32_t values[7];
+ int i = -1;
+ struct client *client;
+ int16_t mon_x;
+ int16_t mon_y;
+ uint16_t mon_width;
+ uint16_t mon_height;
+
+ PDEBUG("event: Configure request. mask = %d\n", e->value_mask);
+
+ /* Find the client. */
+ client = findclient(e->window);
+ if (NULL == client)
+ {
+ PDEBUG("We don't know about this window yet.\n");
+ }
+
+ if (NULL == client || NULL == client->monitor)
+ {
+ mon_x = 0;
+ mon_y = 0;
+ mon_width = screen->width_in_pixels;
+ mon_height = screen->height_in_pixels;
+ }
+ else
+ {
+ mon_x = client->monitor->x;
+ mon_y = client->monitor->y;
+ mon_width = client->monitor->width;
+ mon_height = client->monitor->height;
+ }
+
+ /*
+ * We ignore border width configurations, but handle all
+ * others.
+ */
+
+ if (e->value_mask & XCB_CONFIG_WINDOW_X)
+ {
+ PDEBUG("Changing X coordinate to %d\n", e->x);
+ mask |= XCB_CONFIG_WINDOW_X;
+ i ++;
+
+ if (client)
+ {
+ client->x = e->x;
+ if (client->x < mon_x)
+ {
+ client->x = mon_x;
+ }
+ else if (client->x + client->width > mon_x + mon_width)
+ {
+ client->x = (mon_x + mon_width) - client->width;
+ }
+
+ values[i] = client->x;
+ }
+ else
+ {
+ values[i] = e->x;
+ }
+ }
+
+ if (e->value_mask & XCB_CONFIG_WINDOW_Y)
+ {
+ PDEBUG("Changing Y coordinate to %d.\n", e->y);
+ mask |= XCB_CONFIG_WINDOW_Y;
+ i ++;
+
+ if (client)
+ {
+ client->y = e->y;
+ if (client->y < mon_y)
+ {
+ client->y = mon_y;
+ }
+ else if (client->y + client->height > mon_y + mon_height)
+ {
+ client->y = (mon_y + mon_height) - client->height;
+ }
+
+ values[i] = client->y;
+ }
+ else
+ {
+ values[i] = e->y;
+ }
+ }
+
+ if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH)
+ {
+ PDEBUG("Changing width to %d.\n", e->width);
+ mask |= XCB_CONFIG_WINDOW_WIDTH;
+ i ++;
+
+ if (client)
+ {
+ client->width = e->width;
+
+ if (client->width + BORDERWIDTH * 2 > mon_width)
+ {
+ client->width = mon_width - BORDERWIDTH * 2;
+ }
+
+ values[i] = client->width;
+ }
+ else
+ {
+ values[i] = e->width;
+ }
+ }
+
+ if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
+ {
+ PDEBUG("Changing height to %d.\n", e->height);
+ mask |= XCB_CONFIG_WINDOW_HEIGHT;
+ i ++;
+
+ if (client)
+ {
+ client->height = e->height;
+ if (client->height + BORDERWIDTH * 2 > mon_height)
+ {
+ client->height = mon_height - BORDERWIDTH * 2;
+ }
+
+ values[i] = client->height;
+ }
+ else
+ {
+ values[i] = e->height;
+ }
+ }
+
+ if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING)
+ {
+ mask |= XCB_CONFIG_WINDOW_SIBLING;
+ i ++;
+ values[i] = e->sibling;
+ }
+
+ if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
+ {
+ PDEBUG("Changing stack order.\n");
+ mask |= XCB_CONFIG_WINDOW_STACK_MODE;
+ i ++;
+ values[i] = e->stack_mode;
+ }
+
+ if (-1 != i)
+ {
+ xcb_configure_window(conn, e->window, mask, values);
+ xcb_flush(conn);
+ }
+}
+
void events(void)
{
xcb_generic_event_t *ev;
@@ -2657,6 +3334,16 @@ void events(void)
}
#endif
+ /* Note that we ignore XCB_RANDR_NOTIFY. */
+ if (ev->response_type
+ == randrbase + XCB_RANDR_SCREEN_CHANGE_NOTIFY)
+ {
+ PDEBUG("RANDR screen change notify. Checking outputs.\n");
+ getrandr();
+ free(ev);
+ continue;
+ }
+
switch (ev->response_type & ~0x80)
{
case XCB_MAP_REQUEST:
@@ -2708,10 +3395,6 @@ void events(void)
case XCB_BUTTON_PRESS:
{
xcb_button_press_event_t *e;
- int16_t x;
- int16_t y;
- uint16_t width;
- uint16_t height;
e = (xcb_button_press_event_t *) ev;
PDEBUG("Button %d pressed in window %ld, subwindow %d "
@@ -2765,13 +3448,7 @@ void events(void)
/* Raise window. */
raisewindow(focuswin->id);
-
- /* Get window geometry. */
- if (!getgeom(focuswin->id, &x, &y, &width, &height))
- {
- break;
- }
-
+
/* Mouse button 1 was pressed. */
if (1 == e->detail)
{
@@ -2792,7 +3469,7 @@ void events(void)
/* Warp pointer to lower right. */
xcb_warp_pointer(conn, XCB_NONE, focuswin->id, 0, 0, 0,
- 0, width, height);
+ 0, focuswin->width, focuswin->height);
}
/*
@@ -2808,7 +3485,8 @@ void events(void)
*/
xcb_grab_pointer(conn, 0, screen->root,
XCB_EVENT_MASK_BUTTON_RELEASE
- | XCB_EVENT_MASK_BUTTON_MOTION,
+ | XCB_EVENT_MASK_BUTTON_MOTION
+ | XCB_EVENT_MASK_POINTER_MOTION_HINT,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC,
screen->root,
@@ -2824,7 +3502,7 @@ void events(void)
case XCB_MOTION_NOTIFY:
{
- xcb_motion_notify_event_t *e;
+ xcb_query_pointer_reply_t *pointer;
/*
* We can't do anything if we don't have a focused window
@@ -2834,26 +3512,41 @@ void events(void)
{
break;
}
-
- e = (xcb_motion_notify_event_t *) ev;
/*
+ * This is not really a real notify, but just a hint that
+ * the mouse pointer moved. This means we need to get the
+ * current pointer position ourselves.
+ */
+ pointer = xcb_query_pointer_reply(
+ conn, xcb_query_pointer(conn, screen->root), 0);
+
+ if (NULL == pointer)
+ {
+ PDEBUG("Couldn't get pointer position.\n");
+ break;
+ }
+
+ /*
* Our pointer is moving and since we even get this event
* we're either resizing or moving a window.
*/
if (mode == MCWM_MOVE)
{
- mousemove(focuswin->id, e->root_x, e->root_y);
+ mousemove(focuswin, pointer->root_x, pointer->root_y);
}
else if (mode == MCWM_RESIZE)
{
- mouseresize(focuswin, e->root_x, e->root_y);
+ mouseresize(focuswin, pointer->root_x, pointer->root_y);
}
else
{
PDEBUG("Motion event when we're not moving our resizing!\n");
}
+
+ free(pointer);
}
+
break;
case XCB_BUTTON_RELEASE:
@@ -2871,8 +3564,6 @@ void events(void)
{
int16_t x;
int16_t y;
- uint16_t width;
- uint16_t height;
/* We're finished moving or resizing. */
@@ -2897,20 +3588,14 @@ void events(void)
* if the pointer just happens to be on top of another
* window when we ungrab the pointer, so we have to
* warp the pointer before to prevent this.
- */
- if (!getgeom(focuswin->id, &x, &y, &width, &height))
- {
- break;
- }
-
- /*
+ *
* Move to saved position within window or if that
* position is now outside current window, move inside
* window.
*/
- if (mode_x > width)
+ if (mode_x > focuswin->width)
{
- x = width / 2;
+ x = focuswin->width / 2;
if (0 == x)
{
x = 1;
@@ -2922,9 +3607,9 @@ void events(void)
x = mode_x;
}
- if (mode_y > height)
+ if (mode_y > focuswin->height)
{
- y = height / 2;
+ y = focuswin->height / 2;
if (0 == y)
{
y = 1;
@@ -2937,7 +3622,6 @@ void events(void)
xcb_warp_pointer(conn, XCB_NONE, focuswin->id, 0, 0, 0, 0,
x, y);
-
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
xcb_flush(conn); /* Important! */
@@ -3064,15 +3748,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",
@@ -3086,82 +3769,28 @@ 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();
+ }
}
}
}
break;
case XCB_CONFIGURE_REQUEST:
- {
- xcb_configure_request_event_t *e
- = (xcb_configure_request_event_t *)ev;
- uint32_t mask = 0;
- uint32_t values[7];
- int i = -1;
-
- PDEBUG("event: Configure request. mask = %d\n", e->value_mask);
-
- /*
- * We ignore border width configurations, but handle all
- * others.
- */
-
- if (e->value_mask & XCB_CONFIG_WINDOW_X)
- {
- PDEBUG("Changing X coordinate to %d\n", e->x);
- mask |= XCB_CONFIG_WINDOW_X;
- i ++;
- values[i] = e->x;
- }
-
- if (e->value_mask & XCB_CONFIG_WINDOW_Y)
- {
- PDEBUG("Changing Y coordinate to %d.\n", e->y);
- mask |= XCB_CONFIG_WINDOW_Y;
- i ++;
- values[i] = e->y;
- }
-
- if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH)
- {
- PDEBUG("Changing width to %d.\n", e->width);
- mask |= XCB_CONFIG_WINDOW_WIDTH;
- i ++;
- values[i] = e->width;
- }
-
- if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
- {
- PDEBUG("Changing height to %d.\n", e->height);
- mask |= XCB_CONFIG_WINDOW_HEIGHT;
- i ++;
- values[i] = e->height;
- }
-
- if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING)
- {
- mask |= XCB_CONFIG_WINDOW_SIBLING;
- i ++;
- values[i] = e->sibling;
- }
-
- if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
- {
- PDEBUG("Changing stack order.\n");
- mask |= XCB_CONFIG_WINDOW_STACK_MODE;
- i ++;
- values[i] = e->stack_mode;
- }
-
- if (-1 != i)
- {
- xcb_configure_window(conn, e->window, mask, values);
- xcb_flush(conn);
- }
- }
+ configurerequest((xcb_configure_request_event_t *) ev);
break;
case XCB_CIRCULATE_REQUEST:
@@ -3240,8 +3869,14 @@ void events(void)
if (client->id == e->window)
{
PDEBUG("Forgetting about %d\n", e->window);
+ if (focuswin == client)
+ {
+ focuswin = NULL;
+ }
+
forgetclient(client);
- break;
+ /* We're finished. Break out of for loop. */
+ break;
}
} /* for */
}
@@ -3373,7 +4008,10 @@ int main(int argc, char **argv)
atom_desktop = xcb_atom_get(conn, "_NET_WM_DESKTOP");
wm_delete_window = xcb_atom_get(conn, "WM_DELETE_WINDOW");
wm_protocols = xcb_atom_get(conn, "WM_PROTOCOLS");
-
+
+ /* Check for RANDR extension and configure. */
+ randrbase = setuprandr();
+
/* Loop over all clients and set up stuff. */
if (0 != setupscreen())
{