/*
* Much code and ideas taken from dwm under the following license:
* MIT/X Consortium License
- *
+ *
* 2006-2008 Anselm R Garbe <garbeam at gmail dot com>
* 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
* 2006-2007 Jukka Salmi <jukka at salmi dot ch>
* 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
* 2007-2008 Peter Hartlich <sgkkr at hartlich dot com>
* 2008 Martin Hurton <martin dot hurton at gmail dot com>
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
static const char *cvstag = "$scrotwm$";
-#define SWM_VERSION "0.9.5"
+#define SWM_VERSION "0.9.17"
#include <stdio.h>
#include <stdlib.h>
/* #define SWM_DEBUG */
#ifdef SWM_DEBUG
-#define DPRINTF(x...) do { if (swm_debug) fprintf(stderr, x); } while(0)
-#define DNPRINTF(n,x...) do { if (swm_debug & n) fprintf(stderr, x); } while(0)
+#define DPRINTF(x...) do { if (swm_debug) fprintf(stderr, x); } while (0)
+#define DNPRINTF(n,x...) do { if (swm_debug & n) fprintf(stderr, x); } while (0)
#define SWM_D_MISC 0x0001
#define SWM_D_EVENT 0x0002
#define SWM_D_WS 0x0004
#define SWM_D_CLASS 0x0100
#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
| SWM_D_CLASS
| SWM_D_KEY
| SWM_D_QUIRK
+ | SWM_D_SPAWN
+ | SWM_D_EVENTQ
+ | SWM_D_CONF
;
#else
#define DPRINTF(x...)
#define WIDTH(r) (r)->g.w
#define HEIGHT(r) (r)->g.h
#define SWM_MAX_FONT_STEPS (3)
+#define WINID(w) (w ? w->id : 0)
#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;
+Atom takefocus;
+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;
-int ignore_enter = 0;
unsigned int numlockmask = 0;
Display *display;
int bar_extra_running = 0;
int bar_verbose = 1;
int bar_height = 0;
+int stack_enabled = 1;
int clock_enabled = 1;
int title_name_enabled = 0;
int title_class_enabled = 0;
XGCValues bar_gcv;
int bar_fidx = 0;
XFontStruct *bar_fs;
-char *bar_fonts[] = {
- "-*-terminus-medium-*-*-*-*-*-*-*-*-*-*-*",
- "-*-times-medium-r-*-*-*-*-*-*-*-*-*-*",
- NULL
-};
-
-/* terminal + args */
-char *spawn_term[] = { "xterm", NULL };
-char *spawn_screenshot[] = { "screenshot.sh", NULL, NULL };
-char *spawn_lock[] = { "xlock", NULL };
-char *spawn_initscr[] = { "initscreen.sh", NULL };
-char *spawn_menu[] = { "dmenu_run", "-fn", NULL, "-nb", NULL,
- "-nf", NULL, "-sb", NULL, "-sf", NULL, NULL };
+char *bar_fonts[] = { NULL, NULL, NULL, NULL };/* XXX Make fully dynamic */
+char *spawn_term[] = { NULL, NULL }; /* XXX Make fully dynamic */
#define SWM_MENU_FN (2)
#define SWM_MENU_NB (4)
struct swm_region {
TAILQ_ENTRY(swm_region) entry;
struct swm_geometry g;
- struct workspace *ws; /* current workspace on this region */
+ struct workspace *ws; /* current workspace on this region */
struct swm_screen *s; /* screen idx */
Window bar_window;
-};
+};
TAILQ_HEAD(swm_region_list, swm_region);
struct ws_win {
TAILQ_ENTRY(ws_win) entry;
Window id;
+ Window transient;
+ struct ws_win *child_trans; /* transient child window */
struct swm_geometry g;
- int got_focus;
int floating;
- int transient;
int manual;
int font_size_boundary[SWM_MAX_FONT_STEPS];
int font_steps;
int last_inc;
int can_delete;
+ int take_focus;
+ int java;
unsigned long quirks;
struct workspace *ws; /* always valid */
struct swm_screen *s; /* always valid, never changes */
kf_version,
kf_spawn_lock,
kf_spawn_initscr,
+ kf_spawn_custom,
+ kf_dumpwins,
kf_invalid
};
void horizontal_stack(struct workspace *, struct swm_geometry *);
void max_stack(struct workspace *, struct swm_geometry *);
+struct ws_win *find_window(Window);
+
void grabbuttons(struct ws_win *, int);
void new_region(struct swm_screen *, int, int, int, int);
+void unmanage_window(struct ws_win *);
+long getstate(Window);
struct layout {
void (*l_stack)(struct workspace *, struct swm_geometry *);
void (*l_config)(struct workspace *, int);
+ u_int32_t flags;
+#define SWM_L_FOCUSPREV (1<<0)
+#define SWM_L_MAPONFOCUS (1<<1)
+ char *name;
} layouts[] = {
/* stack, configure */
- { vertical_stack, vertical_config},
- { horizontal_stack, horizontal_config},
- { max_stack, NULL},
- { NULL, NULL},
+ { vertical_stack, vertical_config, 0, "[|]" },
+ { horizontal_stack, horizontal_config, 0, "[-]" },
+ { max_stack, NULL,
+ SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV, "[ ]"},
+ { NULL, NULL, 0, NULL },
};
#define SWM_H_SLICE (32)
/* define work spaces */
struct workspace {
int idx; /* workspace index */
- int restack; /* restack on switch */
struct layout *cur_layout; /* current layout handlers */
struct ws_win *focus; /* may be NULL */
struct ws_win *focus_prev; /* may be NULL */
struct swm_region *r; /* may be NULL */
+ struct swm_region *old_r; /* may be NULL */
struct ws_win_list winlist; /* list of windows in ws */
+ struct ws_win_list unmanagedlist; /* list of dead windows in ws */
/* stacker state */
struct {
SWM_S_COLOR_FOCUS, SWM_S_COLOR_UNFOCUS, SWM_S_COLOR_MAX };
/* physical screen mapping */
-#define SWM_WS_MAX (10) /* XXX Too small? */
+#define SWM_WS_MAX (10)
struct swm_screen {
- int idx; /* screen index */
+ int idx; /* screen index */
struct swm_region_list rl; /* list of regions on this screen */
struct swm_region_list orl; /* list of old regions */
Window root;
struct swm_screen *screens;
int num_screens;
-struct ws_win *cur_focus = NULL;
-
/* args to functions */
union arg {
int id;
#define SWM_ARG_ID_FOCUSNEXT (0)
#define SWM_ARG_ID_FOCUSPREV (1)
#define SWM_ARG_ID_FOCUSMAIN (2)
-#define SWM_ARG_ID_SWAPNEXT (3)
-#define SWM_ARG_ID_SWAPPREV (4)
-#define SWM_ARG_ID_SWAPMAIN (5)
-#define SWM_ARG_ID_MASTERSHRINK (6)
-#define SWM_ARG_ID_MASTERGROW (7)
-#define SWM_ARG_ID_MASTERADD (8)
-#define SWM_ARG_ID_MASTERDEL (9)
-#define SWM_ARG_ID_STACKRESET (10)
-#define SWM_ARG_ID_STACKINIT (11)
-#define SWM_ARG_ID_CYCLEWS_UP (12)
-#define SWM_ARG_ID_CYCLEWS_DOWN (13)
-#define SWM_ARG_ID_CYCLESC_UP (14)
-#define SWM_ARG_ID_CYCLESC_DOWN (15)
-#define SWM_ARG_ID_STACKINC (16)
-#define SWM_ARG_ID_STACKDEC (17)
-#define SWM_ARG_ID_SS_ALL (0)
-#define SWM_ARG_ID_SS_WINDOW (1)
-#define SWM_ARG_ID_DONTCENTER (0)
-#define SWM_ARG_ID_CENTER (1)
-#define SWM_ARG_ID_KILLWINDOW (0)
-#define SWM_ARG_ID_DELETEWINDOW (1)
+#define SWM_ARG_ID_FOCUSCUR (4)
+#define SWM_ARG_ID_SWAPNEXT (10)
+#define SWM_ARG_ID_SWAPPREV (11)
+#define SWM_ARG_ID_SWAPMAIN (12)
+#define SWM_ARG_ID_MASTERSHRINK (20)
+#define SWM_ARG_ID_MASTERGROW (21)
+#define SWM_ARG_ID_MASTERADD (22)
+#define SWM_ARG_ID_MASTERDEL (23)
+#define SWM_ARG_ID_STACKRESET (30)
+#define SWM_ARG_ID_STACKINIT (31)
+#define SWM_ARG_ID_CYCLEWS_UP (40)
+#define SWM_ARG_ID_CYCLEWS_DOWN (41)
+#define SWM_ARG_ID_CYCLESC_UP (42)
+#define SWM_ARG_ID_CYCLESC_DOWN (43)
+#define SWM_ARG_ID_STACKINC (50)
+#define SWM_ARG_ID_STACKDEC (51)
+#define SWM_ARG_ID_SS_ALL (60)
+#define SWM_ARG_ID_SS_WINDOW (61)
+#define SWM_ARG_ID_DONTCENTER (70)
+#define SWM_ARG_ID_CENTER (71)
+#define SWM_ARG_ID_KILLWINDOW (80)
+#define SWM_ARG_ID_DELETEWINDOW (81)
char **argv;
};
+void focus(struct swm_region *, union arg *);
+void focus_magic(struct ws_win *, int);
+#define SWM_F_GENERIC (0)
+#define SWM_F_TRANSIENT (1)
/* quirks */
struct quirk {
char *class;
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));
+}
+
+void
+dumpwins(struct swm_region *r, union arg *args)
+{
+ struct ws_win *win;
+ unsigned int state;
+ XWindowAttributes wa;
+
+ if (r->ws == NULL) {
+ fprintf(stderr, "invalid workspace\n");
+ return;
+ }
+
+ fprintf(stderr, "=== managed window list ws %02d ===\n", r->ws->idx);
+
+ TAILQ_FOREACH(win, &r->ws->winlist, entry) {
+ state = getstate(win->id);
+ if (!XGetWindowAttributes(display, win->id, &wa))
+ fprintf(stderr, "window: %lu failed "
+ "XGetWindowAttributes\n", win->id);
+ fprintf(stderr, "window: %lu map_state: %d state: %d\n",
+ win->id, wa.map_state, state);
+ }
+
+ fprintf(stderr, "===== unmanaged window list =====\n");
+ TAILQ_FOREACH(win, &r->ws->unmanagedlist, entry) {
+ state = getstate(win->id);
+ if (!XGetWindowAttributes(display, win->id, &wa))
+ fprintf(stderr, "window: %lu failed "
+ "XGetWindowAttributes\n", win->id);
+ fprintf(stderr, "window: %lu map_state: %d state: %d\n",
+ win->id, wa.map_state, state);
+ }
+
+ fprintf(stderr, "=================================\n");
+}
+#else
+#define dumpevent(e)
+void
+dumpwins(struct swm_region *r, union arg *args)
+{
+}
+#endif /* SWM_DEBUG */
+
void expose(XEvent *);
void keypress(XEvent *);
void buttonpress(XEvent *);
void enternotify(XEvent *);
void focusin(XEvent *);
void focusout(XEvent *);
+void mapnotify(XEvent *);
void mappingnotify(XEvent *);
void maprequest(XEvent *);
void propertynotify(XEvent *);
[EnterNotify] = enternotify,
[FocusIn] = focusin,
[FocusOut] = focusout,
+ [MapNotify] = mapnotify,
[MappingNotify] = mappingnotify,
[MapRequest] = maprequest,
[PropertyNotify] = propertynotify,
[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, "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)
{
{
if (i > 0 && i <= ScreenCount(display)) {
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");
} else if (i == -1) {
- for (i = 0; i < ScreenCount(display); i++)
+ for (i = 0; i < ScreenCount(display); i++) {
screens[i].c[c].color = name_to_color(val);
- if ((screens[i - 1].c[c].name = strdup(val)) == NULL)
+ free(screens[i].c[c].name);
+ if ((screens[i].c[c].name = strdup(val)) == NULL)
errx(1, "strdup");
+ }
} else
errx(1, "invalid screen index: %d out of bounds (maximum %d)\n",
i, ScreenCount(display));
errx(1, "region %ux%u+%u+%u not within screen boundaries "
"(%ux%u)\n", w, h, x, y,
DisplayWidth(display, sidx), DisplayHeight(display, sidx));
-
+
new_region(&screens[sidx], x, y, w, h);
}
}
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;
char s[SWM_BAR_MAX];
char loc[SWM_BAR_MAX];
char *b;
- XClassHint *xch;
- Status status;
+ char *stack = "";
if (bar_enabled == 0)
return;
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;
- if (title_class_enabled)
- strlcat(s, xch->res_class, sizeof s);
- if (title_name_enabled && title_class_enabled)
- strlcat(s, ":", sizeof s);
- if (title_name_enabled)
- 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) {
- snprintf(loc, sizeof loc, "%d:%d %s %s %s",
- x++, r->ws->idx + 1, s, bar_ext, bar_vertext);
+ if (r && r->ws)
+ bar_class_name(s, sizeof s, r->ws->focus);
+
+ if (stack_enabled)
+ stack = r->ws->cur_layout->name;
+
+ snprintf(loc, sizeof loc, "%d:%d %s %s %s %s",
+ x++, r->ws->idx + 1, stack, s, bar_ext,
+ bar_vertext);
bar_print(r, loc);
}
}
- XSync(display, False);
alarm(bar_delay);
}
bar_toggle(struct swm_region *r, union arg *args)
{
struct swm_region *tmpr;
- int i, j, sc = ScreenCount(display);
+ int i, sc = ScreenCount(display);
DNPRINTF(SWM_D_MISC, "bar_toggle\n");
XMapRaised(display, tmpr->bar_window);
bar_enabled = !bar_enabled;
- for (i = 0; i < sc; i++)
- for (j = 0; j < SWM_WS_MAX; j++)
- screens[i].ws[j].restack = 1;
stack();
/* must be after stack */
errx(1, "couldn't load font");
bar_height = bar_fs->ascent + bar_fs->descent + 3;
- r->bar_window = XCreateSimpleWindow(display,
+ r->bar_window = XCreateSimpleWindow(display,
r->s->root, X(r), Y(r), WIDTH(r) - 2, bar_height - 2,
1, r->s->c[SWM_S_COLOR_BAR_BORDER].color,
r->s->c[SWM_S_COLOR_BAR].color);
}
void
+set_win_state(struct ws_win *win, long state)
+{
+ long data[] = {state, None};
+
+ DNPRINTF(SWM_D_EVENT, "set_win_state: window: %lu\n", win->id);
+
+ if (win == NULL)
+ return;
+
+ XChangeProperty(display, win->id, astate, astate, 32, PropModeReplace,
+ (unsigned char *)data, 2);
+}
+
+long
+getstate(Window w)
+{
+ int format, status;
+ long result = -1;
+ unsigned char *p = NULL;
+ unsigned long n, extra;
+ Atom real;
+
+ status = XGetWindowProperty(display, w, astate, 0L, 2L, False, astate,
+ &real, &format, &n, &extra, (unsigned char **)&p);
+ if (status != Success)
+ return (-1);
+ if (n != 0)
+ result = *((long *)p);
+ XFree(p);
+ return (result);
+}
+
+void
version(struct swm_region *r, union arg *args)
{
bar_version = !bar_version;
{
XClientMessageEvent cm;
+ if (win == NULL)
+ return;
+
bzero(&cm, sizeof cm);
cm.type = ClientMessage;
cm.window = win->id;
}
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)
{
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;
}
void
+unmap_window(struct ws_win *win)
+{
+ if (win == NULL)
+ return;
+
+ /* don't unmap again */
+ if (getstate(win->id) == IconicState)
+ return;
+
+ set_win_state(win, IconicState);
+
+ XUnmapWindow(display, win->id);
+}
+
+void
unmap_all(void)
{
struct ws_win *win;
for (i = 0; i < ScreenCount(display); i++)
for (j = 0; j < SWM_WS_MAX; j++)
TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry)
- XUnmapWindow(display, win->id);
+ unmap_window(win);
}
void
{
XKeyEvent event;
+ if (win == NULL)
+ return;
+
event.display = display; /* Ignored, but what the hell */
event.window = win->id;
event.root = win->s->root;
if (screens[i].root == root)
break;
- if (XQueryPointer(display, screens[i].root,
+ if (XQueryPointer(display, screens[i].root,
&rr, &cr, &x, &y, &wx, &wy, &mask) != False) {
/* choose a region based on pointer location */
TAILQ_FOREACH(r, &screens[i].rl, entry)
}
struct ws_win *
+find_unmanaged_window(Window id)
+{
+ struct ws_win *win;
+ int i, j;
+
+ for (i = 0; i < ScreenCount(display); i++)
+ for (j = 0; j < SWM_WS_MAX; j++)
+ TAILQ_FOREACH(win, &screens[i].ws[j].unmanagedlist,
+ entry)
+ if (id == win->id)
+ return (win);
+ return (NULL);
+}
+
+struct ws_win *
find_window(Window id)
{
struct ws_win *win;
if (fork() == 0) {
if (display)
close(ConnectionNumber(display));
- setenv("LD_PRELOAD", SWM_LIB, 1);
+ setenv("LD_PRELOAD", SWM_LIB, 1);
if (asprintf(&ret, "%d", r->ws->idx)) {
setenv("_SWM_WS", ret, 1);
free(ret);
}
exit(0);
}
- wait(0);
}
void
}
void
-spawnmenu(struct swm_region *r, union arg *args)
+kill_refs(struct ws_win *win)
{
- DNPRINTF(SWM_D_MISC, "spawnmenu\n");
+ int i, x;
+ struct swm_region *r;
+ struct workspace *ws;
+
+ if (win == NULL)
+ return;
- spawn_menu[SWM_MENU_FN] = bar_fonts[bar_fidx];
- spawn_menu[SWM_MENU_NB] = r->s->c[SWM_S_COLOR_BAR].name;
- spawn_menu[SWM_MENU_NF] = r->s->c[SWM_S_COLOR_BAR_FONT].name;
- spawn_menu[SWM_MENU_SB] = r->s->c[SWM_S_COLOR_BAR_BORDER].name;
- spawn_menu[SWM_MENU_SF] = r->s->c[SWM_S_COLOR_BAR].name;
+ 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 (win == ws->focus)
+ ws->focus = NULL;
+ if (win == ws->focus_prev)
+ ws->focus_prev = NULL;
+ }
+}
- spawn(r, args);
+int
+validate_win(struct ws_win *testwin)
+{
+ struct ws_win *win;
+ struct workspace *ws;
+ struct swm_region *r;
+ int i, x, foundit = 0;
+
+ if (testwin == NULL)
+ return(0);
+
+ for (i = 0, foundit = 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];
+ TAILQ_FOREACH(win, &ws->winlist, entry)
+ if (win == testwin)
+ return (0);
+ }
+ return (1);
+}
+
+int
+validate_ws(struct workspace *testws)
+{
+ struct swm_region *r;
+ struct workspace *ws;
+ int foundit, i, x;
+
+ /* validate all ws */
+ for (i = 0, foundit = 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 (ws == testws)
+ return (0);
+ }
+ return (1);
}
void
{
if (win == NULL)
return;
+ if (win->ws == NULL)
+ return;
- if (win->ws->focus != win && win->ws->focus != NULL)
- win->ws->focus_prev = win->ws->focus;
+ if (validate_ws(win->ws))
+ abort();
if (win->ws->r == NULL)
return;
+ if (validate_win(win)) {
+ kill_refs(win);
+ return;
+ }
+
+ if (win->ws->focus == win) {
+ win->ws->focus = NULL;
+ win->ws->focus_prev = win;
+ }
+
+ if (validate_win(win->ws->focus)) {
+ kill_refs(win->ws->focus);
+ win->ws->focus = NULL;
+ }
+ if (validate_win(win->ws->focus_prev)) {
+ kill_refs(win->ws->focus_prev);
+ win->ws->focus_prev = NULL;
+ }
+
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)
- win->ws->focus = NULL;
- if (cur_focus == win)
- cur_focus = NULL;
}
void
if (win == NULL)
return;
+ if (win->ws == 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);
+ if (validate_ws(win->ws))
+ abort();
+ if (validate_win(win)) {
+ kill_refs(win);
+ return;
+ }
+
+ /* use big hammer to make sure it works under all use cases */
+ unfocus_all();
+
+ if (validate_win(win)) {
+ kill_refs(win);
+ return;
}
+
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;
- XSetInputFocus(display, win->id,
- RevertToPointerRoot, CurrentTime);
+ grabbuttons(win, 1);
+ if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS)
+ XMapRaised(display, win->id);
+ XSetWindowBorder(display, win->id,
+ win->ws->r->s->c[SWM_S_COLOR_FOCUS].color);
+ if (win->java == 0)
+ XSetInputFocus(display, win->id,
+ RevertToPointerRoot, CurrentTime);
}
}
struct swm_region *this_r, *other_r;
struct ws_win *win;
struct workspace *new_ws, *old_ws;
+ union arg a;
+
+ if (!(r && r->s))
+ return;
this_r = r;
old_ws = this_r->ws;
"%d -> %d\n", r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r),
old_ws->idx, wsid);
+ if (new_ws == NULL || old_ws == NULL)
+ return;
if (new_ws == old_ws)
return;
other_r = new_ws->r;
- if (!other_r) {
+ if (other_r == NULL) {
/* if the other workspace is hidden, switch windows */
- /* map new window first to prevent ugly blinking */
+ if (old_ws->r != NULL)
+ old_ws->old_r = old_ws->r;
old_ws->r = NULL;
- old_ws->restack = 1;
-
- TAILQ_FOREACH(win, &new_ws->winlist, entry)
- XMapRaised(display, win->id);
TAILQ_FOREACH(win, &old_ws->winlist, entry)
- XUnmapWindow(display, win->id);
+ unmap_window(win);
} else {
other_r->ws = old_ws;
old_ws->r = other_r;
this_r->ws = new_ws;
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();
+ a.id = SWM_ARG_ID_FOCUSCUR;
+ focus(new_ws->r, &a);
bar_update();
}
void
cyclescr(struct swm_region *r, union arg *args)
{
- struct swm_region *rr;
- int i;
+ struct swm_region *rr = NULL;
+ union arg a;
+ int i, x, y;
+
+ /* do nothing if we don't have more than one screen */
+ if (!(ScreenCount(display) > 1 || outputs > 1))
+ return;
i = r->s->idx;
switch (args->id) {
default:
return;
};
- unfocus_all();
- XSetInputFocus(display, PointerRoot, RevertToPointerRoot, CurrentTime);
- XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, rr->g.x,
- rr->g.y + bar_enabled ? bar_height : 0);
+ if (rr == NULL)
+ return;
+
+ /* move mouse to region */
+ x = rr->g.x + 1;
+ y = rr->g.y + 1 + bar_enabled ? bar_height : 0;
+ XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, x, y);
+
+ a.id = SWM_ARG_ID_FOCUSCUR;
+ focus(rr, &a);
+
+ if (rr->ws->focus) {
+ /* move to focus window */
+ x = rr->ws->focus->g.x + 1;
+ y = rr->ws->focus->g.y + 1;
+ XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, x, y);
+ }
}
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;
else
TAILQ_INSERT_BEFORE(target, source, entry);
break;
- case SWM_ARG_ID_SWAPNEXT:
+ case SWM_ARG_ID_SWAPNEXT:
target = TAILQ_NEXT(source, entry);
TAILQ_REMOVE(wl, source, entry);
if (target == NULL)
target = TAILQ_FIRST(wl);
if (target == source) {
if (source->ws->focus_prev != NULL &&
- source->ws->focus_prev != target)
-
+ source->ws->focus_prev != target)
+
source = source->ws->focus_prev;
else
return;
}
+ if (target == NULL || source == NULL)
+ return;
source->ws->focus_prev = target;
TAILQ_REMOVE(wl, target, entry);
TAILQ_INSERT_BEFORE(source, target, entry);
return;
}
- ignore_enter = 1;
stack();
}
void
+focus_prev(struct ws_win *win)
+{
+ struct ws_win *winfocus = NULL, *winlostfocus = NULL;
+ struct ws_win *cur_focus = NULL;
+ struct ws_win_list *wl = NULL;
+ struct workspace *ws = NULL;
+
+ DNPRINTF(SWM_D_FOCUS, "focus_prev: id %lu\n", WINID(win));
+
+ if (!(win && win->ws))
+ return;
+
+ ws = win->ws;
+ wl = &ws->winlist;
+ cur_focus = ws->focus;
+ winlostfocus = cur_focus;
+
+ /* pickle, just focus on whatever */
+ if (cur_focus == NULL) {
+ /* use prev_focus if valid */
+ if (ws->focus_prev && ws->focus_prev != cur_focus &&
+ find_window(WINID(ws->focus_prev)))
+ winfocus = ws->focus_prev;
+ if (winfocus == NULL)
+ winfocus = TAILQ_FIRST(wl);
+ goto done;
+ }
+
+ /* if transient focus on parent */
+ if (cur_focus->transient) {
+ winfocus = find_window(cur_focus->transient);
+ goto done;
+ }
+
+ /* if in max_stack try harder */
+ /* XXX needs more love */
+ if (ws->cur_layout->flags & SWM_L_FOCUSPREV) {
+ if (cur_focus != ws->focus_prev)
+ winfocus = ws->focus_prev;
+ else if (cur_focus != ws->focus)
+ winfocus = ws->focus;
+ goto done;
+ }
+
+ if (cur_focus == win)
+ winfocus = TAILQ_PREV(win, ws_win_list, entry);
+ if (winfocus == NULL)
+ winfocus = TAILQ_FIRST(wl);
+ if (winfocus == NULL || winfocus == win)
+ winfocus = TAILQ_NEXT(cur_focus, entry);
+done:
+ if (winfocus == winlostfocus || winfocus == NULL)
+ return;
+ focus_magic(winfocus, SWM_F_GENERIC);
+}
+
+void
focus(struct swm_region *r, union arg *args)
{
- struct ws_win *winfocus, *winlostfocus;
- struct ws_win_list *wl;
+ struct ws_win *winfocus = NULL, *winlostfocus = NULL;
+ struct ws_win *cur_focus = NULL;
+ struct ws_win_list *wl = NULL;
+ struct workspace *ws = NULL;
+
+ if (!(r && r->ws))
+ return;
DNPRINTF(SWM_D_FOCUS, "focus: id %d\n", args->id);
- if (cur_focus == NULL)
+
+ /* treat FOCUS_CUR special */
+ if (args->id == SWM_ARG_ID_FOCUSCUR) {
+ if (r->ws->focus)
+ winfocus = r->ws->focus;
+ else if (r->ws->focus_prev)
+ winfocus = r->ws->focus_prev;
+ else
+ winfocus = TAILQ_FIRST(&r->ws->winlist);
+
+ focus_magic(winfocus, SWM_F_GENERIC);
return;
+ }
- wl = &cur_focus->ws->winlist;
+ if ((cur_focus = r->ws->focus) == NULL)
+ return;
+ ws = r->ws;
+ wl = &ws->winlist;
winlostfocus = cur_focus;
switch (args->id) {
- case SWM_ARG_ID_FOCUSPREV:
+ case SWM_ARG_ID_FOCUSPREV:
winfocus = TAILQ_PREV(cur_focus, ws_win_list, entry);
if (winfocus == NULL)
winfocus = TAILQ_LAST(wl, ws_win_list);
winfocus = TAILQ_FIRST(wl);
if (winfocus == cur_focus)
winfocus = cur_focus->ws->focus_prev;
- if (winfocus == NULL)
- return;
break;
default:
if (winfocus == winlostfocus || winfocus == NULL)
return;
- XMapRaised(display, winfocus->id);
- focus_win(winfocus);
- XSync(display, False);
+ focus_magic(winfocus, SWM_F_GENERIC);
}
void
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];
- ignore_enter = 1;
+
stack();
+ a.id = SWM_ARG_ID_FOCUSCUR;
+ focus(r, &a);
+ bar_update();
}
void
if (bar_enabled) {
g.y += bar_height;
g.h -= bar_height;
- }
-
- r->ws->restack = 0;
+ }
r->ws->cur_layout->l_stack(r->ws, &g);
}
}
if (font_adjusted)
font_adjusted--;
- XSync(display, False);
}
void
unsigned int mask;
XWindowChanges wc;
+ if (win == NULL)
+ return;
+
bzero(&wc, sizeof wc);
mask = CWX | CWY | CWBorderWidth | CWWidth | CWHeight;
- if ((win->quirks & SWM_Q_FULLSCREEN) && (win->g.w == WIDTH(r)) &&
- (win->g.h == HEIGHT(r)))
+ if ((win->quirks & SWM_Q_FULLSCREEN) && (win->g.w >= WIDTH(r)) &&
+ (win->g.h >= HEIGHT(r)))
wc.border_width = 0;
else
wc.border_width = 1;
wc.y = (HEIGHT(r) - win->g.h) / 2;
}
- DNPRINTF(SWM_D_STACK, "stack_floater: win %lu x %d y %d w %d h %d\n",
+ /* adjust for region */
+ if (wc.x < r->g.x)
+ wc.x += r->g.x;
+ if (wc.y < r->g.y)
+ wc.y += r->g.y;
+
+ win->g.x = wc.x;
+ win->g.y = wc.y;
+ win->g.w = wc.width;
+ win->g.h = wc.height;
+
+ DNPRINTF(SWM_D_MISC, "stack_floater: 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);
}
/*
if (!(win->quirks & SWM_Q_XTERM_FONTADJ) ||
win->floating || win->transient)
return;
-
+
if (win->sh.width_inc && win->last_inc != win->sh.width_inc &&
win->g.w / win->sh.width_inc < term_width &&
win->font_steps < SWM_MAX_FONT_STEPS) {
{
XWindowChanges wc;
struct swm_geometry win_g, r_g = *g;
- struct ws_win *win, *winfocus;
- int i, j, s, stacks;
+ 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;
int split, colno, winno, mwin, msize, mscale;
- int remain, missing, v_slice;
+ int remain, missing, v_slice, reconfigure;
unsigned int mask;
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;
}
msize = win_g.w;
- if (flip)
+ if (flip)
win_g.x += r_g.w - msize;
} else {
msize = -2;
h_inc = win->sh.width_inc;
h_base = win->sh.base_width;
} else {
- h_inc = win->sh.height_inc;
+ h_inc = win->sh.height_inc;
h_base = win->sh.base_height;
}
if (j == colno - 1) {
extra += remain;
}
}
-
+
if (j == 0)
win_g.y = r_g.y;
else
bzero(&wc, sizeof wc);
wc.border_width = 1;
+ reconfigure = 0;
if (rot) {
- win->g.x = wc.x = win_g.y;
- win->g.y = wc.y = win_g.x;
- win->g.w = wc.width = win_g.h;
- win->g.h = wc.height = win_g.w;
+ if (win->g.x != win_g.y || win->g.y != win_g.x ||
+ win->g.w != win_g.h || win->g.h != win_g.w) {
+ reconfigure = 1;
+ win->g.x = wc.x = win_g.y;
+ win->g.y = wc.y = win_g.x;
+ win->g.w = wc.width = win_g.h;
+ win->g.h = wc.height = win_g.w;
+ }
} else {
- win->g.x = wc.x = win_g.x;
- win->g.y = wc.y = win_g.y;
- win->g.w = wc.width = win_g.w;
- win->g.h = wc.height = win_g.h;
+ if (win->g.x != win_g.x || win->g.y != win_g.y ||
+ win->g.w != win_g.w || win->g.h != win_g.h) {
+ reconfigure = 1;
+ win->g.x = wc.x = win_g.x;
+ win->g.y = wc.y = win_g.y;
+ win->g.w = wc.width = win_g.w;
+ win->g.h = wc.height = win_g.h;
+ }
+ }
+ if (reconfigure) {
+ adjust_font(win);
+ mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
+ XConfigureWindow(display, win->id, mask, &wc);
+ configreq_win(win);
}
- adjust_font(win);
- mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
- XConfigureWindow(display, win->id, mask, &wc);
XMapRaised(display, win->id);
last_h = win_g.h;
stack_floater(win, ws->r);
XMapRaised(display, win->id);
}
-
- if (winfocus)
- focus_win(winfocus); /* has to be done outside of the loop */
}
void
/* 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;
+ struct ws_win *win, *wintrans = NULL, *parent = NULL;
unsigned int mask;
+ int winno;
DNPRINTF(SWM_D_STACK, "max_stack: workspace: %d\n", ws->idx);
- if (count_win(ws, 0) == 0)
+ if (ws == NULL)
return;
- if (ws->focus == NULL)
- ws->focus = TAILQ_FIRST(&ws->winlist);
- winfocus = cur_focus ? cur_focus : ws->focus;
+ winno = count_win(ws, 0);
+ if (winno == 0 && count_win(ws, 1) == 0)
+ return;
TAILQ_FOREACH(win, &ws->winlist, entry) {
- if (win->transient != 0 || win->floating != 0) {
- if (win == ws->focus) {
- /* XXX maximize? */
- stack_floater(win, ws->r);
- XMapRaised(display, win->id);
- } else
- XUnmapWindow(display, win->id);
- } else {
+ if (win->transient) {
+ wintrans = win;
+ parent = find_window(win->transient);
+ continue;
+ }
+
+ /* only reconfigure if necessary */
+ if (win->g.x != gg.x || win->g.y != gg.y || win->g.w != gg.w ||
+ win->g.h != gg.h) {
bzero(&wc, sizeof wc);
wc.border_width = 1;
win->g.x = wc.x = gg.x;
win->g.h = wc.height = gg.h;
mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
XConfigureWindow(display, win->id, mask, &wc);
-
- if (win == ws->focus) {
- XMapRaised(display, win->id);
- } else
- XUnmapWindow(display, win->id);
+ configreq_win(win);
}
+ /* unmap only if we don't have multi screen */
+ if (win != ws->focus)
+ if (!(ScreenCount(display) > 1 || outputs > 1))
+ unmap_window(win);
}
- if (winfocus)
- focus_win(winfocus); /* has to be done outside of the loop */
+ /* put the last transient on top */
+ if (wintrans) {
+ if (parent)
+ XMapRaised(display, parent->id);
+ stack_floater(wintrans, ws->r);
+ focus_magic(wintrans, SWM_F_TRANSIENT);
+ }
}
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 = win;
struct workspace *ws, *nws;
Atom ws_idx_atom = 0;
unsigned char ws_idx_str[SWM_PROPLEN];
+ union arg a;
+ if (r && r->ws)
+ win = r->ws->focus;
+ else
+ return;
if (win == NULL)
return;
+ if (win->ws->idx == wsid)
+ return;
DNPRINTF(SWM_D_MOVE, "send_to_ws: win: %lu\n", win->id);
ws = win->ws;
nws = &win->s->ws[wsid];
- XUnmapWindow(display, win->id);
-
- /* find a window to focus */
- ws->focus = TAILQ_PREV(win, ws_win_list, entry);
- if (ws->focus == NULL)
- ws->focus = TAILQ_FIRST(&ws->winlist);
- if (ws->focus == win)
- ws->focus = NULL;
-
+ a.id = SWM_ARG_ID_FOCUSPREV;
+ focus(r, &a);
+ unmap_window(win);
TAILQ_REMOVE(&ws->winlist, win, entry);
-
TAILQ_INSERT_TAIL(&nws->winlist, win, entry);
win->ws = nws;
XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8,
PropModeReplace, ws_idx_str, SWM_PROPLEN);
}
-
- if (count_win(nws, 1) == 1)
- nws->focus = win;
- ws->restack = 1;
- nws->restack = 1;
-
stack();
}
}
void
-screenshot(struct swm_region *r, union arg *args)
-{
- union arg a;
-
- DNPRINTF(SWM_D_MISC, "screenshot\n");
-
- if (ss_enabled == 0)
- return;
-
- switch (args->id) {
- case SWM_ARG_ID_SS_ALL:
- spawn_screenshot[1] = "full";
- break;
- case SWM_ARG_ID_SS_WINDOW:
- spawn_screenshot[1] = "window";
- break;
- default:
- return;
- }
- a.argv = spawn_screenshot;
- spawn(r, &a);
-}
-
-void
floating_toggle(struct swm_region *r, union arg *args)
{
- struct ws_win *win = cur_focus;
+ struct ws_win *win = r->ws->focus;
+ union arg a;
if (win == NULL)
return;
win->floating = !win->floating;
win->manual = 0;
stack();
- focus_win(win);
+ a.id = SWM_ARG_ID_FOCUSCUR;
+ focus(win->ws->r, &a);
}
void
win->id, wc.x, wc.y, wc.width, wc.height);
XConfigureWindow(display, win->id, mask, &wc);
- config_win(win);
+ configreq_win(win);
}
void
{
XEvent ev;
Time time = 0;
+ struct swm_region *r = win->ws->r;
- DNPRINTF(SWM_D_MOUSE, "resize: win %lu floating %d trans %d\n",
+ DNPRINTF(SWM_D_MOUSE, "resize: win %lu floating %d trans %lu\n",
win->id, win->floating, win->transient);
if (!(win->transient != 0 || win->floating != 0))
handler[ev.type](&ev);
break;
case MotionNotify:
+ /* do not allow resize outside of region */
+ if (ev.xmotion.y_root < r->g.y ||
+ ev.xmotion.y_root >= r->g.y + r->g.h - 1)
+ continue;
+ if (ev.xmotion.x_root < r->g.x ||
+ ev.xmotion.x_root >= r->g.x + r->g.w - 1)
+ continue;
+
if (ev.xmotion.x <= 1)
ev.xmotion.x = 1;
if (ev.xmotion.y <= 1)
win->id, wc.x, wc.y, wc.width, wc.height);
XConfigureWindow(display, win->id, mask, &wc);
- config_win(win);
+ configreq_win(win);
}
void
XEvent ev;
Time time = 0;
int restack = 0;
+ struct swm_region *r = win->ws->r;
- DNPRINTF(SWM_D_MOUSE, "move: win %lu floating %d trans %d\n",
+ DNPRINTF(SWM_D_MOUSE, "move: win %lu floating %d trans %lu\n",
win->id, win->floating, win->transient);
if (win->floating == 0) {
handler[ev.type](&ev);
break;
case MotionNotify:
+ /* don't allow to move window out of region */
+ if (ev.xmotion.y_root < r->g.y ||
+ ev.xmotion.y_root + win->g.h >= r->g.y + r->g.h - 1)
+ continue;
+ if (ev.xmotion.x_root < r->g.x ||
+ ev.xmotion.x_root + win->g.w >= r->g.x + r->g.w - 1)
+ continue;
+
win->g.x = ev.xmotion.x_root;
win->g.y = ev.xmotion.y_root;
}
/* key definitions */
+void
+dummykeyfunc(struct swm_region *r, union arg *args)
+{
+};
+
+void
+legacyfunc(struct swm_region *r, union arg *args)
+{
+};
+
struct keyfunc {
char name[SWM_FUNCNAME_LEN];
void (*func)(struct swm_region *r, union arg *);
union arg args;
-} keyfuncs[kf_invalid] = {
+} keyfuncs[kf_invalid + 1] = {
/* name function argument */
- { "cycle_layout", cycle_layout, {0} },
- { "stack_reset", stack_config, {.id = SWM_ARG_ID_STACKRESET} },
+ { "cycle_layout", cycle_layout, {0} },
+ { "stack_reset", stack_config, {.id = SWM_ARG_ID_STACKRESET} },
{ "master_shrink", stack_config, {.id = SWM_ARG_ID_MASTERSHRINK} },
{ "master_grow", stack_config, {.id = SWM_ARG_ID_MASTERGROW} },
{ "master_add", stack_config, {.id = SWM_ARG_ID_MASTERADD} },
{ "swap_next", swapwin, {.id = SWM_ARG_ID_SWAPNEXT} },
{ "swap_prev", swapwin, {.id = SWM_ARG_ID_SWAPPREV} },
{ "spawn_term", spawnterm, {.argv = spawn_term} },
- { "spawn_menu", spawnmenu, {.argv = spawn_menu} },
+ { "spawn_menu", legacyfunc, {0} },
{ "quit", quit, {0} },
{ "restart", restart, {0} },
{ "focus_main", focus, {.id = SWM_ARG_ID_FOCUSMAIN} },
{ "ws_8", switchws, {.id = 7} },
{ "ws_9", switchws, {.id = 8} },
{ "ws_10", switchws, {.id = 9} },
- { "ws_next", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP} },
- { "ws_prev", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN} },
- { "screen_next", cyclescr, {.id = SWM_ARG_ID_CYCLESC_UP} },
- { "screen_prev", cyclescr, {.id = SWM_ARG_ID_CYCLESC_DOWN} },
+ { "ws_next", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP} },
+ { "ws_prev", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN} },
+ { "screen_next", cyclescr, {.id = SWM_ARG_ID_CYCLESC_UP} },
+ { "screen_prev", cyclescr, {.id = SWM_ARG_ID_CYCLESC_DOWN} },
{ "mvws_1", send_to_ws, {.id = 0} },
{ "mvws_2", send_to_ws, {.id = 1} },
{ "mvws_3", send_to_ws, {.id = 2} },
{ "bar_toggle", bar_toggle, {0} },
{ "wind_kill", wkill, {.id = SWM_ARG_ID_KILLWINDOW} },
{ "wind_del", wkill, {.id = SWM_ARG_ID_DELETEWINDOW} },
- { "screenshot_all", screenshot, {.id = SWM_ARG_ID_SS_ALL} },
- { "screenshot_wind", screenshot, {.id = SWM_ARG_ID_SS_WINDOW} },
+ { "screenshot_all", legacyfunc, {0} },
+ { "screenshot_wind", legacyfunc, {0} },
{ "float_toggle", floating_toggle,{0} },
{ "version", version, {0} },
- { "spawn_lock", spawn, {.argv = spawn_lock} },
- { "spawn_initscr", spawn, {.argv = spawn_initscr} },
+ { "spawn_lock", legacyfunc, {0} },
+ { "spawn_initscr", legacyfunc, {0} },
+ { "spawn_custom", dummykeyfunc, {0} },
+ { "dumpwins", dumpwins, {0} },
+ { "invalid key func", NULL, {0} },
};
struct key {
unsigned int mod;
KeySym keysym;
enum keyfuncid funcid;
+ char *spawn_name;
};
int keys_size = 0, keys_length = 0;
struct key *keys = NULL;
void (*func)(struct ws_win *, union arg *);
union arg args;
} buttons[] = {
- /* action key mouse button func args */
- { client_click, MODKEY, Button3, resize, {.id = SWM_ARG_ID_DONTCENTER} },
- { client_click, MODKEY | ShiftMask, Button3, resize, {.id = SWM_ARG_ID_CENTER} },
- { client_click, MODKEY, Button1, move, {0} },
+ /* action key mouse button func args */
+ { client_click, MODKEY, Button3, resize, {.id = SWM_ARG_ID_DONTCENTER} },
+ { client_click, MODKEY | ShiftMask, Button3, resize, {.id = SWM_ARG_ID_CENTER} },
+ { client_click, MODKEY, Button1, move, {0} },
};
void
buttons[i].mask = mod;
}
+/* spawn */
+struct spawn_prog {
+ char *name;
+ int argc;
+ char **argv;
+};
+
+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)
+{
+ union arg a;
+ struct spawn_prog *prog = NULL;
+ int i;
+ char *ap, **real_args;
+
+ DNPRINTF(SWM_D_SPAWN, "spawn_custom %s\n", spawn_name);
+
+ /* find program */
+ for (i = 0; i < spawns_length; i++) {
+ if (!strcasecmp(spawn_name, spawns[i].name))
+ prog = &spawns[i];
+ }
+ if (prog == NULL) {
+ fprintf(stderr, "spawn_custom: program %s not found\n",
+ spawn_name);
+ return;
+ }
+
+ /* make room for expanded args */
+ if ((real_args = calloc(prog->argc + 1, sizeof(char *))) == NULL)
+ err(1, "spawn_custom: calloc real_args");
+
+ /* expand spawn_args into real_args */
+ for (i = 0; i < prog->argc; i++) {
+ ap = prog->argv[i];
+ DNPRINTF(SWM_D_SPAWN, "spawn_custom: raw arg = %s\n", ap);
+ if (!strcasecmp(ap, "$bar_border")) {
+ if ((real_args[i] =
+ strdup(r->s->c[SWM_S_COLOR_BAR_BORDER].name))
+ == NULL)
+ err(1, "spawn_custom border color");
+ } else if (!strcasecmp(ap, "$bar_color")) {
+ if ((real_args[i] =
+ strdup(r->s->c[SWM_S_COLOR_BAR].name))
+ == NULL)
+ err(1, "spawn_custom bar color");
+ } else if (!strcasecmp(ap, "$bar_font")) {
+ if ((real_args[i] = strdup(bar_fonts[bar_fidx]))
+ == NULL)
+ err(1, "spawn_custom bar fonts");
+ } else if (!strcasecmp(ap, "$bar_font_color")) {
+ if ((real_args[i] =
+ strdup(r->s->c[SWM_S_COLOR_BAR_FONT].name))
+ == NULL)
+ err(1, "spawn_custom color font");
+ } else if (!strcasecmp(ap, "$color_focus")) {
+ if ((real_args[i] =
+ strdup(r->s->c[SWM_S_COLOR_FOCUS].name))
+ == NULL)
+ err(1, "spawn_custom color focus");
+ } else if (!strcasecmp(ap, "$color_unfocus")) {
+ if ((real_args[i] =
+ strdup(r->s->c[SWM_S_COLOR_UNFOCUS].name))
+ == NULL)
+ err(1, "spawn_custom color unfocus");
+ } else {
+ /* no match --> copy as is */
+ if ((real_args[i] = strdup(ap)) == NULL)
+ err(1, "spawn_custom strdup(ap)");
+ }
+ DNPRINTF(SWM_D_SPAWN, "spawn_custom: cooked arg = %s\n",
+ real_args[i]);
+ }
+
+#ifdef SWM_DEBUG
+ if ((swm_debug & SWM_D_SPAWN) != 0) {
+ fprintf(stderr, "spawn_custom: result = ");
+ for (i = 0; i < prog->argc; i++)
+ fprintf(stderr, "\"%s\" ", real_args[i]);
+ fprintf(stderr, "\n");
+ }
+#endif
+
+ a.argv = real_args;
+ spawn(r, &a);
+ for (i = 0; i < prog->argc; i++)
+ free(real_args[i]);
+ free(real_args);
+}
+
+void
+setspawn(struct spawn_prog *prog)
+{
+ int i, j;
+
+ if (prog == NULL || prog->name == NULL)
+ return;
+
+ /* find existing */
+ for (i = 0; i < spawns_length; i++) {
+ if (!strcmp(spawns[i].name, prog->name)) {
+ /* found */
+ if (prog->argv == NULL) {
+ /* delete */
+ DNPRINTF(SWM_D_SPAWN,
+ "setspawn: delete #%d %s\n",
+ i, spawns[i].name);
+ free(spawns[i].name);
+ for (j = 0; j < spawns[i].argc; j++)
+ free(spawns[i].argv[j]);
+ free(spawns[i].argv);
+ j = spawns_length - 1;
+ if (i < j)
+ spawns[i] = spawns[j];
+ spawns_length--;
+ free(prog->name);
+ } else {
+ /* replace */
+ DNPRINTF(SWM_D_SPAWN,
+ "setspawn: replace #%d %s\n",
+ i, spawns[i].name);
+ free(spawns[i].name);
+ for (j = 0; j < spawns[i].argc; j++)
+ free(spawns[i].argv[j]);
+ free(spawns[i].argv);
+ spawns[i] = *prog;
+ }
+ /* found case handled */
+ free(prog);
+ return;
+ }
+ }
+
+ if (prog->argv == NULL) {
+ fprintf(stderr,
+ "error: setspawn: cannot find program %s", prog->name);
+ free(prog);
+ return;
+ }
+
+ /* not found: add */
+ if (spawns_size == 0 || spawns == NULL) {
+ spawns_size = 4;
+ DNPRINTF(SWM_D_SPAWN, "setspawn: init list %d\n", spawns_size);
+ spawns = malloc((size_t)spawns_size *
+ sizeof(struct spawn_prog));
+ if (spawns == NULL) {
+ fprintf(stderr, "setspawn: malloc failed\n");
+ perror(" failed");
+ quit(NULL, NULL);
+ }
+ } else if (spawns_length == spawns_size) {
+ spawns_size *= 2;
+ DNPRINTF(SWM_D_SPAWN, "setspawn: grow list %d\n", spawns_size);
+ spawns = realloc(spawns, (size_t)spawns_size *
+ sizeof(struct spawn_prog));
+ if (spawns == NULL) {
+ fprintf(stderr, "setspawn: realloc failed\n");
+ perror(" failed");
+ quit(NULL, NULL);
+ }
+ }
+
+ if (spawns_length < spawns_size) {
+ DNPRINTF(SWM_D_SPAWN, "setspawn: add #%d %s\n",
+ spawns_length, prog->name);
+ i = spawns_length++;
+ spawns[i] = *prog;
+ } else {
+ fprintf(stderr, "spawns array problem?\n");
+ if (spawns == NULL) {
+ fprintf(stderr, "spawns array is NULL!\n");
+ quit(NULL, NULL);
+ }
+ }
+ free(prog);
+}
+
+int
+setconfspawn(char *selector, char *value, int flags)
+{
+ struct spawn_prog *prog;
+ char *vp, *cp, *word;
+
+ DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, value);
+ if ((prog = calloc(1, sizeof *prog)) == NULL)
+ err(1, "setconfspawn: calloc prog");
+ prog->name = strdup(selector);
+ if (prog->name == NULL)
+ err(1, "setconfspawn prog->name");
+ if ((cp = vp = strdup(value)) == NULL)
+ err(1, "setconfspawn: strdup(value) ");
+ while ((word = strsep(&cp, " \t")) != NULL) {
+ DNPRINTF(SWM_D_SPAWN, "setconfspawn: arg [%s]\n", word);
+ if (cp)
+ cp += (long)strspn(cp, " \t");
+ if (strlen(word) > 0) {
+ prog->argc++;
+ prog->argv = realloc(prog->argv,
+ prog->argc * sizeof(char *));
+ if ((prog->argv[prog->argc - 1] = strdup(word)) == NULL)
+ err(1, "setconfspawn: strdup");
+ }
+ }
+ free(vp);
+
+ setspawn(prog);
+
+ DNPRINTF(SWM_D_SPAWN, "setconfspawn: done\n");
+ return (0);
+}
+
+void
+setup_spawn(void)
+{
+ setconfspawn("term", "xterm", 0);
+ setconfspawn("screenshot_all", "screenshot.sh full", 0);
+ setconfspawn("screenshot_wind", "screenshot.sh window", 0);
+ setconfspawn("lock", "xlock", 0);
+ setconfspawn("initscr", "initscreen.sh", 0);
+ setconfspawn("menu", "dmenu_run"
+ " -fn $bar_font"
+ " -nb $bar_color"
+ " -nf $bar_font_color"
+ " -sb $bar_border"
+ " -sf $bar_color", 0);
+}
+
+/* key bindings */
#define SWM_MODNAME_SIZE 32
#define SWM_KEY_WS "\n+ \t"
int
{
char *cp, *name;
KeySym uks;
- if (mod == NULL || ks == NULL)
- return (0);
+ DNPRINTF(SWM_D_KEY, "parsekeys: enter [%s]\n", keystr);
+ if (mod == NULL || ks == NULL) {
+ DNPRINTF(SWM_D_KEY, "parsekeys: no mod or key vars\n");
+ return (1);
+ }
+ if (keystr == NULL || strlen(keystr) == 0) {
+ DNPRINTF(SWM_D_KEY, "parsekeys: no keystr\n");
+ return (1);
+ }
cp = keystr;
+ *ks = NoSymbol;
*mod = 0;
while ((name = strsep(&cp, SWM_KEY_WS)) != NULL) {
+ DNPRINTF(SWM_D_KEY, "parsekeys: key [%s]\n", name);
if (cp)
cp += (long)strspn(cp, SWM_KEY_WS);
if (strncasecmp(name, "MOD", SWM_MODNAME_SIZE) == 0)
DNPRINTF(SWM_D_KEY,
"parsekeys: invalid key %s\n",
name);
- return (0);
+ return (1);
}
}
}
- return (1);
+ DNPRINTF(SWM_D_KEY, "parsekeys: leave ok\n");
+ return (0);
}
+
+char *
+strdupsafe(char *str)
+{
+ if (str == NULL)
+ return (NULL);
+ else
+ return (strdup(str));
+}
+
void
-setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid)
+setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name)
{
int i, j;
+ DNPRINTF(SWM_D_KEY, "setkeybinding: enter %s [%s]\n",
+ keyfuncs[kfid].name, spawn_name);
/* find existing */
for (i = 0; i < keys_length; i++) {
if (keys[i].mod == mod && keys[i].keysym == ks) {
DNPRINTF(SWM_D_KEY,
"setkeybinding: delete #%d %s\n",
i, keyfuncs[keys[i].funcid].name);
+ free(keys[i].spawn_name);
j = keys_length - 1;
if (i < j)
keys[i] = keys[j];
keys_length--;
+ DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
return;
} else {
/* found: replace */
DNPRINTF(SWM_D_KEY,
- "setkeybinding: replace #%d %s\n",
- i, keyfuncs[keys[i].funcid].name);
+ "setkeybinding: replace #%d %s %s\n",
+ i, keyfuncs[keys[i].funcid].name,
+ spawn_name);
+ free(keys[i].spawn_name);
keys[i].mod = mod;
keys[i].keysym = ks;
keys[i].funcid = kfid;
+ keys[i].spawn_name = strdupsafe(spawn_name);
+ DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
return;
}
}
if (kfid == kf_invalid) {
fprintf(stderr,
"error: setkeybinding: cannot find mod/key combination");
+ DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
return;
}
/* not found: add */
}
}
if (keys_length < keys_size) {
- DNPRINTF(SWM_D_KEY, "setkeybinding: add %d\n", keys_length);
j = keys_length++;
+ DNPRINTF(SWM_D_KEY, "setkeybinding: add #%d %s %s\n",
+ j, keyfuncs[kfid].name, spawn_name);
keys[j].mod = mod;
keys[j].keysym = ks;
keys[j].funcid = kfid;
+ keys[j].spawn_name = strdupsafe(spawn_name);
} else {
fprintf(stderr, "keys array problem?\n");
if (!keys) {
quit(NULL, NULL);
}
}
+ DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
}
+
int
setconfbinding(char *selector, char *value, int flags)
{
enum keyfuncid kfid;
unsigned int mod;
KeySym ks;
+ int i;
+ DNPRINTF(SWM_D_KEY, "setconfbinding: enter\n");
+ if (selector == NULL) {
+ DNPRINTF(SWM_D_KEY, "setconfbinding: unbind %s\n", value);
+ if (parsekeys(value, mod_key, &mod, &ks) == 0) {
+ kfid = kf_invalid;
+ setkeybinding(mod, ks, kfid, NULL);
+ return (0);
+ } else
+ return (1);
+ }
+ /* search by key function name */
for (kfid = 0; kfid < kf_invalid; (kfid)++) {
if (strncasecmp(selector, keyfuncs[kfid].name,
SWM_FUNCNAME_LEN) == 0) {
- if (parsekeys(value, mod_key, &mod, &ks))
- setkeybinding(mod, ks, kfid);
- else
+ DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match\n",
+ selector);
+ if (parsekeys(value, mod_key, &mod, &ks) == 0) {
+ setkeybinding(mod, ks, kfid, NULL);
return (0);
+ } else
+ return (1);
}
-
}
+ /* search by custom spawn name */
+ for (i = 0; i < spawns_length; i++) {
+ if (strcasecmp(selector, spawns[i].name) == 0) {
+ DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match\n",
+ selector);
+ if (parsekeys(value, mod_key, &mod, &ks) == 0) {
+ setkeybinding(mod, ks, kf_spawn_custom,
+ spawns[i].name);
+ return (0);
+ } else
+ return (1);
+ }
+ }
+ DNPRINTF(SWM_D_KEY, "setconfbinding: no match\n");
return (1);
}
+
void
setup_keys(void)
{
- setkeybinding(MODKEY, XK_space, kf_cycle_layout);
- setkeybinding(MODKEY|ShiftMask, XK_space, kf_stack_reset);
- setkeybinding(MODKEY, XK_h, kf_master_shrink);
- setkeybinding(MODKEY, XK_l, kf_master_grow);
- setkeybinding(MODKEY, XK_comma, kf_master_add);
- setkeybinding(MODKEY, XK_period, kf_master_del);
- setkeybinding(MODKEY|ShiftMask, XK_comma, kf_stack_inc);
- setkeybinding(MODKEY|ShiftMask, XK_period, kf_stack_dec);
- setkeybinding(MODKEY, XK_Return, kf_swap_main);
- setkeybinding(MODKEY, XK_j, kf_focus_next);
- setkeybinding(MODKEY, XK_k, kf_focus_prev);
- setkeybinding(MODKEY|ShiftMask, XK_j, kf_swap_next);
- setkeybinding(MODKEY|ShiftMask, XK_k, kf_swap_prev);
- setkeybinding(MODKEY|ShiftMask, XK_Return, kf_spawn_term);
- setkeybinding(MODKEY, XK_p, kf_spawn_menu);
- setkeybinding(MODKEY|ShiftMask, XK_q, kf_quit);
- setkeybinding(MODKEY, XK_q, kf_restart);
- setkeybinding(MODKEY, XK_m, kf_focus_main);
- setkeybinding(MODKEY, XK_1, kf_ws_1);
- setkeybinding(MODKEY, XK_2, kf_ws_2);
- setkeybinding(MODKEY, XK_3, kf_ws_3);
- setkeybinding(MODKEY, XK_4, kf_ws_4);
- setkeybinding(MODKEY, XK_5, kf_ws_5);
- setkeybinding(MODKEY, XK_6, kf_ws_6);
- setkeybinding(MODKEY, XK_7, kf_ws_7);
- setkeybinding(MODKEY, XK_8, kf_ws_8);
- setkeybinding(MODKEY, XK_9, kf_ws_9);
- setkeybinding(MODKEY, XK_0, kf_ws_10);
- setkeybinding(MODKEY, XK_Right, kf_ws_next);
- setkeybinding(MODKEY, XK_Left, kf_ws_prev);
- setkeybinding(MODKEY|ShiftMask, XK_Right, kf_screen_next);
- setkeybinding(MODKEY|ShiftMask, XK_Left, kf_screen_prev);
- setkeybinding(MODKEY|ShiftMask, XK_1, kf_mvws_1);
- setkeybinding(MODKEY|ShiftMask, XK_2, kf_mvws_2);
- setkeybinding(MODKEY|ShiftMask, XK_3, kf_mvws_3);
- setkeybinding(MODKEY|ShiftMask, XK_4, kf_mvws_4);
- setkeybinding(MODKEY|ShiftMask, XK_5, kf_mvws_5);
- setkeybinding(MODKEY|ShiftMask, XK_6, kf_mvws_6);
- setkeybinding(MODKEY|ShiftMask, XK_7, kf_mvws_7);
- setkeybinding(MODKEY|ShiftMask, XK_8, kf_mvws_8);
- setkeybinding(MODKEY|ShiftMask, XK_9, kf_mvws_9);
- setkeybinding(MODKEY|ShiftMask, XK_0, kf_mvws_10);
- setkeybinding(MODKEY, XK_b, kf_bar_toggle);
- setkeybinding(MODKEY, XK_Tab, kf_focus_next);
- setkeybinding(MODKEY|ShiftMask, XK_Tab, kf_focus_prev);
- setkeybinding(MODKEY|ShiftMask, XK_x, kf_wind_kill);
- setkeybinding(MODKEY, XK_x, kf_wind_del);
- setkeybinding(MODKEY, XK_s, kf_screenshot_all);
- setkeybinding(MODKEY|ShiftMask, XK_s, kf_screenshot_wind);
- setkeybinding(MODKEY, XK_t, kf_float_toggle);
- setkeybinding(MODKEY|ShiftMask, XK_v, kf_version);
- setkeybinding(MODKEY|ShiftMask, XK_Delete, kf_spawn_lock);
- setkeybinding(MODKEY|ShiftMask, XK_i, kf_spawn_initscr);
+ setkeybinding(MODKEY, XK_space, kf_cycle_layout,NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_space, kf_stack_reset, NULL);
+ setkeybinding(MODKEY, XK_h, kf_master_shrink,NULL);
+ setkeybinding(MODKEY, XK_l, kf_master_grow, NULL);
+ setkeybinding(MODKEY, XK_comma, kf_master_add, NULL);
+ setkeybinding(MODKEY, XK_period, kf_master_del, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_comma, kf_stack_inc, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_period, kf_stack_dec, NULL);
+ setkeybinding(MODKEY, XK_Return, kf_swap_main, NULL);
+ setkeybinding(MODKEY, XK_j, kf_focus_next, NULL);
+ setkeybinding(MODKEY, XK_k, kf_focus_prev, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_j, kf_swap_next, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_k, kf_swap_prev, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_Return, kf_spawn_term, NULL);
+ setkeybinding(MODKEY, XK_p, kf_spawn_custom, "menu");
+ setkeybinding(MODKEY|ShiftMask, XK_q, kf_quit, NULL);
+ setkeybinding(MODKEY, XK_q, kf_restart, NULL);
+ setkeybinding(MODKEY, XK_m, kf_focus_main, NULL);
+ setkeybinding(MODKEY, XK_1, kf_ws_1, NULL);
+ setkeybinding(MODKEY, XK_2, kf_ws_2, NULL);
+ setkeybinding(MODKEY, XK_3, kf_ws_3, NULL);
+ setkeybinding(MODKEY, XK_4, kf_ws_4, NULL);
+ setkeybinding(MODKEY, XK_5, kf_ws_5, NULL);
+ setkeybinding(MODKEY, XK_6, kf_ws_6, NULL);
+ setkeybinding(MODKEY, XK_7, kf_ws_7, NULL);
+ setkeybinding(MODKEY, XK_8, kf_ws_8, NULL);
+ setkeybinding(MODKEY, XK_9, kf_ws_9, NULL);
+ setkeybinding(MODKEY, XK_0, kf_ws_10, NULL);
+ setkeybinding(MODKEY, XK_Right, kf_ws_next, NULL);
+ setkeybinding(MODKEY, XK_Left, kf_ws_prev, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_Right, kf_screen_next, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_Left, kf_screen_prev, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_1, kf_mvws_1, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_2, kf_mvws_2, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_3, kf_mvws_3, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_4, kf_mvws_4, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_5, kf_mvws_5, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_6, kf_mvws_6, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_7, kf_mvws_7, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_8, kf_mvws_8, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_9, kf_mvws_9, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_0, kf_mvws_10, NULL);
+ setkeybinding(MODKEY, XK_b, kf_bar_toggle, NULL);
+ setkeybinding(MODKEY, XK_Tab, kf_focus_next, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_Tab, kf_focus_prev, NULL);
+ setkeybinding(MODKEY|ShiftMask, XK_x, kf_wind_kill, NULL);
+ setkeybinding(MODKEY, XK_x, kf_wind_del, NULL);
+ setkeybinding(MODKEY, XK_s, kf_spawn_custom, "screenshot_all");
+ setkeybinding(MODKEY|ShiftMask, XK_s, kf_spawn_custom, "screenshot_wind");
+ setkeybinding(MODKEY, XK_t, kf_float_toggle,NULL);
+ 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");
+#ifdef SWM_DEBUG
+ setkeybinding(MODKEY|ShiftMask, XK_d, kf_dumpwins, NULL);
+#endif
}
+
void
updatenumlockmask(void)
{
None);
} else
XGrabButton(display, AnyButton, AnyModifier, win->id, False,
- BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
-}
-
-void
-expose(XEvent *e)
-{
- DNPRINTF(SWM_D_EVENT, "expose: window: %lu\n", e->xexpose.window);
-}
-
-void
-keypress(XEvent *e)
-{
- unsigned int i;
- KeySym keysym;
- XKeyEvent *ev = &e->xkey;
-
- DNPRINTF(SWM_D_EVENT, "keypress: window: %lu\n", ev->window);
-
- keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0);
- for (i = 0; i < keys_length; i++)
- if (keysym == keys[i].keysym
- && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
- && keyfuncs[keys[i].funcid].func)
- keyfuncs[keys[i].funcid].func(
- root_to_region(ev->root),
- &(keyfuncs[keys[i].funcid].args)
- );
-}
-
-void
-buttonpress(XEvent *e)
-{
- XButtonPressedEvent *ev = &e->xbutton;
-
- struct ws_win *win;
- int i, action;
-
- DNPRINTF(SWM_D_EVENT, "buttonpress: window: %lu\n", ev->window);
-
- action = root_click;
- if ((win = find_window(ev->window)) == NULL)
- return;
- else {
- focus_win(win);
- action = client_click;
- }
-
- for (i = 0; i < LENGTH(buttons); i++)
- if (action == buttons[i].action && buttons[i].func &&
- buttons[i].button == ev->button &&
- CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
- buttons[i].func(win, &buttons[i].args);
-}
-
-void
-set_win_state(struct ws_win *win, long state)
-{
- long data[] = {state, None};
-
- DNPRINTF(SWM_D_EVENT, "set_win_state: window: %lu\n", win->id);
-
- XChangeProperty(display, win->id, astate, astate, 32, PropModeReplace,
- (unsigned char *)data, 2);
+ BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
}
const char *quirkname[] = {
{
char *cp, *name;
int i;
+
if (quirk == NULL)
- return (0);
+ return (1);
+
cp = qstr;
*quirk = 0;
while ((name = strsep(&cp, SWM_Q_WS)) != NULL) {
DNPRINTF(SWM_D_QUIRK, "parsequirks: %s\n", name);
if (i == 0) {
*quirk = 0;
- return (1);
+ return (0);
}
*quirk |= 1 << (i-1);
break;
if (i >= LENGTH(quirkname)) {
DNPRINTF(SWM_D_QUIRK,
"parsequirks: invalid quirk [%s]\n", name);
- return (0);
+ return (1);
}
}
- return (1);
+ return (0);
}
+
void
setquirk(const char *class, const char *name, const int quirk)
{
int i, j;
+
/* find existing */
for (i = 0; i < quirks_length; i++) {
if (!strcmp(quirks[i].class, class) &&
}
}
}
+
int
setconfquirk(char *selector, char *value, int flags)
{
*cp = '\0';
class = selector;
name = cp + 1;
- if ((retval = parsequirks(value, &quirks)))
+ if ((retval = parsequirks(value, &quirks)) == 0)
setquirk(class, name, quirks);
return (retval);
}
/* conf file stuff */
#define SWM_CONF_FILE "scrotwm.conf"
-enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_CLOCK_ENABLED,
- 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_BAR_FONT, SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP,
- SWM_S_DIALOG_RATIO };
+enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_STACK_ENABLED,
+ SWM_S_CLOCK_ENABLED, 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_BAR_FONT, SWM_S_BAR_ACTION,
+ SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO };
int
setconfvalue(char *selector, char *value, int flags)
case SWM_S_BAR_ENABLED:
bar_enabled = atoi(value);
break;
+ case SWM_S_STACK_ENABLED:
+ stack_enabled = atoi(value);
+ break;
case SWM_S_CLOCK_ENABLED:
clock_enabled = atoi(value);
break;
title_name_enabled = atoi(value);
break;
case SWM_S_BAR_FONT:
- bar_fonts[0] = strdup(value);
+ free(bar_fonts[0]);
+ if ((bar_fonts[0] = strdup(value)) == NULL)
+ err(1, "setconfvalue: bar_font");
break;
case SWM_S_BAR_ACTION:
- bar_argv[0] = strdup(value);
+ free(bar_argv[0]);
+ if ((bar_argv[0] = strdup(value)) == NULL)
+ err(1, "setconfvalue: bar_action");
break;
case SWM_S_SPAWN_TERM:
- spawn_term[0] = strdup(value);
+ free(spawn_term[0]);
+ if ((spawn_term[0] = strdup(value)) == NULL)
+ err(1, "setconfvalue: spawn_term");
break;
case SWM_S_SS_APP:
- spawn_screenshot[0] = strdup(value);
break;
case SWM_S_DIALOG_RATIO:
dialog_ratio = atof(value);
dialog_ratio = .6;
break;
default:
- return (0);
+ return (1);
}
- return (1);
+ return (0);
}
int
else if (!strncasecmp(value, "Mod4", strlen("Mod4")))
update_modkey(Mod4Mask);
else
- return (0);
- return (1);
+ return (1);
+ return (0);
}
int
setconfcolor(char *selector, char *value, int flags)
{
setscreencolor(value, ((selector == NULL)?-1:atoi(selector)), flags);
- return (1);
+ return (0);
}
int
setconfregion(char *selector, char *value, int flags)
{
custom_region(value);
- return (1);
+ return (0);
}
/* config options */
{ "bar_action", setconfvalue, SWM_S_BAR_ACTION },
{ "bar_delay", setconfvalue, SWM_S_BAR_DELAY },
{ "bind", setconfbinding, 0 },
+ { "stack_enabled", setconfvalue, SWM_S_STACK_ENABLED },
{ "clock_enabled", setconfvalue, SWM_S_CLOCK_ENABLED },
{ "color_focus", setconfcolor, SWM_S_COLOR_FOCUS },
{ "color_unfocus", setconfcolor, SWM_S_COLOR_UNFOCUS },
{ "cycle_visible", setconfvalue, SWM_S_CYCLE_VISIBLE },
{ "dialog_ratio", setconfvalue, SWM_S_DIALOG_RATIO },
{ "modkey", setconfmodkey, 0 },
+ { "program", setconfspawn, 0 },
{ "quirk", setconfquirk, 0 },
{ "region", setconfregion, 0 },
{ "spawn_term", setconfvalue, SWM_S_SPAWN_TERM },
size_t linelen, lineno = 0;
int wordlen, i, optind;
struct config_option *opt;
- if (filename == NULL)
- return (0);
- if ((config = fopen(filename, "r")) == NULL)
- return (0);
+
+ DNPRINTF(SWM_D_CONF, "conf_load begin\n");
+
+ if (filename == NULL) {
+ fprintf(stderr, "conf_load: no filename\n");
+ return (1);
+ }
+ if ((config = fopen(filename, "r")) == NULL) {
+ warn("conf_load: fopen");
+ return (1);
+ }
+
while (!feof(config)) {
if ((line = fparseln(config, &linelen, &lineno, NULL, 0))
== NULL) {
}
/* get config option */
wordlen = strcspn(cp, "=[ \t\n");
- if (!wordlen) {
+ if (wordlen == 0) {
warnx("%s: line %zd: no option found",
filename, lineno);
- return (0);
+ return (1);
}
optind = -1;
for (i = 0; i < LENGTH(configopt); i++) {
if (optind == -1) {
warnx("%s: line %zd: unknown option %.*s",
filename, lineno, wordlen, cp);
- return (0);
+ return (1);
}
cp += wordlen;
cp += strspn(cp, " \t\n"); /* eat whitespace */
if (*cp == '[') {
cp++;
wordlen = strcspn(cp, "]");
- if (!wordlen) {
- warnx("%s: line %zd: syntax error",
- filename, lineno);
- return (0);
+ if (*cp != ']') {
+ if (wordlen == 0) {
+ warnx("%s: line %zd: syntax error",
+ filename, lineno);
+ return (1);
+ }
+ asprintf(&optsub, "%.*s", wordlen, cp);
}
- asprintf(&optsub, "%.*s", wordlen, cp);
cp += wordlen;
cp += strspn(cp, "] \t\n"); /* eat trailing */
}
/* get RHS value */
optval = strdup(cp);
/* call function to deal with it all */
- if (!configopt[optind].func(optsub, optval,
- configopt[optind].funcflags))
+ if (configopt[optind].func(optsub, optval,
+ configopt[optind].funcflags) != 0) {
+ fprintf(stderr, "%s line %zd: %s\n",
+ filename, lineno, line);
errx(1, "%s: line %zd: invalid data for %s",
filename, lineno, configopt[optind].optname);
+ }
free(optval);
free(optsub);
free(line);
}
- return (1);
+
+ fclose(config);
+ DNPRINTF(SWM_D_CONF, "conf_load end\n");
+
+ return (0);
+}
+
+void
+set_child_transient(struct ws_win *win)
+{
+ struct ws_win *parent;
+
+ parent = find_window(win->transient);
+ if (parent)
+ parent->child_trans = win;
}
struct ws_win *
manage_window(Window id)
{
- Window trans;
+ Window trans = 0;
struct workspace *ws;
- struct ws_win *win;
- int format, i, ws_idx, n;
+ struct ws_win *win, *ww;
+ int format, i, ws_idx, n, border_me = 0;
unsigned long nitems, bytes;
Atom ws_idx_atom = 0, type;
Atom *prot = NULL, *pp;
XWindowChanges wc;
if ((win = find_window(id)) != NULL)
- return (win); /* already being managed */
+ return (win); /* already being managed */
+
+ /* see if we are on the unmanaged list */
+ if ((win = find_unmanaged_window(id)) != NULL) {
+ DNPRINTF(SWM_D_MISC, "manage previously unmanaged window "
+ "%lu\n", win->id);
+ TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry);
+ TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry);
+ if (win->transient)
+ set_child_transient(win);
+ return (win);
+ }
if ((win = calloc(1, sizeof(struct ws_win))) == NULL)
errx(1, "calloc: failed to allocate memory for new window");
XGetWindowProperty(display, id, ws_idx_atom, 0, SWM_PROPLEN,
False, XA_STRING, &type, &format, &nitems, &bytes, &prop);
XGetWindowAttributes(display, id, &win->wa);
+ XGetWMNormalHints(display, id, &win->sh, &mask);
XGetTransientForHint(display, id, &trans);
- XGetWMNormalHints(display, id, &win->sh, &mask); /* XXX function? */
if (trans) {
win->transient = trans;
- DNPRINTF(SWM_D_MISC, "manage_window: win %u transient %u\n",
- (unsigned)win->id, win->transient);
+ set_child_transient(win);
+ DNPRINTF(SWM_D_MISC, "manage_window: win %lu transient %lu\n",
+ win->id, win->transient);
}
/* get supported protocols */
if (XGetWMProtocols(display, id, &prot, &n)) {
- for (i = 0, pp = prot; i < n; i++, pp++)
+ for (i = 0, pp = prot; i < n; i++, pp++) {
+ if (*pp == takefocus)
+ win->take_focus = 1;
if (*pp == adelete)
win->can_delete = 1;
+ }
if (prot)
XFree(prot);
}
errstr, prop);
}
ws = &r->s->ws[ws_idx];
- } else
+ } else {
ws = r->ws;
+ /* this should launch transients in the same ws as parent */
+ if (id && trans)
+ if ((ww = find_window(trans)) != NULL)
+ if (ws->r) {
+ ws = ww->ws;
+ if (ww->ws->r)
+ r = ww->ws->r;
+ else
+ fprintf(stderr,
+ "fix this bug mcbride\n");
+ border_me = 1;
+ }
+ }
/* set up the window layout */
win->id = id;
if (XGetClassHint(display, win->id, &win->ch)) {
DNPRINTF(SWM_D_CLASS, "class: %s name: %s\n",
win->ch.res_class, win->ch.res_name);
+
+ /* java is retarded so treat it special */
+ if (strstr(win->ch.res_name, "sun-awt")) {
+ win->java = 1;
+ border_me = 1;
+ }
+
for (i = 0; i < quirks_length; i++){
if (!strcmp(win->ch.res_class, quirks[i].class) &&
!strcmp(win->ch.res_name, quirks[i].name)) {
DNPRINTF(SWM_D_CLASS, "found: %s name: %s\n",
win->ch.res_class, win->ch.res_name);
- if (quirks[i].quirk & SWM_Q_FLOAT)
+ if (quirks[i].quirk & SWM_Q_FLOAT) {
win->floating = 1;
+ border_me = 1;
+ }
win->quirks = quirks[i].quirk;
}
}
mask |= CWY;
}
if (win->g.w + win->g.x > WIDTH(r)) {
- win->g.x = wc.x = WIDTH(win->ws->r) - win->g.w - 2;
+ win->g.x = wc.x = WIDTH(r) - win->g.w - 2;
mask |= CWX;
}
- wc.border_width = 1;
- mask |= CWBorderWidth;
- XConfigureWindow(display, win->id, mask, &wc);
+ border_me = 1;
}
/* Reset font sizes (the bruteforce way; no default keybinding). */
fake_keypress(win, XK_KP_Add, ShiftMask);
}
+ /* border me */
+ if (border_me) {
+ bzero(&wc, sizeof wc);
+ wc.border_width = 1;
+ mask = CWBorderWidth;
+ XConfigureWindow(display, win->id, mask, &wc);
+ configreq_win(win);
+ }
+
XSelectInput(display, id, EnterWindowMask | FocusChangeMask |
PropertyChangeMask | StructureNotifyMask);
set_win_state(win, NormalState);
/* floaters need to be mapped if they are in the current workspace */
- if (win->floating && (ws->idx == r->ws->idx))
+ if ((win->floating || win->transient) && (ws->idx == r->ws->idx))
XMapRaised(display, win->id);
- /* make new win focused */
- focus_win(win);
-
return (win);
}
void
-unmanage_window(struct ws_win *win)
+free_window(struct ws_win *win)
{
- struct workspace *ws;
+ DNPRINTF(SWM_D_MISC, "free_window: %lu\n", win->id);
if (win == NULL)
return;
- 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;
+ /* needed for restart wm */
+ set_win_state(win, WithdrawnState);
- /* 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->unmanagedlist, win, entry);
- TAILQ_REMOVE(&win->ws->winlist, win, entry);
- set_win_state(win, WithdrawnState);
if (win->ch.res_class)
XFree(win->ch.res_class);
if (win->ch.res_name)
XFree(win->ch.res_name);
+
+ kill_refs(win);
+
+ /* paint memory */
+ memset(win, 0xff, sizeof *win); /* XXX kill later */
+
free(win);
}
void
+unmanage_window(struct ws_win *win)
+{
+ struct ws_win *parent;
+
+ if (win == NULL)
+ return;
+
+ DNPRINTF(SWM_D_MISC, "unmanage_window: %lu\n", win->id);
+
+ if (win->transient) {
+ parent = find_window(win->transient);
+ if (parent)
+ parent->child_trans = NULL;
+ }
+
+ focus_prev(win);
+ TAILQ_REMOVE(&win->ws->winlist, win, entry);
+ TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry);
+
+ kill_refs(win);
+}
+
+void
+focus_magic(struct ws_win *win, int do_trans)
+{
+ DNPRINTF(SWM_D_FOCUS, "focus_magic: %lu %d\n", WINID(win), do_trans);
+
+ if (win == NULL)
+ return;
+
+ if (do_trans == SWM_F_TRANSIENT && win->child_trans) {
+ /* win = parent & has a transient so focus on that */
+ if (win->java) {
+ focus_win(win->child_trans);
+ if (win->child_trans->take_focus)
+ client_msg(win, takefocus);
+ } else {
+ focus_win(win->child_trans);
+ if (win->child_trans->take_focus)
+ client_msg(win->child_trans, takefocus);
+ }
+ } else {
+ /* regular focus */
+ focus_win(win);
+ if (win->take_focus)
+ client_msg(win, takefocus);
+ }
+}
+
+void
+expose(XEvent *e)
+{
+ DNPRINTF(SWM_D_EVENT, "expose: window: %lu\n", e->xexpose.window);
+}
+
+void
+keypress(XEvent *e)
+{
+ unsigned int i;
+ KeySym keysym;
+ XKeyEvent *ev = &e->xkey;
+
+ DNPRINTF(SWM_D_EVENT, "keypress: window: %lu\n", ev->window);
+
+ keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0);
+ for (i = 0; i < keys_length; i++)
+ if (keysym == keys[i].keysym
+ && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
+ && keyfuncs[keys[i].funcid].func) {
+ if (keys[i].funcid == kf_spawn_custom)
+ spawn_custom(
+ root_to_region(ev->root),
+ &(keyfuncs[keys[i].funcid].args),
+ keys[i].spawn_name
+ );
+ else
+ keyfuncs[keys[i].funcid].func(
+ root_to_region(ev->root),
+ &(keyfuncs[keys[i].funcid].args)
+ );
+ }
+}
+
+void
+buttonpress(XEvent *e)
+{
+ struct ws_win *win;
+ int i, action;
+ XButtonPressedEvent *ev = &e->xbutton;
+
+ DNPRINTF(SWM_D_EVENT, "buttonpress: window: %lu\n", ev->window);
+
+ action = root_click;
+ if ((win = find_window(ev->window)) == NULL)
+ return;
+
+ focus_magic(win, SWM_F_TRANSIENT);
+ action = client_click;
+
+ for (i = 0; i < LENGTH(buttons); i++)
+ if (action == buttons[i].action && buttons[i].func &&
+ buttons[i].button == ev->button &&
+ CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
+ buttons[i].func(win, &buttons[i].args);
+}
+
+void
configurerequest(XEvent *e)
{
XConfigureRequestEvent *ev = &e->xconfigurerequest;
XWindowChanges wc;
if ((win = find_window(ev->window)) == NULL)
- new = 1;
+ if ((win = find_unmanaged_window(ev->window)) == NULL)
+ new = 1;
if (new) {
DNPRINTF(SWM_D_EVENT, "configurerequest: new window: %lu\n",
win->g.w = ev->width;
if (ev->value_mask & CWHeight)
win->g.h = ev->height;
- if (win->ws->r != NULL) {
- /* this seems to be full screen */
- if (win->g.w >= WIDTH(win->ws->r)) {
- win->g.x = 0;
- win->g.w = WIDTH(win->ws->r);
- ev->value_mask |= CWX | CWWidth;
- }
- if (win->g.h >= HEIGHT(win->ws->r)) {
- /* kill border */
- win->g.y = 0;
- win->g.h = HEIGHT(win->ws->r);
- ev->value_mask |= CWY | CWHeight;
- }
- }
- if ((ev->value_mask & (CWX | CWY)) &&
- !(ev->value_mask & (CWWidth | CWHeight)))
- config_win(win);
- XMoveResizeWindow(display, win->id,
- win->g.x, win->g.y, win->g.w, win->g.h);
- } else
- config_win(win);
+ }
+ config_win(win);
}
}
DNPRINTF(SWM_D_EVENT, "configurenotify: window: %lu\n",
e->xconfigure.window);
- XMapWindow(display, e->xconfigure.window);
win = find_window(e->xconfigure.window);
if (win) {
XGetWMNormalHints(display, win->id, &win->sh, &mask);
adjust_font(win);
- XMapWindow(display, win->id);
if (font_adjusted)
stack();
}
DNPRINTF(SWM_D_EVENT, "destroynotify: window %lu\n", ev->window);
- if ((win = find_window(ev->window)) != NULL) {
- unmanage_window(win);
- stack();
+ if ((win = find_window(ev->window)) == NULL) {
+ if ((win = find_unmanaged_window(ev->window)) == NULL)
+ return;
+ free_window(win);
+ return;
}
+
+ unmanage_window(win);
+ stack();
+ free_window(win);
}
void
DNPRINTF(SWM_D_EVENT, "enternotify: window: %lu\n", ev->window);
- if (ignore_enter) {
- /* eat event(r) to prevent autofocus */
- ignore_enter--;
+ /*
+ * 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)
return;
- }
- if ((win = find_window(ev->window)) != NULL)
- focus_win(win);
+ focus_magic(win, SWM_F_TRANSIENT);
}
void
focusout(XEvent *e)
{
DNPRINTF(SWM_D_EVENT, "focusout: window: %lu\n", e->xfocus.window);
+}
+
+void
+mapnotify(XEvent *e)
+{
+ struct ws_win *win;
+ XMapEvent *ev = &e->xmap;
- 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;
+ DNPRINTF(SWM_D_EVENT, "mapnotify: window: %lu\n", ev->window);
- /* 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);
- }
- }
+ win = manage_window(ev->window);
+ if (win)
+ set_win_state(win, NormalState);
}
void
{
XMappingEvent *ev = &e->xmapping;
- DNPRINTF(SWM_D_EVENT, "mappingnotify: window: %lu\n", ev->window);
-
XRefreshKeyboardMapping(ev);
if (ev->request == MappingKeyboard)
grabkeys();
void
maprequest(XEvent *e)
{
- XMapRequestEvent *ev = &e->xmaprequest;
+ struct ws_win *win;
+ struct swm_region *r;
XWindowAttributes wa;
+ XMapRequestEvent *ev = &e->xmaprequest;
DNPRINTF(SWM_D_EVENT, "maprequest: window: %lu\n",
e->xmaprequest.window);
return;
if (wa.override_redirect)
return;
- manage_window(e->xmaprequest.window);
+
+ win = manage_window(e->xmaprequest.window);
+ if (win == NULL)
+ return; /* can't happen */
stack();
+
+ /* make new win focused */
+ r = root_to_region(win->wa.root);
+ if (win->ws == r->ws)
+ focus_magic(win, SWM_F_GENERIC);
}
void
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);
+ /* determine if we need to help unmanage this window */
+ win = find_window(e->xunmap.window);
+ if (win == NULL)
+ return;
+
+ /*
+ * XXX this is a work around for going fullscreen on mplayer
+ * remove this and find a better heuristic
+ */
+ if (win->floating)
+ return;
+
+ if (getstate(e->xunmap.window) == NormalState) {
+ unmanage_window(win);
+ stack();
+ }
}
void
DNPRINTF(SWM_D_EVENT, "visibilitynotify: window: %lu\n",
e->xvisibility.window);
if (e->xvisibility.state == VisibilityUnobscured)
- for (i = 0; i < ScreenCount(display); i++)
+ for (i = 0; i < ScreenCount(display); i++)
TAILQ_FOREACH(r, &screens[i].rl, entry)
if (e->xvisibility.window == r->bar_window)
bar_update();
return (0);
}
-long
-getstate(Window w)
-{
- int format, status;
- long result = -1;
- unsigned char *p = NULL;
- unsigned long n, extra;
- Atom real;
-
- status = XGetWindowProperty(display, w, astate, 0L, 2L, False, astate,
- &real, &format, &n, &extra, (unsigned char **)&p);
- if (status != Success)
- return (-1);
- if (n != 0)
- result = *((long *)p);
- XFree(p);
- return (result);
-}
-
void
new_region(struct swm_screen *s, int x, int y, int w, int h)
{
/* remove any old regions */
while ((r = TAILQ_FIRST(&screens[i].rl)) != NULL) {
- r->ws->r = NULL;
+ r->ws->old_r = r->ws->r = NULL;
XDestroyWindow(display, r->bar_window);
TAILQ_REMOVE(&screens[i].rl, r, entry);
TAILQ_INSERT_TAIL(&screens[i].orl, r, entry);
/* 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)
new_region(&screens[i], 0, 0,
DisplayWidth(display, i),
- DisplayHeight(display, i));
- else
+ DisplayHeight(display, i));
+ else
ncrtc = sr->ncrtc;
for (c = 0, ci = NULL; c < ncrtc; c++) {
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,
DisplayWidth(display, i),
- DisplayHeight(display, i));
+ DisplayHeight(display, i));
else
new_region(&screens[i],
ci->x, ci->y, ci->width, ci->height);
#endif /* SWM_XRR_HAS_CRTC */
{
new_region(&screens[i], 0, 0, DisplayWidth(display, i),
- DisplayHeight(display, i));
+ DisplayHeight(display, i));
}
}
screenchange(XEvent *e) {
XRRScreenChangeNotifyEvent *xe = (XRRScreenChangeNotifyEvent *)e;
struct swm_region *r;
- struct ws_win *win;
int i;
DNPRINTF(SWM_D_EVENT, "screenchange: %lu\n", xe->root);
/* brute force for now, just re-enumerate the regions */
scan_xrandr(i);
- /* hide any windows that went away */
- TAILQ_FOREACH(r, &screens[i].rl, entry)
- TAILQ_FOREACH(win, &r->ws->winlist, entry)
- XUnmapWindow(display, win->id);
-
/* add bars to all regions */
for (i = 0; i < ScreenCount(display); i++)
TAILQ_FOREACH(r, &screens[i].rl, entry)
int errorbase, major, minor;
struct workspace *ws;
int ws_idx_atom;
-
+ long state, manage;
if ((screens = calloc(ScreenCount(display),
sizeof(struct swm_screen))) == NULL)
&xrandr_eventbase, &errorbase);
if (xrandr_support)
if (XRRQueryVersion(display, &major, &minor) && major < 1)
- xrandr_support = 0;
+ xrandr_support = 0;
/* map physical screens */
for (i = 0; i < ScreenCount(display); i++) {
for (j = 0; j < SWM_WS_MAX; j++) {
ws = &screens[i].ws[j];
ws->idx = j;
- ws->restack = 1;
ws->focus = NULL;
ws->r = NULL;
+ ws->old_r = NULL;
TAILQ_INIT(&ws->winlist);
+ TAILQ_INIT(&ws->unmanagedlist);
for (k = 0; layouts[k].l_stack != NULL; k++)
if (layouts[k].l_config != NULL)
/* attach windows to a region */
/* normal windows */
for (j = 0; j < no; j++) {
- XGetWindowAttributes(display, wins[j], &wa);
if (!XGetWindowAttributes(display, wins[j], &wa) ||
wa.override_redirect ||
XGetTransientForHint(display, wins[j], &d1))
continue;
- if (wa.map_state == IsViewable ||
- getstate(wins[j]) == NormalState)
+ state = getstate(wins[j]);
+ manage = state == IconicState;
+ if (wa.map_state == IsViewable || manage)
manage_window(wins[j]);
}
/* transient windows */
for (j = 0; j < no; j++) {
- if (!XGetWindowAttributes(display, wins[j], &wa))
+ if (!XGetWindowAttributes(display, wins[j], &wa) ||
+ wa.override_redirect)
continue;
+ state = getstate(wins[j]);
+ manage = state == IconicState;
if (XGetTransientForHint(display, wins[j], &d1) &&
- (wa.map_state == IsViewable || getstate(wins[j]) ==
- NormalState))
+ manage)
manage_window(wins[j]);
}
if (wins) {
}
void
+setup_globals(void)
+{
+ if ((bar_fonts[0] = strdup("-*-terminus-medium-*-*-*-*-*-*-*-*-*-*-*"))
+ == NULL)
+ err(1, "setup_globals: strdup");
+ if ((bar_fonts[1] = strdup("-*-times-medium-r-*-*-*-*-*-*-*-*-*-*"))
+ == NULL)
+ err(1, "setup_globals: strdup");
+ if ((bar_fonts[2] = strdup("-misc-fixed-medium-r-*-*-*-*-*-*-*-*-*-*"))
+ == NULL)
+ err(1, "setup_globals: strdup");
+ if ((spawn_term[0] = strdup("xterm")) == NULL)
+ err(1, "setup_globals: strdup");
+}
+
+void
workaround(void)
{
int i;
main(int argc, char *argv[])
{
struct passwd *pwd;
- struct swm_region *r;
+ struct swm_region *r, *rr;
+ struct ws_win *winfocus = NULL;
+ struct timeval tv;
+ union arg a;
char conf[PATH_MAX], *cfile = NULL;
struct stat sb;
XEvent e;
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);
+ takefocus = XInternAtom(display, "WM_TAKE_FOCUS", False);
/* look for local and global conf file */
pwd = getpwuid(getuid());
errx(1, "invalid user %d", getuid());
setup_screens();
+ setup_globals();
setup_keys();
setup_quirks();
+ setup_spawn();
snprintf(conf, sizeof conf, "%s/.%s", pwd->pw_dir, SWM_CONF_FILE);
if (stat(conf, &sb) != -1) {
/* 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();
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 (running == 0)
+ goto done;
if (e.type < LASTEvent) {
+ dumpevent(&e);
if (handler[e.type])
handler[e.type](&e);
else
}
}
}
+
+ /* if we are being restarted go focus on first window */
+ if (winfocus) {
+ rr = winfocus->ws->r;
+ if (rr == NULL) {
+ /* not a visible window */
+ winfocus = NULL;
+ continue;
+ }
+ /* move pointer to first screen if multi 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);
+
+ a.id = SWM_ARG_ID_FOCUSCUR;
+ focus(rr, &a);
+ winfocus = NULL;
+ continue;
+ }
+
+ FD_ZERO(&rd);
+ FD_SET(xfd, &rd);
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ if (select(xfd + 1, &rd, NULL, NULL, &tv) == -1)
+ if (errno != EINTR)
+ DNPRINTF(SWM_D_MISC, "select failed");
+ if (running == 0)
+ goto done;
+ if (bar_alarm) {
+ bar_alarm = 0;
+ bar_update();
+ }
}
+done:
+ bar_extra_stop();
XCloseDisplay(display);