+ unsigned int mask = 0;
+ unsigned int changed = 0;
+ unsigned int orig_flags;
+
+ if (win == NULL)
+ return;
+
+ if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom)
+ mask = EWMH_F_FULLSCREEN;
+ if (state == ewmh[_NET_WM_STATE_ABOVE].atom)
+ mask = EWMH_F_ABOVE;
+ if (state == ewmh[_SWM_WM_STATE_MANUAL].atom)
+ mask = SWM_F_MANUAL;
+ if (state == ewmh[_NET_WM_STATE_SKIP_PAGER].atom)
+ mask = EWMH_F_SKIP_PAGER;
+ if (state == ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom)
+ mask = EWMH_F_SKIP_TASKBAR;
+
+
+ orig_flags = win->ewmh_flags;
+
+ switch (action) {
+ case _NET_WM_STATE_REMOVE:
+ win->ewmh_flags &= ~mask;
+ break;
+ case _NET_WM_STATE_ADD:
+ win->ewmh_flags |= mask;
+ break;
+ case _NET_WM_STATE_TOGGLE:
+ win->ewmh_flags ^= mask;
+ break;
+ }
+
+ changed = (win->ewmh_flags & mask) ^ (orig_flags & mask) ? 1 : 0;
+
+ if (state == ewmh[_NET_WM_STATE_ABOVE].atom)
+ if (changed)
+ if (!floating_toggle_win(win))
+ win->ewmh_flags = orig_flags; /* revert */
+ if (state == ewmh[_SWM_WM_STATE_MANUAL].atom)
+ if (changed)
+ win->manual = (win->ewmh_flags & SWM_F_MANUAL) != 0;
+ if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom)
+ if (changed)
+ if (!ewmh_set_win_fullscreen(win,
+ win->ewmh_flags & EWMH_F_FULLSCREEN))
+ win->ewmh_flags = orig_flags; /* revert */
+
+ XDeleteProperty(display, win->id, ewmh[_NET_WM_STATE].atom);
+
+ if (win->ewmh_flags & EWMH_F_FULLSCREEN)
+ XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom,
+ XA_ATOM, 32, PropModeAppend,
+ (unsigned char *)&ewmh[_NET_WM_STATE_FULLSCREEN].atom, 1);
+ if (win->ewmh_flags & EWMH_F_SKIP_PAGER)
+ XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom,
+ XA_ATOM, 32, PropModeAppend,
+ (unsigned char *)&ewmh[_NET_WM_STATE_SKIP_PAGER].atom, 1);
+ if (win->ewmh_flags & EWMH_F_SKIP_TASKBAR)
+ XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom,
+ XA_ATOM, 32, PropModeAppend,
+ (unsigned char *)&ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom, 1);
+ if (win->ewmh_flags & EWMH_F_ABOVE)
+ XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom,
+ XA_ATOM, 32, PropModeAppend,
+ (unsigned char *)&ewmh[_NET_WM_STATE_ABOVE].atom, 1);
+ if (win->ewmh_flags & SWM_F_MANUAL)
+ XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom,
+ XA_ATOM, 32, PropModeAppend,
+ (unsigned char *)&ewmh[_SWM_WM_STATE_MANUAL].atom, 1);
+}
+
+void
+ewmh_get_win_state(struct ws_win *win)
+{
+ int success, i;
+ unsigned long n;
+ Atom *states;
+
+ if (win == NULL)
+ return;
+
+ win->ewmh_flags = 0;
+ if (win->floating)
+ win->ewmh_flags |= EWMH_F_ABOVE;
+ if (win->manual)
+ win->ewmh_flags |= SWM_F_MANUAL;
+
+ success = get_property(win->id, ewmh[_NET_WM_STATE].atom,
+ (~0L), XA_ATOM, &n, (void *)&states);
+
+ if (!success)
+ return;
+
+ for (i = 0; i < n; i++)
+ ewmh_update_win_state(win, states[i], _NET_WM_STATE_ADD);
+
+ XFree(states);
+}
+
+/* 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 "
+ "transient: %lu\n",
+ win->id, wa.map_state, state, win->transient);
+ }
+
+ 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 "
+ "transient: %lu\n",
+ win->id, wa.map_state, state, win->transient);
+ }
+
+ 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 configurerequest(XEvent *);
+void configurenotify(XEvent *);
+void destroynotify(XEvent *);
+void enternotify(XEvent *);
+void focusevent(XEvent *);
+void mapnotify(XEvent *);
+void mappingnotify(XEvent *);
+void maprequest(XEvent *);
+void propertynotify(XEvent *);
+void unmapnotify(XEvent *);
+void visibilitynotify(XEvent *);
+void clientmessage(XEvent *);
+
+void (*handler[LASTEvent])(XEvent *) = {
+ [Expose] = expose,
+ [KeyPress] = keypress,
+ [ButtonPress] = buttonpress,
+ [ConfigureRequest] = configurerequest,
+ [ConfigureNotify] = configurenotify,
+ [DestroyNotify] = destroynotify,
+ [EnterNotify] = enternotify,
+ [FocusIn] = focusevent,
+ [FocusOut] = focusevent,
+ [MapNotify] = mapnotify,
+ [MappingNotify] = mappingnotify,
+ [MapRequest] = maprequest,
+ [PropertyNotify] = propertynotify,
+ [UnmapNotify] = unmapnotify,
+ [VisibilityNotify] = visibilitynotify,
+ [ClientMessage] = clientmessage,
+};
+
+void
+sighdlr(int sig)
+{
+ int saved_errno, status;
+ pid_t pid;
+
+ saved_errno = errno;
+
+ switch (sig) {
+ case SIGCHLD:
+ while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) != 0) {
+ if (pid == -1) {
+ if (errno == EINTR)
+ continue;
+#ifdef SWM_DEBUG
+ if (errno != ECHILD)
+ warn("sighdlr: waitpid");
+#endif /* SWM_DEBUG */
+ break;
+ }
+ if (pid == searchpid)
+ search_resp = 1;
+
+#ifdef SWM_DEBUG
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0)
+ warnx("sighdlr: child exit status: %d",
+ WEXITSTATUS(status));
+ } else
+ warnx("sighdlr: child is terminated "
+ "abnormally");
+#endif /* SWM_DEBUG */
+ }
+ break;
+
+ case SIGHUP:
+ restart_wm = 1;
+ break;
+ case SIGINT:
+ case SIGTERM:
+ case SIGQUIT:
+ running = 0;
+ break;
+ }
+
+ 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)
+{
+ Colormap cmap;
+ Status status;
+ XColor screen_def, exact_def;
+ unsigned long result = 0;
+ char cname[32] = "#";
+
+ cmap = DefaultColormap(display, screens[0].idx);
+ status = XAllocNamedColor(display, cmap, colorname,
+ &screen_def, &exact_def);
+ if (!status) {
+ strlcat(cname, colorname + 2, sizeof cname - 1);
+ status = XAllocNamedColor(display, cmap, cname, &screen_def,
+ &exact_def);
+ }
+ if (status)
+ result = screen_def.pixel;
+ else
+ fprintf(stderr, "color '%s' not found.\n", colorname);
+
+ return (result);
+}
+
+void
+setscreencolor(char *val, int i, int c)
+{
+ 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++) {
+ 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");
+ }
+ } else
+ errx(1, "invalid screen index: %d out of bounds (maximum %d)\n",
+ i, ScreenCount(display));
+}
+
+void
+fancy_stacker(struct workspace *ws)
+{
+ strlcpy(ws->stacker, "[ ]", sizeof ws->stacker);
+ if (ws->cur_layout->l_stack == vertical_stack)
+ snprintf(ws->stacker, sizeof ws->stacker, "[%d|%d]",
+ ws->l_state.vertical_mwin, ws->l_state.vertical_stacks);
+ if (ws->cur_layout->l_stack == horizontal_stack)
+ snprintf(ws->stacker, sizeof ws->stacker, "[%d-%d]",
+ ws->l_state.horizontal_mwin, ws->l_state.horizontal_stacks);
+}
+
+void
+plain_stacker(struct workspace *ws)
+{
+ strlcpy(ws->stacker, "[ ]", sizeof ws->stacker);
+ if (ws->cur_layout->l_stack == vertical_stack)
+ strlcpy(ws->stacker, "[|]", sizeof ws->stacker);
+ if (ws->cur_layout->l_stack == horizontal_stack)
+ strlcpy(ws->stacker, "[-]", sizeof ws->stacker);
+}
+
+void
+custom_region(char *val)
+{
+ unsigned int sidx, x, y, w, h;
+
+ 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");
+ if (sidx < 1 || sidx > ScreenCount(display))
+ errx(1, "invalid screen index: %d out of bounds (maximum %d)\n",
+ sidx, ScreenCount(display));
+ sidx--;
+
+ if (w < 1 || h < 1)
+ errx(1, "region %ux%u+%u+%u too small\n", w, h, x, y);
+
+ if (x > DisplayWidth(display, sidx) ||
+ y > DisplayHeight(display, sidx) ||
+ w + x > DisplayWidth(display, sidx) ||
+ h + y > DisplayHeight(display, sidx)) {
+ fprintf(stderr, "ignoring region %ux%u+%u+%u "
+ "- not within screen boundaries "
+ "(%ux%u)\n", w, h, x, y,
+ DisplayWidth(display, sidx), DisplayHeight(display, sidx));
+ return;
+ }
+
+ new_region(&screens[sidx], x, y, w, h);
+}
+
+void
+socket_setnonblock(int fd)
+{
+ int flags;
+
+ if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
+ err(1, "fcntl F_GETFL");
+ flags |= O_NONBLOCK;
+ if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
+ err(1, "fcntl F_SETFL");
+}
+
+void
+bar_print(struct swm_region *r, char *s)
+{
+ int textwidth, x;
+ size_t len;
+
+ XClearWindow(display, r->bar_window);
+ XSetForeground(display, bar_gc, r->s->c[SWM_S_COLOR_BAR_FONT].color);
+
+ len = strlen(s);
+ textwidth = XTextWidth(bar_fs, s, len);
+
+ switch (bar_justify) {
+ case SWM_BAR_JUSTIFY_LEFT:
+ x = SWM_BAR_OFFSET;
+ break;
+ case SWM_BAR_JUSTIFY_CENTER:
+ x = (WIDTH(r) - textwidth) / 2;
+ break;
+ case SWM_BAR_JUSTIFY_RIGHT:
+ x = WIDTH(r) - textwidth - SWM_BAR_OFFSET;
+ break;
+ }
+
+ if (x < SWM_BAR_OFFSET)
+ x = SWM_BAR_OFFSET;
+
+ XDrawString(display, r->bar_window, bar_gc, x, bar_fs->ascent, s, len);
+}
+
+void
+bar_extra_stop(void)
+{
+ if (bar_pipe[0]) {
+ close(bar_pipe[0]);