X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=958f6523bda10802532be38d834fb73a554dccba;hb=68bba3e25eabe8257674ed972fbe4f0d99aa4e1f;hp=3279e7fe619a32f4b7af493465390f458cf9eb3e;hpb=c64a9f13209b14b8a266e1322ec2567cdfcb40a0;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index 3279e7f..958f652 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -1,9 +1,10 @@ /* $scrotwm$ */ /* - * Copyright (c) 2009-2010 Marco Peereboom - * Copyright (c) 2009 Ryan McBride + * Copyright (c) 2009-2010-2011 Marco Peereboom + * Copyright (c) 2009-2010-2011 Ryan McBride * Copyright (c) 2009 Darrin Chandler * Copyright (c) 2009 Pierre-Yves Ritschard + * Copyright (c) 2011 Jason L. Wright * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -99,7 +100,7 @@ static const char *cvstag = "$scrotwm$"; #endif #endif -/* #define SWM_DEBUG */ +/*#define SWM_DEBUG*/ #ifdef SWM_DEBUG #define DPRINTF(x...) do { if (swm_debug) fprintf(stderr, x); } while (0) #define DNPRINTF(n,x...) do { if (swm_debug & n) fprintf(stderr, x); } while (0) @@ -286,6 +287,7 @@ struct ws_win { XWindowAttributes wa; XSizeHints sh; XClassHint ch; + XWMHints *hints; }; TAILQ_HEAD(ws_win_list, ws_win); @@ -402,9 +404,8 @@ union arg { }; void focus(struct swm_region *, union arg *); -void focus_magic(struct ws_win *, int); -#define SWM_F_GENERIC (0) -#define SWM_F_TRANSIENT (1) +void focus_magic(struct ws_win *); + /* quirks */ struct quirk { char *class; @@ -656,7 +657,7 @@ ewmh_set_win_fullscreen(struct ws_win *win, int fs) win->g.y = rg.y; win->g.w = rg.w; win->g.h = rg.h; - } else { + } else { if (win->g_floatvalid) { /* refloat at last floating relative position */ win->g.x = win->g_float.x - win->rg_float.x + rg.x; @@ -933,8 +934,9 @@ dumpwins(struct swm_region *r, union arg *args) 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, "window: %lu map_state: %d state: %d " + "transient: %lu\n", + win->id, wa.map_state, state, win->transient); } fprintf(stderr, "===== unmanaged window list =====\n"); @@ -943,8 +945,9 @@ dumpwins(struct swm_region *r, union arg *args) 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, "window: %lu map_state: %d state: %d " + "transient: %lu\n", + win->id, wa.map_state, state, win->transient); } fprintf(stderr, "=================================\n"); @@ -1379,6 +1382,18 @@ bar_setup(struct swm_region *r) } void +drain_enter_notify(void) +{ + int i = 0; + XEvent cne; + + while (XCheckMaskEvent(display, EnterWindowMask, &cne)) + i++; + + DNPRINTF(SWM_D_MISC, "drain_enter_notify: drained %d\n", i); +} + +void set_win_state(struct ws_win *win, long state) { long data[] = {state, None}; @@ -1898,6 +1913,7 @@ focus_win(struct ws_win *win) if (win->java == 0) XSetInputFocus(display, win->id, RevertToParent, CurrentTime); + XMapRaised(display, win->id); grabbuttons(win, 1); XSetWindowBorder(display, win->id, win->ws->r->s->c[SWM_S_COLOR_FOCUS].color); @@ -1956,12 +1972,16 @@ switchws(struct swm_region *r, union arg *args) stack(); a.id = SWM_ARG_ID_FOCUSCUR; focus(new_ws->r, &a); + bar_update(); /* unmap old windows */ if (unmap_old) TAILQ_FOREACH(win, &old_ws->winlist, entry) unmap_window(win); + + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); } void @@ -2064,6 +2084,29 @@ cyclescr(struct swm_region *r, union arg *args) } void +sort_windows(struct ws_win_list *wl) +{ + struct ws_win *win, *parent, *nxt; + + if (wl == NULL) + return; + + for (win = TAILQ_FIRST(wl); win != TAILQ_END(wl); win = nxt) { + nxt = TAILQ_NEXT(win, entry); + if (win->transient) { + parent = find_window(win->transient); + if (parent == NULL) { + fprintf(stderr, "not possible bug\n"); + continue; + } + TAILQ_REMOVE(wl, win, entry); + TAILQ_INSERT_AFTER(wl, parent, win, entry); + } + } + +} + +void swapwin(struct swm_region *r, union arg *args) { struct ws_win *target, *source; @@ -2084,8 +2127,12 @@ swapwin(struct swm_region *r, union arg *args) switch (args->id) { case SWM_ARG_ID_SWAPPREV: + if (source->transient) + source = find_window(source->transient); target = TAILQ_PREV(source, ws_win_list, entry); - TAILQ_REMOVE(wl, cur_focus, entry); + if (target && target->transient) + target = find_window(target->transient); + TAILQ_REMOVE(wl, source, entry); if (target == NULL) TAILQ_INSERT_TAIL(wl, source, entry); else @@ -2093,6 +2140,9 @@ swapwin(struct swm_region *r, union arg *args) break; case SWM_ARG_ID_SWAPNEXT: target = TAILQ_NEXT(source, entry); + /* move the parent and let the sort handle the move */ + if (source->transient) + source = find_window(source->transient); TAILQ_REMOVE(wl, source, entry); if (target == NULL) TAILQ_INSERT_HEAD(wl, source, entry); @@ -2126,6 +2176,8 @@ swapwin(struct swm_region *r, union arg *args) return; } + sort_windows(wl); + stack(); } @@ -2186,7 +2238,7 @@ done: if (winfocus == winlostfocus || winfocus == NULL) return; - focus_magic(winfocus, SWM_F_GENERIC); + focus_magic(winfocus); } void @@ -2213,7 +2265,7 @@ focus(struct swm_region *r, union arg *args) if (winfocus->iconic == 0) break; - focus_magic(winfocus, SWM_F_GENERIC); + focus_magic(winfocus); return; } @@ -2230,18 +2282,18 @@ focus(struct swm_region *r, union arg *args) if (head == NULL) head = TAILQ_LAST(wl, ws_win_list); winfocus = head; - for (;;) { - if (winfocus == NULL) - break; - if (!winfocus->iconic) - break; - winfocus = TAILQ_PREV(winfocus, ws_win_list, entry); - if (winfocus == NULL) - winfocus = TAILQ_LAST(wl, ws_win_list); - if (winfocus == head) { - winfocus = NULL; - break; - } + if (WINID(winfocus) == cur_focus->transient) { + head = TAILQ_PREV(winfocus, ws_win_list, entry); + if (head == NULL) + head = TAILQ_LAST(wl, ws_win_list); + winfocus = head; + } + + /* skip iconics */ + if (winfocus && winfocus->iconic) { + TAILQ_FOREACH_REVERSE(winfocus, wl, ws_win_list, entry) + if (winfocus->iconic == 0) + break; } break; @@ -2250,18 +2302,12 @@ focus(struct swm_region *r, union arg *args) if (head == NULL) head = TAILQ_FIRST(wl); winfocus = head; - for (;;) { - if (winfocus == NULL) - break; - if (!winfocus->iconic) - break; - winfocus = TAILQ_NEXT(winfocus, entry); - if (winfocus == NULL) - winfocus = TAILQ_FIRST(wl); - if (winfocus == head) { - winfocus = NULL; - break; - } + + /* skip iconics */ + if (winfocus && winfocus->iconic) { + TAILQ_FOREACH(winfocus, wl, entry) + if (winfocus->iconic == 0) + break; } break; @@ -2274,11 +2320,10 @@ focus(struct swm_region *r, union arg *args) default: return; } - if (winfocus == winlostfocus || winfocus == NULL) return; - focus_magic(winfocus, SWM_F_GENERIC); + focus_magic(winfocus); } void @@ -2347,6 +2392,9 @@ stack(void) { } if (font_adjusted) font_adjusted--; + + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); } void @@ -2411,22 +2459,22 @@ stack_floater(struct ws_win *win, struct swm_region *r) * floaters and transients are auto-centred unless moved * or resized */ - win->g.x = r->g.x + (WIDTH(r) - win->g.w) / 2 - border_width; - win->g.y = r->g.y + (HEIGHT(r) - win->g.h) / 2 - border_width; + win->g.x = r->g.x + (WIDTH(r) - win->g.w) / 2 - wc.border_width; + win->g.y = r->g.y + (HEIGHT(r) - win->g.h) / 2 - wc.border_width; } /* win can be outside r if new r smaller than old r */ /* Ensure top left corner inside r (move probs otherwise) */ - if (win->g.x < r->g.x - border_width) - win->g.x = r->g.x - border_width; + if (win->g.x < r->g.x - wc.border_width) + win->g.x = r->g.x - wc.border_width; if (win->g.x > r->g.x + r->g.w - 1) win->g.x = (win->g.w > r->g.w) ? r->g.x : - (r->g.x + r->g.w - win->g.w - 2 * border_width); - if (win->g.y < r->g.y - border_width) - win->g.y = r->g.y - border_width; + (r->g.x + r->g.w - win->g.w - 2 * wc.border_width); + if (win->g.y < r->g.y - wc.border_width) + win->g.y = r->g.y - wc.border_width; if (win->g.y > r->g.y + r->g.h - 1) win->g.y = (win->g.h > r->g.h) ? r->g.y : - (r->g.y + r->g.h - win->g.h - 2 * border_width); + (r->g.y + r->g.h - win->g.h - 2 * wc.border_width); wc.x = win->g.x; wc.y = win->g.y; @@ -2659,14 +2707,13 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) j++; } - notiles: +notiles: /* now, stack all the floaters and transients */ TAILQ_FOREACH(win, &ws->winlist, entry) { if (win->transient == 0 && win->floating == 0) continue; - if (win->iconic == 0) + if (win->iconic == 1) continue; - if (win->ewmh_flags & EWMH_F_FULLSCREEN) { fs_win = win; continue; @@ -2840,7 +2887,7 @@ max_stack(struct workspace *ws, struct swm_geometry *g) if (parent) XMapRaised(display, parent->id); stack_floater(wintrans, ws->r); - focus_magic(wintrans, SWM_F_TRANSIENT); + focus_magic(wintrans); } } @@ -2848,7 +2895,7 @@ void send_to_ws(struct swm_region *r, union arg *args) { int wsid = args->id; - struct ws_win *win = win; + struct ws_win *win = NULL, *parent; struct workspace *ws, *nws; Atom ws_idx_atom = 0; unsigned char ws_idx_str[SWM_PROPLEN]; @@ -2870,6 +2917,15 @@ send_to_ws(struct swm_region *r, union arg *args) a.id = SWM_ARG_ID_FOCUSPREV; focus(r, &a); + if (win->transient) { + parent = find_window(win->transient); + if (parent) { + unmap_window(parent); + TAILQ_REMOVE(&ws->winlist, parent, entry); + TAILQ_INSERT_TAIL(&nws->winlist, parent, entry); + parent->ws = nws; + } + } unmap_window(win); TAILQ_REMOVE(&ws->winlist, win, entry); TAILQ_INSERT_TAIL(&nws->winlist, win, entry); @@ -3221,7 +3277,7 @@ resize(struct ws_win *win, union arg *args) XUngrabPointer(display, CurrentTime); /* drain events */ - while (XCheckMaskEvent(display, EnterWindowMask, &ev)); + drain_enter_notify(); } void @@ -3315,7 +3371,7 @@ move(struct ws_win *win, union arg *args) XUngrabPointer(display, CurrentTime); /* drain events */ - while (XCheckMaskEvent(display, EnterWindowMask, &ev)); + drain_enter_notify(); } /* user/key callable function IDs */ @@ -4265,6 +4321,7 @@ setup_quirks(void) setquirk("Xitk", "Xine Window", SWM_Q_FLOAT | SWM_Q_ANYWHERE); setquirk("xine", "xine Video Fullscreen Window", SWM_Q_FULLSCREEN | SWM_Q_FLOAT); setquirk("pcb", "pcb", SWM_Q_FLOAT); + setquirk("SDL_App", "SDL_App", SWM_Q_FLOAT | SWM_Q_FULLSCREEN); } /* conf file stuff */ @@ -4542,13 +4599,52 @@ conf_load(char *filename) } void -set_child_transient(struct ws_win *win) +set_child_transient(struct ws_win *win, Window *trans) { - struct ws_win *parent; + struct ws_win *parent, *w; + XWMHints *wmh = NULL; + struct swm_region *r; + struct workspace *ws; parent = find_window(win->transient); if (parent) parent->child_trans = win; + else { + DNPRINTF(SWM_D_MISC, "set_child_transient: parent doesn't exist" + " for %lu trans %lu\n", win->id, win->transient); + + if (win->hints == NULL) { + fprintf(stderr, "no hints for %lu\n", win->id); + return; + } + + r = root_to_region(win->wa.root); + ws = r->ws; + /* parent doen't exist in our window list */ + TAILQ_FOREACH(w, &ws->winlist, entry) { + if (wmh) + XFree(wmh); + + if ((wmh = XGetWMHints(display, w->id)) == NULL) { + fprintf(stderr, "can't get hints for %lu\n", + w->id); + continue; + } + + if (win->hints->window_group != wmh->window_group) + continue; + + w->child_trans = win; + win->transient = w->id; + *trans = w->id; + DNPRINTF(SWM_D_MISC, "set_child_transient: asjusting " + "transient to %lu\n", win->transient); + break; + } + } + + if (wmh) + XFree(wmh); } struct ws_win * @@ -4575,9 +4671,12 @@ manage_window(Window id) 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); - if (win->transient) - set_child_transient(win); + if (win->transient) { + set_child_transient(win, &trans); + } if (trans && (ww = find_window(trans))) + TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry); + else + TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry); ewmh_update_actions(win); return (win); } @@ -4594,10 +4693,11 @@ manage_window(Window id) False, XA_STRING, &type, &format, &nitems, &bytes, &prop); XGetWindowAttributes(display, id, &win->wa); XGetWMNormalHints(display, id, &win->sh, &mask); + win->hints = XGetWMHints(display, id); XGetTransientForHint(display, id, &trans); if (trans) { win->transient = trans; - set_child_transient(win); + set_child_transient(win, &trans); DNPRINTF(SWM_D_MISC, "manage_window: win %lu transient %lu\n", win->id, win->transient); } @@ -4650,7 +4750,10 @@ manage_window(Window id) win->id = id; win->ws = ws; win->s = r->s; /* this never changes */ - TAILQ_INSERT_TAIL(&ws->winlist, win, entry); + if (trans && (ww = find_window(trans))) + TAILQ_INSERT_AFTER(&ws->winlist, ww, win, entry); + else + TAILQ_INSERT_TAIL(&ws->winlist, win, entry); win->g.w = win->wa.width; win->g.h = win->wa.height; @@ -4735,10 +4838,6 @@ manage_window(Window id) XSelectInput(display, id, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask); - if (win->iconic) - set_win_state(win, IconicState); - else - set_win_state(win, NormalState); /* floaters need to be mapped if they are in the current workspace */ if ((win->floating || win->transient) && (ws->idx == r->ws->idx)) @@ -4792,8 +4891,7 @@ unmanage_window(struct ws_win *win) /* focus on root just in case */ XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime); - if (!win->floating) - focus_prev(win); + focus_prev(win); TAILQ_REMOVE(&win->ws->winlist, win, entry); TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry); @@ -4802,14 +4900,14 @@ unmanage_window(struct ws_win *win) } void -focus_magic(struct ws_win *win, int do_trans) +focus_magic(struct ws_win *win) { - DNPRINTF(SWM_D_FOCUS, "focus_magic: %lu %d\n", WINID(win), do_trans); + DNPRINTF(SWM_D_FOCUS, "focus_magic: %lu\n", WINID(win)); if (win == NULL) return; - if (do_trans == SWM_F_TRANSIENT && win->child_trans) { + if (win->child_trans) { /* win = parent & has a transient so focus on that */ if (win->java) { focus_win(win->child_trans); @@ -4883,7 +4981,7 @@ buttonpress(XEvent *e) if ((win = find_window(ev->window)) == NULL) return; - focus_magic(win, SWM_F_TRANSIENT); + focus_magic(win); action = client_click; for (i = 0; i < LENGTH(buttons); i++) @@ -4983,11 +5081,6 @@ enternotify(XEvent *e) switch (focus_mode) { case SWM_FOCUS_DEFAULT: - if (QLength(display)) { - DNPRINTF(SWM_D_EVENT, "ignore enternotify %d\n", - QLength(display)); - return; - } break; case SWM_FOCUS_FOLLOW: break; @@ -5078,7 +5171,7 @@ enternotify(XEvent *e) return; } - focus_magic(win, SWM_F_TRANSIENT); + focus_magic(win); } /* lets us use one switch statement for arbitrary mode/detail combinations */ @@ -5176,7 +5269,7 @@ maprequest(XEvent *e) /* make new win focused */ r = root_to_region(win->wa.root); if (win->ws == r->ws) - focus_magic(win, SWM_F_GENERIC); + focus_magic(win); } void @@ -5237,6 +5330,21 @@ unmapnotify(XEvent *e) if (getstate(e->xunmap.window) == NormalState) { unmanage_window(win); stack(); + + /* giant hack for apps that don't destroy transient windows */ + /* eat a bunch of events to prevent remanaging the window */ + XEvent cne; + while (XCheckWindowEvent(display, e->xunmap.window, + EnterWindowMask, &cne)) + ; + while (XCheckWindowEvent(display, e->xunmap.window, + StructureNotifyMask, &cne)) + ; + while (XCheckWindowEvent(display, e->xunmap.window, + SubstructureNotifyMask, &cne)) + ; + /* resend unmap because we ated it */ + XUnmapWindow(display, e->xunmap.window); } }