X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=d31cde521fc9123b3678243fd550a22ebe90aa37;hb=cb5c5c3b1ad477ec724f764d8de02b96c4c35af5;hp=0dda0108009746c316c72fb0aff97cb208047a8a;hpb=7dae26a1622d49d3546c560fe7c71cd1aafe824d;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index 0dda010..d31cde5 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -198,7 +198,7 @@ GC bar_gc; XGCValues bar_gcv; int bar_fidx = 0; XFontStruct *bar_fs; -char *bar_fonts[] = { NULL, NULL, NULL }; /* XXX Make fully dynamic */ +char *bar_fonts[] = { NULL, NULL, NULL, NULL };/* XXX Make fully dynamic */ char *spawn_term[] = { NULL, NULL }; /* XXX Make fully dynamic */ #define SWM_MENU_FN (2) @@ -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 @@ -1203,32 +1244,35 @@ 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); - /* get focus window */ - if (new_ws->focus) - winfocus = new_ws->focus; - else if (new_ws->focus_prev) - winfocus = new_ws->focus_prev; + if (new_ws == old_ws) + return; + /* get focus window */ if (new_ws->focus) winfocus = new_ws->focus; else if (new_ws->focus_prev) winfocus = new_ws->focus_prev; - - if (new_ws == old_ws) - return; + else + winfocus = TAILQ_FIRST(&new_ws->winlist); other_r = new_ws->r; - if (!other_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; @@ -1422,14 +1466,19 @@ void cycle_layout(struct swm_region *r, union arg *args) { struct workspace *ws = r->ws; + struct ws_win *winfocus; DNPRINTF(SWM_D_EVENT, "cycle_layout: workspace: %d\n", ws->idx); + winfocus = ws->focus; + ws->cur_layout++; if (ws->cur_layout->l_stack == NULL) ws->cur_layout = &layouts[0]; + ignore_enter = 1; stack(); + focus_win(winfocus); } void @@ -1485,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)) && @@ -1506,6 +1558,10 @@ stack_floater(struct ws_win *win, struct swm_region *r) wc.y = (HEIGHT(r) - win->g.h) / 2; } + /* adjust for region */ + wc.x += r->g.x; + wc.y += r->g.y; + DNPRINTF(SWM_D_STACK, "stack_floater: win %lu x %d y %d w %d h %d\n", win->id, wc.x, wc.y, wc.width, wc.height); @@ -1809,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; @@ -1844,23 +1887,24 @@ 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 send_to_ws(struct swm_region *r, union arg *args) { int wsid = args->id; - struct ws_win *win = r->ws->focus; + struct ws_win *win = r->ws->focus, *winfocus = NULL; struct workspace *ws, *nws; Atom ws_idx_atom = 0; unsigned char ws_idx_str[SWM_PROPLEN]; @@ -1873,14 +1917,20 @@ send_to_ws(struct swm_region *r, union arg *args) ws = win->ws; nws = &win->s->ws[wsid]; - XUnmapWindow(display, win->id); - /* find a window to focus */ - ws->focus = TAILQ_PREV(win, ws_win_list, entry); - if (ws->focus == NULL) - ws->focus = TAILQ_FIRST(&ws->winlist); - if (ws->focus == win) - ws->focus = NULL; + 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); + } + /* out of windows in ws so focus on nws instead */ + if (winfocus == NULL) + winfocus = win; + + unmap_window(win); TAILQ_REMOVE(&ws->winlist, win, entry); @@ -1903,6 +1953,7 @@ send_to_ws(struct swm_region *r, union arg *args) nws->restack = 1; stack(); + focus_win(winfocus); } void @@ -2796,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", @@ -3189,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; @@ -3214,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", @@ -3247,13 +3287,17 @@ 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) { - ws = ww->ws; - r = ws->r; - } - } + if (id && trans) + if ((ww = find_window(trans)) != NULL) + if (ws->r) { + ws = ww->ws; + if (ww->ws->r) + r = ww->ws->r; + else + fprintf(stderr, + "fix this bug mcbride\n"); + border_me = 1; + } } /* set up the window layout */ @@ -3302,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). */ @@ -3318,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); @@ -3444,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 { @@ -3471,7 +3525,7 @@ enternotify(XEvent *e) if (ignore_enter) { /* eat event(r) to prevent autofocus */ - ignore_enter--; + ignore_enter = 0; return; } /* @@ -3498,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) @@ -3512,6 +3571,9 @@ mappingnotify(XEvent *e) void maprequest(XEvent *e) { + struct ws_win *win; + struct swm_region *r; + XMapRequestEvent *ev = &e->xmaprequest; XWindowAttributes wa; @@ -3528,9 +3590,11 @@ maprequest(XEvent *e) stack(); /* make new win focused */ - struct ws_win *win; win = find_window(ev->window); - focus_win(win); + r = root_to_region(win->wa.root); + + if (win->ws == r->ws) + focus_win(win); } void @@ -3571,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 @@ -3621,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) { @@ -3726,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); @@ -3794,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++) @@ -3813,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) @@ -3851,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++) @@ -3878,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 */ @@ -3887,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) { @@ -3907,6 +3988,9 @@ setup_globals(void) if ((bar_fonts[1] = strdup("-*-times-medium-r-*-*-*-*-*-*-*-*-*-*")) == NULL) err(1, "setup_globals: strdup"); + if ((bar_fonts[2] = strdup("-misc-fixed-medium-r-*-*-*-*-*-*-*-*-*-*")) + == NULL) + err(1, "setup_globals: strdup"); if ((spawn_term[0] = strdup("xterm")) == NULL) err(1, "setup_globals: strdup"); } @@ -4009,6 +4093,8 @@ main(int argc, char *argv[]) while (running) { while (XPending(display)) { XNextEvent(display, &e); + if (running == 0) + goto done; if (e.type < LASTEvent) { dumpevent(&e); if (handler[e.type]) @@ -4034,7 +4120,7 @@ main(int argc, char *argv[]) /* if we are being restarted go focus on first window */ if (winfocus) { rr = TAILQ_FIRST(&screens[0].rl); - /* move pointer to first screen */ + /* move pointer to first screen if multi screen */ if (ScreenCount(display) > 1 || outputs > 1) XWarpPointer(display, None, rr->s[0].root, 0, 0, 0, 0, rr->g.x, @@ -4049,13 +4135,15 @@ main(int argc, char *argv[]) FD_SET(xfd, &rd); if (select(xfd + 1, &rd, NULL, NULL, NULL) == -1) if (errno != EINTR) - errx(1, "select failed"); + DNPRINTF(SWM_D_MISC, "select failed"); + if (running == 0) + goto done; if (bar_alarm) { bar_alarm = 0; bar_update(); } } - +done: bar_extra_stop(); XCloseDisplay(display);