summaryrefslogtreecommitdiff
path: root/mcwm.c
diff options
context:
space:
mode:
Diffstat (limited to 'mcwm.c')
-rw-r--r--mcwm.c478
1 files changed, 336 insertions, 142 deletions
diff --git a/mcwm.c b/mcwm.c
index 613d53e..5aa5197 100644
--- a/mcwm.c
+++ b/mcwm.c
@@ -7,8 +7,8 @@
* MC, mc at the domain hack.org
* http://hack.org/mc/
*
- * Copyright (c) 2010,2011 Michael Cardell Widerkrantz, mc at the
- * domain hack.org.
+ * Copyright (c) 2010, 2011, 2012 Michael Cardell Widerkrantz, mc at
+ * the domain hack.org.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -45,6 +45,9 @@
#include <X11/keysym.h>
+#include <xcb/xproto.h>
+#include <xcb/xcb_util.h>
+
#ifdef DEBUG
#include "events.h"
#endif
@@ -106,6 +109,7 @@ typedef enum {
KEY_RET,
KEY_X,
KEY_TAB,
+ KEY_BACKTAB,
KEY_1,
KEY_2,
KEY_3,
@@ -123,10 +127,12 @@ typedef enum {
KEY_END,
KEY_PREVSCR,
KEY_NEXTSCR,
+ KEY_ICONIFY,
+ KEY_PREVWS,
+ KEY_NEXTWS,
KEY_MAX
} key_enum_t;
-
struct monitor
{
xcb_randr_output_t id;
@@ -234,6 +240,7 @@ struct keys
{ USERKEY_TERMINAL, 0 },
{ USERKEY_MAX, 0 },
{ USERKEY_CHANGE, 0 },
+ { USERKEY_BACKCHANGE, 0 },
{ USERKEY_WS1, 0 },
{ USERKEY_WS2, 0 },
{ USERKEY_WS3, 0 },
@@ -250,7 +257,10 @@ struct keys
{ USERKEY_BOTRIGHT, 0 },
{ USERKEY_DELETE, 0 },
{ USERKEY_PREVSCREEN, 0 },
- { USERKEY_NEXTSCREEN, 0 },
+ { USERKEY_NEXTSCREEN, 0 },
+ { USERKEY_ICONIFY, 0 },
+ { USERKEY_PREVWS, 0 },
+ { USERKEY_NEXTWS, 0 },
};
/* All keycodes generating our MODKEY mask. */
@@ -272,6 +282,7 @@ struct conf
uint32_t focuscol; /* Focused border colour. */
uint32_t unfocuscol; /* Unfocused border colour. */
uint32_t fixedcol; /* Fixed windows border colour. */
+ bool allowicons; /* Allow windows to be unmapped. */
} conf;
xcb_atom_t atom_desktop; /*
@@ -281,6 +292,8 @@ xcb_atom_t atom_desktop; /*
*/
xcb_atom_t wm_delete_window; /* WM_DELETE_WINDOW event to close windows. */
+xcb_atom_t wm_change_state;
+xcb_atom_t wm_state;
xcb_atom_t wm_protocols; /* WM_PROTOCOLS. */
@@ -323,10 +336,10 @@ 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 focusnext(bool reverse);
static void setunfocus(xcb_drawable_t win);
static void setfocus(struct client *client);
-static int start_terminal(void);
+static int start(char *program);
static void resizelim(struct client *client);
static void moveresize(xcb_drawable_t win, uint16_t x, uint16_t y,
uint16_t width, uint16_t height);
@@ -339,6 +352,7 @@ 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 void hide(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);
@@ -355,6 +369,7 @@ static void configurerequest(xcb_configure_request_event_t *e);
static void events(void);
static void printhelp(void);
static void sigcatch(int sig);
+static xcb_atom_t getatom(char *atom_name);
/* Function bodies. */
@@ -372,7 +387,6 @@ static void sigcatch(int sig);
*/
void finishtabbing(void)
{
-
mode = 0;
if (NULL != lastfocuswin)
@@ -503,7 +517,7 @@ void setwmdesktop(xcb_drawable_t win, uint32_t ws)
PDEBUG("Changing _NET_WM_DESKTOP on window %d to %d\n", win, ws);
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
- atom_desktop, CARDINAL, 32, 1,
+ atom_desktop, XCB_ATOM_CARDINAL, 32, 1,
&ws);
}
@@ -521,8 +535,9 @@ int32_t getwmdesktop(xcb_drawable_t win)
uint32_t *wsp;
uint32_t ws;
- cookie = xcb_get_any_property(conn, false, win, atom_desktop,
- sizeof (int32_t));
+ cookie = xcb_get_property(conn, false, win, atom_desktop,
+ XCB_GET_PROPERTY_TYPE_ANY, 0,
+ sizeof (int32_t));
reply = xcb_get_property_reply(conn, cookie, NULL);
if (NULL == reply)
@@ -737,9 +752,7 @@ uint32_t getcolor(const char *colstr)
xcb_alloc_named_color_cookie_t colcookie;
colormap = screen->default_colormap;
-
colcookie = xcb_alloc_named_color(conn, colormap, strlen(colstr), colstr);
-
col_reply = xcb_alloc_named_color_reply(conn, colcookie, &error);
if (NULL != error)
{
@@ -826,7 +839,6 @@ void forgetwin(xcb_window_t win)
}
free(item->data);
-
delitem(&winlist, item);
return;
@@ -925,7 +937,8 @@ void fitonscreen(struct client *client)
willmove = true;
willresize = true;
}
- else if (client->x + client->width + conf.borderwidth * 2 > mon_x + mon_width)
+ else if (client->x + client->width + conf.borderwidth * 2
+ > mon_x + mon_width)
{
client->x = mon_x + mon_width - (client->width + conf.borderwidth * 2);
willmove = true;
@@ -938,10 +951,12 @@ void fitonscreen(struct client *client)
willmove = true;
willresize = true;
}
- else if (client->y + client->height + conf.borderwidth * 2 > mon_y + mon_height)
+ else if (client->y + client->height + conf.borderwidth * 2
+ > mon_y + mon_height)
{
- client->y = mon_y + mon_height - (client->height + conf.borderwidth * 2);
- willmove = true;
+ client->y = mon_y + mon_height - (client->height + conf.borderwidth
+ * 2);
+ willmove = true;
}
if (willmove)
@@ -963,8 +978,6 @@ void fitonscreen(struct client *client)
*/
void newwin(xcb_window_t win)
{
- int16_t pointx;
- int16_t pointy;
struct client *client;
if (NULL != findclient(win))
@@ -978,14 +991,6 @@ 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;
- }
-
/*
* Set up stuff, like borders, add the window to the client list,
* et cetera.
@@ -1002,12 +1007,23 @@ void newwin(xcb_window_t win)
/*
* If the client doesn't say the user specified the coordinates
- * for the window we store it where our pointer is instead.
+ * for the window we map it where our pointer is instead.
*/
if (!client->usercoord)
{
+ int16_t pointx;
+ int16_t pointy;
PDEBUG("Coordinates not set by user. Using pointer: %d,%d.\n",
pointx, pointy);
+
+ /* 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;
+ }
+
client->x = pointx;
client->y = pointy;
@@ -1021,7 +1037,7 @@ void newwin(xcb_window_t win)
/* Find the physical output this window will be on if RANDR is active. */
if (-1 != randrbase)
{
- client->monitor = findmonbycoord(pointx, pointy);
+ client->monitor = findmonbycoord(client->x, client->y);
if (NULL == client->monitor)
{
/*
@@ -1040,6 +1056,11 @@ void newwin(xcb_window_t win)
/* Show window on screen. */
xcb_map_window(conn, client->id);
+ /* Declare window normal. */
+ long data[] = { XCB_ICCCM_WM_STATE_NORMAL, XCB_NONE };
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->id,
+ wm_state, wm_state, 32, 2, data);
+
/*
* Move cursor into the middle of the window so we don't lose the
* pointer to another window.
@@ -1136,8 +1157,8 @@ struct client *setupwin(xcb_window_t win)
/*
* Get the window's incremental size step, if any.
*/
- if (!xcb_get_wm_normal_hints_reply(
- conn, xcb_get_wm_normal_hints_unchecked(
+ if (!xcb_icccm_get_wm_normal_hints_reply(
+ conn, xcb_icccm_get_wm_normal_hints_unchecked(
conn, win), &hints, NULL))
{
PDEBUG("Couldn't get size hints.\n");
@@ -1147,25 +1168,25 @@ struct client *setupwin(xcb_window_t win)
* The user specified the position coordinates. Remember that so
* we can use geometry later.
*/
- if (hints.flags & XCB_SIZE_HINT_US_POSITION)
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_US_POSITION)
{
client->usercoord = true;
}
- if (hints.flags & XCB_SIZE_HINT_P_MIN_SIZE)
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)
{
client->min_width = hints.min_width;
client->min_height = hints.min_height;
}
- if (hints.flags & XCB_SIZE_HINT_P_MAX_SIZE)
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)
{
client->max_width = hints.max_width;
client->max_height = hints.max_height;
}
- if (hints.flags & XCB_SIZE_HINT_P_RESIZE_INC)
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC)
{
client->width_inc = hints.width_inc;
client->height_inc = hints.height_inc;
@@ -1174,7 +1195,7 @@ struct client *setupwin(xcb_window_t win)
client->height_inc);
}
- if (hints.flags & XCB_SIZE_HINT_BASE_SIZE)
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE)
{
client->base_width = hints.base_width;
client->base_height = hints.base_height;
@@ -1252,6 +1273,12 @@ int setupkeys(void)
/* Now grab the rest of the keys with the MODKEY modifier. */
for (i = KEY_F; i < KEY_MAX; i ++)
{
+ if (XK_VoidSymbol == keys[i].keysym)
+ {
+ keys[i].keycode = 0;
+ continue;
+ }
+
keys[i].keycode = keysymtokeycode(keys[i].keysym, keysyms);
if (0 == keys[i].keycode)
{
@@ -1441,7 +1468,7 @@ int setuprandr(void)
extension = xcb_get_extension_data(conn, &xcb_randr_id);
if (!extension->present)
{
- printf("No RANDR.\n");
+ PDEBUG("No RANDR extension.\n");
return -1;
}
else
@@ -1866,7 +1893,8 @@ void movelim(struct client *client)
if (client->y + client->height > mon_y + mon_height - conf.borderwidth * 2)
{
- client->y = (mon_y + mon_height - conf.borderwidth * 2) - client->height;
+ client->y = (mon_y + mon_height - conf.borderwidth * 2)
+ - client->height;
}
movewindow(client->id, client->x, client->y);
@@ -1890,11 +1918,10 @@ void movewindow(xcb_drawable_t win, uint16_t x, uint16_t y)
| XCB_CONFIG_WINDOW_Y, values);
xcb_flush(conn);
-
}
/* Change focus to next in window ring. */
-void focusnext(void)
+void focusnext(bool reverse)
{
struct client *client = NULL;
@@ -1938,25 +1965,54 @@ void focusnext(void)
}
else
{
- if (NULL == focuswin->wsitem[curws]->next)
+ if (reverse)
{
- /*
- * We were at the end of list. Focusing on first window in
- * list unless we were already there.
- */
- if (focuswin->wsitem[curws] != wslist[curws]->data)
+ if (NULL == focuswin->wsitem[curws]->prev)
{
- PDEBUG("End of list. Focusing first in list: %p\n",
- wslist[curws]);
- client = wslist[curws]->data;
+ /*
+ * We were at the head of list. Focusing on last
+ * window in list unless we were already there.
+ */
+ struct item *last = wslist[curws];
+ while (NULL != last->next)
+ last = last->next;
+ if (focuswin->wsitem[curws] != last->data)
+ {
+ PDEBUG("Beginning of list. Focusing last in list: %p\n",
+ last);
+ client = last->data;
+ }
+ }
+ else
+ {
+ /* Otherwise, focus the next in list. */
+ PDEBUG("Tabbing. Focusing next: %p.\n",
+ focuswin->wsitem[curws]->prev);
+ client = focuswin->wsitem[curws]->prev->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->wsitem[curws]->next)
+ {
+ /*
+ * We were at the end of list. Focusing on first window in
+ * list unless we were already there.
+ */
+ 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 */
@@ -2085,15 +2141,10 @@ void setfocus(struct client *client)
focuswin = client;
}
-/*
- * Start a program specified in conf.terminal.
- *
- * Returns 0 on success.
- */
-int start_terminal(void)
+int start(char *program)
{
pid_t pid;
-
+
pid = fork();
if (-1 == pid)
{
@@ -2102,10 +2153,10 @@ int start_terminal(void)
}
else if (0 == pid)
{
- pid_t termpid;
-
- /* In our first child. */
+ char *argv[2];
+ /* In the child. */
+
/*
* Make this process a new process leader, otherwise the
* terminal will die when the wm dies. Also, this makes any
@@ -2117,39 +2168,15 @@ int start_terminal(void)
exit(1);
}
- /*
- * Fork again for the terminal process. This way, the wm won't
- * know anything about it.
- */
- termpid = fork();
- if (-1 == termpid)
+ argv[0] = program;
+ argv[1] = NULL;
+
+ if (-1 == execvp(program, argv))
{
- perror("fork");
+ perror("execve");
exit(1);
}
- else if (0 == termpid)
- {
- char *argv[2];
-
- /* In the second child, now starting terminal. */
-
- argv[0] = conf.terminal;
- argv[1] = NULL;
-
- if (-1 == execvp(conf.terminal, argv))
- {
- perror("execve");
- exit(1);
- }
- } /* second child */
-
- /* Exit our first child so the wm can pick up and continue. */
exit(0);
- } /* first child */
- else
- {
- /* Wait for the first forked process to exit. */
- waitpid(pid, NULL, 0);
}
return 0;
@@ -2189,14 +2216,16 @@ void resizelim(struct client *client)
client->width = client->min_width;
}
- if (client->x + client->width + conf.borderwidth * 2 > mon_x + mon_width)
+ if (client->x + client->width + conf.borderwidth * 2 > mon_x + mon_width)
{
- client->width = mon_width - ((client->x - mon_x) + conf.borderwidth * 2);
+ client->width = mon_width - ((client->x - mon_x) + conf.borderwidth
+ * 2);
}
if (client->y + client->height + conf.borderwidth * 2 > mon_y + mon_height)
{
- client->height = mon_height - ((client->y - mon_y) + conf.borderwidth * 2);
+ client->height = mon_height - ((client->y - mon_y) + conf.borderwidth
+ * 2);
}
resize(client->id, client->width, client->height);
@@ -2419,8 +2448,9 @@ void movestep(struct client *client, char direction)
* 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 - conf.borderwidth && start_x < client->width + conf.borderwidth
- && start_y > 0 - conf.borderwidth && start_y < client->height + conf.borderwidth )
+ if (start_x > 0 - conf.borderwidth && start_x < client->width
+ + conf.borderwidth && start_y > 0 - conf.borderwidth && start_y
+ < client->height + conf.borderwidth)
{
xcb_warp_pointer(conn, XCB_NONE, client->id, 0, 0, 0, 0,
start_x, start_y);
@@ -2632,13 +2662,28 @@ void maxvert(struct client *client)
client->vertmaxed = true;
}
+void hide(struct client *client)
+{
+ long data[] = { XCB_ICCCM_WM_STATE_ICONIC, XCB_NONE };
+
+ /*
+ * Unmap window and declare iconic.
+ *
+ * Unmapping will generate an UnmapNotify event so we can forget
+ * about the window later.
+ */
+ xcb_unmap_window(conn, client->id);
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->id,
+ wm_state, wm_state, 32, 2, data);
+ xcb_flush(conn);
+}
+
bool getpointer(xcb_drawable_t win, int16_t *x, int16_t *y)
{
xcb_query_pointer_reply_t *pointer;
- pointer = xcb_query_pointer_reply(
- conn, xcb_query_pointer(conn, win), 0);
-
+ pointer
+ = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, win), 0);
if (NULL == pointer)
{
return false;
@@ -2657,9 +2702,8 @@ bool getgeom(xcb_drawable_t win, int16_t *x, int16_t *y, uint16_t *width,
{
xcb_get_geometry_reply_t *geom;
- geom = xcb_get_geometry_reply(conn,
- xcb_get_geometry(conn, win), NULL);
-
+ geom
+ = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
if (NULL == geom)
{
return false;
@@ -2758,7 +2802,6 @@ void topright(void)
xcb_flush(conn);
}
-
void botleft(void)
{
int16_t pointx;
@@ -2793,10 +2836,9 @@ void botleft(void)
}
focuswin->x = mon_x;
- focuswin->y = mon_y + mon_height - (focuswin->height + conf.borderwidth * 2);
-
+ focuswin->y = mon_y + mon_height - (focuswin->height + conf.borderwidth
+ * 2);
movewindow(focuswin->id, focuswin->x, focuswin->y);
-
xcb_warp_pointer(conn, XCB_NONE, focuswin->id, 0, 0, 0, 0,
pointx, pointy);
xcb_flush(conn);
@@ -2839,11 +2881,9 @@ void botright(void)
}
focuswin->x = mon_x + mon_width - (focuswin->width + conf.borderwidth * 2);
-
- focuswin->y = mon_y + mon_height - (focuswin->height + conf.borderwidth * 2);
-
+ focuswin->y = mon_y + mon_height - (focuswin->height + conf.borderwidth
+ * 2);
movewindow(focuswin->id, focuswin->x, focuswin->y);
-
xcb_warp_pointer(conn, XCB_NONE, focuswin->id, 0, 0, 0, 0,
pointx, pointy);
xcb_flush(conn);
@@ -2852,7 +2892,7 @@ void botright(void)
void deletewin(void)
{
xcb_get_property_cookie_t cookie;
- xcb_get_wm_protocols_reply_t protocols;
+ xcb_icccm_get_wm_protocols_reply_t protocols;
bool use_delete = false;
uint32_t i;
@@ -2862,14 +2902,20 @@ void deletewin(void)
}
/* Check if WM_DELETE is supported. */
- cookie = xcb_get_wm_protocols_unchecked(conn, focuswin->id, wm_protocols);
- if (xcb_get_wm_protocols_reply(conn, cookie, &protocols, NULL) == 1) {
+ cookie = xcb_icccm_get_wm_protocols_unchecked(conn, focuswin->id,
+ wm_protocols);
+ if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &protocols, NULL) == 1)
+ {
for (i = 0; i < protocols.atoms_len; i++)
+ {
if (protocols.atoms[i] == wm_delete_window)
+ {
use_delete = true;
+ }
+ }
}
- xcb_get_wm_protocols_reply_wipe(&protocols);
+ xcb_icccm_get_wm_protocols_reply_wipe(&protocols);
if (use_delete)
{
@@ -2954,9 +3000,10 @@ void handle_keypress(xcb_key_press_event_t *ev)
for (key = KEY_MAX, i = KEY_F; i < KEY_MAX; i ++)
{
- if (ev->detail == keys[i].keycode)
+ if (ev->detail == keys[i].keycode && 0 != keys[i].keycode)
{
key = i;
+ break;
}
}
if (key == KEY_MAX)
@@ -2973,7 +3020,7 @@ void handle_keypress(xcb_key_press_event_t *ev)
return;
}
- if (MCWM_TABBING == mode && key != KEY_TAB)
+ if (MCWM_TABBING == mode && key != KEY_TAB && key != KEY_BACKTAB)
{
/* First finish tabbing around. Then deal with the next key. */
finishtabbing();
@@ -3000,6 +3047,10 @@ void handle_keypress(xcb_key_press_event_t *ev)
resizestep(focuswin, 'l');
break;
+ case KEY_TAB: /* shifted tab counts as backtab */
+ focusnext(true);
+ break;
+
default:
/* Ignore other shifted keys. */
break;
@@ -3010,7 +3061,7 @@ void handle_keypress(xcb_key_press_event_t *ev)
switch (key)
{
case KEY_RET: /* return */
- start_terminal();
+ start(conf.terminal);
break;
case KEY_F: /* f */
@@ -3034,7 +3085,11 @@ void handle_keypress(xcb_key_press_event_t *ev)
break;
case KEY_TAB: /* tab */
- focusnext();
+ focusnext(false);
+ break;
+
+ case KEY_BACKTAB: /* backtab */
+ focusnext(true);
break;
case KEY_M: /* m */
@@ -3117,6 +3172,28 @@ void handle_keypress(xcb_key_press_event_t *ev)
nextscreen();
break;
+ case KEY_ICONIFY:
+ if (conf.allowicons)
+ {
+ hide(focuswin);
+ }
+ break;
+
+ case KEY_PREVWS:
+ if (curws > 0)
+ {
+ changeworkspace(curws - 1);
+ }
+ else
+ {
+ changeworkspace(WORKSPACES - 1);
+ }
+ break;
+
+ case KEY_NEXTWS:
+ changeworkspace((curws + 1) % WORKSPACES);
+ break;
+
default:
/* Ignore other keys. */
break;
@@ -3373,17 +3450,29 @@ void events(void)
FD_SET(fd, &in);
/*
- * Check for events, again and again. When poll returns NULL,
- * we block on select() until the event file descriptor gets
- * readable again.
+ * Check for events, again and again. When poll returns NULL
+ * (and it does that a lot), we block on select() until the
+ * event file descriptor gets readable again.
*
* We do it this way instead of xcb_wait_for_event() since
- * select() will return if we we're interrupted by a signal.
- * We like that.
+ * select() will return if we were interrupted by a signal. We
+ * like that.
*/
ev = xcb_poll_for_event(conn);
if (NULL == ev)
{
+ PDEBUG("xcb_poll_for_event() returned NULL.\n");
+
+ /*
+ * Check if we have an unrecoverable connection error,
+ * like a disconnected X server.
+ */
+ if (xcb_connection_has_error(conn))
+ {
+ cleanup(0);
+ exit(1);
+ }
+
found = select(fd + 1, &in, NULL, NULL, NULL);
if (-1 == found)
{
@@ -3486,6 +3575,32 @@ void events(void)
e->detail, (long)e->event, e->child, e->event_x,
e->event_y);
+ if (0 == e->child)
+ {
+ /* Mouse click on root window. Start programs? */
+
+ switch (e->detail)
+ {
+ case 1: /* Mouse button one. */
+ start(MOUSE1);
+ break;
+
+ case 2: /* Middle mouse button. */
+ start(MOUSE2);
+ break;
+
+ case 3: /* Mouse button three. */
+ start(MOUSE3);
+ break;
+
+ default:
+ break;
+ } /* switch */
+
+ /* Break out of event switch. */
+ break;
+ }
+
/*
* If we don't have any currently focused window, we can't
* do anything. We don't want to do anything if the mouse
@@ -3498,11 +3613,6 @@ void events(void)
}
/*
- * XXX if 0 == e->child, we're on the root window. Do
- * something on the root when mouse buttons are pressed?
- */
-
- /*
* If middle button was pressed, raise window or lower
* it if it was already on top.
*/
@@ -3877,6 +3987,30 @@ void events(void)
configurerequest((xcb_configure_request_event_t *) ev);
break;
+ case XCB_CLIENT_MESSAGE:
+ {
+ xcb_client_message_event_t *e
+ = (xcb_client_message_event_t *)ev;
+
+ if (conf.allowicons)
+ {
+ if (e->type == wm_change_state
+ && e->format == 32
+ && e->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC)
+ {
+ long data[] = { XCB_ICCCM_WM_STATE_ICONIC, XCB_NONE };
+
+ /* Unmap window and declare iconic. */
+
+ xcb_unmap_window(conn, e->window);
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, e->window,
+ wm_state, wm_state, 32, 2, data);
+ xcb_flush(conn);
+ }
+ } /* if */
+ }
+ break;
+
case XCB_CIRCULATE_REQUEST:
{
xcb_circulate_request_event_t *e
@@ -3990,6 +4124,31 @@ void sigcatch(int sig)
sigcode = sig;
}
+/*
+ * Get a defined atom from the X server.
+ */
+xcb_atom_t getatom(char *atom_name)
+{
+ xcb_intern_atom_cookie_t atom_cookie;
+ xcb_atom_t atom;
+ xcb_intern_atom_reply_t *rep;
+
+ atom_cookie = xcb_intern_atom(conn, 0, strlen(atom_name), atom_name);
+ rep = xcb_intern_atom_reply(conn, atom_cookie, NULL);
+ if (NULL != rep)
+ {
+ atom = rep->atom;
+ free(rep);
+ return atom;
+ }
+
+ /*
+ * XXX Note that we return 0 as an atom if anything goes wrong.
+ * Might become interesting.
+ */
+ return 0;
+}
+
int main(int argc, char **argv)
{
uint32_t mask = 0;
@@ -4001,9 +4160,18 @@ int main(int argc, char **argv)
char *focuscol;
char *unfocuscol;
char *fixedcol;
-
+ int scrno;
+ xcb_screen_iterator_t iter;
+
/* Install signal handlers. */
+ /* We ignore child exists. Don't create zombies. */
+ if (SIG_ERR == signal(SIGCHLD, SIG_IGN))
+ {
+ perror("mcwm: signal");
+ exit(1);
+ }
+
if (SIG_ERR == signal(SIGINT, sigcatch))
{
perror("mcwm: signal");
@@ -4020,13 +4188,14 @@ int main(int argc, char **argv)
conf.borderwidth = BORDERWIDTH;
conf.terminal = TERMINAL;
+ conf.allowicons = ALLOWICONS;
focuscol = FOCUSCOL;
unfocuscol = UNFOCUSCOL;
fixedcol = FIXEDCOL;
while (1)
{
- ch = getopt(argc, argv, "b:t:f:u:x:");
+ ch = getopt(argc, argv, "b:it:f:u:x:");
if (-1 == ch)
{
@@ -4041,6 +4210,10 @@ int main(int argc, char **argv)
conf.borderwidth = atoi(optarg);
break;
+ case 'i':
+ conf.allowicons = true;
+ break;
+
case 't':
conf.terminal = optarg;
break;
@@ -4062,16 +4235,33 @@ int main(int argc, char **argv)
exit(0);
} /* switch */
}
-
- conn = xcb_connect(NULL, NULL);
+
+ /*
+ * Use $DISPLAY. After connecting scrno will contain the value of
+ * the display's screen.
+ */
+ conn = xcb_connect(NULL, &scrno);
if (xcb_connection_has_error(conn))
{
perror("xcb_connect");
exit(1);
}
-
- /* Get the first screen */
- screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
+
+ /* Find our screen. */
+ iter = xcb_setup_roots_iterator(xcb_get_setup(conn));
+ for (int i = 0; i < scrno; ++ i)
+ {
+ xcb_screen_next(&iter);
+ }
+
+ screen = iter.data;
+ if (!screen)
+ {
+ fprintf (stderr, "mcwm: Can't get the current screen. Exiting.\n");
+ xcb_disconnect(conn);
+ exit(1);
+ }
+
root = screen->root;
PDEBUG("Screen size: %dx%d\nRoot window: %d\n", screen->width_in_pixels,
@@ -4083,17 +4273,20 @@ int main(int argc, char **argv)
conf.fixedcol = getcolor(fixedcol);
/* Get some atoms. */
- 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");
-
+ atom_desktop = getatom("_NET_WM_DESKTOP");
+ wm_delete_window = getatom("WM_DELETE_WINDOW");
+ wm_change_state = getatom("WM_CHANGE_STATE");
+ wm_state = getatom("WM_STATE");
+ wm_protocols = getatom("WM_PROTOCOLS");
+
/* Check for RANDR extension and configure. */
randrbase = setuprandr();
/* Loop over all clients and set up stuff. */
if (0 != setupscreen())
{
- fprintf(stderr, "Failed to initialize windows. Exiting.\n");
+ fprintf(stderr, "mcwm: Failed to initialize windows. Exiting.\n");
+ xcb_disconnect(conn);
exit(1);
}
@@ -4101,6 +4294,7 @@ int main(int argc, char **argv)
if (0 != setupkeys())
{
fprintf(stderr, "mcwm: Couldn't set up keycodes. Exiting.");
+ xcb_disconnect(conn);
exit(1);
}
@@ -4111,7 +4305,7 @@ int main(int argc, char **argv)
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
1 /* left mouse button */,
MOUSEMODKEY);
-
+
xcb_grab_button(conn, 0, root, XCB_EVENT_MASK_BUTTON_PRESS
| XCB_EVENT_MASK_BUTTON_RELEASE,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,