X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=d31cde521fc9123b3678243fd550a22ebe90aa37;hb=cb5c5c3b1ad477ec724f764d8de02b96c4c35af5;hp=a4e3f61902aef2d6cc4eae841e134a27c0c3c9e9;hpb=3b1be00edc0e9237804e9a1c24399dd2613c163f;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index a4e3f61..d31cde5 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -338,6 +338,7 @@ struct workspace { struct ws_win *focus; /* may be NULL */ struct ws_win *focus_prev; /* may be NULL */ 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 */ /* stacker state */ @@ -547,7 +548,7 @@ void destroynotify(XEvent *); void enternotify(XEvent *); void focusin(XEvent *); void focusout(XEvent *); -void mappingnotify(XEvent *); +void mapnotify(XEvent *); void maprequest(XEvent *); void propertynotify(XEvent *); void unmapnotify(XEvent *); @@ -563,7 +564,7 @@ void (*handler[LASTEvent])(XEvent *) = { [EnterNotify] = enternotify, [FocusIn] = focusin, [FocusOut] = focusout, - [MappingNotify] = mappingnotify, + [MapNotify] = mapnotify, [MapRequest] = maprequest, [PropertyNotify] = propertynotify, [UnmapNotify] = unmapnotify, @@ -578,7 +579,7 @@ sighdlr(int sig) switch (sig) { case SIGCHLD: while ((pid = waitpid(WAIT_ANY, NULL, WNOHANG)) != -1) { - DNPRINTF(SWM_D_MISC, stderr, "reaping: %d\n", pid); + DNPRINTF(SWM_D_MISC, "reaping: %d\n", pid); if (pid <= 0) break; } @@ -908,6 +909,36 @@ bar_setup(struct swm_region *r) } void +set_win_state(struct ws_win *win, long state) +{ + long data[] = {state, None}; + + DNPRINTF(SWM_D_EVENT, "set_win_state: window: %lu\n", win->id); + + XChangeProperty(display, win->id, astate, astate, 32, PropModeReplace, + (unsigned char *)data, 2); +} + +long +getstate(Window w) +{ + int format, status; + long result = -1; + unsigned char *p = NULL; + unsigned long n, extra; + Atom real; + + status = XGetWindowProperty(display, w, astate, 0L, 2L, False, astate, + &real, &format, &n, &extra, (unsigned char **)&p); + if (status != Success) + return (-1); + if (n != 0) + result = *((long *)p); + XFree(p); + return (result); +} + +void version(struct swm_region *r, union arg *args) { bar_version = !bar_version; @@ -981,6 +1012,16 @@ quit(struct swm_region *r, union arg *args) } void +unmap_window(struct ws_win *win) +{ + if (win == NULL) + return; + + set_win_state(win, IconicState); + XUnmapWindow(display, win->id); +} + +void unmap_all(void) { struct ws_win *win; @@ -989,7 +1030,7 @@ unmap_all(void) for (i = 0; i < ScreenCount(display); i++) for (j = 0; j < SWM_WS_MAX; j++) TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) - XUnmapWindow(display, win->id); + unmap_window(win); } void @@ -1217,15 +1258,21 @@ switchws(struct swm_region *r, union arg *args) other_r = new_ws->r; if (other_r == NULL) { /* if the other workspace is hidden, switch windows */ - /* map new window first to prevent ugly blinking */ + if (old_ws->r != NULL) + old_ws->old_r = old_ws->r; old_ws->r = NULL; old_ws->restack = 1; - TAILQ_FOREACH(win, &new_ws->winlist, entry) - XMapRaised(display, win->id); + /* + * 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) + XMapRaised(display, win->id); TAILQ_FOREACH(win, &old_ws->winlist, entry) - XUnmapWindow(display, win->id); + unmap_window(win); } else { other_r->ws = old_ws; old_ws->r = other_r; @@ -1487,6 +1534,9 @@ stack_floater(struct ws_win *win, struct swm_region *r) unsigned int mask; XWindowChanges wc; + if (win == NULL) + return; + bzero(&wc, sizeof wc); mask = CWX | CWY | CWBorderWidth | CWWidth | CWHeight; if ((win->quirks & SWM_Q_FULLSCREEN) && (win->g.w == WIDTH(r)) && @@ -1815,32 +1865,19 @@ max_stack(struct workspace *ws, struct swm_geometry *g) { XWindowChanges wc; struct swm_geometry gg = *g; - struct ws_win *win, *winfocus; + struct ws_win *win, *wintrans = NULL; unsigned int mask; int winno; - /* XXX this function needs to be rewritten it sucks crap */ - DNPRINTF(SWM_D_STACK, "max_stack: workspace: %d\n", ws->idx); winno = count_win(ws, 0); if (winno == 0 && count_win(ws, 1) == 0) return; - if (ws->focus == NULL) - ws->focus = TAILQ_FIRST(&ws->winlist); - winfocus = ws->focus; - TAILQ_FOREACH(win, &ws->winlist, entry) { - if (win->transient != 0 || win->floating != 0) { - if (win == ws->focus) { - /* XXX maximize? */ - stack_floater(win, ws->r); - XMapRaised(display, win->id); - } else { - /* XXX this sucks */ - XUnmapWindow(display, win->id); - } + if (win->transient != 0) { + wintrans = win; } else { bzero(&wc, sizeof wc); wc.border_width = 1; @@ -1850,16 +1887,17 @@ max_stack(struct workspace *ws, struct swm_geometry *g) win->g.h = wc.height = gg.h; mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; XConfigureWindow(display, win->id, mask, &wc); - - if (win == ws->focus) { - XMapRaised(display, win->id); - } else - XUnmapWindow(display, win->id); + if (win != ws->focus) + unmap_window(win); } } - if (winfocus) - focus_win(winfocus); /* has to be done outside of the loop */ + /* put the last transient on top */ + if (wintrans) { + stack_floater(wintrans, ws->r); + XMapRaised(display, wintrans->id); + focus_win(wintrans); /* override */ + } } void @@ -1892,7 +1930,7 @@ send_to_ws(struct swm_region *r, union arg *args) if (winfocus == NULL) winfocus = win; - XUnmapWindow(display, win->id); + unmap_window(win); TAILQ_REMOVE(&ws->winlist, win, entry); @@ -2809,17 +2847,6 @@ buttonpress(XEvent *e) buttons[i].func(win, &buttons[i].args); } -void -set_win_state(struct ws_win *win, long state) -{ - long data[] = {state, None}; - - DNPRINTF(SWM_D_EVENT, "set_win_state: window: %lu\n", win->id); - - XChangeProperty(display, win->id, astate, astate, 32, PropModeReplace, - (unsigned char *)data, 2); -} - const char *quirkname[] = { "NONE", /* config string for "no value" */ "FLOAT", @@ -3202,10 +3229,10 @@ conf_load(char *filename) struct ws_win * manage_window(Window id) { - Window trans; + Window trans = 0; struct workspace *ws; struct ws_win *win, *ww; - int format, i, ws_idx, n; + int format, i, ws_idx, n, border_me = 0; unsigned long nitems, bytes; Atom ws_idx_atom = 0, type; Atom *prot = NULL, *pp; @@ -3227,8 +3254,8 @@ manage_window(Window id) XGetWindowProperty(display, id, ws_idx_atom, 0, SWM_PROPLEN, False, XA_STRING, &type, &format, &nitems, &bytes, &prop); XGetWindowAttributes(display, id, &win->wa); + XGetWMNormalHints(display, id, &win->sh, &mask); XGetTransientForHint(display, id, &trans); - XGetWMNormalHints(display, id, &win->sh, &mask); /* XXX function? */ if (trans) { win->transient = trans; DNPRINTF(SWM_D_MISC, "manage_window: win %u transient %u\n", @@ -3260,19 +3287,19 @@ manage_window(Window id) } else { ws = r->ws; /* this should launch transients in the same ws as parent */ - /* XXX doesn't work for intel xrandr */ if (id && trans) if ((ww = find_window(trans)) != NULL) if (ws->r) { ws = ww->ws; - r = ww->ws->r; + if (ww->ws->r) + r = ww->ws->r; + else + fprintf(stderr, + "fix this bug mcbride\n"); + border_me = 1; } } - /* shouldn't happen but does... */ - if (ws->r == NULL) - ws->r = r; /* use found r since it isn't filled in */ - /* set up the window layout */ win->id = id; win->ws = ws; @@ -3319,12 +3346,10 @@ manage_window(Window id) mask |= CWY; } if (win->g.w + win->g.x > WIDTH(r)) { - win->g.x = wc.x = WIDTH(win->ws->r) - win->g.w - 2; + win->g.x = wc.x = WIDTH(r) - win->g.w - 2; mask |= CWX; } - wc.border_width = 1; - mask |= CWBorderWidth; - XConfigureWindow(display, win->id, mask, &wc); + border_me = 1; } /* Reset font sizes (the bruteforce way; no default keybinding). */ @@ -3335,13 +3360,21 @@ manage_window(Window id) fake_keypress(win, XK_KP_Add, ShiftMask); } + /* border me */ + if (border_me) { + bzero(&wc, sizeof wc); + wc.border_width = 1; + mask = CWBorderWidth; + XConfigureWindow(display, win->id, mask, &wc); + } + XSelectInput(display, id, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask); set_win_state(win, NormalState); /* floaters need to be mapped if they are in the current workspace */ - if (win->floating && (ws->idx == r->ws->idx)) + if ((win->floating || win->transient) && (ws->idx == r->ws->idx)) XMapRaised(display, win->id); return (win); @@ -3461,7 +3494,11 @@ destroynotify(XEvent *e) /* find a window to focus */ ws = win->ws; wl = &ws->winlist; - if (ws->focus == win) { + + /* if we are transient give focus to parent */ + if (win->transient) + winfocus = find_window(win->transient); + else if (ws->focus == win) { if (TAILQ_FIRST(wl) == win) winfocus = TAILQ_NEXT(win, entry); else { @@ -3488,7 +3525,7 @@ enternotify(XEvent *e) if (ignore_enter) { /* eat event(r) to prevent autofocus */ - ignore_enter--; + ignore_enter = 0; return; } /* @@ -3515,11 +3552,16 @@ focusout(XEvent *e) } void -mappingnotify(XEvent *e) +mapnotify(XEvent *e) { + struct ws_win *win; XMappingEvent *ev = &e->xmapping; - DNPRINTF(SWM_D_EVENT, "mappingnotify: window: %lu\n", ev->window); + DNPRINTF(SWM_D_EVENT, "mapnotify: window: %lu\n", ev->window); + + win = find_window(ev->window); + if (win) + set_win_state(win, NormalState); XRefreshKeyboardMapping(ev); if (ev->request == MappingKeyboard) @@ -3550,7 +3592,8 @@ maprequest(XEvent *e) /* make new win focused */ win = find_window(ev->window); r = root_to_region(win->wa.root); - if (win->ws == r->ws) /* XXX this probably breaks multi screen */ + + if (win->ws == r->ws) focus_win(win); } @@ -3592,7 +3635,40 @@ propertynotify(XEvent *e) void unmapnotify(XEvent *e) { + struct ws_win *win, *winfocus; + struct workspace *ws; + DNPRINTF(SWM_D_EVENT, "unmapnotify: window: %lu\n", e->xunmap.window); + + /* determine if we need to help unmanage this window */ + win = find_window(e->xunmap.window); + if (win == NULL) + return; + if (win->transient) + return; + + if (getstate(e->xunmap.window) == NormalState) { + /* + * this window does not have a destroy event but but it is no + * longer visible due to the app unmapping it so unmanage it + */ + + /* find something to focus */ + ws = win->ws; + winfocus = TAILQ_PREV(win, ws_win_list, entry); + if (TAILQ_FIRST(&ws->winlist) == win) + winfocus = TAILQ_NEXT(win, entry); + else { + winfocus = TAILQ_PREV(ws->focus, ws_win_list, entry); + if (winfocus == NULL) + winfocus = TAILQ_LAST(&ws->winlist, ws_win_list); + } + + /* trash window and refocus */ + unmanage_window(win); + stack(); + focus_win(winfocus); + } } void @@ -3642,25 +3718,6 @@ active_wm(void) return (0); } -long -getstate(Window w) -{ - int format, status; - long result = -1; - unsigned char *p = NULL; - unsigned long n, extra; - Atom real; - - status = XGetWindowProperty(display, w, astate, 0L, 2L, False, astate, - &real, &format, &n, &extra, (unsigned char **)&p); - if (status != Success) - return (-1); - if (n != 0) - result = *((long *)p); - XFree(p); - return (result); -} - void new_region(struct swm_screen *s, int x, int y, int w, int h) { @@ -3747,7 +3804,7 @@ scan_xrandr(int i) /* remove any old regions */ while ((r = TAILQ_FIRST(&screens[i].rl)) != NULL) { - r->ws->r = NULL; + r->ws->old_r = r->ws->r = NULL; XDestroyWindow(display, r->bar_window); TAILQ_REMOVE(&screens[i].rl, r, entry); TAILQ_INSERT_TAIL(&screens[i].orl, r, entry); @@ -3815,7 +3872,7 @@ screenchange(XEvent *e) { /* hide any windows that went away */ TAILQ_FOREACH(r, &screens[i].rl, entry) TAILQ_FOREACH(win, &r->ws->winlist, entry) - XUnmapWindow(display, win->id); + unmap_window(win); /* add bars to all regions */ for (i = 0; i < ScreenCount(display); i++) @@ -3834,7 +3891,7 @@ setup_screens(void) int errorbase, major, minor; struct workspace *ws; int ws_idx_atom; - + long state, manage; if ((screens = calloc(ScreenCount(display), sizeof(struct swm_screen))) == NULL) @@ -3872,6 +3929,7 @@ setup_screens(void) ws->restack = 1; ws->focus = NULL; ws->r = NULL; + ws->old_r = NULL; TAILQ_INIT(&ws->winlist); for (k = 0; layouts[k].l_stack != NULL; k++) @@ -3899,8 +3957,9 @@ setup_screens(void) XGetTransientForHint(display, wins[j], &d1)) continue; - if (wa.map_state == IsViewable || - getstate(wins[j]) == NormalState) + state = getstate(wins[j]); + manage = state == NormalState || state == IconicState; + if (wa.map_state == IsViewable || manage) manage_window(wins[j]); } /* transient windows */ @@ -3908,9 +3967,10 @@ setup_screens(void) if (!XGetWindowAttributes(display, wins[j], &wa)) continue; + state = getstate(wins[j]); + manage = state == NormalState || state == IconicState; if (XGetTransientForHint(display, wins[j], &d1) && - (wa.map_state == IsViewable || getstate(wins[j]) == - NormalState)) + manage) manage_window(wins[j]); } if (wins) {