X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=49b11f7367d8acd54588c93e8c08a4c673dae212;hb=8b505ff30ac34ba9cd06759a2887b4c2e0e9bcea;hp=e68277446beb4869586a6765909e518b1cc9d3eb;hpb=ec833b84b1acee0dc58a9960d4a3012411ace726;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index e682774..49b11f7 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -8,6 +8,7 @@ * Copyright (c) 2011-2012 Reginald Kennedy * Copyright (c) 2011-2012 Lawrence Teo * Copyright (c) 2011-2012 Tiago Cunha + * Copyright (c) 2012 David Hill * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -121,7 +122,7 @@ static const char *buildstr = SPECTRWM_VERSION; #endif #endif -#if defined(__OpenBSD__) +#ifndef XCB_ICCCM_NUM_WM_HINTS_ELEMENTS #define XCB_ICCCM_SIZE_HINT_P_MIN_SIZE XCB_SIZE_HINT_P_MIN_SIZE #define XCB_ICCCM_SIZE_HINT_P_MAX_SIZE XCB_SIZE_HINT_P_MAX_SIZE #define XCB_ICCCM_SIZE_HINT_P_RESIZE_INC XCB_SIZE_HINT_P_RESIZE_INC @@ -647,49 +648,89 @@ struct ewmh_hint { }; /* function prototypes */ -xcb_char2b_t *char2b(const char *); +void buttonpress(xcb_button_press_event_t *); +void clientmessage(xcb_client_message_event_t *); int conf_load(char *, int); +void configurenotify(xcb_configure_notify_event_t *); +void configurerequest(xcb_configure_request_event_t *); void constrain_window(struct ws_win *, struct swm_region *, int); +void destroynotify(xcb_destroy_notify_event_t *); void do_sync(void); +void enternotify(xcb_enter_notify_event_t *); +void event_error(xcb_generic_error_t *); void event_handle(xcb_generic_event_t *); +char *expand_tilde(char *); +void expose(xcb_expose_event_t *); struct ws_win *find_window(xcb_window_t); int floating_toggle_win(struct ws_win *); void focus(struct swm_region *, union arg *); void focus_magic(struct ws_win *); +#ifdef SWM_DEBUG +void focusin(xcb_focus_in_event_t *); +#endif xcb_atom_t get_atom_from_string(const char *); +#ifdef SWM_DEBUG +char *get_atom_name(xcb_atom_t); +char *get_notify_detail_label(uint8_t); +char *get_notify_mode_label(uint8_t); +#endif xcb_screen_t *get_screen(int); char *get_win_name(xcb_window_t); -uint16_t getstate(xcb_window_t); +uint32_t getstate(xcb_window_t); void grabbuttons(struct ws_win *, int); +void keypress(xcb_key_press_event_t *); +#ifdef SWM_DEBUG +void leavenotify(xcb_leave_notify_event_t *); +#endif void map_window_raised(xcb_window_t); +void mapnotify(xcb_map_notify_event_t *); +void mappingnotify(xcb_mapping_notify_event_t *); +void maprequest(xcb_map_request_event_t *); void new_region(struct swm_screen *, int, int, int, int); int parse_rgb(const char *, uint16_t *, uint16_t *, uint16_t *); +void propertynotify(xcb_property_notify_event_t *); void spawn_select(struct swm_region *, union arg *, char *, int *); +void screenchange(xcb_randr_screen_change_notify_event_t *); void store_float_geom(struct ws_win *, struct swm_region *); void unmanage_window(struct ws_win *); +void unmapnotify(xcb_unmap_notify_event_t *); void update_window(struct ws_win *); -#ifdef SWM_DEBUG -char *get_atom_name(xcb_atom_t); -#endif +/*void visibilitynotify(xcb_visibility_notify_event_t *);*/ -/* function definitions */ -xcb_char2b_t * -char2b(const char *str) +char * +expand_tilde(char *s) { - xcb_char2b_t *s; - size_t i, len; + struct passwd *pwd; + int i; + char user[LOGIN_NAME_MAX]; + const char *sc = s; + char *result; - len = strlen(str); - s = malloc(len * sizeof(xcb_char2b_t)); - if (!s) - return (NULL); + if (s == NULL) + errx(1, "expand_tilde: NULL string."); - for (i = 0; i < len; i++) { - s[i].byte1 = '\0'; - s[i].byte2 = str[i]; + if (s[0] != '~') { + result = strdup(sc); + goto out; } - return (s); + ++s; + for (i = 0; s[i] != '/' && s[i] != '\0'; ++i) + user[i] = s[i]; + user[i] = '\0'; + s = &s[i]; + + pwd = strlen(user) == 0 ? getpwuid(getuid()) : getpwnam(user); + if (pwd == NULL) + result = strdup(sc); + else + if (asprintf(&result, "%s%s", pwd->pw_dir, s) == -1) + result = NULL; +out: + if (result == NULL) + errx(1, "expand_tilde: failed to allocate memory."); + + return result; } int @@ -841,15 +882,16 @@ teardown_ewmh(void) pc = xcb_get_property(conn, 0, screens[i].root, sup_check, XCB_ATOM_WINDOW, 0, 1); pr = xcb_get_property_reply(conn, pc, NULL); - if (pr) { + if (!pr) + continue; + if (pr->format == sup_check) { id = *((xcb_window_t *)xcb_get_property_value(pr)); xcb_destroy_window(conn, id); xcb_delete_property(conn, screens[i].root, sup_check); xcb_delete_property(conn, screens[i].root, sup_list); - - free(pr); } + free(pr); } } @@ -1068,7 +1110,7 @@ void dumpwins(struct swm_region *r, union arg *args) { struct ws_win *win; - uint16_t state; + uint32_t state; xcb_get_window_attributes_cookie_t c; xcb_get_window_attributes_reply_t *wa; @@ -1119,23 +1161,6 @@ dumpwins(struct swm_region *r, union arg *args) } #endif /* SWM_DEBUG */ -void event_error(xcb_generic_error_t *); -void expose(xcb_expose_event_t *); -void keypress(xcb_key_press_event_t *); -void buttonpress(xcb_button_press_event_t *); -void configurerequest(xcb_configure_request_event_t *); -void configurenotify(xcb_configure_notify_event_t *); -void destroynotify(xcb_destroy_notify_event_t *); -void enternotify(xcb_enter_notify_event_t *); -void mapnotify(xcb_map_notify_event_t *); -void mappingnotify(xcb_mapping_notify_event_t *); -void maprequest(xcb_map_request_event_t *); -void propertynotify(xcb_property_notify_event_t *); -void unmapnotify(xcb_unmap_notify_event_t *); -/*void visibilitynotify(xcb_visibility_notify_event_t *);*/ -void clientmessage(xcb_client_message_event_t *); -void screenchange(xcb_randr_screen_change_notify_event_t *); - void sighdlr(int sig) { @@ -1867,7 +1892,7 @@ bar_refresh(void) void bar_setup(struct swm_region *r) { - char *font, *fontpos; + char *font, *fontpos, *dup, *search; int count; xcb_screen_t *screen = get_screen(r->s->idx); uint32_t wa[3]; @@ -1880,7 +1905,10 @@ bar_setup(struct swm_region *r) err(1, "bar_setup: calloc: failed to allocate memory."); if (bar_font == NULL) { - while ((font = strsep(&bar_fonts, ",")) != NULL) { + if ((dup = strdup(bar_fonts)) == NULL) + errx(1, "insufficient memory."); + search = dup; + while ((font = strsep(&search, ",")) != NULL) { if (*font == '\0') continue; @@ -1908,6 +1936,7 @@ bar_setup(struct swm_region *r) break; } } + free(dup); } if (bar_font == NULL) @@ -1984,10 +2013,10 @@ set_win_state(struct ws_win *win, uint16_t state) a_state, 32, 2, data); } -uint16_t +uint32_t getstate(xcb_window_t w) { - uint16_t result = 0; + uint32_t result = 0; xcb_get_property_cookie_t c; xcb_get_property_reply_t *r; @@ -1995,7 +2024,8 @@ getstate(xcb_window_t w) r = xcb_get_property_reply(conn, c, NULL); if (r) { - result = *((uint16_t *)xcb_get_property_value(r)); + if (r->type == a_state && r->format == 32 && r->length == 2) + result = *((uint32_t *)xcb_get_property_value(r)); free(r); } @@ -2219,6 +2249,8 @@ fake_keypress(struct ws_win *win, xcb_keysym_t keysym, uint16_t modifiers) event.response_type = XCB_KEY_RELEASE; xcb_send_event(conn, 1, win->id, XCB_EVENT_MASK_KEY_RELEASE, (const char *)&event); + + free(keycode); } void @@ -2319,8 +2351,10 @@ find_window(xcb_window_t id) return (NULL); /* if we were looking for the parent return that window instead */ - if (r->parent == 0 || r->root == r->parent) + if (r->parent == 0 || r->root == r->parent) { + free(r); return (NULL); + } /* look for parent */ for (i = 0; i < num_screens; i++) @@ -3750,12 +3784,10 @@ get_win_name(xcb_window_t win) if (xcb_icccm_get_wm_name_reply(conn, c, &r, NULL)) { if (r.name_len > 0) { name = malloc(r.name_len + 1); - if (!name) { - xcb_icccm_get_text_property_reply_wipe(&r); - return (NULL); + if (name) { + memcpy(name, r.name, r.name_len); + name[r.name_len] = '\0'; } - memcpy(name, r.name, r.name_len); - name[r.name_len] = '\0'; } xcb_icccm_get_text_property_reply_wipe(&r); } @@ -4300,8 +4332,6 @@ resize(struct ws_win *win, union arg *args) unsigned int shape; /* cursor style */ xcb_cursor_t cursor; xcb_font_t cursor_font; - xcb_grab_pointer_cookie_t gpc; - xcb_grab_pointer_reply_t *gpr; xcb_query_pointer_reply_t *xpr; xcb_generic_event_t *evt; xcb_motion_notify_event_t *mne; @@ -4385,16 +4415,9 @@ resize(struct ws_win *win, union arg *args) xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font, shape, shape + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff); - gpc = xcb_grab_pointer(conn, 0, win->id, MOUSEMASK, + xcb_grab_pointer(conn, 0, win->id, MOUSEMASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE, cursor, XCB_CURRENT_TIME), - gpr = xcb_grab_pointer_reply(conn, gpc, NULL); - if (!gpr) { - xcb_free_cursor(conn, cursor); - xcb_close_font(conn, cursor_font); - free(xpr); - return; - } xcb_flush(conn); resizing = 1; @@ -4474,7 +4497,6 @@ resize(struct ws_win *win, union arg *args) xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); xcb_free_cursor(conn, cursor); xcb_close_font(conn, cursor_font); - free(gpr); free(xpr); DNPRINTF(SWM_D_EVENT, "resize: done\n"); } @@ -4502,8 +4524,6 @@ move(struct ws_win *win, union arg *args) struct swm_region *r = NULL; xcb_font_t cursor_font; xcb_cursor_t cursor; - xcb_grab_pointer_cookie_t gpc; - xcb_grab_pointer_reply_t *gpr; xcb_query_pointer_reply_t *qpr; xcb_generic_event_t *evt; xcb_motion_notify_event_t *mne; @@ -4568,15 +4588,9 @@ move(struct ws_win *win, union arg *args) xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font, XC_fleur, XC_fleur + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff); - gpc = xcb_grab_pointer(conn, 0, win->id, MOUSEMASK, + xcb_grab_pointer(conn, 0, win->id, MOUSEMASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_WINDOW_NONE, cursor, XCB_CURRENT_TIME); - gpr = xcb_grab_pointer_reply(conn, gpc, NULL); - if (!gpr) { - xcb_free_cursor(conn, cursor); - xcb_close_font(conn, cursor_font); - return; - } /* get cursor offset from window root */ qpr = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, win->id), @@ -5145,12 +5159,17 @@ setspawn(char *name, char *args) int setconfspawn(char *selector, char *value, int flags) { + char *args; + /* suppress unused warning since var is needed */ (void)flags; - DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, value); + args = expand_tilde(value); - setspawn(selector, value); + DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, args); + + setspawn(selector, args); + free(args); DNPRINTF(SWM_D_SPAWN, "setconfspawn: done\n"); return (0); @@ -5528,7 +5547,7 @@ updatenumlockmask(void) { unsigned int i, j; xcb_get_modifier_mapping_reply_t *modmap_r; - xcb_keycode_t *modmap, kc; + xcb_keycode_t *modmap, kc, *keycode; DNPRINTF(SWM_D_MISC, "updatenumlockmask\n"); numlockmask = 0; @@ -5542,10 +5561,11 @@ updatenumlockmask(void) for (j = 0; j < modmap_r->keycodes_per_modifier; j++) { kc = modmap[i * modmap_r->keycodes_per_modifier + j]; - - if (kc == *((xcb_keycode_t *)xcb_key_symbols_get_keycode(syms, - XK_Num_Lock))) + keycode = xcb_key_symbols_get_keycode(syms, + XK_Num_Lock); + if (kc == *keycode) numlockmask = (1 << i); + free(keycode); } } free(modmap_r); @@ -5580,6 +5600,7 @@ grabkeys(void) kp->mod | modifiers[j], *code, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + free(code); } } } @@ -5824,7 +5845,7 @@ setconfvalue(char *selector, char *value, int flags) switch (flags) { case SWM_S_BAR_ACTION: free(bar_argv[0]); - if ((bar_argv[0] = strdup(value)) == NULL) + if ((bar_argv[0] = expand_tilde(value)) == NULL) err(1, "setconfvalue: bar_action"); break; case SWM_S_BAR_AT_BOTTOM: @@ -6405,7 +6426,8 @@ window_get_pid(xcb_window_t win) goto tryharder; } - ret = *((pid_t *)xcb_get_property_value(pr)); + if (pr->type == apid && pr->format == 32) + ret = *((pid_t *)xcb_get_property_value(pr)); free(pr); return (ret); @@ -6417,7 +6439,7 @@ tryharder: pr = xcb_get_property_reply(conn, pc, NULL); if (!pr) return (0); - if (pr->type != XCB_ATOM_STRING) { + if (pr->type != apid) { free(pr); return (0); } @@ -6441,7 +6463,9 @@ get_ws_idx(xcb_window_t id) xcb_get_property(conn, 0, id, a_swm_ws, XCB_ATOM_STRING, 0, SWM_PROPLEN), NULL); - if (gpr) { + if (!gpr) + return (-1); + if (gpr->type) { proplen = xcb_get_property_value_length(gpr); if (proplen > 0) { prop = malloc(proplen + 1); @@ -6452,8 +6476,8 @@ get_ws_idx(xcb_window_t id) prop[proplen] = '\0'; } } - free(gpr); } + free(gpr); if (prop) { DNPRINTF(SWM_D_PROP, "get_ws_idx: _SWM_WS: %s\n", prop); @@ -6462,6 +6486,7 @@ get_ws_idx(xcb_window_t id) DNPRINTF(SWM_D_PROP, "get_ws_idx: window: #%s: %s", errstr, prop); } + free(prop); } return ws_idx; @@ -6480,6 +6505,7 @@ manage_window(xcb_window_t id) struct quirk *qp; uint32_t event_mask, i; xcb_icccm_get_wm_protocols_reply_t wpr; + xcb_icccm_get_wm_class_reply_t tmpch; if ((win = find_window(id)) != NULL) return (win); /* already being managed */ @@ -6645,7 +6671,12 @@ manage_window(xcb_window_t id) if (xcb_icccm_get_wm_class_reply(conn, xcb_icccm_get_wm_class(conn, win->id), - &win->ch, NULL)) { + &tmpch, NULL)) { + win->ch.class_name = tmpch.class_name; + win->ch.instance_name = tmpch.instance_name; + + xcb_icccm_get_wm_class_reply_wipe(&tmpch); + DNPRINTF(SWM_D_CLASS, "manage_window: class: %s, name: %s\n", win->ch.class_name, win->ch.instance_name); @@ -6702,6 +6733,9 @@ manage_window(xcb_window_t id) event_mask = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY; +#ifdef SWM_DEBUG + event_mask |= XCB_EVENT_MASK_LEAVE_WINDOW; +#endif xcb_change_window_attributes(conn, id, XCB_CW_EVENT_MASK, &event_mask); @@ -6725,8 +6759,6 @@ free_window(struct ws_win *win) if (win->wa) free(win->wa); - xcb_icccm_get_wm_class_reply_wipe(&win->ch); - kill_refs(win); /* paint memory */ @@ -6820,6 +6852,16 @@ expose(xcb_expose_event_t *e) xcb_flush(conn); } +#ifdef SWM_DEBUG +void +focusin(xcb_focus_in_event_t *e) +{ + DNPRINTF(SWM_D_EVENT, "focusin: window: 0x%x, mode: %s(%u), " + "detail: %s(%u)\n", e->event, get_notify_mode_label(e->mode), + e->mode, get_notify_detail_label(e->detail), e->detail); +} +#endif + void keypress(xcb_key_press_event_t *e) { @@ -7010,13 +7052,78 @@ destroynotify(xcb_destroy_notify_event_t *e) free_window(win); } +#ifdef SWM_DEBUG +char * +get_notify_detail_label(uint8_t detail) +{ + char *label; + + switch (detail) { + case XCB_NOTIFY_DETAIL_ANCESTOR: + label = "Ancestor"; + break; + case XCB_NOTIFY_DETAIL_VIRTUAL: + label = "Virtual"; + break; + case XCB_NOTIFY_DETAIL_INFERIOR: + label = "Inferior"; + break; + case XCB_NOTIFY_DETAIL_NONLINEAR: + label = "Nonlinear"; + break; + case XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL: + label = "NonlinearVirtual"; + break; + case XCB_NOTIFY_DETAIL_POINTER: + label = "Pointer"; + break; + case XCB_NOTIFY_DETAIL_POINTER_ROOT: + label = "PointerRoot"; + break; + case XCB_NOTIFY_DETAIL_NONE: + label = "None"; + break; + default: + label = "Unknown"; + } + + return label; +} + +char * +get_notify_mode_label(uint8_t mode) +{ + char *label; + + switch (mode) { + case XCB_NOTIFY_MODE_NORMAL: + label = "Normal"; + break; + case XCB_NOTIFY_MODE_GRAB: + label = "Grab"; + break; + case XCB_NOTIFY_MODE_UNGRAB: + label = "Ungrab"; + break; + case XCB_NOTIFY_MODE_WHILE_GRABBED: + label = "WhileGrabbed"; + break; + default: + label = "Unknown"; + } + + return label; +} +#endif + void enternotify(xcb_enter_notify_event_t *e) { struct ws_win *win; - DNPRINTF(SWM_D_FOCUS, "enternotify: window: 0x%x, mode: %d, detail: " - "%d, root: 0x%x, subwindow: 0x%x, same_screen_focus: %s, " - "state: %d\n", e->event, e->mode, e->detail, e->root, + DNPRINTF(SWM_D_FOCUS, "enternotify: window: 0x%x, mode: %s(%d), " + "detail: %s(%d), root: 0x%x, subwindow: 0x%x, same_screen_focus: " + "%s, state: %d\n", e->event, get_notify_mode_label(e->mode), + e->mode, get_notify_detail_label(e->detail), e->detail, e->root, e->child, YESNO(e->same_screen_focus), e->state); if (e->mode != XCB_NOTIFY_MODE_NORMAL) { @@ -7044,6 +7151,19 @@ enternotify(xcb_enter_notify_event_t *e) xcb_flush(conn); } +#ifdef SWM_DEBUG +void +leavenotify(xcb_leave_notify_event_t *e) +{ + struct ws_win *win; + DNPRINTF(SWM_D_FOCUS, "leavenotify: window: 0x%x, mode: %s(%d), " + "detail: %s(%d), root: 0x%x, subwindow: 0x%x, same_screen_focus: " + "%s, state: %d\n", e->event, get_notify_mode_label(e->mode), + e->mode, get_notify_detail_label(e->detail), e->detail, e->root, + e->child, YESNO(e->same_screen_focus), e->state); +} +#endif + /* lets us use one switch statement for arbitrary mode/detail combinations */ #define MERGE_MEMBERS(a,b) (((a & 0xffff) << 16) | (b & 0xffff)) @@ -7113,7 +7233,7 @@ maprequest(xcb_map_request_event_t *e) char * get_atom_name(xcb_atom_t atom) { - char *name; + char *name = NULL; size_t len; xcb_get_atom_name_reply_t *r; @@ -7127,14 +7247,12 @@ get_atom_name(xcb_atom_t atom) if (name) { memcpy(name, xcb_get_atom_name_name(r), len); name[len] = '\0'; - - return name; } } free(r); } - return NULL; + return (name); } #endif @@ -7420,8 +7538,9 @@ scan_xrandr(int i) return; } else ncrtc = srr->num_crtcs; + + crtc = xcb_randr_get_screen_resources_current_crtcs(srr); for (c = 0; c < ncrtc; c++) { - crtc = xcb_randr_get_screen_resources_current_crtcs(srr); cic = xcb_randr_get_crtc_info(conn, crtc[c], XCB_CURRENT_TIME); cir = xcb_randr_get_crtc_info_reply(conn, cic, NULL); @@ -7733,14 +7852,18 @@ event_handle(xcb_generic_event_t *evt) EVENT(XCB_DESTROY_NOTIFY, destroynotify); EVENT(XCB_ENTER_NOTIFY, enternotify); EVENT(XCB_EXPOSE, expose); - /*EVENT(XCB_FOCUS_IN, );*/ +#ifdef SWM_DEBUG + EVENT(XCB_FOCUS_IN, focusin); +#endif /*EVENT(XCB_FOCUS_OUT, );*/ /*EVENT(XCB_GRAPHICS_EXPOSURE, );*/ /*EVENT(XCB_GRAVITY_NOTIFY, );*/ EVENT(XCB_KEY_PRESS, keypress); /*EVENT(XCB_KEY_RELEASE, keypress);*/ /*EVENT(XCB_KEYMAP_NOTIFY, );*/ - /*EVENT(XCB_LEAVE_NOTIFY, );*/ +#ifdef SWM_DEBUG + EVENT(XCB_LEAVE_NOTIFY, leavenotify); +#endif EVENT(XCB_MAP_NOTIFY, mapnotify); EVENT(XCB_MAP_REQUEST, maprequest); EVENT(XCB_MAPPING_NOTIFY, mappingnotify);