summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Cardell Widerkrantz <mc@hack.org>2011-02-22 16:15:12 +0100
committerMichael Cardell Widerkrantz <mc@hack.org>2011-03-08 12:14:38 +0100
commit976951dfeb0f36f5ba2c86ade574cff4b64ea8c7 (patch)
treec96de700b92c5e6b3874da0c68e85a30cb96264a
parent4762de7978fbba95e3de54a8779cfee949f57d76 (diff)
downloadmcwm-976951dfeb0f36f5ba2c86ade574cff4b64ea8c7.zip
Add support for Alt-Tabbing to the last focused window.
-rw-r--r--NEWS7
-rw-r--r--TODO46
-rw-r--r--config.h1
-rw-r--r--list.c108
-rw-r--r--list.h1
-rw-r--r--mcwm.c173
6 files changed, 297 insertions, 39 deletions
diff --git a/NEWS b/NEWS
index ae6068e..b10914c 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,13 @@
User visible changes
+2011-02-23
+
+ * If you change focus window mcwm remembers where we last had
+ focus. If you start using MODKEY+Tab to move around the window
+ list the first Tab will always bring you to where we last had
+ focus.
+
2011-02-19
* Resets per window state of max or vertical max when physical
diff --git a/TODO b/TODO
index 2b4334c..ca4264e 100644
--- a/TODO
+++ b/TODO
@@ -28,32 +28,50 @@
Save the subwindows of the root window and focus each when pressing
modkey + user_key_change. First option always last focused window.
- Partly done. I have added a linked list of all windows and can walk
- around them in a simple window ring.
-
I would like it to work like this: modkey-Tab-Tab-Tab... Release
modkey to focus on a window *and* to remember the window where we
started. The window we remember would be moved to the next position
in the window list.
+ This will also need to work if the change focus with the mouse.
+
A single modkey-Tab would then get the focus to end up in the window where
- we started.
+ we started tabbing or where we last had our focus if changing with
+ the mouse.
+
+ This is done, but in a bit ugly way. I have bound Alt_L explicitly
+ and looking for key release events.
+
+ It is possible to ask for what keys give XCB_MOD_MASK_4 or whatever
+ MODKEY is.
+
+ GetModifierMapping
+
+ This request returns the keycodes of the keys being used as
+ modifiers. The number of keycodes in the list is
+ 8*keycodes-per-modifier. The keycodes are divided into eight sets,
+ with each set containing keycodes-per-modifier elements. The sets
+ are assigned to the modifiers Shift, Lock, Control, Mod1, Mod2,
+ Mod3, Mod4, and Mod5, in order. The keycodes-per-modifier value is
+ chosen arbitrarily by the server; zeroes are used to fill in
+ unused elements within each set. If only zero values are given in
+ a set, the use of the corresponding modifier has been disabled.
+ The order of keycodes within each set is chosen arbitrarily by the
+ server.
+
+ xcb_get_modifier_mapping()
- It's possible to get a Release Event from the Alt key. Consider what
- xev(1) says about the key.
+ xcb_get_modifier_mapping_unchecked()
- I don't know if it's possible to ask the X server what keycode currently
- gives you XCB_MOD_MASK_4 or whatever, which would be the nicest way.
+ xcb_keycode_t * xcb_get_modifier_mapping_keycodes()
- I guess, but I haven't yet tried, that I will have to do a specific grab
- key for the XK_Alt_L or whatever instead.
+ xcb_keycode_t *
+ xcb_get_modifier_mapping_keycodes (const xcb_get_modifier_mapping_reply_t *R /**< */);
- This also means we have to add a new state, just like MCWM_MOVE et
- cetera, to know that we're currently jumping around the window list
- trying to find our next focused window.
+ xcb_get_modifier_mapping_keycodes_length (const xcb_get_modifier_mapping_reply_t *R /**< */);
How do we re-establish stack order after moving around windows to
- focus on?
+ focus on? Do we want to?
* Virtual screens/workspaces
diff --git a/config.h b/config.h
index db44bb3..0e6b949 100644
--- a/config.h
+++ b/config.h
@@ -76,3 +76,4 @@
#define USERKEY_BOTLEFT XK_B
#define USERKEY_BOTRIGHT XK_N
#define USERKEY_DELETE XK_End
+#define USERKEY_MOD XK_Alt_L
diff --git a/list.c b/list.c
index ab278a1..4751433 100644
--- a/list.c
+++ b/list.c
@@ -43,6 +43,53 @@ void movetohead(struct item **mainlist, struct item *item)
*mainlist = item;
}
+void movetonext(struct item **mainlist, struct item *item, struct item *next)
+{
+ if (NULL == item || NULL == next || NULL == mainlist || NULL == *mainlist)
+ {
+ return;
+ }
+
+ if (item->next == next || item == next)
+ {
+ /* Already in position. Do nothing. */
+ return;
+ }
+
+ /* Braid together the list where next used to be. */
+
+ if (NULL != next->next)
+ {
+ next->next->prev = next->prev;
+ }
+
+ if (NULL != next->prev)
+ {
+ next->prev->next = next->next;
+ }
+ else
+ {
+ /* next is currently head. move head one step further along. */
+ if (NULL != next->next)
+ {
+ *mainlist = next->next;
+ next->next->prev = NULL;
+ }
+ }
+
+ /* Position next after item and braid together list again. */
+ next->prev = item;
+ next->next = item->next;
+
+ if (NULL != next->next)
+ {
+ next->next->prev = next;
+ }
+
+ /* Remember where next is now. */
+ item->next = next;
+}
+
/*
*/
struct item *additem(struct item **mainlist)
@@ -120,10 +167,14 @@ void listall(struct item *mainlist)
{
struct item *item;
int i;
+
+ printf("Listing all:\n");
for (item = mainlist, i = 1; item != NULL; item = item->next, i ++)
{
printf("%d at %p: %s.\n", i, (void *)item, (char *)item->data);
+ printf(" prev: %p\n", item->prev);
+ printf(" next: %p\n", item->next);
}
}
@@ -133,7 +184,10 @@ int main(void)
struct item *item1;
struct item *item2;
struct item *item3;
- struct item *item4;
+ struct item *item4;
+ struct item *item;
+ struct item *nextitem;
+ int i;
char *foo1 = "1";
char *foo2 = "2";
char *foo3 = "3";
@@ -179,12 +233,58 @@ int main(void)
printf("Current elements:\n");
listall(mainlist);
- movetohead(&mainlist, item2);
+ printf("----------------------------------------------------------------------\n");
+
+ printf("Moving item3 to be after item2\n");
+ movetonext(&mainlist, item2, item3);
+ printf("Current elements:\n");
+ listall(mainlist);
+
+ printf("----------------------------------------------------------------------\n");
+
+ printf("Moving head! item4 to be after item2\n");
+ movetonext(&mainlist, item2, item4);
printf("Current elements:\n");
listall(mainlist);
+
+ printf("----------------------------------------------------------------------\n");
+ printf("Moving tail! item1 to be after item2\n");
+ movetonext(&mainlist, item2, item1);
+ printf("Current elements:\n");
+ listall(mainlist);
+
printf("----------------------------------------------------------------------\n");
+ printf("Moving head to be after tail.\n");
+ movetonext(&mainlist, item3, item2);
+ printf("Current elements:\n");
+ listall(mainlist);
+
+ printf("Moving all the items after each other.\n");
+ /* item3 is tail. work backwards. */
+ for (item = mainlist, i = 1;
+ item != NULL;
+ item = item->next, i ++)
+ {
+ for (nextitem = item2; nextitem != NULL; nextitem = nextitem->prev)
+ {
+ movetonext(&mainlist, nextitem, item);
+ printf("Current elements:\n");
+ listall(mainlist);
+ }
+ }
+
+ printf("----------------------------------------------------------------------\n");
+
+#if 0
+ movetohead(&mainlist, item2);
+ printf("Current elements:\n");
+ listall(mainlist);
+
+ printf("----------------------------------------------------------------------\n");
+#endif
+
printf("Deleting item stored at %p\n", item3);
delitem(&mainlist, item3);
printf("Current elements:\n");
@@ -203,7 +303,9 @@ int main(void)
listall(mainlist);
puts("");
-
+
+ printf("----------------------------------------------------------------------\n");
+
exit(0);
}
#endif
diff --git a/list.h b/list.h
index ffa323d..ee16e7e 100644
--- a/list.h
+++ b/list.h
@@ -6,6 +6,7 @@ struct item
};
void movetohead(struct item **mainlist, struct item *item);
+void movetonext(struct item **mainlist, struct item *item, struct item *next);
struct item *additem(struct item **mainlist);
void delitem(struct item **mainlist, struct item *item);
void listitems(struct item *mainlist);
diff --git a/mcwm.c b/mcwm.c
index fc2d5df..1ba6681 100644
--- a/mcwm.c
+++ b/mcwm.c
@@ -30,6 +30,7 @@
#include <getopt.h>
#include <string.h>
#include <signal.h>
+#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -73,6 +74,12 @@
/* We're currently resizing a window with the mouse. */
#define MCWM_RESIZE 3
+/*
+ * We're currently tabbing around the window list, looking for a new
+ * window to focus on.
+ */
+#define MCWM_TABBING 4
+
/* Our highest workspace. */
#define WORKSPACE_MAX 9
@@ -112,6 +119,7 @@ typedef enum {
KEY_B,
KEY_N,
KEY_END,
+ KEY_ALT,
KEY_MAX
} key_enum_t;
@@ -145,7 +153,12 @@ xcb_connection_t *conn; /* Connection to X server. */
xcb_screen_t *screen; /* Our current screen. */
uint32_t curws = 0; /* Current workspace. */
struct client *focuswin; /* Current focus window. */
+struct client *lastfocuswin; /* Last focused window. NOTE! Only
+ * used to communicate between
+ * start and end of tabbing
+ * mode. */
struct item *winlist = NULL; /* Global list of all client windows. */
+int mode = 0; /* Internal mode, such as move or resize */
/*
* Workspace list: Every workspace has a list of all visible
@@ -172,7 +185,7 @@ struct keys
xcb_keycode_t keycode;
} keys[KEY_MAX] =
{
- { USERKEY_FIX, 0 },
+ { USERKEY_FIX, 0 },
{ USERKEY_MOVE_LEFT, 0 },
{ USERKEY_MOVE_DOWN, 0 },
{ USERKEY_MOVE_UP, 0 },
@@ -180,8 +193,8 @@ struct keys
{ USERKEY_MAXVERT, 0 },
{ USERKEY_RAISE, 0 },
{ USERKEY_TERMINAL, 0 },
- { USERKEY_MAX, 0 },
- { USERKEY_CHANGE, 0, },
+ { USERKEY_MAX, 0 },
+ { USERKEY_CHANGE, 0 },
{ USERKEY_WS1, 0 },
{ USERKEY_WS2, 0 },
{ USERKEY_WS3, 0 },
@@ -196,7 +209,8 @@ struct keys
{ USERKEY_TOPRIGHT, 0 },
{ USERKEY_BOTLEFT, 0 },
{ USERKEY_BOTRIGHT, 0 },
- { USERKEY_DELETE, 0 }
+ { USERKEY_DELETE, 0 },
+ { USERKEY_MOD, 0 },
};
/* Global configuration. */
@@ -985,7 +999,7 @@ int setupkeys(void)
/* Get all the keysymbols. */
keysyms = xcb_key_symbols_alloc(conn);
-
+
for (i = KEY_F; i < KEY_MAX; i ++)
{
keys[i].keycode = keysymtokeycode(keys[i].keysym, keysyms);
@@ -999,17 +1013,38 @@ int setupkeys(void)
return -1;
}
- /* Grab this key. */
- xcb_grab_key(conn, 1, screen->root, MODKEY, keys[i].keycode,
- XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+ if (i == KEY_ALT)
+ {
+ /*
+ * Grab Alt with all modifiers.
+ *
+ * FIXME: We can ask the X server for the keycode that
+ * gives us the MODKEY mask with the GetModifierMapping
+ * request.
+ */
+ xcb_grab_key(conn, 1, screen->root, XCB_MOD_MASK_ANY,
+ keys[KEY_ALT].keycode,
+ XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+ }
+ else
+ {
+ /* Grab other keys with a modifier mask. */
+ xcb_grab_key(conn, 1, screen->root, MODKEY, keys[i].keycode,
+ XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
- /*
- * XXX Also grab it's shifted counterpart. A bit ugly here
- * because we grab all of them not just the ones we want.
- */
- xcb_grab_key(conn, 1, screen->root, MODKEY | SHIFTMOD, keys[i].keycode,
- XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+ /*
+ * XXX Also grab it's shifted counterpart. A bit ugly here
+ * because we grab all of them not just the ones we want.
+ */
+ xcb_grab_key(conn, 1, screen->root, MODKEY | SHIFTMOD,
+ keys[i].keycode,
+ XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+ }
} /* for */
+
+
+ /* Need this to take effect NOW! */
+ xcb_flush(conn);
/* Get rid of the key symbols table. */
free(keysyms);
@@ -1196,7 +1231,7 @@ void movewindow(xcb_drawable_t win, uint16_t x, uint16_t y)
/* Change focus to next in window ring. */
void focusnext(void)
{
- struct client *client;
+ struct client *client = NULL;
#if DEBUG
if (NULL != focuswin)
@@ -1205,7 +1240,26 @@ void focusnext(void)
}
#endif
- /* If we currently have no focus, focus first in list. */
+ if (NULL == wslist[curws])
+ {
+ PDEBUG("No windows to focus on in this workspace.\n");
+ return;
+ }
+
+ if (MCWM_TABBING != mode)
+ {
+ /*
+ * Remember what we last focused on. We need this when the
+ * MODKEY is released and we move the last focused window in
+ * the tabbing order list.
+ */
+ lastfocuswin = focuswin;
+ mode = MCWM_TABBING;
+
+ PDEBUG("Began tabbing.\n");
+ }
+
+ /* If we currently have no focus focus first in list. */
if (NULL == focuswin)
{
if (NULL == wslist[curws])
@@ -1213,7 +1267,7 @@ void focusnext(void)
PDEBUG("No windows to focus on.\n");
return;
}
-
+ PDEBUG("Focusing first in list: %p\n", wslist[curws]);
client = wslist[curws]->data;
}
else
@@ -1222,17 +1276,24 @@ void focusnext(void)
{
/*
* We were at the end of list. Focusing on first window in
- * list.
+ * list unless we were already there.
*/
- client = wslist[curws]->data;
+ if (focuswin->wsitem[curws] != wslist[curws]->data)
+ {
+ PDEBUG("End of list. Focusing first in list: %p\n",
+ wslist[curws]);
+ client = wslist[curws]->data;
+ }
}
else
{
/* Otherwise, focus the next in list. */
+ PDEBUG("Tabbing. Focusing next: %p.\n",
+ focuswin->wsitem[curws]->next);
client = focuswin->wsitem[curws]->next->data;
}
} /* if NULL focuswin */
-
+
/*
* Raise window if it's occluded, then warp pointer into it and
* set keyboard focus to it.
@@ -2251,6 +2312,12 @@ void handle_keypress(xcb_key_press_event_t *ev)
return;
}
+ if (MCWM_TABBING == mode && key != KEY_TAB)
+ {
+ /* We don't allow any other key while in this mode. */
+ return;
+ }
+
/* Is it shifted? */
if (ev->state & SHIFTMOD)
{
@@ -2391,7 +2458,7 @@ void handle_keypress(xcb_key_press_event_t *ev)
void events(void)
{
xcb_generic_event_t *ev;
- int mode = 0; /* Internal mode, such as move or resize */
+
int16_t mode_x = 0; /* X coord when in special mode */
int16_t mode_y = 0; /* Y coord when in special mode */
int fd; /* Our X file descriptor */
@@ -2472,7 +2539,9 @@ void events(void)
e = (xcb_destroy_notify_event_t *) ev;
/*
- * If we had focus in this window, forget about the focus.
+ * If we had focus or our last focus in this window,
+ * forget about the focus.
+ *
* We will get an EnterNotify if there's another window
* under the pointer so we can set the focus proper later.
*/
@@ -2483,6 +2552,13 @@ void events(void)
focuswin = NULL;
}
}
+ if (NULL != lastfocuswin)
+ {
+ if (lastfocuswin->id == e->window)
+ {
+ lastfocuswin = NULL;
+ }
+ }
/*
* Find this window in list of clients and forget about
@@ -2741,6 +2817,38 @@ void events(void)
}
break;
+ case XCB_KEY_RELEASE:
+ {
+ xcb_key_release_event_t *e = (xcb_key_release_event_t *)ev;
+
+ PDEBUG("Key %d released.\n", e->detail);
+
+ if (e->detail == keys[KEY_ALT].keycode && MCWM_TABBING == mode)
+ {
+ /* MODKEY was released after tabbing around the
+ * workspace window ring. This means this mode is
+ * finished and we have found a new focus window.
+ *
+ * We need to move first the window we used to focus
+ * on to the head of the window list and then move the
+ * new focus to the head of the list as well. The list
+ * should always start with the window we're focusing
+ * on.
+ */
+
+ mode = 0;
+
+ if (NULL != lastfocuswin)
+ {
+ movetohead(&wslist[curws], lastfocuswin->wsitem[curws]);
+ lastfocuswin = NULL;
+ }
+
+ movetohead(&wslist[curws], focuswin->wsitem[curws]);
+ } /* if KEY_ALT */
+ }
+ break;
+
case XCB_ENTER_NOTIFY:
{
xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *)ev;
@@ -2783,6 +2891,27 @@ void events(void)
client = findclient(e->event);
if (NULL != client)
{
+ if (MCWM_TABBING != mode)
+ {
+ /*
+ * We are focusing on a new window. Since
+ * we're not currently tabbing around the
+ * window ring, we need to update the
+ * current workspace window list: Move
+ * first the old focus to the head of the
+ * list and then the new focus to the head
+ * of the list.
+ */
+ if (NULL != focuswin)
+ {
+ movetohead(&wslist[curws],
+ focuswin->wsitem[curws]);
+ lastfocuswin = NULL;
+ }
+
+ movetohead(&wslist[curws], client->wsitem[curws]);
+ } /* if not tabbing */
+
setfocus(client);
}
}