static const char *cvstag =
"$scrotwm$";
-#define SWM_VERSION "0.9.30"
+#define SWM_VERSION "0.9.32"
#include <stdio.h>
#include <stdlib.h>
};
TAILQ_HEAD(ws_win_list, ws_win);
+/* pid goo */
+struct pid_e {
+ TAILQ_ENTRY(pid_e) entry;
+ long pid;
+ int ws;
+};
+TAILQ_HEAD(pid_list, pid_e);
+struct pid_list pidlist = TAILQ_HEAD_INITIALIZER(pidlist);
+
/* layout handlers */
void stack(void);
void vertical_config(struct workspace *, int);
{ NULL, NULL, 0, NULL },
};
-/* position of max_stack mode in the layouts array */
-#define SWM_MAX_STACK 2
+/* position of max_stack mode in the layouts array, index into layouts! */
+#define SWM_V_STACK (0)
+#define SWM_H_STACK (1)
+#define SWM_MAX_STACK (2)
#define SWM_H_SLICE (32)
#define SWM_V_SLICE (32)
errno = saved_errno;
}
+struct pid_e *
+find_pid(long pid)
+{
+ struct pid_e *p = NULL;
+
+ DNPRINTF(SWM_D_MISC, "find_pid: %lu\n", pid);
+
+ if (pid == 0)
+ return (NULL);
+
+ TAILQ_FOREACH(p, &pidlist, entry) {
+ if (p->pid == pid)
+ return (p);
+ }
+
+ return (NULL);
+}
+
unsigned long
name_to_color(char *colorname)
{
}
void
-spawn(struct swm_region *r, union arg *args, int close_fd)
+spawn(int ws_idx, union arg *args, int close_fd)
{
int fd;
char *ret = NULL;
setenv("LD_PRELOAD", SWM_LIB, 1);
- if (asprintf(&ret, "%d", r->ws->idx) == -1) {
+ if (asprintf(&ret, "%d", ws_idx) == -1) {
perror("_SWM_WS");
_exit(1);
}
{
DNPRINTF(SWM_D_MISC, "spawnterm\n");
- if (term_width)
- setenv("_SWM_XTERM_FONTADJ", "", 1);
- if (fork() == 0)
- spawn(r, args, 1);
+ if (fork() == 0) {
+ if (term_width)
+ setenv("_SWM_XTERM_FONTADJ", "", 1);
+ spawn(r->ws->idx, args, 1);
+ }
}
void
return;
a.argv = real_args;
if (fork() == 0)
- spawn(r, &a, 1);
+ spawn(r->ws->idx, &a, 1);
for (i = 0; i < spawn_argc; i++)
free(real_args[i]);
errx(1, "dup2");
close(select_list_pipe[1]);
close(select_resp_pipe[0]);
- spawn(r, &a, 0);
+ spawn(r->ws->idx, &a, 0);
break;
default: /* parent */
close(select_list_pipe[0]);
return (0);
}
+int
+setautorun(char *selector, char *value, int flags)
+{
+ int ws_id;
+ char s[1024];
+ char *ap, *sp = s;
+ union arg a;
+ int argc = 0;
+ long pid;
+ struct pid_e *p;
+
+ if (getenv("SWM_STARTED"))
+ return (0);
+
+ 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");
+ ws_id--;
+ if (ws_id < 0 || ws_id >= SWM_WS_MAX)
+ errx(1, "autorun: invalid workspace %d\n", ws_id + 1);
+
+ /*
+ * This is a little intricate
+ *
+ * If the pid already exists we simply reuse it because it means it was
+ * used before AND not claimed by manage_window. We get away with
+ * altering it in the parent after INSERT because this can not be a race
+ */
+ a.argv = NULL;
+ while ((ap = strsep(&sp, " \t")) != NULL) {
+ if (*ap == '\0')
+ continue;
+ DNPRINTF(SWM_D_SPAWN, "setautorun: arg [%s]\n", ap);
+ argc++;
+ if ((a.argv = realloc(a.argv, argc * sizeof(char *))) == NULL)
+ err(1, "setautorun: realloc");
+ a.argv[argc - 1] = ap;
+ }
+
+ if ((a.argv = realloc(a.argv, (argc + 1) * sizeof(char *))) == NULL)
+ err(1, "setautorun: realloc");
+ a.argv[argc] = NULL;
+
+ if ((pid = fork()) == 0) {
+ spawn(ws_id, &a, 1);
+ /* NOTREACHED */
+ _exit(1);
+ }
+ free(a.argv);
+
+ /* parent */
+ p = find_pid(pid);
+ if (p == NULL) {
+ p = calloc(1, sizeof *p);
+ if (p == NULL)
+ return (1);
+ TAILQ_INSERT_TAIL(&pidlist, p, entry);
+ }
+
+ p->pid = pid;
+ p->ws = ws_id;
+
+ return (0);
+}
+
+int
+setlayout(char *selector, char *value, int flags)
+{
+ int ws_id, st, i;
+ char s[1024];
+ struct workspace *ws;
+
+ if (getenv("SWM_STARTED"))
+ return (0);
+
+ bzero(s, sizeof s);
+ if (sscanf(value, "ws[%d]:%1023c", &ws_id, s) != 2)
+ errx(1, "invalid layout entry, should be 'ws[<idx>]:<type>'\n");
+ ws_id--;
+ if (ws_id < 0 || ws_id >= SWM_WS_MAX)
+ errx(1, "layout: invalid workspace %d\n", ws_id + 1);
+
+ if (!strcasecmp(s, "vertical"))
+ st = SWM_V_STACK;
+ else if (!strcasecmp(s, "horizontal"))
+ st = SWM_H_STACK;
+ else if (!strcasecmp(s, "fullscreen"))
+ st = SWM_MAX_STACK;
+ else
+ errx(1, "invalid layout entry, should be 'ws[<idx>]:<type>'\n");
+
+ for (i = 0; i < ScreenCount(display); i++) {
+ ws = (struct workspace *)&screens[i].ws;
+ ws[ws_id].cur_layout = &layouts[st];
+ }
+
+ return (0);
+}
+
/* config options */
struct config_option {
char *optname;
- int (*func)(char*, char*, int);
- int funcflags;
+ int (*func)(char*, char*, int);
+ int funcflags;
};
struct config_option configopt[] = {
{ "bar_enabled", setconfvalue, SWM_S_BAR_ENABLED },
{ "bar_at_bottom", setconfvalue, SWM_S_BAR_AT_BOTTOM },
{ "bar_border", setconfcolor, SWM_S_COLOR_BAR_BORDER },
- { "bar_border_width", setconfvalue, SWM_S_BAR_BORDER_WIDTH },
+ { "bar_border_width", setconfvalue, SWM_S_BAR_BORDER_WIDTH },
{ "bar_color", setconfcolor, SWM_S_COLOR_BAR },
{ "bar_font_color", setconfcolor, SWM_S_COLOR_BAR_FONT },
{ "bar_font", setconfvalue, SWM_S_BAR_FONT },
{ "term_width", setconfvalue, SWM_S_TERM_WIDTH },
{ "title_class_enabled", setconfvalue, SWM_S_TITLE_CLASS_ENABLED },
{ "title_name_enabled", setconfvalue, SWM_S_TITLE_NAME_ENABLED },
- { "focus_mode", setconfvalue, SWM_S_FOCUS_MODE },
- { "disable_border", setconfvalue, SWM_S_DISABLE_BORDER },
- { "border_width", setconfvalue, SWM_S_BORDER_WIDTH },
+ { "focus_mode", setconfvalue, SWM_S_FOCUS_MODE },
+ { "disable_border", setconfvalue, SWM_S_DISABLE_BORDER },
+ { "border_width", setconfvalue, SWM_S_BORDER_WIDTH },
+ { "autorun", setautorun, 0 },
+ { "layout", setlayout, 0 },
};
XFree(wmh);
}
+long
+window_get_pid(Window win)
+{
+ Atom actual_type_return;
+ int actual_format_return = 0;
+ unsigned long nitems_return = 0;
+ unsigned long bytes_after_return = 0;
+ long *pid = NULL;
+ long ret = 0;
+ const char *errstr;
+ unsigned char *prop = NULL;
+
+ if (XGetWindowProperty(display, win,
+ XInternAtom(display, "_NET_WM_PID", False), 0, 1, False,
+ XA_CARDINAL, &actual_type_return, &actual_format_return,
+ &nitems_return, &bytes_after_return,
+ (unsigned char**)(void*)&pid) != Success)
+ goto tryharder;
+ if (actual_type_return != XA_CARDINAL)
+ goto tryharder;
+ if (pid == NULL)
+ goto tryharder;
+
+ ret = *pid;
+ XFree(pid);
+
+ return (ret);
+
+tryharder:
+ if (XGetWindowProperty(display, win,
+ XInternAtom(display, "_SWM_PID", False), 0, SWM_PROPLEN, False,
+ XA_STRING, &actual_type_return, &actual_format_return,
+ &nitems_return, &bytes_after_return, &prop) != Success)
+ return (0);
+ if (actual_type_return != XA_STRING)
+ return (0);
+ if (prop == NULL)
+ return (0);
+
+ ret = strtonum(prop, 0, UINT_MAX, &errstr);
+ /* ignore error because strtonum returns 0 anyway */
+ XFree(prop);
+
+ return (ret);
+}
+
struct ws_win *
manage_window(Window id)
{
long mask;
const char *errstr;
XWindowChanges wc;
+ struct pid_e *p;
if ((win = find_window(id)) != NULL)
return (win); /* already being managed */
win->id = id;
+ /* see if we need to override the workspace */
+ p = find_pid(window_get_pid(id));
+
/* Get all the window data in one shot */
ws_idx_atom = XInternAtom(display, "_SWM_WS", False);
- if (ws_idx_atom)
+ if (ws_idx_atom) {
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);
win->hints = XGetWMHints(display, id);
* transient, * put it in the same workspace
*/
r = root_to_region(win->wa.root);
- if (prop && win->transient == 0) {
+ if (p) {
+ ws = &r->s->ws[p->ws];
+ TAILQ_REMOVE(&pidlist, p, entry);
+ free(p);
+ p = NULL;
+ } else if (prop && win->transient == 0) {
DNPRINTF(SWM_D_PROP, "got property _SWM_WS=%s\n", prop);
ws_idx = strtonum(prop, 0, 9, &errstr);
if (errstr) {
int i, j, k;
int errorbase, major, minor;
struct workspace *ws;
- int ws_idx_atom;
if ((screens = calloc(ScreenCount(display),
sizeof(struct swm_screen))) == NULL)
errx(1, "calloc: screens");
- ws_idx_atom = XInternAtom(display, "_SWM_WS", False);
-
/* initial Xrandr setup */
xrandr_support = XRRQueryExtension(display,
&xrandr_eventbase, &errorbase);
if (cfile)
conf_load(cfile);
- custom_region("screen[1]:1280x1009+0+15");
-
setup_ewmh();
/* set some values to work around bad programs */
workaround();
/* grab existing windows (before we build the bars) */
grab_windows();
+ if (getenv("SWM_STARTED") == NULL)
+ setenv("SWM_STARTED", "YES", 1);
+
/* setup all bars */
for (i = 0; i < ScreenCount(display); i++)
TAILQ_FOREACH(r, &screens[i].rl, entry) {