diff options
Diffstat (limited to 'mcwm.c')
-rw-r--r-- | mcwm.c | 478 |
1 files changed, 336 insertions, 142 deletions
@@ -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, |