X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=92145c4facb165fb449364fa211b718779c9881a;hb=4a043e85195b7337a6087d38d0c6c5c6817f187f;hp=c43b0eaf5d9e0ca0782c7560987dbe8759dfede2;hpb=7392ce9247c9e4ea8716c6f985b6f6d8a9a351cd;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index c43b0ea..92145c4 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2009-2010-2011 Marco Peereboom - * Copyright (c) 2009-2010-2011 Ryan McBride + * Copyright (c) 2009-2012 Marco Peereboom + * Copyright (c) 2009-2011 Ryan McBride * Copyright (c) 2009 Darrin Chandler * Copyright (c) 2009 Pierre-Yves Ritschard * Copyright (c) 2010 Tuukka Kataja * Copyright (c) 2011 Jason L. Wright + * Copyright (c) 2011-2012 Reginald Kennedy * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -178,6 +179,7 @@ Atom aprot; Atom adelete; Atom takefocus; Atom a_wmname; +Atom a_netwmname; Atom a_utf8_string; Atom a_string; Atom a_swm_iconic; @@ -1239,7 +1241,7 @@ socket_setnonblock(int fd) void bar_print(struct swm_region *r, char *s) { - int textwidth, x; + int textwidth, x = 0; size_t len; XClearWindow(display, r->bar_window); @@ -2428,8 +2430,14 @@ focus_prev(struct ws_win *win) if (winfocus == NULL || winfocus == win) winfocus = TAILQ_NEXT(cur_focus, entry); done: - if (winfocus == winlostfocus || winfocus == NULL) + if (winfocus == winlostfocus || winfocus == NULL) { + /* update the bar so that title/class/name will be cleared. */ + if (window_name_enabled || title_name_enabled || + title_class_enabled) + bar_update(); + return; + } focus_magic(winfocus); } @@ -2441,6 +2449,7 @@ focus(struct swm_region *r, union arg *args) struct ws_win *cur_focus = NULL; struct ws_win_list *wl = NULL; struct workspace *ws = NULL; + int all_iconics; if (!(r && r->ws)) return; @@ -2466,6 +2475,17 @@ focus(struct swm_region *r, union arg *args) return; ws = r->ws; wl = &ws->winlist; + if (TAILQ_EMPTY(wl)) + return; + /* make sure there is at least one uniconified window */ + all_iconics = 1; + TAILQ_FOREACH(winfocus, wl, entry) + if (winfocus->iconic == 0) { + all_iconics = 0; + break; + } + if (all_iconics) + return; winlostfocus = cur_focus; @@ -2484,9 +2504,13 @@ focus(struct swm_region *r, union arg *args) /* skip iconics */ if (winfocus && winfocus->iconic) { - TAILQ_FOREACH_REVERSE(winfocus, wl, ws_win_list, entry) + while (winfocus != cur_focus) { + if (winfocus == NULL) + winfocus = TAILQ_LAST(wl, ws_win_list); if (winfocus->iconic == 0) break; + winfocus = TAILQ_PREV(winfocus, ws_win_list, entry); + } } break; @@ -2498,9 +2522,13 @@ focus(struct swm_region *r, union arg *args) /* skip iconics */ if (winfocus && winfocus->iconic) { - TAILQ_FOREACH(winfocus, wl, entry) + while (winfocus != cur_focus) { + if (winfocus == NULL) + winfocus = TAILQ_FIRST(wl); if (winfocus->iconic == 0) break; + winfocus = TAILQ_NEXT(winfocus, entry); + } } break; @@ -2513,8 +2541,14 @@ focus(struct swm_region *r, union arg *args) default: return; } - if (winfocus == winlostfocus || winfocus == NULL) + if (winfocus == winlostfocus || winfocus == NULL) { + /* update the bar so that title/class/name will be cleared. */ + if (window_name_enabled || title_name_enabled || + title_class_enabled) + bar_update(); + return; + } focus_magic(winfocus); } @@ -2559,12 +2593,17 @@ void stack(void) { struct swm_geometry g; struct swm_region *r; - int i, j; + int i; +#ifdef SWM_DEBUG + int j; +#endif DNPRINTF(SWM_D_STACK, "stack\n"); for (i = 0; i < ScreenCount(display); i++) { +#ifdef SWM_DEBUG j = 0; +#endif TAILQ_FOREACH(r, &screens[i].rl, entry) { DNPRINTF(SWM_D_STACK, "stacking workspace %d " "(screen %d, region %d)\n", r->ws->idx, i, j++); @@ -3100,7 +3139,7 @@ send_to_ws(struct swm_region *r, union arg *args) unsigned char ws_idx_str[SWM_PROPLEN]; union arg a; - if (r && r->ws) + if (r && r->ws && r->ws->focus) win = r->ws->focus; else return; @@ -3128,6 +3167,8 @@ send_to_ws(struct swm_region *r, union arg *args) unmap_window(win); TAILQ_REMOVE(&ws->winlist, win, entry); TAILQ_INSERT_TAIL(&nws->winlist, win, entry); + if (TAILQ_EMPTY(&ws->winlist)) + r->ws->focus = NULL; win->ws = nws; /* Try to update the window's workspace property */ @@ -3249,7 +3290,7 @@ uniconify(struct swm_region *r, union arg *args) if (win->iconic == 0) continue; - name = get_win_name(display, win->id, a_wmname, a_string, + name = get_win_name(display, win->id, a_netwmname, a_utf8_string, &len); if (name == NULL) continue; @@ -3405,7 +3446,7 @@ search_resp_uniconify(char *resp, unsigned long len) 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); + name = get_win_name(display, win->id, a_netwmname, a_utf8_string, &len); if (name == NULL) continue; if (asprintf(&s, "%s.%lu", name, win->id) == -1) { @@ -3648,25 +3689,57 @@ floating_toggle(struct swm_region *r, union arg *args) } void -resize_window(struct ws_win *win, int center) +constrain_window(struct ws_win *win, struct swm_region *r, int resizable) +{ + if (win->g.x + win->g.w > r->g.x + r->g.w - border_width) { + if (resizable) + win->g.w = r->g.x + r->g.w - win->g.x - border_width; + else + win->g.x = r->g.x + r->g.w - win->g.w - border_width; + } + + if (win->g.x < r->g.x - border_width) { + if (resizable) + win->g.w -= r->g.x - win->g.x - border_width; + + win->g.x = r->g.x - border_width; + } + + if (win->g.y + win->g.h > r->g.y + r->g.h - border_width) { + if (resizable) + win->g.h = r->g.y + r->g.h - win->g.y - border_width; + else + win->g.y = r->g.y + r->g.h - win->g.h - border_width; + } + + if (win->g.y < r->g.y - border_width) { + if (resizable) + win->g.h -= r->g.y - win->g.y - border_width; + + win->g.y = r->g.y - border_width; + } + + if (win->g.w < 1) + win->g.w = 1; + if (win->g.h < 1) + win->g.h = 1; +} + +void +update_window(struct ws_win *win) { unsigned int mask; XWindowChanges wc; - struct swm_region *r; - r = root_to_region(win->wa.root); bzero(&wc, sizeof wc); - mask = CWBorderWidth | CWWidth | CWHeight; + mask = CWBorderWidth | CWWidth | CWHeight | CWX | CWY; wc.border_width = border_width; + wc.x = win->g.x; + wc.y = win->g.y; wc.width = win->g.w; wc.height = win->g.h; - if (center == SWM_ARG_ID_CENTER) { - wc.x = (WIDTH(r) - win->g.w) / 2 - border_width; - wc.y = (HEIGHT(r) - win->g.h) / 2 - border_width; - mask |= CWX | CWY; - } - DNPRINTF(SWM_D_STACK, "resize_window: win %lu x %d y %d w %d h %d\n", + DNPRINTF(SWM_D_STACK, "update_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); @@ -3680,8 +3753,15 @@ resize(struct ws_win *win, union arg *args) XEvent ev; Time time = 0; struct swm_region *r = NULL; - int relx, rely; int resize_step = 0; + Window rr, cr; + int x, y, wx, wy; + unsigned int mask; + struct swm_geometry g; + int top = 0, left = 0; + int dx, dy; + Cursor cursor; + unsigned int shape; /* cursor style */ if (win == NULL) return; @@ -3724,7 +3804,8 @@ resize(struct ws_win *win, union arg *args) break; } if (resize_step) { - resize_window(win, 0); + constrain_window(win, r, 1); + update_window(win); store_float_geom(win,r); return; } @@ -3732,22 +3813,33 @@ resize(struct ws_win *win, union arg *args) if (focus_mode == SWM_FOCUS_DEFAULT) drain_enter_notify(); - if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, - GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess) - return; + /* get cursor offset from window root */ + if (!XQueryPointer(display, win->id, &rr, &cr, &x, &y, &wx, &wy, &mask)) + return; - /* 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 - 1; - else - relx = r->g.x + r->g.w - win->g.x - 1; + g = win->g; - if ( win->g.y + win->g.h < r->g.y + r->g.h - 1) - rely = win->g.h - 1; - else - rely = r->g.y + r->g.h - win->g.y - 1; + if (wx < win->g.w / 2) + left = 1; + + if (wy < win->g.h / 2) + top = 1; + + if (args->id == SWM_ARG_ID_CENTER) + shape = XC_sizing; + else if (top) + shape = (left) ? XC_top_left_corner : XC_top_right_corner; + else + shape = (left) ? XC_bottom_left_corner : XC_bottom_right_corner; + + cursor = XCreateFontCursor(display, shape); + + if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, + GrabModeAsync, None, cursor, CurrentTime) != GrabSuccess) { + XFreeCursor(display, cursor); + return; + } - XWarpPointer(display, None, win->id, 0, 0, 0, 0, relx, rely); do { XMaskEvent(display, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); @@ -3758,38 +3850,69 @@ resize(struct ws_win *win, union arg *args) handler[ev.type](&ev); break; case MotionNotify: - /* do not allow resize outside of region */ - if ( ev.xmotion.x_root < r->g.x || - ev.xmotion.x_root > r->g.x + r->g.w - 1 || - ev.xmotion.y_root < r->g.y || - ev.xmotion.y_root > r->g.y + r->g.h - 1) - continue; + /* cursor offset/delta from start of the operation */ + dx = ev.xmotion.x_root - x; + dy = ev.xmotion.y_root - y; - if (ev.xmotion.x <= 1) - ev.xmotion.x = 1; - if (ev.xmotion.y <= 1) - ev.xmotion.y = 1; - win->g.w = ev.xmotion.x + 1; - win->g.h = ev.xmotion.y + 1; + /* vertical */ + if (top) + dy = -dy; + + if (args->id == SWM_ARG_ID_CENTER) { + if (g.h / 2 + dy < 1) + dy = 1 - g.h / 2; + + win->g.y = g.y - dy; + win->g.h = g.h + 2 * dy; + } else { + if (g.h + dy < 1) + dy = 1 - g.h; + + if (top) + win->g.y = g.y - dy; + + win->g.h = g.h + dy; + } + + /* horizontal */ + if (left) + dx = -dx; + + if (args->id == SWM_ARG_ID_CENTER) { + if (g.w / 2 + dx < 1) + dx = 1 - g.w / 2; + + win->g.x = g.x - dx; + win->g.w = g.w + 2 * dx; + } else { + if (g.w + dx < 1) + dx = 1 - g.w; + + if (left) + win->g.x = g.x - dx; + + win->g.w = g.w + dx; + } + + constrain_window(win, r, 1); /* 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); + update_window(win); } break; } } while (ev.type != ButtonRelease); if (time) { XSync(display, False); - resize_window(win, args->id); + update_window(win); } store_float_geom(win,r); - XWarpPointer(display, None, win->id, 0, 0, 0, 0, win->g.w - 1, - win->g.h - 1); XUngrabPointer(display, CurrentTime); + XFreeCursor(display, cursor); /* drain events */ drain_enter_notify(); @@ -3808,25 +3931,6 @@ resize_step(struct swm_region *r, union arg *args) resize(win, args); } - -void -move_window(struct ws_win *win) -{ - unsigned int mask; - XWindowChanges wc; - - bzero(&wc, sizeof wc); - 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); -} - #define SWM_MOVE_STEPS (50) void @@ -3837,6 +3941,10 @@ move(struct ws_win *win, union arg *args) int move_step = 0; struct swm_region *r = NULL; + Window rr, cr; + int x, y, wx, wy; + unsigned int mask; + if (win == NULL) return; r = win->ws->r; @@ -3880,16 +3988,21 @@ move(struct ws_win *win, union arg *args) break; } if (move_step) { - move_window(win); + constrain_window(win, r, 0); + update_window(win); store_float_geom(win,r); return; } - if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, - GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess) + GrabModeAsync, None, XCreateFontCursor(display, XC_fleur), + CurrentTime) != GrabSuccess) return; - XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0); + + /* get cursor offset from window root */ + if (!XQueryPointer(display, win->id, &rr, &cr, &x, &y, &wx, &wy, &mask)) + return; + do { XMaskEvent(display, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); @@ -3900,31 +4013,25 @@ move(struct ws_win *win, union arg *args) handler[ev.type](&ev); break; case MotionNotify: - /* don't allow to move window origin out of region */ - if ( ev.xmotion.x_root < r->g.x || - ev.xmotion.x_root > r->g.x + r->g.w - 1 || - ev.xmotion.y_root < r->g.y || - ev.xmotion.y_root > r->g.y + r->g.h - 1) - continue; + win->g.x = ev.xmotion.x_root - wx - border_width; + win->g.y = ev.xmotion.y_root - wy - border_width; - win->g.x = ev.xmotion.x_root - border_width; - win->g.y = ev.xmotion.y_root - border_width; + constrain_window(win, r, 0); /* 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); + update_window(win); } break; } } while (ev.type != ButtonRelease); if (time) { XSync(display, False); - move_window(win); + update_window(win); } store_float_geom(win,r); - XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0); XUngrabPointer(display, CurrentTime); /* drain events */ @@ -5367,7 +5474,7 @@ conf_load(char *filename, int keymapping) if (wordlen == 0) { warnx("%s: line %zd: no option found", filename, lineno); - return (1); + goto out; } optind = -1; for (i = 0; i < LENGTH(configopt); i++) { @@ -5381,12 +5488,12 @@ conf_load(char *filename, int keymapping) if (optind == -1) { warnx("%s: line %zd: unknown option %.*s", filename, lineno, wordlen, cp); - return (1); + goto out; } if (keymapping && strcmp(opt->optname, "bind")) { warnx("%s: line %zd: invalid option %.*s", filename, lineno, wordlen, cp); - return (1); + goto out; } cp += wordlen; cp += strspn(cp, " \t\n"); /* eat whitespace */ @@ -5399,9 +5506,16 @@ conf_load(char *filename, int keymapping) if (wordlen == 0) { warnx("%s: line %zd: syntax error", filename, lineno); + goto out; + } + + if(asprintf(&optsub, "%.*s", wordlen, cp) == + -1) { + warnx("%s: line %zd: unable to allocate" + "memory for selector", filename, + lineno); return (1); } - asprintf(&optsub, "%.*s", wordlen, cp); } cp += wordlen; cp += strspn(cp, "] \t\n"); /* eat trailing */ @@ -5426,6 +5540,12 @@ conf_load(char *filename, int keymapping) DNPRINTF(SWM_D_CONF, "conf_load end\n"); return (0); + +out: + free(line); + fclose(config); + + return (1); } void @@ -5969,6 +6089,11 @@ enternotify(XEvent *e) ev->window, ev->mode, ev->detail, ev->root, ev->subwindow, ev->same_screen, ev->focus, ev->state); + if (ev->mode != NotifyNormal) { + DNPRINTF(SWM_D_EVENT, "ignoring enternotify: generated by cursor grab.\n"); + return; + } + switch (focus_mode) { case SWM_FOCUS_DEFAULT: break; @@ -6168,8 +6293,8 @@ propertynotify(XEvent *e) struct ws_win *win; XPropertyEvent *ev = &e->xproperty; - DNPRINTF(SWM_D_EVENT, "propertynotify: window: %lu\n", - ev->window); + DNPRINTF(SWM_D_EVENT, "propertynotify: window: %lu atom:%s\n", + ev->window, XGetAtomName(display, ev->atom)); win = find_window(ev->window); if (win == NULL) @@ -6184,8 +6309,8 @@ propertynotify(XEvent *e) } switch (ev->atom) { - case XA_WM_NORMAL_HINTS: #if 0 + case XA_WM_NORMAL_HINTS: long mask; XGetWMNormalHints(display, win->id, &win->sh, &mask); fprintf(stderr, "normal hints: flag 0x%x\n", win->sh.flags); @@ -6197,6 +6322,11 @@ propertynotify(XEvent *e) XMoveResizeWindow(display, win->id, win->g.x, win->g.y, win->g.w, win->g.h); #endif + case XA_WM_CLASS: + if (title_name_enabled || title_class_enabled) + bar_update(); + break; + case XA_WM_NAME: if (window_name_enabled) bar_update(); break; @@ -6706,6 +6836,7 @@ main(int argc, char *argv[]) adelete = XInternAtom(display, "WM_DELETE_WINDOW", False); takefocus = XInternAtom(display, "WM_TAKE_FOCUS", False); a_wmname = XInternAtom(display, "WM_NAME", False); + a_netwmname = XInternAtom(display, "_NET_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);