X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=0dda0108009746c316c72fb0aff97cb208047a8a;hb=597613109eb2103c3a196742ec04953b0996d6ae;hp=bab17a439dcd22ec4d6c1cfb6b5a4dd02a7e9b7c;hpb=370f758d740cda81264f23d9d1a24a99e18ba0bd;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index bab17a4..0dda010 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -52,7 +52,7 @@ static const char *cvstag = "$scrotwm$"; -#define SWM_VERSION "0.9.6" +#define SWM_VERSION "0.9.9" #include #include @@ -110,6 +110,8 @@ static const char *cvstag = "$scrotwm$"; #define SWM_D_KEY 0x0200 #define SWM_D_QUIRK 0x0400 #define SWM_D_SPAWN 0x0800 +#define SWM_D_EVENTQ 0x1000 +#define SWM_D_CONF 0x2000 u_int32_t swm_debug = 0 | SWM_D_MISC @@ -124,6 +126,8 @@ u_int32_t swm_debug = 0 | SWM_D_KEY | SWM_D_QUIRK | SWM_D_SPAWN + | SWM_D_EVENTQ + | SWM_D_CONF ; #else #define DPRINTF(x...) @@ -146,16 +150,17 @@ u_int32_t swm_debug = 0 #define SWM_MAX_FONT_STEPS (3) #ifndef SWM_LIB -#define SWM_LIB "/usr/X11R6/lib/swmhack.so" +#define SWM_LIB "/usr/local/lib/libswmhack.so" #endif char **start_argv; Atom astate; Atom aprot; Atom adelete; +volatile sig_atomic_t running = 1; +int outputs = 0; int (*xerrorxlib)(Display *, XErrorEvent *); int other_wm; -int running = 1; int ss_enabled = 0; int xrandr_support; int xrandr_eventbase; @@ -227,7 +232,6 @@ struct ws_win { TAILQ_ENTRY(ws_win) entry; Window id; struct swm_geometry g; - int got_focus; int floating; int transient; int manual; @@ -368,8 +372,6 @@ struct swm_screen { struct swm_screen *screens; int num_screens; -struct ws_win *cur_focus = NULL; - /* args to functions */ union arg { int id; @@ -415,6 +417,127 @@ int quirks_size = 0, quirks_length = 0; struct quirk *quirks = NULL; /* events */ +#ifdef SWM_DEBUG +void +dumpevent(XEvent *e) +{ + char *name = NULL; + + switch (e->type) { + case KeyPress: + name = "KeyPress"; + break; + case KeyRelease: + name = "KeyRelease"; + break; + case ButtonPress: + name = "ButtonPress"; + break; + case ButtonRelease: + name = "ButtonRelease"; + break; + case MotionNotify: + name = "MotionNotify"; + break; + case EnterNotify: + name = "EnterNotify"; + break; + case LeaveNotify: + name = "LeaveNotify"; + break; + case FocusIn: + name = "FocusIn"; + break; + case FocusOut: + name = "FocusOut"; + break; + case KeymapNotify: + name = "KeymapNotify"; + break; + case Expose: + name = "Expose"; + break; + case GraphicsExpose: + name = "GraphicsExpose"; + break; + case NoExpose: + name = "NoExpose"; + break; + case VisibilityNotify: + name = "VisibilityNotify"; + break; + case CreateNotify: + name = "CreateNotify"; + break; + case DestroyNotify: + name = "DestroyNotify"; + break; + case UnmapNotify: + name = "UnmapNotify"; + break; + case MapNotify: + name = "MapNotify"; + break; + case MapRequest: + name = "MapRequest"; + break; + case ReparentNotify: + name = "ReparentNotify"; + break; + case ConfigureNotify: + name = "ConfigureNotify"; + break; + case ConfigureRequest: + name = "ConfigureRequest"; + break; + case GravityNotify: + name = "GravityNotify"; + break; + case ResizeRequest: + name = "ResizeRequest"; + break; + case CirculateNotify: + name = "CirculateNotify"; + break; + case CirculateRequest: + name = "CirculateRequest"; + break; + case PropertyNotify: + name = "PropertyNotify"; + break; + case SelectionClear: + name = "SelectionClear"; + break; + case SelectionRequest: + name = "SelectionRequest"; + break; + case SelectionNotify: + name = "SelectionNotify"; + break; + case ColormapNotify: + name = "ColormapNotify"; + break; + case ClientMessage: + name = "ClientMessage"; + break; + case MappingNotify: + name = "MappingNotify"; + break; + } + + if (name) + DNPRINTF(SWM_D_EVENTQ ,"window: %lu event: %s (%d), %d " + "remaining\n", + e->xany.window, name, e->type, QLength(display)); + else + DNPRINTF(SWM_D_EVENTQ, "window: %lu unknown event %d, %d " + "remaining\n", + e->xany.window, e->type, QLength(display)); +} +#else +#define dumpevent(e) +#endif /* SWM_DEBUG */ + void expose(XEvent *); void keypress(XEvent *); void buttonpress(XEvent *); @@ -447,6 +570,40 @@ void (*handler[LASTEvent])(XEvent *) = { [VisibilityNotify] = visibilitynotify, }; +void +sighdlr(int sig) +{ + pid_t pid; + + switch (sig) { + case SIGCHLD: + while ((pid = waitpid(WAIT_ANY, NULL, WNOHANG)) != -1) { + DNPRINTF(SWM_D_MISC, stderr, "reaping: %d\n", pid); + if (pid <= 0) + break; + } + break; + case SIGINT: + case SIGTERM: + case SIGHUP: + case SIGQUIT: + running = 0; + break; + } +} + +void +installsignal(int sig, char *name) +{ + struct sigaction sa; + + sa.sa_handler = sighdlr; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction(sig, &sa, NULL) == -1) + err(1, "could not install %s handler", name); +} + unsigned long name_to_color(char *colorname) { @@ -556,18 +713,45 @@ bar_extra_stop(void) } void +bar_class_name(char *s, ssize_t sz, struct ws_win *cur_focus) +{ + int do_class, do_name; + Status status; + XClassHint *xch = NULL; + + if ((title_name_enabled == 1 || title_class_enabled == 1) && + cur_focus != NULL) { + if ((xch = XAllocClassHint()) == NULL) + goto out; + status = XGetClassHint(display, cur_focus->id, xch); + if (status == BadWindow || status == BadAlloc) + goto out; + do_class = (title_class_enabled && xch->res_class != NULL); + do_name = (title_name_enabled && xch->res_name != NULL); + if (do_class) + strlcat(s, xch->res_class, sz); + if (do_class && do_name) + strlcat(s, ":", sz); + if (do_name) + strlcat(s, xch->res_name, sz); + strlcat(s, " ", sz); + } +out: + if (xch) + XFree(xch); +} + +void bar_update(void) { time_t tmt; struct tm tm; struct swm_region *r; - int i, x, do_class, do_name; + int i, x; size_t len; char s[SWM_BAR_MAX]; char loc[SWM_BAR_MAX]; char *b; - XClassHint *xch; - Status status; if (bar_enabled == 0) return; @@ -593,29 +777,13 @@ bar_update(void) localtime_r(&tmt, &tm); strftime(s, sizeof s, "%a %b %d %R %Z %Y ", &tm); } - xch = NULL; - if ((title_name_enabled == 1 || title_class_enabled == 1) && - cur_focus != NULL) { - if ((xch = XAllocClassHint()) == NULL) - goto out; - status = XGetClassHint(display, cur_focus->id, xch); - if (status == BadWindow || status == BadAlloc) - goto out; - do_class = (title_class_enabled && xch->res_class != NULL); - do_name = (title_name_enabled && xch->res_name != NULL); - if (do_class) - strlcat(s, xch->res_class, sizeof s); - if (do_class && do_name) - strlcat(s, ":", sizeof s); - if (do_name) - strlcat(s, xch->res_name, sizeof s); - } -out: - if (xch) - XFree(xch); + for (i = 0; i < ScreenCount(display); i++) { x = 1; TAILQ_FOREACH(r, &screens[i].rl, entry) { + if (r && r->ws) + bar_class_name(s, sizeof s, r->ws->focus); + snprintf(loc, sizeof loc, "%d:%d %s %s %s", x++, r->ws->idx + 1, s, bar_ext, bar_vertext); bar_print(r, loc); @@ -969,20 +1137,17 @@ unfocus_win(struct ws_win *win) if (win == NULL) return; - if (win->ws->focus != win && win->ws->focus != NULL) - win->ws->focus_prev = win->ws->focus; - if (win->ws->r == NULL) return; grabbuttons(win, 0); XSetWindowBorder(display, win->id, win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color); - win->got_focus = 0; - if (win->ws->focus == win) + + if (win->ws->focus == win) { win->ws->focus = NULL; - if (cur_focus == win) - cur_focus = NULL; + win->ws->focus_prev = win; + } } void @@ -997,6 +1162,7 @@ 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 @@ -1007,25 +1173,17 @@ focus_win(struct ws_win *win) if (win == NULL) return; - if (cur_focus) - unfocus_win(cur_focus); - if (win->ws->focus) { - /* probably shouldn't happen due to the previous unfocus_win */ - DNPRINTF(SWM_D_FOCUS, "unfocusing win->ws->focus: %lu\n", - win->ws->focus->id); - unfocus_win(win->ws->focus); - } + /* use big hammer to make sure it works under all use cases */ + unfocus_all(); win->ws->focus = win; + if (win->ws->r != NULL) { - cur_focus = win; - if (!win->got_focus) { - XSetWindowBorder(display, win->id, - win->ws->r->s->c[SWM_S_COLOR_FOCUS].color); - grabbuttons(win, 1); - } - win->got_focus = 1; + XSetWindowBorder(display, win->id, + win->ws->r->s->c[SWM_S_COLOR_FOCUS].color); + grabbuttons(win, 1); XSetInputFocus(display, win->id, RevertToPointerRoot, CurrentTime); + XSync(display, False); } } @@ -1034,7 +1192,7 @@ switchws(struct swm_region *r, union arg *args) { int wsid = args->id; struct swm_region *this_r, *other_r; - struct ws_win *win; + struct ws_win *win, *winfocus = NULL; struct workspace *new_ws, *old_ws; this_r = r; @@ -1045,6 +1203,17 @@ 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->focus) + winfocus = new_ws->focus; + else if (new_ws->focus_prev) + winfocus = new_ws->focus_prev; + if (new_ws == old_ws) return; @@ -1068,12 +1237,8 @@ switchws(struct swm_region *r, union arg *args) new_ws->r = this_r; ignore_enter = 1; - /* set focus */ - if (new_ws->focus == NULL) - new_ws->focus = TAILQ_FIRST(&new_ws->winlist); - if (new_ws->focus) - focus_win(new_ws->focus); stack(); + focus_win(winfocus); bar_update(); } @@ -1146,12 +1311,15 @@ void swapwin(struct swm_region *r, union arg *args) { struct ws_win *target, *source; + struct ws_win *cur_focus; struct ws_win_list *wl; DNPRINTF(SWM_D_WS, "swapwin id %d " "in screen %d region %dx%d+%d+%d ws %d\n", args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx); + + cur_focus = r->ws->focus; if (cur_focus == NULL) return; @@ -1205,8 +1373,11 @@ focus(struct swm_region *r, union arg *args) { struct ws_win *winfocus, *winlostfocus; struct ws_win_list *wl; + struct ws_win *cur_focus; DNPRINTF(SWM_D_FOCUS, "focus: id %d\n", args->id); + + cur_focus = r->ws->focus; if (cur_focus == NULL) return; @@ -1380,7 +1551,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) { XWindowChanges wc; struct swm_geometry win_g, r_g = *g; - struct ws_win *win, *winfocus; + struct ws_win *win; int i, j, s, stacks; int w_inc = 1, h_inc, w_base = 1, h_base; int hrh, extra = 0, h_slice, last_h = 0; @@ -1391,13 +1562,10 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d\n rot=%s flip=%s", ws->idx, rot ? "yes" : "no", flip ? "yes" : "no"); - if ((winno = count_win(ws, 0)) == 0) + 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 = cur_focus ? cur_focus : ws->focus; - TAILQ_FOREACH(win, &ws->winlist, entry) if (win->transient == 0 && win->floating == 0) break; @@ -1539,9 +1707,6 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) stack_floater(win, ws->r); XMapRaised(display, win->id); } - - if (winfocus) - focus_win(winfocus); /* has to be done outside of the loop */ } void @@ -1640,20 +1805,25 @@ horizontal_stack(struct workspace *ws, struct swm_geometry *g) /* fullscreen view */ void -max_stack(struct workspace *ws, struct swm_geometry *g) { +max_stack(struct workspace *ws, struct swm_geometry *g) +{ XWindowChanges wc; struct swm_geometry gg = *g; struct ws_win *win, *winfocus; 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); - if (count_win(ws, 0) == 0) + 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 = cur_focus ? cur_focus : ws->focus; + winfocus = ws->focus; TAILQ_FOREACH(win, &ws->winlist, entry) { if (win->transient != 0 || win->floating != 0) { @@ -1661,8 +1831,10 @@ max_stack(struct workspace *ws, struct swm_geometry *g) { /* XXX maximize? */ stack_floater(win, ws->r); XMapRaised(display, win->id); - } else + } else { + /* XXX this sucks */ XUnmapWindow(display, win->id); + } } else { bzero(&wc, sizeof wc); wc.border_width = 1; @@ -1688,7 +1860,7 @@ void send_to_ws(struct swm_region *r, union arg *args) { int wsid = args->id; - struct ws_win *win = cur_focus; + struct ws_win *win = r->ws->focus; struct workspace *ws, *nws; Atom ws_idx_atom = 0; unsigned char ws_idx_str[SWM_PROPLEN]; @@ -1751,7 +1923,7 @@ wkill(struct swm_region *r, union arg *args) void floating_toggle(struct swm_region *r, union arg *args) { - struct ws_win *win = cur_focus; + struct ws_win *win = r->ws->focus; if (win == NULL) return; @@ -2252,7 +2424,7 @@ setup_spawn(void) " -nb $bar_color" " -nf $bar_font_color" " -sb $bar_border" - " -sf bar_color", 0); + " -sf $bar_color", 0); } /* key bindings */ @@ -2926,7 +3098,9 @@ conf_load(char *filename) size_t linelen, lineno = 0; int wordlen, i, optind; struct config_option *opt; - DPRINTF("conf_load begin\n"); + + DNPRINTF(SWM_D_CONF, "conf_load begin\n"); + if (filename == NULL) { fprintf(stderr, "conf_load: no filename\n"); return (1); @@ -2935,6 +3109,7 @@ conf_load(char *filename) warn("conf_load: fopen"); return (1); } + while (!feof(config)) { if ((line = fparseln(config, &linelen, &lineno, NULL, 0)) == NULL) { @@ -3004,8 +3179,10 @@ conf_load(char *filename) free(optsub); free(line); } + fclose(config); - DPRINTF("conf_load end\n"); + DNPRINTF(SWM_D_CONF, "conf_load end\n"); + return (0); } @@ -3014,7 +3191,7 @@ manage_window(Window id) { Window trans; struct workspace *ws; - struct ws_win *win; + struct ws_win *win, *ww; int format, i, ws_idx, n; unsigned long nitems, bytes; Atom ws_idx_atom = 0, type; @@ -3067,8 +3244,17 @@ manage_window(Window id) errstr, prop); } ws = &r->s->ws[ws_idx]; - } else + } 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; + } + } + } /* set up the window layout */ win->id = id; @@ -3141,9 +3327,6 @@ manage_window(Window id) if (win->floating && (ws->idx == r->ws->idx)) XMapRaised(display, win->id); - /* make new win focused */ - focus_win(win); - return (win); } @@ -3157,24 +3340,7 @@ unmanage_window(struct ws_win *win) DNPRINTF(SWM_D_MISC, "unmanage_window: %lu\n", win->id); - /* don't unmanage if we are switching workspaces */ ws = win->ws; - if (ws->restack) - return; - - /* find a window to focus */ - if (ws->focus == win) - ws->focus = TAILQ_PREV(win, ws_win_list, entry); - if (ws->focus == NULL) - ws->focus = TAILQ_FIRST(&ws->winlist); - if (ws->focus == NULL || ws->focus == win) { - ws->focus = NULL; - unfocus_win(win); - } else - focus_win(ws->focus); - if (ws->focus_prev == win) - ws->focus_prev = NULL; - TAILQ_REMOVE(&win->ws->winlist, win, entry); set_win_state(win, WithdrawnState); if (win->ch.res_class) @@ -3266,14 +3432,32 @@ configurenotify(XEvent *e) void destroynotify(XEvent *e) { - struct ws_win *win; + 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); if ((win = find_window(ev->window)) != NULL) { + /* find a window to focus */ + ws = win->ws; + wl = &ws->winlist; + if (ws->focus == win) { + if (TAILQ_FIRST(wl) == win) + winfocus = TAILQ_NEXT(win, entry); + else { + winfocus = TAILQ_PREV(ws->focus, ws_win_list, entry); + if (winfocus == NULL) + winfocus = TAILQ_LAST(wl, ws_win_list); + } + } + unmanage_window(win); stack(); + if (winfocus) + focus_win(winfocus); } } @@ -3290,6 +3474,12 @@ enternotify(XEvent *e) ignore_enter--; return; } + /* + * happens when a window is created or destroyed and the border + * crosses the mouse pointer + */ + if (QLength(display)) + return; if ((win = find_window(ev->window)) != NULL) focus_win(win); @@ -3305,23 +3495,6 @@ void focusout(XEvent *e) { DNPRINTF(SWM_D_EVENT, "focusout: window: %lu\n", e->xfocus.window); - - if (cur_focus && cur_focus->ws->r && - cur_focus->id == e->xfocus.window) { - struct swm_screen *s = cur_focus->ws->r->s; - Window rr, cr; - int x, y, wx, wy; - unsigned int mask; - - /* Try to detect synergy hiding the cursor. */ - if (XQueryPointer(display, cur_focus->id, - &rr, &cr, &x, &y, &wx, &wy, &mask) != False && - cr == 0 && !mask && - x == DisplayWidth(display, s->idx)/2 && - y == DisplayHeight(display, s->idx)/2) { - unfocus_win(cur_focus); - } - } } void @@ -3349,9 +3522,15 @@ maprequest(XEvent *e) return; if (wa.override_redirect) return; + manage_window(e->xmaprequest.window); stack(); + + /* make new win focused */ + struct ws_win *win; + win = find_window(ev->window); + focus_win(win); } void @@ -3392,14 +3571,7 @@ propertynotify(XEvent *e) void unmapnotify(XEvent *e) { - XDestroyWindowEvent *ev = &e->xdestroywindow; - struct ws_win *win; - DNPRINTF(SWM_D_EVENT, "unmapnotify: window: %lu\n", e->xunmap.window); - - if ((win = find_window(ev->window)) != NULL) - if (win->transient) - unmanage_window(win); } void @@ -3562,6 +3734,7 @@ scan_xrandr(int i) /* map virtual screens onto physical screens */ #ifdef SWM_XRR_HAS_CRTC + outputs = 0; if (xrandr_support) { sr = XRRGetScreenResources(display, screens[i].root); if (sr == NULL) @@ -3575,6 +3748,7 @@ scan_xrandr(int i) ci = XRRGetCrtcInfo(display, sr, sr->crtcs[c]); if (ci->noutput == 0) continue; + outputs++; if (ci != NULL && ci->mode == None) new_region(&screens[i], 0, 0, @@ -3761,7 +3935,8 @@ int main(int argc, char *argv[]) { struct passwd *pwd; - struct swm_region *r; + struct swm_region *r, *rr; + struct ws_win *winfocus = NULL; char conf[PATH_MAX], *cfile = NULL; struct stat sb; XEvent e; @@ -3780,6 +3955,13 @@ main(int argc, char *argv[]) if (active_wm()) errx(1, "other wm running"); + /* handle some signale */ + installsignal(SIGINT, "INT"); + installsignal(SIGHUP, "HUP"); + installsignal(SIGQUIT, "QUIT"); + installsignal(SIGTERM, "TERM"); + installsignal(SIGCHLD, "CHLD"); + astate = XInternAtom(display, "WM_STATE", False); aprot = XInternAtom(display, "WM_PROTOCOLS", False); adelete = XInternAtom(display, "WM_DELETE_WINDOW", False); @@ -3811,8 +3993,11 @@ main(int argc, char *argv[]) /* setup all bars */ for (i = 0; i < ScreenCount(display); i++) - TAILQ_FOREACH(r, &screens[i].rl, entry) + TAILQ_FOREACH(r, &screens[i].rl, entry) { + if (winfocus == NULL) + winfocus = TAILQ_FIRST(&r->ws->winlist); bar_setup(r); + } /* set some values to work around bad programs */ workaround(); @@ -3822,18 +4007,10 @@ main(int argc, char *argv[]) xfd = ConnectionNumber(display); while (running) { - FD_ZERO(&rd); - FD_SET(xfd, &rd); - if (select(xfd + 1, &rd, NULL, NULL, NULL) == -1) - if (errno != EINTR) - errx(1, "select failed"); - if (bar_alarm) { - bar_alarm = 0; - bar_update(); - } while (XPending(display)) { XNextEvent(display, &e); if (e.type < LASTEvent) { + dumpevent(&e); if (handler[e.type]) handler[e.type](&e); else @@ -3853,8 +4030,34 @@ 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 */ + if (ScreenCount(display) > 1 || outputs > 1) + XWarpPointer(display, None, rr->s[0].root, + 0, 0, 0, 0, rr->g.x, + rr->g.y + bar_enabled ? bar_height : 0); + + focus_win(winfocus); + winfocus = NULL; + continue; + } + + FD_ZERO(&rd); + FD_SET(xfd, &rd); + if (select(xfd + 1, &rd, NULL, NULL, NULL) == -1) + if (errno != EINTR) + errx(1, "select failed"); + if (bar_alarm) { + bar_alarm = 0; + bar_update(); + } } + bar_extra_stop(); + XCloseDisplay(display); return (0);