X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=3279e7fe619a32f4b7af493465390f458cf9eb3e;hb=c64a9f13209b14b8a266e1322ec2567cdfcb40a0;hp=eb917a46a41ebeaccc516ceb25611d1e6b0431e8;hpb=3a3519197381416cc7a61a432e11a5358827fe0d;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index eb917a4..3279e7f 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -52,7 +52,7 @@ static const char *cvstag = "$scrotwm$"; -#define SWM_VERSION "0.9.27" +#define SWM_VERSION "0.9.30" #include #include @@ -168,6 +168,10 @@ Atom astate; Atom aprot; Atom adelete; Atom takefocus; +Atom a_wmname; +Atom a_utf8_string; +Atom a_string; +Atom a_swm_iconic; volatile sig_atomic_t running = 1; volatile sig_atomic_t restart_wm = 0; int outputs = 0; @@ -186,6 +190,13 @@ int term_width = 0; int font_adjusted = 0; unsigned int mod_key = MODKEY; +/* dmenu search */ +struct swm_region *search_r; +int select_list_pipe[2]; +int select_resp_pipe[2]; +pid_t searchpid; +volatile sig_atomic_t search_resp; + /* dialog windows */ double dialog_ratio = .6; /* status bar */ @@ -198,6 +209,7 @@ int bar_version = 0; sig_atomic_t bar_alarm = 0; int bar_delay = 30; int bar_enabled = 1; +int bar_border_width = 1; int bar_at_bottom = 0; int bar_extra = 1; int bar_extra_running = 0; @@ -208,8 +220,10 @@ int clock_enabled = 1; char *clock_format = NULL; int title_name_enabled = 0; int title_class_enabled = 0; +int window_name_enabled = 0; int focus_mode = SWM_FOCUS_DEFAULT; int disable_border = 0; +int border_width = 1; pid_t bar_pid; GC bar_gc; XGCValues bar_gcv; @@ -258,6 +272,7 @@ struct ws_win { int floatmaxed; /* flag: floater was maxed in max_stack */ int floating; int manual; + int iconic; unsigned int ewmh_flags; int font_size_boundary[SWM_MAX_FONT_STEPS]; int font_steps; @@ -453,6 +468,7 @@ struct ewmh_hint { void store_float_geom(struct ws_win *win, struct swm_region *r); int floating_toggle_win(struct ws_win *win); +void spawn_select(struct swm_region *, union arg *, char *, int *); int get_property(Window id, Atom atom, long count, Atom type, @@ -476,6 +492,52 @@ get_property(Window id, Atom atom, long count, Atom type, } void +update_iconic(struct ws_win *win, int newv) +{ + int32_t v = newv; + Atom iprop; + + win->iconic = newv; + + iprop = XInternAtom(display, "_SWM_ICONIC", False); + if (!iprop) + return; + if (newv) + XChangeProperty(display, win->id, iprop, XA_INTEGER, 32, + PropModeReplace, (unsigned char *)&v, 1); + else + XDeleteProperty(display, win->id, iprop); +} + +int +get_iconic(struct ws_win *win) +{ + int32_t v = 0; + int retfmt, status; + Atom iprop, rettype; + unsigned long nitems, extra; + unsigned char *prop = NULL; + + iprop = XInternAtom(display, "_SWM_ICONIC", False); + if (!iprop) + goto out; + status = XGetWindowProperty(display, win->id, iprop, 0L, 1L, + False, XA_INTEGER, &rettype, &retfmt, &nitems, &extra, &prop); + if (status != Success) + goto out; + if (rettype != XA_INTEGER || retfmt != 32) + goto out; + if (nitems != 1) + goto out; + v = *((int32_t *)prop); + +out: + if (prop != NULL) + XFree(prop); + return (v); +} + +void setup_ewmh(void) { int i,j; @@ -950,6 +1012,8 @@ sighdlr(int sig) #endif /* SWM_DEBUG */ break; } + if (pid == searchpid) + search_resp = 1; #ifdef SWM_DEBUG if (WIFEXITED(status)) { @@ -1040,10 +1104,12 @@ custom_region(char *val) if (x < 0 || x > DisplayWidth(display, sidx) || y < 0 || y > DisplayHeight(display, sidx) || w + x > DisplayWidth(display, sidx) || - h + y > DisplayHeight(display, sidx)) - errx(1, "region %ux%u+%u+%u not within screen boundaries " + h + y > DisplayHeight(display, sidx)) { + fprintf(stderr, "ignoring region %ux%u+%u+%u - not within screen boundaries " "(%ux%u)\n", w, h, x, y, DisplayWidth(display, sidx), DisplayHeight(display, sidx)); + return; + } new_region(&screens[sidx], x, y, w, h); } @@ -1114,6 +1180,23 @@ out: } void +bar_window_name(char *s, ssize_t sz, struct ws_win *cur_focus) +{ + char *title; + + if (window_name_enabled && cur_focus != NULL) { + XFetchName(display, cur_focus->id, &title); + if (title) { + if (cur_focus->floating) + strlcat(s, "(f) ", sz); + strlcat(s, title, sz); + strlcat(s, " ", sz); + XFree(title); + } + } +} + +void bar_update(void) { time_t tmt; @@ -1157,8 +1240,10 @@ bar_update(void) x = 1; TAILQ_FOREACH(r, &screens[i].rl, entry) { strlcpy(cn, "", sizeof cn); - if (r && r->ws) + if (r && r->ws) { bar_class_name(cn, sizeof cn, r->ws->focus); + bar_window_name(cn, sizeof cn, r->ws->focus); + } if (stack_enabled) stack = r->ws->cur_layout->name; @@ -1273,13 +1358,13 @@ bar_setup(struct swm_region *r) if (bar_fs == NULL) errx(1, "couldn't create font structure"); - bar_height = bar_fs->ascent + bar_fs->descent + 3; + bar_height = bar_fs->ascent + bar_fs->descent + 1 + 2 * bar_border_width; x = X(r); y = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r); r->bar_window = XCreateSimpleWindow(display, - r->s->root, x, y, WIDTH(r) - 2, bar_height - 2, - 1, r->s->c[SWM_S_COLOR_BAR_BORDER].color, + r->s->root, x, y, WIDTH(r) - 2 * bar_border_width, bar_height - 2 * bar_border_width, + bar_border_width, r->s->c[SWM_S_COLOR_BAR_BORDER].color, r->s->c[SWM_S_COLOR_BAR].color); bar_gc = XCreateGC(display, r->bar_window, 0, &bar_gcv); XSetFont(display, bar_gc, bar_fs->fid); @@ -1353,49 +1438,44 @@ 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) +config_win(struct ws_win *win, XConfigureRequestEvent *ev) { 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; - ce.window = win->id; - ce.x = win->g.x; - ce.y = win->g.y; - ce.width = win->g.w; - ce.height = win->g.h; - ce.border_width = 1; /* XXX store this! */ - ce.above = None; - ce.override_redirect = False; + if (ev == NULL) { + 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); + + ce.type = ConfigureNotify; + ce.display = display; + ce.event = win->id; + ce.window = win->id; + ce.x = win->g.x; + ce.y = win->g.y; + ce.width = win->g.w; + ce.height = win->g.h; + ce.border_width = border_width; + ce.above = None; + ce.override_redirect = False; + } else { + DNPRINTF(SWM_D_MISC, "config_win: ev win %lu x %d y %d w %d h %d\n", + ev->window, ev->x, ev->y, ev->width, ev->height); + ce.type = ConfigureNotify; + ce.display = ev->display; + ce.event = ev->window; + ce.window = ev->window; + ce.x = ev->x; + ce.y = ev->y; + ce.width = ev->width; + ce.height = ev->height; + ce.border_width = ev->border_width; + ce.above = ev->above; + ce.override_redirect = False; + } + XSendEvent(display, win->id, False, StructureNotifyMask, (XEvent *)&ce); } @@ -1410,6 +1490,8 @@ count_win(struct workspace *ws, int count_transient) continue; if (count_transient == 0 && win->transient) continue; + if (win->iconic) + continue; count++; } DNPRINTF(SWM_D_MISC, "count_win: %d\n", count); @@ -1581,40 +1663,40 @@ find_window(Window id) } void -spawn(struct swm_region *r, union arg *args) +spawn(struct swm_region *r, union arg *args, int close_fd) { int fd; char *ret = NULL; DNPRINTF(SWM_D_MISC, "spawn: %s\n", args->argv[0]); - if (fork() == 0) { - if (display) - close(ConnectionNumber(display)); + if (display) + close(ConnectionNumber(display)); - setenv("LD_PRELOAD", SWM_LIB, 1); + setenv("LD_PRELOAD", SWM_LIB, 1); - if (asprintf(&ret, "%d", r->ws->idx) == -1) { - perror("_SWM_WS"); - _exit(1); - } - setenv("_SWM_WS", ret, 1); - free(ret); - ret = NULL; + if (asprintf(&ret, "%d", r->ws->idx) == -1) { + perror("_SWM_WS"); + _exit(1); + } + setenv("_SWM_WS", ret, 1); + free(ret); + ret = NULL; - if (asprintf(&ret, "%d", getpid()) == -1) { - perror("_SWM_PID"); - _exit(1); - } - setenv("_SWM_PID", ret, 1); - free(ret); - ret = NULL; + if (asprintf(&ret, "%d", getpid()) == -1) { + perror("_SWM_PID"); + _exit(1); + } + setenv("_SWM_PID", ret, 1); + free(ret); + ret = NULL; - if (setsid() == -1) { - perror("setsid"); - _exit(1); - } + if (setsid() == -1) { + perror("setsid"); + _exit(1); + } + if (close_fd) { /* * close stdin and stdout to prevent interaction between apps * and the baraction script @@ -1628,12 +1710,12 @@ spawn(struct swm_region *r, union arg *args) dup2(fd, STDOUT_FILENO); if (fd > 2) close(fd); + } - execvp(args->argv[0], args->argv); + execvp(args->argv[0], args->argv); - perror("execvp"); - _exit(1); - } + perror("execvp"); + _exit(1); } void @@ -1643,7 +1725,8 @@ spawnterm(struct swm_region *r, union arg *args) if (term_width) setenv("_SWM_XTERM_FONTADJ", "", 1); - spawn(r, args); + if (fork() == 0) + spawn(r, args, 1); } void @@ -1711,7 +1794,7 @@ void unfocus_win(struct ws_win *win) { XEvent cne; - Window none = None; + Window none = None; DNPRINTF(SWM_D_FOCUS, "unfocus_win: id: %lu\n", WINID(win)); @@ -1721,7 +1804,7 @@ unfocus_win(struct ws_win *win) return; if (validate_ws(win->ws)) - abort(); /* XXX replace with return at some point */ + return; /* XXX this gets hit with thunderbird, needs fixing */ if (win->ws->r == NULL) return; @@ -1789,7 +1872,7 @@ focus_win(struct ws_win *win) return; if (validate_ws(win->ws)) - abort(); /* XXX replace with return at some point */ + return; /* XXX this gets hit with thunderbird, needs fixing */ if (validate_win(win)) { kill_refs(win); @@ -1825,6 +1908,9 @@ focus_win(struct ws_win *win) ewmh[_NET_ACTIVE_WINDOW].atom, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&win->id,1); } + + if (window_name_enabled) + bar_update(); } void @@ -2106,7 +2192,7 @@ done: void focus(struct swm_region *r, union arg *args) { - struct ws_win *winfocus = NULL, *winlostfocus = NULL; + struct ws_win *winfocus = NULL, *winlostfocus = NULL, *head; struct ws_win *cur_focus = NULL; struct ws_win_list *wl = NULL; struct workspace *ws = NULL; @@ -2118,12 +2204,14 @@ focus(struct swm_region *r, union arg *args) /* treat FOCUS_CUR special */ if (args->id == SWM_ARG_ID_FOCUSCUR) { - if (r->ws->focus) + if (r->ws->focus && r->ws->focus->iconic == 0) winfocus = r->ws->focus; - else if (r->ws->focus_prev) + else if (r->ws->focus_prev && r->ws->focus_prev->iconic == 0) winfocus = r->ws->focus_prev; else - winfocus = TAILQ_FIRST(&r->ws->winlist); + TAILQ_FOREACH(winfocus, &r->ws->winlist, entry) + if (winfocus->iconic == 0) + break; focus_magic(winfocus, SWM_F_GENERIC); return; @@ -2138,15 +2226,43 @@ focus(struct swm_region *r, union arg *args) switch (args->id) { case SWM_ARG_ID_FOCUSPREV: - winfocus = TAILQ_PREV(cur_focus, ws_win_list, entry); - if (winfocus == NULL) - winfocus = TAILQ_LAST(wl, ws_win_list); + head = TAILQ_PREV(cur_focus, ws_win_list, entry); + 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; + } + } break; case SWM_ARG_ID_FOCUSNEXT: - winfocus = TAILQ_NEXT(cur_focus, entry); - if (winfocus == NULL) - winfocus = TAILQ_FIRST(wl); + head = TAILQ_NEXT(cur_focus, entry); + 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; + } + } break; case SWM_ARG_ID_FOCUSMAIN: @@ -2217,8 +2333,8 @@ stack(void) { /* start with screen geometry, adjust for bar */ g = r->g; - g.w -= 2; - g.h -= 2; + g.w -= 2 * border_width; + g.h -= 2 * border_width; if (bar_enabled) { if (!bar_at_bottom) g.y += bar_height; @@ -2284,7 +2400,7 @@ stack_floater(struct ws_win *win, struct swm_region *r) (win->g.h >= HEIGHT(r))) wc.border_width = 0; else - wc.border_width = 1; + wc.border_width = border_width; if (win->transient && (win->quirks & SWM_Q_TRANSSZ)) { win->g.w = (double)WIDTH(r) * dialog_ratio; win->g.h = (double)HEIGHT(r) * dialog_ratio; @@ -2295,22 +2411,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; - win->g.y = r->g.y + (HEIGHT(r) - win->g.h) / 2; + 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 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 ) - win->g.x = r->g.x; + if (win->g.x < r->g.x - border_width) + win->g.x = r->g.x - 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); - if (win->g.y < r->g.y ) - win->g.y = r->g.y; + (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; 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); + (r->g.y + r->g.h - win->g.h - 2 * border_width); wc.x = win->g.x; wc.y = win->g.y; @@ -2328,7 +2444,6 @@ stack_floater(struct ws_win *win, struct swm_region *r) win->id, wc.x, wc.y, wc.width, wc.height); XConfigureWindow(display, win->id, mask, &wc); - configreq_win(win); } /* @@ -2387,7 +2502,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) return; TAILQ_FOREACH(win, &ws->winlist, entry) - if (win->transient == 0 && win->floating == 0) + if (win->transient == 0 && win->floating == 0 && win->iconic == 0) break; if (win == NULL) @@ -2436,17 +2551,19 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) } else { msize = -2; colno = split = winno / stacks; - win_g.w = ((r_g.w - (stacks * 2) + 2) / stacks); + win_g.w = ((r_g.w - (stacks * 2 * border_width) + 2 * border_width) / stacks); } hrh = r_g.h / colno; extra = r_g.h - (colno * hrh); - win_g.h = hrh - 2; + win_g.h = hrh - 2 * border_width; /* stack all the tiled windows */ i = j = 0, s = stacks; TAILQ_FOREACH(win, &ws->winlist, entry) { if (win->transient != 0 || win->floating != 0) continue; + if (win->iconic != 0) + continue; if (win->ewmh_flags & EWMH_F_FULLSCREEN) { fs_win = win; @@ -2463,15 +2580,15 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) if (flip) win_g.x = r_g.x; else - win_g.x += win_g.w + 2; - win_g.w = (r_g.w - msize - (stacks * 2)) / stacks; + win_g.x += win_g.w + 2 * border_width; + win_g.w = (r_g.w - msize - (stacks * 2 * border_width)) / stacks; if (s == 1) - win_g.w += (r_g.w - msize - (stacks * 2)) % + win_g.w += (r_g.w - msize - (stacks * 2 * border_width)) % stacks; s--; j = 0; } - win_g.h = hrh - 2; + win_g.h = hrh - 2 * border_width; if (rot) { h_inc = win->sh.width_inc; h_base = win->sh.base_width; @@ -2498,15 +2615,15 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) if (j == 0) win_g.y = r_g.y; else - win_g.y += last_h + 2; + win_g.y += last_h + 2 * border_width; bzero(&wc, sizeof wc); if (disable_border && bar_enabled == 0 && winno == 1){ wc.border_width = 0; - win_g.w += 2; - win_g.h += 2; + win_g.w += 2 * border_width; + win_g.h += 2 * border_width; } else - wc.border_width = 1; + wc.border_width = border_width; reconfigure = 0; if (rot) { if (win->g.x != win_g.y || win->g.y != win_g.x || @@ -2531,7 +2648,6 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) adjust_font(win); mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; XConfigureWindow(display, win->id, mask, &wc); - configreq_win(win); } if (XGetWindowAttributes(display, win->id, &wa)) @@ -2548,6 +2664,8 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) TAILQ_FOREACH(win, &ws->winlist, entry) { if (win->transient == 0 && win->floating == 0) continue; + if (win->iconic == 0) + continue; if (win->ewmh_flags & EWMH_F_FULLSCREEN) { fs_win = win; @@ -2700,17 +2818,16 @@ max_stack(struct workspace *ws, struct swm_geometry *g) win->g.x = wc.x = gg.x; win->g.y = wc.y = gg.y; if (bar_enabled){ - wc.border_width = 1; + wc.border_width = border_width; win->g.w = wc.width = gg.w; win->g.h = wc.height = gg.h; } else { wc.border_width = 0; - win->g.w = wc.width = gg.w + 2; - win->g.h = wc.height = gg.h + 2; + win->g.w = wc.width = gg.w + 2 * border_width; + win->g.h = wc.height = gg.h + 2 * border_width; } mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; XConfigureWindow(display, win->id, mask, &wc); - configreq_win(win); } /* unmap only if we don't have multi screen */ if (win != ws->focus) @@ -2772,6 +2889,151 @@ send_to_ws(struct swm_region *r, union arg *args) } void +iconify(struct swm_region *r, union arg *args) +{ + union arg a; + + if (r->ws->focus == NULL) + return; + unmap_window(r->ws->focus); + update_iconic(r->ws->focus, 1); + stack(); + r->ws->focus = NULL; + a.id = SWM_ARG_ID_FOCUSCUR; + focus(r, &a); +} + +unsigned char * +get_win_name(Display *dpy, Window win, Atom wname, Atom stype, + unsigned long *slen) +{ + int status, retfmt; + unsigned long nitems, nbytes, nextra; + unsigned char *prop = NULL; + Atom rettype; + + status = XGetWindowProperty(dpy, win, wname, 0L, 0L, False, stype, + &rettype, &retfmt, &nitems, &nbytes, &prop); + if (status != Success) + return (NULL); + XFree(prop); + + status = XGetWindowProperty(dpy, win, wname, 0L, nbytes, False, + stype, &rettype, &retfmt, &nitems, &nextra, &prop); + if (status != Success) { + XFree(prop); + return (NULL); + } + if (rettype != stype) { + XFree(prop); + return (NULL); + } + *slen = nitems; + return (prop); +} + +void +uniconify(struct swm_region *r, union arg *args) +{ + struct ws_win *win; + FILE *lfile; + char *name; + int count = 0; + unsigned long len; + + DNPRINTF(SWM_D_MISC, "uniconify\n"); + + if (r && r->ws == NULL) + return; + + /* make sure we have anything to uniconify */ + TAILQ_FOREACH(win, &r->ws->winlist, entry) { + if (win->ws == NULL) + continue; /* should never happen */ + if (win->iconic == 0) + continue; + count++; + } + if (count == 0) + return; + + search_r = r; + + spawn_select(r, args, "uniconify", &searchpid); + + if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) + return; + + TAILQ_FOREACH(win, &r->ws->winlist, entry) { + if (win->ws == NULL) + continue; /* should never happen */ + if (win->iconic == 0) + continue; + + name = get_win_name(display, win->id, a_wmname, a_string, + &len); + if (name == NULL) + continue; + fprintf(lfile, "%s.%lu\n", name, win->id); + XFree(name); + } + + fclose(lfile); +} + +#define MAX_RESP_LEN 1024 + +void +search_do_resp(void) +{ + ssize_t rbytes; + struct ws_win *win; + char *name, *resp, *s; + unsigned long len; + + DNPRINTF(SWM_D_MISC, "search_do_resp:\n"); + + search_resp = 0; + searchpid = 0; + + if ((resp = calloc(1, MAX_RESP_LEN + 1)) == NULL) { + fprintf(stderr, "search: calloc\n"); + return; + } + + rbytes = read(select_resp_pipe[0], resp, MAX_RESP_LEN); + if (rbytes <= 0) { + fprintf(stderr, "search: read error: %s\n", strerror(errno)); + goto done; + } + resp[rbytes] = '\0'; + len = strlen(resp); + + DNPRINTF(SWM_D_MISC, "search_do_resp: resp %s\n", resp); + TAILQ_FOREACH(win, &search_r->ws->winlist, entry) { + if (win->iconic == 0) + continue; + name = get_win_name(display, win->id, a_wmname, a_string, &len); + if (name == NULL) + continue; + if (asprintf(&s, "%s.%lu", name, win->id) == -1) { + XFree(name); + continue; + } + XFree(name); + if (strncmp(s, resp, len) == 0) { + /* XXX this should be a callback to generalize */ + update_iconic(win, 0); + free(s); + break; + } + free(s); + } +done: + free(resp); +} + +void wkill(struct swm_region *r, union arg *args) { DNPRINTF(SWM_D_MISC, "wkill %d\n", args->id); @@ -2832,6 +3094,9 @@ floating_toggle(struct swm_region *r, union arg *args) struct ws_win *win = r->ws->focus; union arg a; + if (win == NULL) + return; + ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom, _NET_WM_STATE_TOGGLE); @@ -2853,12 +3118,12 @@ resize_window(struct ws_win *win, int center) r = root_to_region(win->wa.root); bzero(&wc, sizeof wc); mask = CWBorderWidth | CWWidth | CWHeight; - wc.border_width = 1; + wc.border_width = border_width; wc.width = win->g.w; wc.height = win->g.h; if (center == SWM_ARG_ID_CENTER) { - wc.x = (WIDTH(r) - win->g.w) / 2; - wc.y = (HEIGHT(r) - win->g.h) / 2; + wc.x = (WIDTH(r) - win->g.w) / 2 - border_width; + wc.y = (HEIGHT(r) - win->g.h) / 2 - border_width; mask |= CWX | CWY; } @@ -2866,7 +3131,6 @@ resize_window(struct ws_win *win, int center) win->id, wc.x, wc.y, wc.width, wc.height); XConfigureWindow(display, win->id, mask, &wc); - configreq_win(win); } void @@ -2903,14 +3167,14 @@ resize(struct ws_win *win, union arg *args) /* place pointer at bottom left corner or nearest point inside r */ if ( win->g.x + win->g.w < r->g.x + r->g.w - 1) - relx = win->g.w; + relx = win->g.w - 1; else - relx = r->g.x + r->g.w - win->g.x - 2; + relx = r->g.x + r->g.w - win->g.x - 1; if ( win->g.y + win->g.h < r->g.y + r->g.h - 1) - rely = win->g.h; + rely = win->g.h - 1; else - rely = r->g.y + r->g.h - win->g.y - 2; + rely = r->g.y + r->g.h - win->g.y - 1; XWarpPointer(display, None, win->id, 0, 0, 0, 0, relx, rely); do { @@ -2934,11 +3198,11 @@ resize(struct ws_win *win, union arg *args) ev.xmotion.x = 1; if (ev.xmotion.y <= 1) ev.xmotion.y = 1; - win->g.w = ev.xmotion.x; - win->g.h = ev.xmotion.y; + win->g.w = ev.xmotion.x + 1; + win->g.h = ev.xmotion.y + 1; - /* not free, don't sync more than 60 times / second */ - if ((ev.xmotion.time - time) > (1000 / 60) ) { + /* not free, don't sync more than 120 times / second */ + if ((ev.xmotion.time - time) > (1000 / 120) ) { time = ev.xmotion.time; XSync(display, False); resize_window(win, args->id); @@ -2972,12 +3236,12 @@ move_window(struct ws_win *win) mask = CWX | CWY; wc.x = win->g.x; wc.y = win->g.y; + wc.border_width = border_width; DNPRINTF(SWM_D_STACK, "move_window: win %lu x %d y %d w %d h %d\n", win->id, wc.x, wc.y, wc.width, wc.height); XConfigureWindow(display, win->id, mask, &wc); - configreq_win(win); } void @@ -3012,7 +3276,7 @@ move(struct ws_win *win, union arg *args) if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess) return; - XWarpPointer(display, None, win->id, 0, 0, 0, 0, -1, -1); + XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0); do { XMaskEvent(display, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); @@ -3030,11 +3294,11 @@ move(struct ws_win *win, union arg *args) ev.xmotion.y_root > r->g.y + r->g.h - 1) continue; - win->g.x = ev.xmotion.x_root; - win->g.y = ev.xmotion.y_root; + win->g.x = ev.xmotion.x_root - border_width; + win->g.y = ev.xmotion.y_root - border_width; - /* not free, don't sync more than 60 times / second */ - if ((ev.xmotion.time - time) > (1000 / 60) ) { + /* not free, don't sync more than 120 times / second */ + if ((ev.xmotion.time - time) > (1000 / 120) ) { time = ev.xmotion.time; XSync(display, False); move_window(win); @@ -3109,7 +3373,9 @@ enum keyfuncid { kf_spawn_lock, kf_spawn_initscr, kf_spawn_custom, - kf_dumpwins, + kf_iconify, + kf_uniconify, + kf_dumpwins, /* MUST BE LAST */ kf_invalid }; @@ -3183,7 +3449,9 @@ struct keyfunc { { "spawn_lock", legacyfunc, {0} }, { "spawn_initscr", legacyfunc, {0} }, { "spawn_custom", dummykeyfunc, {0} }, - { "dumpwins", dumpwins, {0} }, + { "iconify", iconify, {0} }, + { "uniconify", uniconify, {0} }, + { "dumpwins", dumpwins, {0} }, /* MUST BE LAST */ { "invalid key func", NULL, {0} }, }; struct key { @@ -3239,15 +3507,15 @@ struct spawn_prog { int spawns_size = 0, spawns_length = 0; struct spawn_prog *spawns = NULL; -void -spawn_custom(struct swm_region *r, union arg *args, char *spawn_name) +int +spawn_expand(struct swm_region *r, union arg *args, char *spawn_name, + char ***ret_args) { - union arg a; struct spawn_prog *prog = NULL; int i; char *ap, **real_args; - DNPRINTF(SWM_D_SPAWN, "spawn_custom %s\n", spawn_name); + DNPRINTF(SWM_D_SPAWN, "spawn_expand %s\n", spawn_name); /* find program */ for (i = 0; i < spawns_length; i++) { @@ -3257,7 +3525,7 @@ spawn_custom(struct swm_region *r, union arg *args, char *spawn_name) if (prog == NULL) { fprintf(stderr, "spawn_custom: program %s not found\n", spawn_name); - return; + return (-1); } /* make room for expanded args */ @@ -3314,10 +3582,66 @@ spawn_custom(struct swm_region *r, union arg *args, char *spawn_name) fprintf(stderr, "\n"); } #endif + *ret_args = real_args; + return (prog->argc); +} + +void +spawn_custom(struct swm_region *r, union arg *args, char *spawn_name) +{ + union arg a; + char **real_args; + int spawn_argc, i; + if ((spawn_argc = spawn_expand(r, args, spawn_name, &real_args)) < 0) + return; a.argv = real_args; - spawn(r, &a); - for (i = 0; i < prog->argc; i++) + if (fork() == 0) + spawn(r, &a, 1); + + for (i = 0; i < spawn_argc; i++) + free(real_args[i]); + free(real_args); +} + +void +spawn_select(struct swm_region *r, union arg *args, char *spawn_name, int *pid) +{ + union arg a; + char **real_args; + int i, spawn_argc; + + if ((spawn_argc = spawn_expand(r, args, spawn_name, &real_args)) < 0) + return; + a.argv = real_args; + + if (pipe(select_list_pipe) == -1) + err(1, "pipe error"); + if (pipe(select_resp_pipe) == -1) + err(1, "pipe error"); + + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + err(1, "could not disable SIGPIPE"); + switch (*pid = fork()) { + case -1: + err(1, "cannot fork"); + break; + case 0: /* child */ + if (dup2(select_list_pipe[0], 0) == -1) + errx(1, "dup2"); + if (dup2(select_resp_pipe[1], 1) == -1) + errx(1, "dup2"); + close(select_list_pipe[1]); + close(select_resp_pipe[0]); + spawn(r, &a, 0); + break; + default: /* parent */ + close(select_list_pipe[0]); + close(select_resp_pipe[1]); + break; + } + + for (i = 0; i < spawn_argc; i++) free(real_args[i]); free(real_args); } @@ -3458,6 +3782,13 @@ setup_spawn(void) " -nf $bar_font_color" " -sb $bar_border" " -sf $bar_color", 0); + setconfspawn("uniconify", "dmenu" + " -i" + " -fn $bar_font" + " -nb $bar_color" + " -nf $bar_font_color" + " -sb $bar_border" + " -sf $bar_color", 0); } /* key bindings */ @@ -3707,6 +4038,8 @@ setup_keys(void) setkeybinding(MODKEY|ShiftMask, XK_v, kf_version, NULL); setkeybinding(MODKEY|ShiftMask, XK_Delete, kf_spawn_custom, "lock"); setkeybinding(MODKEY|ShiftMask, XK_i, kf_spawn_custom, "initscr"); + setkeybinding(MODKEY, XK_w, kf_iconify, NULL); + setkeybinding(MODKEY|ShiftMask, XK_w, kf_uniconify, NULL); #ifdef SWM_DEBUG setkeybinding(MODKEY|ShiftMask, XK_d, kf_dumpwins, NULL); #endif @@ -3937,11 +4270,11 @@ setup_quirks(void) /* conf file stuff */ #define SWM_CONF_FILE "scrotwm.conf" -enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_STACK_ENABLED, +enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_BAR_BORDER_WIDTH, SWM_S_STACK_ENABLED, SWM_S_CLOCK_ENABLED, SWM_S_CLOCK_FORMAT, SWM_S_CYCLE_EMPTY, SWM_S_CYCLE_VISIBLE, SWM_S_SS_ENABLED, SWM_S_TERM_WIDTH, - SWM_S_TITLE_CLASS_ENABLED, SWM_S_TITLE_NAME_ENABLED, - SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BAR_FONT, + SWM_S_TITLE_CLASS_ENABLED, SWM_S_TITLE_NAME_ENABLED, SWM_S_WINDOW_NAME_ENABLED, + SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BORDER_WIDTH, SWM_S_BAR_FONT, SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO, SWM_S_BAR_AT_BOTTOM }; @@ -3956,6 +4289,9 @@ setconfvalue(char *selector, char *value, int flags) case SWM_S_BAR_ENABLED: bar_enabled = atoi(value); break; + case SWM_S_BAR_BORDER_WIDTH: + bar_border_width = atoi(value); + break; case SWM_S_BAR_AT_BOTTOM: bar_at_bottom = atoi(value); break; @@ -3987,6 +4323,9 @@ setconfvalue(char *selector, char *value, int flags) case SWM_S_TITLE_CLASS_ENABLED: title_class_enabled = atoi(value); break; + case SWM_S_WINDOW_NAME_ENABLED: + window_name_enabled = atoi(value); + break; case SWM_S_TITLE_NAME_ENABLED: title_name_enabled = atoi(value); break; @@ -4003,6 +4342,9 @@ setconfvalue(char *selector, char *value, int flags) case SWM_S_DISABLE_BORDER: disable_border = atoi(value); break; + case SWM_S_BORDER_WIDTH: + border_width = atoi(value); + break; case SWM_S_BAR_FONT: free(bar_fonts[0]); if ((bar_fonts[0] = strdup(value)) == NULL) @@ -4071,6 +4413,7 @@ struct config_option configopt[] = { { "bar_enabled", setconfvalue, SWM_S_BAR_ENABLED }, { "bar_at_bottom", setconfvalue, SWM_S_BAR_AT_BOTTOM }, { "bar_border", setconfcolor, SWM_S_COLOR_BAR_BORDER }, + { "bar_border_width", setconfvalue, SWM_S_BAR_BORDER_WIDTH }, { "bar_color", setconfcolor, SWM_S_COLOR_BAR }, { "bar_font_color", setconfcolor, SWM_S_COLOR_BAR_FONT }, { "bar_font", setconfvalue, SWM_S_BAR_FONT }, @@ -4092,11 +4435,13 @@ struct config_option configopt[] = { { "spawn_term", setconfvalue, SWM_S_SPAWN_TERM }, { "screenshot_enabled", setconfvalue, SWM_S_SS_ENABLED }, { "screenshot_app", setconfvalue, SWM_S_SS_APP }, + { "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_ENABLED }, { "term_width", setconfvalue, SWM_S_TERM_WIDTH }, { "title_class_enabled", setconfvalue, SWM_S_TITLE_CLASS_ENABLED }, { "title_name_enabled", setconfvalue, SWM_S_TITLE_NAME_ENABLED }, { "focus_mode", setconfvalue, SWM_S_FOCUS_MODE }, { "disable_border", setconfvalue, SWM_S_DISABLE_BORDER }, + { "border_width", setconfvalue, SWM_S_BORDER_WIDTH }, }; @@ -4240,6 +4585,8 @@ manage_window(Window id) if ((win = calloc(1, sizeof(struct ws_win))) == NULL) errx(1, "calloc: failed to allocate memory for new window"); + win->id = id; + /* Get all the window data in one shot */ ws_idx_atom = XInternAtom(display, "_SWM_WS", False); if (ws_idx_atom) @@ -4267,6 +4614,8 @@ manage_window(Window id) XFree(prot); } + win->iconic = get_iconic(win); + /* * Figure out where to put the window. If it was previously assigned to * a workspace (either by spawn() or manually moving), and isn't @@ -4379,16 +4728,17 @@ manage_window(Window id) /* border me */ if (border_me) { bzero(&wc, sizeof wc); - wc.border_width = 1; + wc.border_width = border_width; mask = CWBorderWidth; XConfigureWindow(display, win->id, mask, &wc); - configreq_win(win); } XSelectInput(display, id, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask); - - set_win_state(win, NormalState); + 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)) @@ -4570,17 +4920,7 @@ configurerequest(XEvent *e) } else { DNPRINTF(SWM_D_EVENT, "configurerequest: change window: %lu\n", ev->window); - if (win->floating) { - if (ev->value_mask & CWX) - win->g.x = ev->x; - if (ev->value_mask & CWY) - win->g.y = ev->y; - if (ev->value_mask & CWWidth) - win->g.w = ev->width; - if (ev->value_mask & CWHeight) - win->g.h = ev->height; - } - config_win(win); + config_win(win, ev); } } @@ -4848,12 +5188,18 @@ propertynotify(XEvent *e) DNPRINTF(SWM_D_EVENT, "propertynotify: window: %lu\n", ev->window); - if (ev->state == PropertyDelete) - return; /* ignore */ win = find_window(ev->window); if (win == NULL) return; + if (ev->state == PropertyDelete && ev->atom == a_swm_iconic) { + update_iconic(win, 0); + XMapRaised(display, win->id); + stack(); + focus_win(win); + return; + } + switch (ev->atom) { case XA_WM_NORMAL_HINTS: #if 0 @@ -4868,6 +5214,8 @@ propertynotify(XEvent *e) XMoveResizeWindow(display, win->id, win->g.x, win->g.y, win->g.w, win->g.h); #endif + if (window_name_enabled) + bar_update(); break; default: break; @@ -4948,7 +5296,7 @@ clientmessage(XEvent *e) else { /* TODO: Change stack sizes */ } - config_win(win); + config_win(win, NULL); } if (ev->message_type == ewmh[_NET_WM_STATE].atom) { DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_STATE \n"); @@ -5011,7 +5359,7 @@ new_region(struct swm_screen *s, int x, int y, int w, int h) (X(r) + WIDTH(r)) > x && Y(r) < (y + h) && (Y(r) + HEIGHT(r)) > y) { - if (r->ws->r != NULL) + if (r->ws->r != NULL) r->ws->old_r = r->ws->r; r->ws->r = NULL; XDestroyWindow(display, r->bar_window); @@ -5353,6 +5701,10 @@ main(int argc, char *argv[]) aprot = XInternAtom(display, "WM_PROTOCOLS", False); adelete = XInternAtom(display, "WM_DELETE_WINDOW", False); takefocus = XInternAtom(display, "WM_TAKE_FOCUS", False); + a_wmname = XInternAtom(display, "WM_NAME", False); + a_utf8_string = XInternAtom(display, "UTF8_STRING", False); + a_string = XInternAtom(display, "STRING", False); + a_swm_iconic = XInternAtom(display, "_SWM_ICONIC", False); /* look for local and global conf file */ pwd = getpwuid(getuid()); @@ -5457,6 +5809,8 @@ main(int argc, char *argv[]) DNPRINTF(SWM_D_MISC, "select failed"); if (restart_wm == 1) restart(NULL, NULL); + if (search_resp == 1) + search_do_resp(); if (running == 0) goto done; if (bar_alarm) {