X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=c14e854e53c16fd33afff1ac106be4573302ffba;hb=ea1edcdfb28e8c22d96bcc7057541fb08ab15fc1;hp=34ea9096b9f4e6a9a561edff94127b0982d43fd8;hpb=8230a09707adc3dd91b5929e975f4064aafae460;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index 34ea909..c14e854 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -52,7 +52,7 @@ static const char *cvstag = "$scrotwm$"; -#define SWM_VERSION "0.9.12" +#define SWM_VERSION "0.9.14" #include #include @@ -304,6 +304,7 @@ enum keyfuncid { kf_screenshot_wind, kf_float_toggle, kf_version, + kf_dumpwins, kf_spawn_lock, kf_spawn_initscr, kf_spawn_custom, @@ -321,6 +322,7 @@ void max_stack(struct workspace *, struct swm_geometry *); void grabbuttons(struct ws_win *, int); void new_region(struct swm_screen *, int, int, int, int); void unmanage_window(struct ws_win *); +long getstate(Window); struct layout { void (*l_stack)(struct workspace *, struct swm_geometry *); @@ -350,6 +352,7 @@ struct workspace { struct swm_region *r; /* may be NULL */ struct swm_region *old_r; /* may be NULL */ struct ws_win_list winlist; /* list of windows in ws */ + struct ws_win_list unmanagedlist; /* list of dead windows in ws */ /* stacker state */ struct { @@ -545,8 +548,48 @@ dumpevent(XEvent *e) "remaining\n", e->xany.window, e->type, QLength(display)); } + +void +dumpwins(struct swm_region *r, union arg *args) +{ + struct ws_win *win; + unsigned int state; + XWindowAttributes wa; + + if (r->ws == NULL) { + fprintf(stderr, "invalid workspace\n"); + return; + } + + fprintf(stderr, "=== managed window list ws %02d ===\n", r->ws->idx); + + TAILQ_FOREACH(win, &r->ws->winlist, entry) { + state = getstate(win->id); + if (!XGetWindowAttributes(display, win->id, &wa)) + fprintf(stderr, "window: %lu failed " + "XGetWindowAttributes\n", win->id); + fprintf(stderr, "window: %lu map_state: %d state: %d\n", + win->id, wa.map_state, state); + } + + fprintf(stderr, "===== unmanaged window list =====\n"); + TAILQ_FOREACH(win, &r->ws->unmanagedlist, entry) { + state = getstate(win->id); + if (!XGetWindowAttributes(display, win->id, &wa)) + fprintf(stderr, "window: %lu failed " + "XGetWindowAttributes\n", win->id); + fprintf(stderr, "window: %lu map_state: %d state: %d\n", + win->id, wa.map_state, state); + } + + fprintf(stderr, "=================================\n"); +} #else #define dumpevent(e) +void +dumpwins(struct swm_region *r, union arg *args) +{ +} #endif /* SWM_DEBUG */ void expose(XEvent *); @@ -925,18 +968,11 @@ void set_win_state(struct ws_win *win, long state) { long data[] = {state, None}; - XWindowAttributes wa; DNPRINTF(SWM_D_EVENT, "set_win_state: window: %lu\n", win->id); if (win == NULL) return; - /* make sure we drain everything */ - XSync(display, True); - - /* make sure we still exist too */ - if (XGetWindowAttributes(display, win->id, &wa) == BadWindow) - return; XChangeProperty(display, win->id, astate, astate, 32, PropModeReplace, (unsigned char *)data, 2); @@ -1066,22 +1102,14 @@ quit(struct swm_region *r, union arg *args) void unmap_window(struct ws_win *win) { - XWindowAttributes wa; - if (win == NULL) return; - /* make sure we still exist too */ - if (XGetWindowAttributes(display, win->id, &wa) == BadWindow) - return; - /* don't unmap again */ - if (wa.map_state == IsUnmapped && getstate(win->id) == IconicState) + if (getstate(win->id) == IconicState) return; - /* java shits itself when windows are set to iconic state */ - if (win->java == 0) - set_win_state(win, IconicState); + set_win_state(win, IconicState); XUnmapWindow(display, win->id); } @@ -1177,6 +1205,21 @@ root_to_region(Window root) } struct ws_win * +find_unmanaged_window(Window id) +{ + struct ws_win *win; + int i, j; + + for (i = 0; i < ScreenCount(display); i++) + for (j = 0; j < SWM_WS_MAX; j++) + TAILQ_FOREACH(win, &screens[i].ws[j].unmanagedlist, + entry) + if (id == win->id) + return (win); + return (NULL); +} + +struct ws_win * find_window(Window id) { struct ws_win *win; @@ -1288,11 +1331,11 @@ focus_win(struct ws_win *win) win->ws->focus = win; if (win->ws->r != NULL) { - XSetWindowBorder(display, win->id, - win->ws->r->s->c[SWM_S_COLOR_FOCUS].color); grabbuttons(win, 1); if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS) XMapRaised(display, win->id); + XSetWindowBorder(display, win->id, + win->ws->r->s->c[SWM_S_COLOR_FOCUS].color); if (win->java == 0) XSetInputFocus(display, win->id, RevertToPointerRoot, CurrentTime); @@ -1307,14 +1350,8 @@ switchws(struct swm_region *r, union arg *args) struct ws_win *win, *winfocus = NULL, *parent = NULL; struct workspace *new_ws, *old_ws; - if (!(r && r->s)) { - fprintf(stderr, "r && r->s failed\n"); - abort(); - } - if (wsid < 0 || wsid > SWM_WS_MAX) { - fprintf(stderr, "illegal wsid\n"); - abort(); - } + if (!(r && r->s)) + return; this_r = r; old_ws = this_r->ws; @@ -1324,11 +1361,8 @@ switchws(struct swm_region *r, union arg *args) "%d -> %d\n", r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), old_ws->idx, wsid); - if (new_ws == NULL || old_ws == NULL) { - fprintf(stderr, "new_ws = %p old_ws = %p\n", new_ws, old_ws); - abort(); - } - + if (new_ws == NULL || old_ws == NULL) + return; if (new_ws == old_ws) return; @@ -1347,16 +1381,6 @@ switchws(struct swm_region *r, union arg *args) old_ws->old_r = old_ws->r; old_ws->r = NULL; - /* - * Map new windows first if they were here before - * to minimize ugly blinking. - */ - if (new_ws->old_r == this_r) - TAILQ_FOREACH(win, &new_ws->winlist, entry) - if (!(win->ws->cur_layout->flags & - SWM_L_MAPONFOCUS)) - XMapRaised(display, win->id); - TAILQ_FOREACH(win, &old_ws->winlist, entry) unmap_window(win); } else { @@ -1639,10 +1663,6 @@ stack(void) { "(screen %d, region %d)\n", r->ws->idx, i, j++); /* start with screen geometry, adjust for bar */ - if (r == NULL) { - fprintf(stderr, "illegal r\n"); - abort(); - } g = r->g; g.w -= 2; g.h -= 2; @@ -1650,18 +1670,6 @@ stack(void) { g.y += bar_height; g.h -= bar_height; } - if (r->ws == NULL) { - fprintf(stderr, "illegal ws\n"); - abort(); - } - if (r->ws->cur_layout == NULL) { - fprintf(stderr, "illegal cur_layout\n"); - abort(); - } - if (r->ws->cur_layout->l_stack == NULL) { - fprintf(stderr, "illegal l_stack\n"); - abort(); - } r->ws->cur_layout->l_stack(r->ws, &g); } } @@ -2374,6 +2382,7 @@ struct keyfunc { { "spawn_lock", legacyfunc, {0} }, { "spawn_initscr", legacyfunc, {0} }, { "spawn_custom", dummykeyfunc, {0} }, + { "dumpwins", dumpwins, {0} }, { "invalid key func", NULL, {0} }, }; struct key { @@ -2896,6 +2905,9 @@ setup_keys(void) setkeybinding(MODKEY|ShiftMask, XK_v, kf_version, NULL); setkeybinding(MODKEY|ShiftMask, XK_Delete, kf_spawn_custom, "lock"); setkeybinding(MODKEY|ShiftMask, XK_i, kf_spawn_custom, "initscr"); +#ifdef SWM_DEBUG + setkeybinding(MODKEY|ShiftMask, XK_d, kf_dumpwins, NULL); +#endif } void @@ -3370,7 +3382,16 @@ manage_window(Window id) XWindowChanges wc; if ((win = find_window(id)) != NULL) - return (win); /* already being managed */ + return (win); /* already being managed */ + + /* see if we are on the unmanaged list */ + if ((win = find_unmanaged_window(id)) != NULL) { + DNPRINTF(SWM_D_MISC, "manage previously unmanaged window " + "%lu\n", win->id); + TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry); + TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry); + return (win); + } if ((win = calloc(1, sizeof(struct ws_win))) == NULL) errx(1, "calloc: failed to allocate memory for new window"); @@ -3520,9 +3541,28 @@ manage_window(Window id) } void +free_window(struct ws_win *win) +{ + DNPRINTF(SWM_D_MISC, "free_window: %lu\n", win->id); + + if (win == NULL) + return; + + /* needed for restart wm */ + set_win_state(win, WithdrawnState); + + TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry); + + if (win->ch.res_class) + XFree(win->ch.res_class); + if (win->ch.res_name) + XFree(win->ch.res_name); + free(win); +} + +void unmanage_window(struct ws_win *win) { - struct workspace *ws; struct ws_win *parent; if (win == NULL) @@ -3530,22 +3570,14 @@ unmanage_window(struct ws_win *win) DNPRINTF(SWM_D_MISC, "unmanage_window: %lu\n", win->id); - /* needed for restart wm */ - set_win_state(win, WithdrawnState); - if (win->transient) { parent = find_window(win->transient); if (parent) parent->child_trans = NULL; } - ws = win->ws; TAILQ_REMOVE(&win->ws->winlist, win, entry); - if (win->ch.res_class) - XFree(win->ch.res_class); - if (win->ch.res_name) - XFree(win->ch.res_name); - free(win); + TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry); } void @@ -3705,12 +3737,10 @@ configurenotify(XEvent *e) DNPRINTF(SWM_D_EVENT, "configurenotify: window: %lu\n", e->xconfigure.window); - XMapWindow(display, e->xconfigure.window); win = find_window(e->xconfigure.window); if (win) { XGetWMNormalHints(display, win->id, &win->sh, &mask); adjust_font(win); - XMapWindow(display, win->id); if (font_adjusted) stack(); } @@ -3719,72 +3749,67 @@ configurenotify(XEvent *e) void destroynotify(XEvent *e) { - struct ws_win *win, *w, *winfocus = NULL; + struct ws_win *win, *w, *wn, *winfocus = NULL; struct workspace *ws; struct ws_win_list *wl; XDestroyWindowEvent *ev = &e->xdestroywindow; - XEvent de; + int unmanaged = 0; DNPRINTF(SWM_D_EVENT, "destroynotify: window %lu\n", ev->window); - if ((win = find_window(ev->window)) != NULL) { - /* find a window to focus */ - ws = win->ws; - wl = &ws->winlist; - - /* if we are transient give focus to parent */ - if (win->transient) - winfocus = find_window(win->transient); - else if (ws->focus == win) { - /* if in max_stack try harder */ - if (ws->cur_layout->flags & SWM_L_FOCUSPREV) { - if (win != ws->focus_prev) - winfocus = ws->focus_prev; - else if (win != ws->focus) - winfocus = ws->focus; - } - - /* fallback and normal handling */ - if (winfocus == NULL) { - if (TAILQ_FIRST(wl) == win) - winfocus = TAILQ_NEXT(win, entry); - else { - winfocus = TAILQ_PREV(ws->focus, - ws_win_list, entry); - if (winfocus == NULL) - winfocus = TAILQ_LAST(wl, - ws_win_list); - } - } - } - unmanage_window(win); + if ((win = find_window(ev->window)) == NULL) { + if ((win = find_unmanaged_window(ev->window)) == NULL) + return; + unmanaged = 1; + } - /* - * Under stress conditions windows sometimes do not get removed - * from the managed list. Use a very large hammer to get rid - * of them. A smaller hammer would be nice. - */ - TAILQ_FOREACH(w, &ws->winlist, entry) { - if (win == w) - continue; /* can't happen but oh well */ + /* find a window to focus */ + ws = win->ws; + wl = &ws->winlist; - if (getstate(w->id) != -1) - continue; + for (w = TAILQ_FIRST(&ws->winlist); w != TAILQ_END(&ws->winlist); w = wn) { + wn = TAILQ_NEXT(w, entry); + if (win == w) + continue; /* can't happen but oh well */ - /* see if we have a destroy event */ - if (XCheckIfEvent(display, &de, destroy_notify_cb, - (char *)w) == False) - unmanage_window(w); /* no event, help it */ - else - XPutBackEvent(display, &de); /* oops */ + if (getstate(w->id) != -1) + continue; + unmanage_window(w); + } + /* if we are transient give focus to parent */ + if (win->transient) + winfocus = find_window(win->transient); + else if (ws->focus == win) { + /* if in max_stack try harder */ + if (ws->cur_layout->flags & SWM_L_FOCUSPREV) { + if (win != ws->focus_prev) + winfocus = ws->focus_prev; + else if (win != ws->focus) + winfocus = ws->focus; } - ignore_enter = 1; - stack(); - if (winfocus) - focus_win(winfocus); - ignore_enter = 0; + /* fallback and normal handling */ + if (winfocus == NULL) { + if (TAILQ_FIRST(wl) == win) + winfocus = TAILQ_NEXT(win, entry); + else { + winfocus = TAILQ_PREV(ws->focus, + ws_win_list, entry); + if (winfocus == NULL) + winfocus = TAILQ_LAST(wl, + ws_win_list); + } + } } + if (unmanaged == 0) + unmanage_window(win); + free_window(win); + + ignore_enter = 1; + stack(); + if (winfocus) + focus_win(winfocus); + ignore_enter = 0; } void @@ -3833,7 +3858,7 @@ mapnotify(XEvent *e) DNPRINTF(SWM_D_EVENT, "mapnotify: window: %lu\n", ev->window); - win = find_window(ev->window); + win = manage_window(ev->window); if (win) set_win_state(win, NormalState); } @@ -3927,10 +3952,6 @@ unmapnotify(XEvent *e) if (win == NULL) return; - /* igonore transients and floaters, like mplayer */ - if (win->transient || win->floating) - return; - /* java can not deal with this heuristic */ if (win->java) return; @@ -4228,6 +4249,7 @@ setup_screens(void) ws->r = NULL; ws->old_r = NULL; TAILQ_INIT(&ws->winlist); + TAILQ_INIT(&ws->unmanagedlist); for (k = 0; layouts[k].l_stack != NULL; k++) if (layouts[k].l_config != NULL) @@ -4254,7 +4276,7 @@ setup_screens(void) continue; state = getstate(wins[j]); - manage = state == NormalState || state == IconicState; + manage = state == IconicState; if (wa.map_state == IsViewable || manage) manage_window(wins[j]); } @@ -4265,7 +4287,7 @@ setup_screens(void) continue; state = getstate(wins[j]); - manage = state == NormalState || state == IconicState; + manage = state == IconicState; if (XGetTransientForHint(display, wins[j], &d1) && manage) manage_window(wins[j]);