X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=3f1566ae6f46fdd72f182486b837fbfa8754a87f;hb=841e741913acb91111fabae2f93b7257e845722e;hp=5c61da0ad84f38418641bcad49bd0a5d8d7a55aa;hpb=5fbfa251ad6e7467cc6501e1fe44cd5d108567f1;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index 5c61da0..3f1566a 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -52,7 +52,7 @@ static const char *cvstag = "$scrotwm$"; -#define SWM_VERSION "0.9.10" +#define SWM_VERSION "1.0" #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 *); @@ -941,6 +944,8 @@ set_win_state(struct ws_win *win, long state) DNPRINTF(SWM_D_EVENT, "set_win_state: window: %lu\n", win->id); + if (win == NULL) + return; /* make sure we drain everything */ XSync(display, True); @@ -1028,6 +1033,21 @@ count_win(struct workspace *ws, int count_transient) { struct ws_win *win; int count = 0; + int state; + + /* + * Under stress conditions windows sometimes do not get removed from + * the managed list quickly enough. Use a very large hammer to get rid + * of them. A smaller hammer would be nice. + */ + TAILQ_FOREACH(win, &ws->winlist, entry) { + state = getstate(win->id); + if (state == -1) { + DNPRINTF(SWM_D_MISC, "count_win:removing: %lu\n", + win->id); + unmanage_window(win); + } + } TAILQ_FOREACH(win, &ws->winlist, entry) { if (count_transient == 0 && win->floating) @@ -1075,7 +1095,10 @@ unmap_window(struct ws_win *win) if (wa.map_state == IsUnmapped && getstate(win->id) == IconicState) return; - set_win_state(win, IconicState); + /* java shits itself when windows are set to iconic state */ + if (win->java == 0) + set_win_state(win, IconicState); + XUnmapWindow(display, win->id); /* make sure we wait for XUnmapWindow completion */ @@ -1284,8 +1307,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); + if (win->java == 0) + XSetInputFocus(display, win->id, + RevertToPointerRoot, CurrentTime); } } @@ -3304,7 +3328,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; @@ -3331,14 +3355,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); } @@ -3397,6 +3427,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)) { @@ -3409,6 +3444,8 @@ manage_window(Window id) } } + if (win->java && win->transient) { + } /* alter window position if quirky */ if (win->quirks & SWM_Q_ANYWHERE) { win->manual = 1; /* don't center the quirky windows */ @@ -3457,19 +3494,18 @@ void unmanage_window(struct ws_win *win) { struct workspace *ws; - XEvent ev; + struct ws_win *parent; if (win == NULL) return; DNPRINTF(SWM_D_MISC, "unmanage_window: %lu\n", win->id); - set_win_state(win, WithdrawnState); - XSync(display, True); - - /* drain all events for this window, just in case */ - while (XCheckTypedWindowEvent(display, win->id, -1, &ev)) - ; + if (win->transient) { + parent = find_window(win->transient); + if (parent) + parent->child_trans = NULL; + } ws = win->ws; TAILQ_REMOVE(&win->ws->winlist, win, entry); @@ -3481,6 +3517,28 @@ 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); + } +} + +void expose(XEvent *e) { DNPRINTF(SWM_D_EVENT, "expose: window: %lu\n", e->xexpose.window); @@ -3527,10 +3585,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 && @@ -3624,15 +3681,10 @@ destroynotify(XEvent *e) struct ws_win *win, *winfocus = NULL; struct workspace *ws; struct ws_win_list *wl; - XDestroyWindowEvent *ev = &e->xdestroywindow; DNPRINTF(SWM_D_EVENT, "destroynotify: window %lu\n", ev->window); - XSync(display, True); - - SWM_EV_PROLOGUE(display); - if ((win = find_window(ev->window)) != NULL) { /* find a window to focus */ ws = win->ws; @@ -3643,9 +3695,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) { @@ -3660,15 +3715,14 @@ destroynotify(XEvent *e) } } } - ignore_enter = 1; unmanage_window(win); + + ignore_enter = 1; stack(); if (winfocus) focus_win(winfocus); ignore_enter = 0; } - - SWM_EV_EPILOGUE(display); } void @@ -3691,11 +3745,10 @@ enternotify(XEvent *e) if (QLength(display)) return; - if ((win = find_window(ev->window)) != NULL) { - if (win->ws->focus == win) - return; - focus_win(win); - } + if ((win = find_window(ev->window)) == NULL) + return; + + focus_magic(win); } void @@ -3718,13 +3771,9 @@ mapnotify(XEvent *e) 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); - - SWM_EV_EPILOGUE(display); } void @@ -3749,26 +3798,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 @@ -3814,26 +3860,29 @@ 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; + 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->transient) winfocus = find_window(win->transient); - else if (win != ws->focus && win != ws->focus_prev) + 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 */ @@ -3858,9 +3907,6 @@ unmapnotify(XEvent *e) focus_win(winfocus); ignore_enter = 0; } - -done: - SWM_EV_EPILOGUE(display); } void @@ -4236,6 +4282,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());