/*
- * Copyright (c) 2009-2010-2011 Marco Peereboom <marco@peereboom.us>
- * Copyright (c) 2009-2010-2011 Ryan McBride <mcbride@countersiege.com>
+ * Copyright (c) 2009-2012 Marco Peereboom <marco@peereboom.us>
+ * Copyright (c) 2009-2011 Ryan McBride <mcbride@countersiege.com>
* Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
* Copyright (c) 2009 Pierre-Yves Ritschard <pyr@spootnik.org>
* Copyright (c) 2010 Tuukka Kataja <stuge@xor.fi>
* Copyright (c) 2011 Jason L. Wright <jason@thought.net>
+ * Copyright (c) 2011-2012 Reginald Kennedy <rk@rejii.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
Atom adelete;
Atom takefocus;
Atom a_wmname;
+Atom a_netwmname;
Atom a_utf8_string;
Atom a_string;
Atom a_swm_iconic;
volatile sig_atomic_t search_resp;
int search_resp_action;
+struct search_window {
+ TAILQ_ENTRY(search_window) entry;
+ int idx;
+ struct ws_win *win;
+ Window indicator;
+};
+TAILQ_HEAD(search_winlist, search_window);
+
+struct search_winlist search_wl;
+
/* search actions */
enum {
SWM_SEARCH_NONE,
- SWM_SEARCH_UNICONIFY
+ SWM_SEARCH_UNICONIFY,
+ SWM_SEARCH_NAME_WORKSPACE,
+ SWM_SEARCH_SEARCH_WORKSPACE,
+ SWM_SEARCH_SEARCH_WINDOW
};
/* dialog windows */
/* define work spaces */
struct workspace {
int idx; /* workspace index */
+ char *name; /* workspace name */
int always_raise; /* raise windows on focus */
struct layout *cur_layout; /* current layout handlers */
struct ws_win *focus; /* may be NULL */
screens[i - 1].c[c].color = name_to_color(val);
free(screens[i - 1].c[c].name);
if ((screens[i - 1].c[c].name = strdup(val)) == NULL)
- errx(1, "strdup");
+ err(1, "strdup");
} else if (i == -1) {
for (i = 0; i < ScreenCount(display); i++) {
screens[i].c[c].color = name_to_color(val);
free(screens[i].c[c].name);
if ((screens[i].c[c].name = strdup(val)) == NULL)
- errx(1, "strdup");
+ err(1, "strdup");
}
} else
- errx(1, "invalid screen index: %d out of bounds (maximum %d)\n",
+ errx(1, "invalid screen index: %d out of bounds (maximum %d)",
i, ScreenCount(display));
}
if (sscanf(val, "screen[%u]:%ux%u+%u+%u", &sidx, &w, &h, &x, &y) != 5)
errx(1, "invalid custom region, "
- "should be 'screen[<n>]:<n>x<n>+<n>+<n>\n");
+ "should be 'screen[<n>]:<n>x<n>+<n>+<n>");
if (sidx < 1 || sidx > ScreenCount(display))
- errx(1, "invalid screen index: %d out of bounds (maximum %d)\n",
+ errx(1, "invalid screen index: %d out of bounds (maximum %d)",
sidx, ScreenCount(display));
sidx--;
if (w < 1 || h < 1)
- errx(1, "region %ux%u+%u+%u too small\n", w, h, x, y);
+ errx(1, "region %ux%u+%u+%u too small", w, h, x, y);
if (x > DisplayWidth(display, sidx) ||
y > DisplayHeight(display, sidx) ||
void
bar_print(struct swm_region *r, char *s)
{
- int textwidth, x;
+ int textwidth, x = 0;
size_t len;
XClearWindow(display, r->bar_window);
struct swm_region *r;
int i, x;
size_t len;
+ char ws[SWM_BAR_MAX];
char s[SWM_BAR_MAX];
char cn[SWM_BAR_MAX];
char loc[SWM_BAR_MAX];
x = 1;
TAILQ_FOREACH(r, &screens[i].rl, entry) {
strlcpy(cn, "", sizeof cn);
+ strlcpy(ws, "", sizeof ws);
if (r && r->ws) {
bar_urgent(cn, sizeof cn);
bar_class_name(cn, sizeof cn, r->ws->focus);
bar_window_name(cn, sizeof cn, r->ws->focus);
+ if (r->ws->name)
+ snprintf(ws, sizeof ws, "<%s>", r->ws->name);
}
if (stack_enabled)
stack = r->ws->stacker;
- snprintf(loc, sizeof loc, "%d:%d %s %s%s %s %s",
- x++, r->ws->idx + 1, stack, s, cn, bar_ext, bar_vertext);
+ snprintf(loc, sizeof loc, "%d:%d %s %s %s%s %s %s",
+ x++, r->ws->idx + 1, stack, ws, s, cn, bar_ext,
+ bar_vertext);
bar_print(r, loc);
}
}
socket_setnonblock(bar_pipe[0]);
socket_setnonblock(bar_pipe[1]); /* XXX hmmm, really? */
if (dup2(bar_pipe[0], 0) == -1)
- errx(1, "dup2");
+ err(1, "dup2");
if (dup2(bar_pipe[1], 1) == -1)
- errx(1, "dup2");
+ err(1, "dup2");
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
err(1, "could not disable SIGPIPE");
switch (bar_pid = fork()) {
}
}
if (bar_fonts[i] == NULL)
- errx(1, "couldn't load font");
+ errx(1, "couldn't load font");
if (bar_fs == NULL)
errx(1, "couldn't create font structure");
/* disable alarm because the following code may not be interrupted */
alarm(0);
if (signal(SIGALRM, SIG_IGN) == SIG_ERR)
- errx(1, "can't disable alarm");
+ err(1, "can't disable alarm");
bar_extra_stop();
bar_extra = 1;
struct ws_win *win;
struct workspace *ws;
struct swm_region *r;
- int i, x, foundit = 0;
+ int i, x;
if (testwin == NULL)
return (0);
- for (i = 0, foundit = 0; i < ScreenCount(display); i++)
+ for (i = 0; i < ScreenCount(display); i++)
TAILQ_FOREACH(r, &screens[i].rl, entry)
for (x = 0; x < SWM_WS_MAX; x++) {
ws = &r->s->ws[x];
{
struct swm_region *r;
struct workspace *ws;
- int foundit, i, x;
+ int i, x;
/* validate all ws */
- for (i = 0, foundit = 0; i < ScreenCount(display); i++)
+ for (i = 0; i < ScreenCount(display); i++)
TAILQ_FOREACH(r, &screens[i].rl, entry)
for (x = 0; x < SWM_WS_MAX; x++) {
ws = &r->s->ws[x];
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);
}
struct ws_win *cur_focus = NULL;
struct ws_win_list *wl = NULL;
struct workspace *ws = NULL;
+ int all_iconics;
if (!(r && r->ws))
return;
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;
/* 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;
/* 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;
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);
}
cycle_layout(struct swm_region *r, union arg *args)
{
struct workspace *ws = r->ws;
- struct ws_win *winfocus;
union arg a;
DNPRINTF(SWM_D_EVENT, "cycle_layout: workspace: %d\n", ws->idx);
- winfocus = ws->focus;
-
ws->cur_layout++;
if (ws->cur_layout->l_stack == NULL)
ws->cur_layout = &layouts[0];
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++);
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;
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 */
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;
}
void
+name_workspace(struct swm_region *r, union arg *args)
+{
+ FILE *lfile;
+
+ DNPRINTF(SWM_D_MISC, "name_workspace\n");
+
+ if (r == NULL)
+ return;
+
+ search_r = r;
+ search_resp_action = SWM_SEARCH_NAME_WORKSPACE;
+
+ spawn_select(r, args, "name_workspace", &searchpid);
+
+ if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL)
+ return;
+
+ fprintf(lfile, "%s", "");
+ fclose(lfile);
+}
+
+void
+search_workspace(struct swm_region *r, union arg *args)
+{
+ int i;
+ struct workspace *ws;
+ FILE *lfile;
+
+ DNPRINTF(SWM_D_MISC, "search_workspace\n");
+
+ if (r == NULL)
+ return;
+
+ search_r = r;
+ search_resp_action = SWM_SEARCH_SEARCH_WORKSPACE;
+
+ spawn_select(r, args, "search", &searchpid);
+
+ if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL)
+ return;
+
+ for (i = 0; i < SWM_WS_MAX; i++) {
+ ws = &r->s->ws[i];
+ if (ws == NULL)
+ continue;
+ fprintf(lfile, "%d%s%s\n", ws->idx + 1,
+ (ws->name ? ":" : ""), (ws->name ? ws->name : ""));
+ }
+
+ fclose(lfile);
+}
+
+void
+search_win_cleanup(void)
+{
+ struct search_window *sw = NULL;
+
+ while ((sw = TAILQ_FIRST(&search_wl)) != NULL) {
+ XDestroyWindow(display, sw->indicator);
+ TAILQ_REMOVE(&search_wl, sw, entry);
+ free(sw);
+ }
+}
+
+void
+search_win(struct swm_region *r, union arg *args)
+{
+ struct ws_win *win = NULL;
+ struct search_window *sw = NULL;
+ Window w;
+ GC gc;
+ XGCValues gcv;
+ int i;
+ char s[8];
+ FILE *lfile;
+ size_t len;
+ int textwidth;
+
+ DNPRINTF(SWM_D_MISC, "search_win\n");
+
+ search_r = r;
+ search_resp_action = SWM_SEARCH_SEARCH_WINDOW;
+
+ spawn_select(r, args, "search", &searchpid);
+
+ if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL)
+ return;
+
+ TAILQ_INIT(&search_wl);
+
+ i = 1;
+ TAILQ_FOREACH(win, &r->ws->winlist, entry) {
+ if (win->iconic == 1)
+ continue;
+
+ sw = calloc(1, sizeof(struct search_window));
+ if (sw == NULL) {
+ fprintf(stderr, "search_win: calloc: %s", strerror(errno));
+ fclose(lfile);
+ search_win_cleanup();
+ return;
+ }
+ sw->idx = i;
+ sw->win = win;
+
+ snprintf(s, sizeof s, "%d", i);
+ len = strlen(s);
+ textwidth = XTextWidth(bar_fs, s, len);
+
+ w = XCreateSimpleWindow(display,
+ win->id, 0, 0, textwidth + 12,
+ bar_fs->ascent + bar_fs->descent + 4, 1,
+ r->s->c[SWM_S_COLOR_UNFOCUS].color,
+ r->s->c[SWM_S_COLOR_FOCUS].color);
+
+ sw->indicator = w;
+ TAILQ_INSERT_TAIL(&search_wl, sw, entry);
+
+ gc = XCreateGC(display, w, 0, &gcv);
+ XSetFont(display, gc, bar_fs->fid);
+ XMapRaised(display, w);
+ XSetForeground(display, gc, r->s->c[SWM_S_COLOR_BAR].color);
+
+ XDrawString(display, w, gc, 6, bar_fs->ascent + 2, s, len);
+
+ fprintf(lfile, "%d\n", i);
+ i++;
+ }
+
+ fclose(lfile);
+}
+
+void
search_resp_uniconify(char *resp, unsigned long len)
{
unsigned char *name;
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) {
}
}
+void
+search_resp_name_workspace(char *resp, unsigned long len)
+{
+ struct workspace *ws;
+
+ DNPRINTF(SWM_D_MISC, "search_resp_name_workspace: resp %s\n", resp);
+
+ if (search_r->ws == NULL)
+ return;
+ ws = search_r->ws;
+
+ if (ws->name) {
+ free(search_r->ws->name);
+ search_r->ws->name = NULL;
+ }
+
+ if (len > 1) {
+ ws->name = strdup(resp);
+ if (ws->name == NULL) {
+ DNPRINTF(SWM_D_MISC, "search_resp_name_workspace: strdup: %s",
+ strerror(errno));
+ return;
+ }
+ }
+}
+
+void
+search_resp_search_workspace(char *resp, unsigned long len)
+{
+ char *p, *q;
+ int ws_idx;
+ const char *errstr;
+ union arg a;
+
+ DNPRINTF(SWM_D_MISC, "search_resp_search_workspace: resp %s\n", resp);
+
+ q = strdup(resp);
+ if (!q) {
+ DNPRINTF(SWM_D_MISC, "search_resp_search_workspace: strdup: %s",
+ strerror(errno));
+ return;
+ }
+ p = strchr(q, ':');
+ if (p != NULL)
+ *p = '\0';
+ ws_idx = strtonum(q, 1, SWM_WS_MAX, &errstr);
+ if (errstr) {
+ DNPRINTF(SWM_D_MISC, "workspace idx is %s: %s",
+ errstr, q);
+ free(q);
+ return;
+ }
+ free(q);
+ a.id = ws_idx - 1;
+ switchws(search_r, &a);
+}
+
+void
+search_resp_search_window(char *resp, unsigned long len)
+{
+ char *s;
+ int idx;
+ const char *errstr;
+ struct search_window *sw;
+
+ DNPRINTF(SWM_D_MISC, "search_resp_search_window: resp %s\n", resp);
+
+ s = strdup(resp);
+ if (!s) {
+ DNPRINTF(SWM_D_MISC, "search_resp_search_window: strdup: %s",
+ strerror(errno));
+ return;
+ }
+
+ idx = strtonum(s, 1, INT_MAX, &errstr);
+ if (errstr) {
+ DNPRINTF(SWM_D_MISC, "window idx is %s: %s",
+ errstr, s);
+ free(s);
+ return;
+ }
+ free(s);
+
+ TAILQ_FOREACH(sw, &search_wl, entry)
+ if (idx == sw->idx) {
+ focus_win(sw->win);
+ break;
+ }
+}
+
#define MAX_RESP_LEN 1024
void
goto done;
}
resp[rbytes] = '\0';
+
+ /* XXX:
+ * Older versions of dmenu (Atleast pre 4.4.1) do not send a
+ * newline, so work around that by sanitizing the resp now.
+ */
+ resp[strcspn(resp, "\n")] = '\0';
len = strlen(resp);
switch (search_resp_action) {
case SWM_SEARCH_UNICONIFY:
search_resp_uniconify(resp, len);
break;
+ case SWM_SEARCH_NAME_WORKSPACE:
+ search_resp_name_workspace(resp, len);
+ break;
+ case SWM_SEARCH_SEARCH_WORKSPACE:
+ search_resp_search_workspace(resp, len);
+ break;
+ case SWM_SEARCH_SEARCH_WINDOW:
+ search_resp_search_window(resp, len);
+ break;
}
done:
+ if (search_resp_action == SWM_SEARCH_SEARCH_WINDOW)
+ search_win_cleanup();
+
search_resp_action = SWM_SEARCH_NONE;
close(select_resp_pipe[0]);
free(resp);
}
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);
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;
break;
}
if (resize_step) {
- resize_window(win, 0);
+ constrain_window(win, r, 1);
+ update_window(win);
store_float_geom(win,r);
return;
}
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);
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;
+
+ /* vertical */
+ if (top)
+ dy = -dy;
- 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;
+ 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();
resize(win, args);
}
-
-void
-move_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 = 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
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;
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);
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 */
kf_move_right,
kf_move_up,
kf_move_down,
+ kf_name_workspace,
+ kf_search_workspace,
+ kf_search_win,
kf_dumpwins, /* MUST BE LAST */
kf_invalid
};
{ "move_right", move_step, {.id = SWM_ARG_ID_MOVERIGHT} },
{ "move_up", move_step, {.id = SWM_ARG_ID_MOVEUP} },
{ "move_down", move_step, {.id = SWM_ARG_ID_MOVEDOWN} },
+ { "name_workspace", name_workspace, {0} },
+ { "search_workspace", search_workspace, {0} },
+ { "search_win", search_win, {0} },
{ "dumpwins", dumpwins, {0} }, /* MUST BE LAST */
{ "invalid key func", NULL, {0} },
};
break;
case 0: /* child */
if (dup2(select_list_pipe[0], 0) == -1)
- errx(1, "dup2");
+ err(1, "dup2");
if (dup2(select_resp_pipe[1], 1) == -1)
- errx(1, "dup2");
+ err(1, "dup2");
close(select_list_pipe[1]);
close(select_resp_pipe[0]);
spawn(r->ws->idx, &a, 0);
" -nf $bar_font_color"
" -sb $bar_border"
" -sf $bar_color", 0);
+ setconfspawn("name_workspace", "dmenu"
+ " -p Workspace"
+ " -fn $bar_font"
+ " -nb $bar_color"
+ " -nf $bar_font_color"
+ " -sb $bar_border"
+ " -sf $bar_color", 0);
}
/* key bindings */
setkeybinding(MODKEY, XK_bracketright,kf_move_right, NULL);
setkeybinding(MODKEY|ShiftMask, XK_bracketleft, kf_move_up, NULL);
setkeybinding(MODKEY|ShiftMask, XK_bracketright,kf_move_down, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_slash, kf_name_workspace,NULL);
+ setkeybinding(MODKEY, XK_slash, kf_search_workspace,NULL);
+ setkeybinding(MODKEY, XK_f, kf_search_win, NULL);
#ifdef SWM_DEBUG
setkeybinding(MODKEY|ShiftMask, XK_d, kf_dumpwins, NULL);
#endif
else if (!strcmp(value, "synergy"))
focus_mode = SWM_FOCUS_SYNERGY;
else
- err(1, "focus_mode");
+ errx(1, "focus_mode");
break;
case SWM_S_DISABLE_BORDER:
disable_border = atoi(value);
bzero(s, sizeof s);
if (sscanf(value, "ws[%d]:%1023c", &ws_id, s) != 2)
- errx(1, "invalid autorun entry, should be 'ws[<idx>]:command'\n");
+ errx(1, "invalid autorun entry, should be 'ws[<idx>]:command'");
ws_id--;
if (ws_id < 0 || ws_id >= SWM_WS_MAX)
- errx(1, "autorun: invalid workspace %d\n", ws_id + 1);
+ errx(1, "autorun: invalid workspace %d", ws_id + 1);
/*
* This is a little intricate
&ws_id, &mg, &ma, &si, &raise, s) != 6)
errx(1, "invalid layout entry, should be 'ws[<idx>]:"
"<master_grow>:<master_add>:<stack_inc>:<always_raise>:"
- "<type>'\n");
+ "<type>'");
ws_id--;
if (ws_id < 0 || ws_id >= SWM_WS_MAX)
- errx(1, "layout: invalid workspace %d\n", ws_id + 1);
+ errx(1, "layout: invalid workspace %d", ws_id + 1);
if (!strcasecmp(s, "vertical"))
st = SWM_V_STACK;
else
errx(1, "invalid layout entry, should be 'ws[<idx>]:"
"<master_grow>:<master_add>:<stack_inc>:<always_raise>:"
- "<type>'\n");
+ "<type>'");
for (i = 0; i < ScreenCount(display); i++) {
ws = (struct workspace *)&screens[i].ws;
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++) {
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 */
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 */
DNPRINTF(SWM_D_CONF, "conf_load end\n");
return (0);
+
+out:
+ free(line);
+ fclose(config);
+
+ return (1);
}
void
}
if ((win = calloc(1, sizeof(struct ws_win))) == NULL)
- errx(1, "calloc: failed to allocate memory for new window");
+ err(1, "calloc: failed to allocate memory for new window");
win->id = id;
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;
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)
}
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);
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;
ws = r->ws;
} else
if ((r = calloc(1, sizeof(struct swm_region))) == NULL)
- errx(1, "calloc: failed to allocate memory for screen");
+ err(1, "calloc: failed to allocate memory for screen");
/* if we don't have a workspace already, find one */
if (ws == NULL) {
}
if (ws == NULL)
- errx(1, "no free workspaces\n");
+ errx(1, "no free workspaces");
X(r) = x;
Y(r) = y;
if (screens[i].root == xe->root)
break;
if (i >= ScreenCount(display))
- errx(1, "screenchange: screen not found\n");
+ errx(1, "screenchange: screen not found");
/* brute force for now, just re-enumerate the regions */
scan_xrandr(i);
if ((screens = calloc(ScreenCount(display),
sizeof(struct swm_screen))) == NULL)
- errx(1, "calloc: screens");
+ err(1, "calloc: screens");
/* initial Xrandr setup */
xrandr_support = XRRQueryExtension(display,
for (j = 0; j < SWM_WS_MAX; j++) {
ws = &screens[i].ws[j];
ws->idx = j;
+ ws->name = NULL;
ws->focus = NULL;
ws->r = NULL;
ws->old_r = NULL;
if ((spawn_term[0] = strdup("xterm")) == NULL)
err(1, "setup_globals: strdup");
if ((clock_format = strdup("%a %b %d %R %Z %Y")) == NULL)
- errx(1, "strdup");
+ err(1, "strdup");
}
void
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);