X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=c6d66a49ef0550d2d722ef9092d18a0adbe5c8ce;hb=43848c3086803582ce3b7047a52673c38abf6d4e;hp=cbba2491a1cdc4bca26528ac67b83bac07e2424d;hpb=a916f33b0a702bde6ed1db75bb078755f5699180;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index cbba249..c6d66a4 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -52,7 +52,7 @@ static const char *cvstag = "$scrotwm$"; -#define SWM_VERSION "0.9.9" +#define SWM_VERSION "0.9.13" #include #include @@ -148,8 +148,6 @@ u_int32_t swm_debug = 0 #define WIDTH(r) (r)->g.w #define HEIGHT(r) (r)->g.h #define SWM_MAX_FONT_STEPS (3) -#define SWM_EV_PROLOGUE(x) do { XGrabServer(x); } while (0) -#define SWM_EV_EPILOGUE(x) do { XUngrabServer(x); XFlush(x); } while (0) #ifndef SWM_LIB #define SWM_LIB "/usr/local/lib/libswmhack.so" @@ -159,6 +157,7 @@ char **start_argv; Atom astate; Atom aprot; Atom adelete; +Atom takefocus; volatile sig_atomic_t running = 1; int outputs = 0; int (*xerrorxlib)(Display *, XErrorEvent *); @@ -234,14 +233,17 @@ TAILQ_HEAD(swm_region_list, swm_region); struct ws_win { TAILQ_ENTRY(ws_win) entry; Window id; + Window transient; + struct ws_win *child_trans; /* transient child window */ struct swm_geometry g; int floating; - int transient; int manual; int font_size_boundary[SWM_MAX_FONT_STEPS]; int font_steps; int last_inc; int can_delete; + int take_focus; + int java; unsigned long quirks; struct workspace *ws; /* always valid */ struct swm_screen *s; /* always valid, never changes */ @@ -318,6 +320,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 *); struct layout { void (*l_stack)(struct workspace *, struct swm_geometry *); @@ -341,7 +344,6 @@ struct layout { /* define work spaces */ struct workspace { int idx; /* workspace index */ - int restack; /* restack on switch */ struct layout *cur_layout; /* current layout handlers */ struct ws_win *focus; /* may be NULL */ struct ws_win *focus_prev; /* may be NULL */ @@ -557,6 +559,7 @@ void enternotify(XEvent *); void focusin(XEvent *); void focusout(XEvent *); void mapnotify(XEvent *); +void mappingnotify(XEvent *); void maprequest(XEvent *); void propertynotify(XEvent *); void unmapnotify(XEvent *); @@ -573,6 +576,7 @@ void (*handler[LASTEvent])(XEvent *) = { [FocusIn] = focusin, [FocusOut] = focusout, [MapNotify] = mapnotify, + [MappingNotify] = mappingnotify, [MapRequest] = maprequest, [PropertyNotify] = propertynotify, [UnmapNotify] = unmapnotify, @@ -816,7 +820,7 @@ void bar_toggle(struct swm_region *r, union arg *args) { struct swm_region *tmpr; - int i, j, sc = ScreenCount(display); + int i, sc = ScreenCount(display); DNPRINTF(SWM_D_MISC, "bar_toggle\n"); @@ -830,9 +834,6 @@ bar_toggle(struct swm_region *r, union arg *args) XMapRaised(display, tmpr->bar_window); bar_enabled = !bar_enabled; - for (i = 0; i < sc; i++) - for (j = 0; j < SWM_WS_MAX; j++) - screens[i].ws[j].restack = 1; stack(); /* must be after stack */ @@ -924,9 +925,19 @@ 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); } @@ -967,6 +978,9 @@ client_msg(struct ws_win *win, Atom a) { XClientMessageEvent cm; + if (win == NULL) + return; + bzero(&cm, sizeof cm); cm.type = ClientMessage; cm.window = win->id; @@ -978,12 +992,38 @@ client_msg(struct ws_win *win, Atom a) } void +configreq_win(struct ws_win *win) +{ + XConfigureRequestEvent cr; + + if (win == NULL) + return; + + bzero(&cr, sizeof cr); + cr.type = ConfigureRequest; + cr.display = display; + cr.parent = win->id; + cr.window = win->id; + cr.x = win->g.x; + cr.y = win->g.y; + cr.width = win->g.w; + cr.height = win->g.h; + cr.border_width = 1; + + XSendEvent(display, win->id, False, StructureNotifyMask, (XEvent *)&cr); +} + +void config_win(struct ws_win *win) { XConfigureEvent ce; DNPRINTF(SWM_D_MISC, "config_win: win %lu x %d y %d w %d h %d\n", win->id, win->g.x, win->g.y, win->g.w, win->g.h); + + if (win == NULL) + return; + ce.type = ConfigureNotify; ce.display = display; ce.event = win->id; @@ -1026,10 +1066,23 @@ quit(struct swm_region *r, union arg *args) void unmap_window(struct ws_win *win) { + XWindowAttributes wa; + if (win == NULL) return; - set_win_state(win, IconicState); + /* 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) + return; + + /* java shits itself when windows are set to iconic state */ + if (win->java == 0) + set_win_state(win, IconicState); + XUnmapWindow(display, win->id); } @@ -1050,6 +1103,9 @@ fake_keypress(struct ws_win *win, int keysym, int modifiers) { XKeyEvent event; + if (win == NULL) + return; + event.display = display; /* Ignored, but what the hell */ event.window = win->id; event.root = win->s->root; @@ -1171,7 +1227,6 @@ spawn(struct swm_region *r, union arg *args) } exit(0); } - wait(0); } void @@ -1189,18 +1244,19 @@ unfocus_win(struct ws_win *win) { if (win == NULL) return; - + if (win->ws == NULL) + return; if (win->ws->r == NULL) return; - grabbuttons(win, 0); - XSetWindowBorder(display, win->id, - win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color); - if (win->ws->focus == win) { win->ws->focus = NULL; win->ws->focus_prev = win; } + + grabbuttons(win, 0); + XSetWindowBorder(display, win->id, + win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color); } void @@ -1215,7 +1271,6 @@ unfocus_all(void) for (j = 0; j < SWM_WS_MAX; j++) TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) unfocus_win(win); - XSync(display, False); } void @@ -1225,6 +1280,8 @@ focus_win(struct ws_win *win) if (win == NULL) return; + if (win->ws == NULL) + return; /* use big hammer to make sure it works under all use cases */ unfocus_all(); @@ -1236,9 +1293,9 @@ focus_win(struct ws_win *win) grabbuttons(win, 1); if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS) XMapRaised(display, win->id); - XSetInputFocus(display, win->id, - RevertToPointerRoot, CurrentTime); - XSync(display, False); + if (win->java == 0) + XSetInputFocus(display, win->id, + RevertToPointerRoot, CurrentTime); } } @@ -1247,9 +1304,18 @@ switchws(struct swm_region *r, union arg *args) { int wsid = args->id; struct swm_region *this_r, *other_r; - struct ws_win *win, *winfocus = NULL; + 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(); + } + this_r = r; old_ws = this_r->ws; new_ws = &this_r->s->ws[wsid]; @@ -1258,6 +1324,11 @@ 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 == old_ws) return; @@ -1275,7 +1346,6 @@ switchws(struct swm_region *r, union arg *args) if (old_ws->r != NULL) old_ws->old_r = old_ws->r; old_ws->r = NULL; - old_ws->restack = 1; /* * Map new windows first if they were here before @@ -1283,7 +1353,9 @@ switchws(struct swm_region *r, union arg *args) */ if (new_ws->old_r == this_r) TAILQ_FOREACH(win, &new_ws->winlist, entry) - XMapRaised(display, win->id); + if (!(win->ws->cur_layout->flags & + SWM_L_MAPONFOCUS)) + XMapRaised(display, win->id); TAILQ_FOREACH(win, &old_ws->winlist, entry) unmap_window(win); @@ -1296,7 +1368,17 @@ switchws(struct swm_region *r, union arg *args) ignore_enter = 1; stack(); - focus_win(winfocus); + if (winfocus) { + /* make sure we see the parent window */ + if (winfocus->transient) { + parent = find_window(winfocus->transient); + if (parent) + focus_win(parent); + } + + focus_win(winfocus); + } + ignore_enter = 0; bar_update(); } @@ -1341,8 +1423,10 @@ cyclews(struct swm_region *r, union arg *args) void cyclescr(struct swm_region *r, union arg *args) { - struct swm_region *rr; - int i; + struct swm_region *rr = NULL; + struct workspace *ws = NULL; + struct ws_win *winfocus = NULL; + int i, x, y; /* do nothing if we don't have more than one screen */ if (!(ScreenCount(display) > 1 || outputs > 1)) @@ -1363,10 +1447,28 @@ cyclescr(struct swm_region *r, union arg *args) default: return; }; + if (rr == NULL) + return; + + ws = rr->ws; + winfocus = ws->focus; + if (winfocus == NULL) + winfocus = ws->focus_prev; + if (winfocus) { + /* use window coordinates */ + x = winfocus->g.x + 1; + y = winfocus->g.y + 1; + } else { + /* use region coordinates */ + x = rr->g.x + 1; + y = rr->g.y + 1 + bar_enabled ? bar_height : 0; + } + unfocus_all(); XSetInputFocus(display, PointerRoot, RevertToPointerRoot, CurrentTime); - XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, rr->g.x + 1, - rr->g.y + bar_enabled + 1 ? bar_height : 0); + XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, x, y); + + focus_win(winfocus); } void @@ -1415,6 +1517,8 @@ swapwin(struct swm_region *r, union arg *args) else return; } + if (target == NULL || source == NULL) + return; source->ws->focus_prev = target; TAILQ_REMOVE(wl, target, entry); TAILQ_INSERT_BEFORE(source, target, entry); @@ -1482,7 +1586,7 @@ void cycle_layout(struct swm_region *r, union arg *args) { struct workspace *ws = r->ws; - struct ws_win *winfocus; + struct ws_win *winfocus, *parent = NULL; DNPRINTF(SWM_D_EVENT, "cycle_layout: workspace: %d\n", ws->idx); @@ -1494,7 +1598,14 @@ cycle_layout(struct swm_region *r, union arg *args) ignore_enter = 1; stack(); - focus_win(winfocus); + /* make sure we see the parent window */ + if (winfocus) { + if (winfocus->transient) + parent = find_window(winfocus->transient); + if (parent) + focus_win(parent); + focus_win(winfocus); + } ignore_enter = 0; } @@ -1528,6 +1639,10 @@ 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; @@ -1535,14 +1650,23 @@ stack(void) { g.y += bar_height; g.h -= bar_height; } - - r->ws->restack = 0; + 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); } } if (font_adjusted) font_adjusted--; - XSync(display, False); } void @@ -1629,7 +1753,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) int w_inc = 1, h_inc, w_base = 1, h_base; int hrh, extra = 0, h_slice, last_h = 0; int split, colno, winno, mwin, msize, mscale; - int remain, missing, v_slice; + int remain, missing, v_slice, reconfigure; unsigned int mask; DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d\n rot=%s flip=%s", @@ -1750,20 +1874,32 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) bzero(&wc, sizeof wc); wc.border_width = 1; + reconfigure = 0; if (rot) { - win->g.x = wc.x = win_g.y; - win->g.y = wc.y = win_g.x; - win->g.w = wc.width = win_g.h; - win->g.h = wc.height = win_g.w; + if (win->g.x != win_g.y || win->g.y != win_g.x || + win->g.w != win_g.h || win->g.h != win_g.w) { + reconfigure = 1; + win->g.x = wc.x = win_g.y; + win->g.y = wc.y = win_g.x; + win->g.w = wc.width = win_g.h; + win->g.h = wc.height = win_g.w; + } } else { - win->g.x = wc.x = win_g.x; - win->g.y = wc.y = win_g.y; - win->g.w = wc.width = win_g.w; - win->g.h = wc.height = win_g.h; + if (win->g.x != win_g.x || win->g.y != win_g.y || + win->g.w != win_g.w || win->g.h != win_g.h) { + reconfigure = 1; + win->g.x = wc.x = win_g.x; + win->g.y = wc.y = win_g.y; + win->g.w = wc.width = win_g.w; + win->g.h = wc.height = win_g.h; + } + } + if (reconfigure) { + adjust_font(win); + mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; + XConfigureWindow(display, win->id, mask, &wc); + configreq_win(win); } - adjust_font(win); - mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; - XConfigureWindow(display, win->id, mask, &wc); XMapRaised(display, win->id); last_h = win_g.h; @@ -1896,9 +2032,14 @@ max_stack(struct workspace *ws, struct swm_geometry *g) return; TAILQ_FOREACH(win, &ws->winlist, entry) { - if (win->transient != 0) { + if (win->transient) { wintrans = win; - } else { + continue; + } + + /* only reconfigure if necessary */ + if (win->g.x != gg.x || win->g.y != gg.y || win->g.w != gg.w || + win->g.h != gg.h) { bzero(&wc, sizeof wc); wc.border_width = 1; win->g.x = wc.x = gg.x; @@ -1907,12 +2048,12 @@ 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); - - /* unmap only if we don't have multi screen */ - if (win != ws->focus) - if (!(ScreenCount(display) > 1 || outputs > 1)) - unmap_window(win); + configreq_win(win); } + /* unmap only if we don't have multi screen */ + if (win != ws->focus) + if (!(ScreenCount(display) > 1 || outputs > 1)) + unmap_window(win); } /* put the last transient on top */ @@ -1957,7 +2098,6 @@ send_to_ws(struct swm_region *r, union arg *args) if (ScreenCount(display) > 1 || outputs > 1) winfocus = win; - unmap_window(win); TAILQ_REMOVE(&ws->winlist, win, entry); TAILQ_INSERT_TAIL(&nws->winlist, win, entry); @@ -1975,8 +2115,6 @@ send_to_ws(struct swm_region *r, union arg *args) if (count_win(nws, 1) == 1) nws->focus = win; - ws->restack = 1; - nws->restack = 1; stack(); if (winfocus) @@ -2564,6 +2702,7 @@ parsekeys(char *keystr, unsigned int currmod, unsigned int *mod, KeySym *ks) DNPRINTF(SWM_D_KEY, "parsekeys: leave ok\n"); return (0); } + char * strdupsafe(char *str) { @@ -2572,6 +2711,7 @@ strdupsafe(char *str) else return (strdup(str)); } + void setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name) { @@ -2652,6 +2792,7 @@ setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name } DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n"); } + int setconfbinding(char *selector, char *value, int flags) { @@ -2698,6 +2839,7 @@ setconfbinding(char *selector, char *value, int flags) DNPRINTF(SWM_D_KEY, "setconfbinding: no match\n"); return (1); } + void setup_keys(void) { @@ -2755,6 +2897,7 @@ setup_keys(void) setkeybinding(MODKEY|ShiftMask, XK_Delete, kf_spawn_custom, "lock"); setkeybinding(MODKEY|ShiftMask, XK_i, kf_spawn_custom, "initscr"); } + void updatenumlockmask(void) { @@ -2866,6 +3009,7 @@ parsequirks(char *qstr, unsigned long *quirk) } return (0); } + void setquirk(const char *class, const char *name, const int quirk) { @@ -2940,6 +3084,7 @@ setquirk(const char *class, const char *name, const int quirk) } } } + int setconfquirk(char *selector, char *value, int flags) { @@ -3213,7 +3358,7 @@ manage_window(Window id) { Window trans = 0; struct workspace *ws; - struct ws_win *win, *ww; + struct ws_win *win, *ww, *parent; int format, i, ws_idx, n, border_me = 0; unsigned long nitems, bytes; Atom ws_idx_atom = 0, type; @@ -3240,14 +3385,20 @@ manage_window(Window id) XGetTransientForHint(display, id, &trans); if (trans) { win->transient = trans; + parent = find_window(win->transient); + if (parent) + parent->child_trans = win; DNPRINTF(SWM_D_MISC, "manage_window: win %u transient %u\n", (unsigned)win->id, win->transient); } /* get supported protocols */ if (XGetWMProtocols(display, id, &prot, &n)) { - for (i = 0, pp = prot; i < n; i++, pp++) + for (i = 0, pp = prot; i < n; i++, pp++) { + if (*pp == takefocus) + win->take_focus = 1; if (*pp == adelete) win->can_delete = 1; + } if (prot) XFree(prot); } @@ -3306,6 +3457,11 @@ manage_window(Window id) if (XGetClassHint(display, win->id, &win->ch)) { DNPRINTF(SWM_D_CLASS, "class: %s name: %s\n", win->ch.res_class, win->ch.res_name); + + /* java is retarded so treat it special */ + if (strstr(win->ch.res_name, "sun-awt")) + win->java = 1; + for (i = 0; i < quirks_length; i++){ if (!strcmp(win->ch.res_class, quirks[i].class) && !strcmp(win->ch.res_name, quirks[i].name)) { @@ -3348,6 +3504,7 @@ manage_window(Window id) wc.border_width = 1; mask = CWBorderWidth; XConfigureWindow(display, win->id, mask, &wc); + configreq_win(win); } XSelectInput(display, id, EnterWindowMask | FocusChangeMask | @@ -3366,15 +3523,24 @@ void unmanage_window(struct ws_win *win) { struct workspace *ws; + struct ws_win *parent; if (win == NULL) return; 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); - set_win_state(win, WithdrawnState); if (win->ch.res_class) XFree(win->ch.res_class); if (win->ch.res_name) @@ -3383,6 +3549,37 @@ unmanage_window(struct ws_win *win) } void +focus_magic(struct ws_win *win) +{ + if (win->child_trans) { + /* win = parent & has a transient so focus on that */ + if (win->java) { + focus_win(win->child_trans); + if (win->child_trans->take_focus) + client_msg(win, takefocus); + } else { + focus_win(win->child_trans); + if (win->child_trans->take_focus) + client_msg(win->child_trans, takefocus); + } + } else { + /* regular focus */ + focus_win(win); + if (win->take_focus) + client_msg(win, takefocus); + } +} + +Bool +destroy_notify_cb(Display *d, XEvent *e, char *arg) +{ + struct ws_win *win = (struct ws_win *)arg; + if (win && win->id == e->xany.window && e->xany.type == DestroyNotify) + return (True); + return (False); +} + +void expose(XEvent *e) { DNPRINTF(SWM_D_EVENT, "expose: window: %lu\n", e->xexpose.window); @@ -3429,10 +3626,9 @@ buttonpress(XEvent *e) action = root_click; if ((win = find_window(ev->window)) == NULL) return; - else { - focus_win(win); - action = client_click; - } + + focus_magic(win); + action = client_click; for (i = 0; i < LENGTH(buttons); i++) if (action == buttons[i].action && buttons[i].func && @@ -3490,11 +3686,11 @@ configurerequest(XEvent *e) ev->value_mask |= CWY | CWHeight; } } + XMoveResizeWindow(display, win->id, + win->g.x, win->g.y, win->g.w, win->g.h); if ((ev->value_mask & (CWX | CWY)) && !(ev->value_mask & (CWWidth | CWHeight))) config_win(win); - XMoveResizeWindow(display, win->id, - win->g.x, win->g.y, win->g.w, win->g.h); } else config_win(win); } @@ -3523,16 +3719,14 @@ configurenotify(XEvent *e) void destroynotify(XEvent *e) { - struct ws_win *win, *winfocus = NULL; + struct ws_win *win, *w, *winfocus = NULL; struct workspace *ws; struct ws_win_list *wl; - XDestroyWindowEvent *ev = &e->xdestroywindow; + XEvent de; DNPRINTF(SWM_D_EVENT, "destroynotify: window %lu\n", ev->window); - SWM_EV_PROLOGUE(display); - if ((win = find_window(ev->window)) != NULL) { /* find a window to focus */ ws = win->ws; @@ -3543,9 +3737,12 @@ destroynotify(XEvent *e) 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 && win != ws->focus_prev) + 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) { @@ -3560,14 +3757,34 @@ destroynotify(XEvent *e) } } } - unmanage_window(win); + + /* + * 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 */ + + if (getstate(w->id) != -1) + continue; + + /* 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 */ + } + + ignore_enter = 1; stack(); if (winfocus) focus_win(winfocus); + ignore_enter = 0; } - - SWM_EV_EPILOGUE(display); } void @@ -3590,8 +3807,10 @@ enternotify(XEvent *e) if (QLength(display)) return; - if ((win = find_window(ev->window)) != NULL) - focus_win(win); + if ((win = find_window(ev->window)) == NULL) + return; + + focus_magic(win); } void @@ -3610,21 +3829,23 @@ void mapnotify(XEvent *e) { struct ws_win *win; - XMappingEvent *ev = &e->xmapping; + XMapEvent *ev = &e->xmap; DNPRINTF(SWM_D_EVENT, "mapnotify: window: %lu\n", ev->window); - SWM_EV_PROLOGUE(display); - win = find_window(ev->window); if (win) set_win_state(win, NormalState); +} + +void +mappingnotify(XEvent *e) +{ + XMappingEvent *ev = &e->xmapping; XRefreshKeyboardMapping(ev); if (ev->request == MappingKeyboard) grabkeys(); - - SWM_EV_EPILOGUE(display); } void @@ -3639,26 +3860,23 @@ maprequest(XEvent *e) DNPRINTF(SWM_D_EVENT, "maprequest: window: %lu\n", e->xmaprequest.window); - SWM_EV_PROLOGUE(display); - if (!XGetWindowAttributes(display, ev->window, &wa)) - goto done; + return; if (wa.override_redirect) - goto done; + return; - manage_window(e->xmaprequest.window); + win = manage_window(e->xmaprequest.window); + if (win == NULL) + return; /* can't happen */ + ignore_enter = 1; stack(); + ignore_enter = 0; /* make new win focused */ - win = find_window(ev->window); r = root_to_region(win->wa.root); - if (win->ws == r->ws) focus_win(win); - -done: - SWM_EV_EPILOGUE(display); } void @@ -3704,26 +3922,34 @@ unmapnotify(XEvent *e) DNPRINTF(SWM_D_EVENT, "unmapnotify: window: %lu\n", e->xunmap.window); - SWM_EV_PROLOGUE(display); - /* determine if we need to help unmanage this window */ win = find_window(e->xunmap.window); if (win == NULL) - goto done; - if (win->transient) - goto done; + return; + + /* igonore transients and floaters, like mplayer */ + if (win->transient || win->floating) + return; + + /* java can not deal with this heuristic */ + if (win->java) + 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 */ - ws = win->ws; /* if we are max_stack try harder to focus on something */ - if (ws->cur_layout->flags & SWM_L_FOCUSPREV) - if (win != ws->focus && win != ws->focus_prev) + if (ws->cur_layout->flags & SWM_L_FOCUSPREV) { + if (win->transient) + winfocus = find_window(win->transient); + else if (win != ws->focus_prev) winfocus = ws->focus_prev; + else if (win != ws->focus) + winfocus = ws->focus; + } /* normal and fallback if haven't found anything to focus on */ if (winfocus == NULL) { @@ -3731,8 +3957,9 @@ unmapnotify(XEvent *e) if (TAILQ_FIRST(&ws->winlist) == win) winfocus = TAILQ_NEXT(win, entry); else { - winfocus = TAILQ_PREV(ws->focus, ws_win_list, - entry); + if (ws->focus) + winfocus = TAILQ_PREV(ws->focus, + ws_win_list, entry); if (winfocus == NULL) winfocus = TAILQ_LAST(&ws->winlist, ws_win_list); @@ -3741,12 +3968,11 @@ unmapnotify(XEvent *e) /* trash window and refocus */ unmanage_window(win); + ignore_enter = 1; stack(); focus_win(winfocus); + ignore_enter = 0; } - -done: - SWM_EV_EPILOGUE(display); } void @@ -3998,7 +4224,6 @@ setup_screens(void) for (j = 0; j < SWM_WS_MAX; j++) { ws = &screens[i].ws[j]; ws->idx = j; - ws->restack = 1; ws->focus = NULL; ws->r = NULL; ws->old_r = NULL; @@ -4023,7 +4248,6 @@ setup_screens(void) /* attach windows to a region */ /* normal windows */ for (j = 0; j < no; j++) { - XGetWindowAttributes(display, wins[j], &wa); if (!XGetWindowAttributes(display, wins[j], &wa) || wa.override_redirect || XGetTransientForHint(display, wins[j], &d1)) @@ -4036,7 +4260,8 @@ setup_screens(void) } /* transient windows */ for (j = 0; j < no; j++) { - if (!XGetWindowAttributes(display, wins[j], &wa)) + if (!XGetWindowAttributes(display, wins[j], &wa) || + wa.override_redirect) continue; state = getstate(wins[j]); @@ -4051,6 +4276,7 @@ setup_screens(void) } } } + void setup_globals(void) { @@ -4093,6 +4319,7 @@ main(int argc, char *argv[]) struct passwd *pwd; struct swm_region *r, *rr; struct ws_win *winfocus = NULL; + struct timeval tv; char conf[PATH_MAX], *cfile = NULL; struct stat sb; XEvent e; @@ -4121,6 +4348,7 @@ main(int argc, char *argv[]) astate = XInternAtom(display, "WM_STATE", False); aprot = XInternAtom(display, "WM_PROTOCOLS", False); adelete = XInternAtom(display, "WM_DELETE_WINDOW", False); + takefocus = XInternAtom(display, "WM_TAKE_FOCUS", False); /* look for local and global conf file */ pwd = getpwuid(getuid()); @@ -4205,7 +4433,9 @@ main(int argc, char *argv[]) FD_ZERO(&rd); FD_SET(xfd, &rd); - if (select(xfd + 1, &rd, NULL, NULL, NULL) == -1) + tv.tv_sec = 1; + tv.tv_usec = 0; + if (select(xfd + 1, &rd, NULL, NULL, &tv) == -1) if (errno != EINTR) DNPRINTF(SWM_D_MISC, "select failed"); if (running == 0)