summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--NEWS25
-rw-r--r--TODO43
-rw-r--r--WISHLIST2
-rw-r--r--config.h2
-rw-r--r--list.c43
-rw-r--r--list.h17
-rw-r--r--mcwm.c1954
-rw-r--r--mcwm.man26
9 files changed, 1420 insertions, 697 deletions
diff --git a/Makefile b/Makefile
index a410c38..92b875d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,12 @@
-VERSION=20110412
+VERSION=20110531
DIST=mcwm-$(VERSION)
SRC=mcwm.c list.c config.h events.h list.h
DISTFILES=LICENSE Makefile NEWS README TODO WISHLIST mcwm.man $(SRC)
CC=gcc
CFLAGS=-g -std=c99 -Wall -Wextra -O2 -I/usr/local/include #-DDEBUG #-DDMALLOC
-LDFLAGS=-L/usr/local/lib -lxcb -lxcb-keysyms -lxcb-icccm -lxcb-atom #-ldmalloc
+LDFLAGS=-L/usr/local/lib -lxcb -lxcb-randr -lxcb-keysyms -lxcb-icccm \
+ -lxcb-atom #-ldmalloc
RM=/bin/rm
PREFIX=/usr/local
diff --git a/NEWS b/NEWS
index 156d134..5160829 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,31 @@
User visible changes
+2011-07-20
+
+ * Speedup when using a trackball or high CPI mouse. Use only mouse
+ pointer hints instead of actual mouse events and let mcwm ask for
+ pointer position.
+
+ Incidentally, this was originally added in June, 2010, but
+ removed a month later after reading Gajewska and Manasse's "Why X
+ Is Not Our Ideal Window System". Real experience shows that I was
+ mistaken.
+
+2011-06-20
+
+ * Fixed windows were always inserted as the next window in window
+ list after changing workspace. Now fixed.
+
+2011-06-01
+
+ * Beginning of RANDR support. mcwm now aware of the number of
+ physical screens and their sizes. Move and resize is now limited
+ by size of physical screen instead of virtual screen.
+
+ * New keys: Mod4 + , moves focused window to previous screen and
+ Mod4 + . moves it to the next screen.
+
2011-03-29
* Panels and other windows with window manager override interfered
diff --git a/TODO b/TODO
index cb49322..397f317 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,22 @@
-*- text -*-
+* Feature: We need to continue dragging for move and resize until
+ *both* MODKEY and mouse button has been released. Will be much nicer
+ with trackball.
+
+* Bug: Window border sometimes visible on other screen in vertical
+ direction.
+
+* Move to first window (or middle of screen) on another screen
+ with MODKEY + . and , instead of moving windows to new screen.
+ Shifted these keys will move window to new screen?
+
+* Handle new modes on physical outputs. What do we have to do?
+
+* A separate workspace list for every physical output.
+
+* Allow hexadecimal colour values on command line.
+
* Grab specific keys
Current code grabs modifier keys and any other keypress. We need to
@@ -61,30 +78,8 @@
Also respect EWMH hints _NET_WM_TYPE_DOCK and _NET_WM_TYPE_DESKTOP.
-* Flag to disable dontmoveoff?
-
-* RandR/Xinerama
-
- Get physical screen characteristics for every screen. Maximize, move
- to corners should respect the screen it's on. We want a set of
- workspaces for every physical screen as well.
-
- xcb_randr_screen_size_t
-
- xcb_randr_screen_size_iterator_t
-
- xcb_randr_get_screen_info_reply_t
-
- xcb_randr_set_screen_size_request_t
-
- How do we handle window moves from one screen to another. Should we
- snap to the physical screen's edge and then allow move to continue?
-
- An idea from Christian: Use a huge virtual screen and make physical
- screens map to it. Perhaps we can actually manage to have a window
- on two physical screens at once?
-
-* Key to move pointer to another physical screen.
+* Flag to disable that mcwm won't allow windows to move off the
+ screen?
* Use xcb-event's event handlers?
diff --git a/WISHLIST b/WISHLIST
index 38f9ce4..58a5591 100644
--- a/WISHLIST
+++ b/WISHLIST
@@ -32,7 +32,7 @@ v Changing focus from keyboard which rememebers last focused window.
- Configurable key bindings.
-- Know about physical screens dynamically (RandR).
+v Know about physical screens dynamically (RandR).
- Key binding to change focus to another physical screen.
diff --git a/config.h b/config.h
index c21ffc6..b5fa661 100644
--- a/config.h
+++ b/config.h
@@ -76,3 +76,5 @@
#define USERKEY_BOTLEFT XK_B
#define USERKEY_BOTRIGHT XK_N
#define USERKEY_DELETE XK_End
+#define USERKEY_PREVSCREEN XK_comma
+#define USERKEY_NEXTSCREEN XK_period
diff --git a/list.c b/list.c
index fcfe33f..d331e24 100644
--- a/list.c
+++ b/list.c
@@ -118,6 +118,49 @@ void delitem(struct item **mainlist, struct item *item)
free(item);
}
+void freeitem(struct item **list, int *stored,
+ struct item *item)
+{
+ if (NULL == list || NULL == *list || NULL == item)
+ {
+ return;
+ }
+
+ if (NULL != item->data)
+ {
+ free(item->data);
+ item->data = NULL;
+ }
+
+ delitem(list, item);
+
+ if (NULL != stored)
+ {
+ (*stored) --;
+ }
+}
+
+/*
+ * Delete all elements in list and free memory resources.
+ */
+void delallitems(struct item **list, int *stored)
+{
+ struct item *item;
+ struct item *next;
+
+ for (item = *list; item != NULL; item = next)
+ {
+ next = item->next;
+ free(item->data);
+ delitem(list, item);
+ }
+
+ if (NULL != stored)
+ {
+ (*stored) = 0;
+ }
+}
+
void listitems(struct item *mainlist)
{
struct item *item;
diff --git a/list.h b/list.h
index ecd2bfb..7c9a94d 100644
--- a/list.h
+++ b/list.h
@@ -18,11 +18,24 @@ void movetohead(struct item **mainlist, struct item *item);
struct item *additem(struct item **mainlist);
/*
- *
+ * Delete item from list mainlist.
*/
void delitem(struct item **mainlist, struct item *item);
/*
- *
+ * Free any data in current item and then delete item. Optionally
+ * update number of items in list if stored != NULL.
+ */
+void freeitem(struct item **list, int *stored,
+ struct item *item);
+
+/*
+ * Delete all items in list. Optionally update number of items in list
+ * if stored != NULL.
+ */
+void delallitems(struct item **list, int *stored);
+
+/*
+ * Print all items in mainlist on stdout.
*/
void listitems(struct item *mainlist);
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())
{
diff --git a/mcwm.man b/mcwm.man
index e77c919..df1976b 100644
--- a/mcwm.man
+++ b/mcwm.man
@@ -1,4 +1,4 @@
-.TH mcwm 1 "Mar 30, 2011" "" ""
+.TH mcwm 1 "Jul 21, 2011" "" ""
.SH NAME
mcwm \- MC's Window Manager for X11.
.SH SYNOPSIS
@@ -27,7 +27,8 @@ mcwm \- MC's Window Manager for X11.
.PP
\-b means draw no window borders.
.PP
-\-t urxvt will start urxvt when MODKEY + Return is pressed.
+\-t urxvt will start urxvt when MODKEY + Return is pressed. Change to
+your prefered terminal program or something else entirely.
.PP
\-f colour sets border colour for focused window to a named colour,
such as "red".
@@ -42,8 +43,8 @@ Nota bene: For mcwm to be at all useful you need to know how what keys
generate the Mod1 and Mod4 modifier masks (default). If you don't
know, use
.B xmodmap(1)
-with the \-pm option to list them. You can change the modifiers in
-config.h and recompiling.
+with the \-pm option to list them. If you don't want to use Mod1 and
+Mod4, you can change the modifiers in the file config.h and recompile.
With the the default configuration, use mcwm like this.
.PP
@@ -116,25 +117,30 @@ the window, change to the workspace you want, then unfix the window on
the new workspace.
.IP \(bu 2
.B y
-move to upper left corner.
+move to upper left corner of physical screen.
.IP \(bu 2
.B u
-move to upper right corner.
+move to upper right corner of physical screen..
.IP \(bu 2
.B b
-move to lower left corner.
+move to lower left corner of physical screen..
.IP \(bu 2
.B n
-move to lower right corner.
+move to lower right corner of physical screen..
.IP \(bu 2
.B 0\-9
go to workspace n, 0-9.
.IP \(bu 2
.B End
close focused window.
+.IP \(bu 2
+.B ,
+move window to previous physical screen.
+.IP \(bu 2
+.B .
+move window to next physical screen.
.RE
.PP
-.PP
Note that all functions activated from the keyboard work on the
currently focused window regardless of the position of the mouse
cursor. Of course, changing workspaces has nothing to do with the
@@ -169,7 +175,7 @@ xrdb \-load ~/.Xresources
mcwm &
# Start a terminal in the foreground. If this dies, X dies.
-urxvt
+exec urxvt
.fi
.in -4
.sp