2007-04-27 11:58:48 -06:00
|
|
|
/*
|
|
|
|
* calmwm - the calm window manager
|
|
|
|
*
|
|
|
|
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
|
|
|
|
*
|
2008-01-11 09:06:44 -07:00
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
2020-04-25 14:07:28 -06:00
|
|
|
* $OpenBSD: xutil.c,v 1.113 2020/04/25 20:07:28 tobias Exp $
|
2007-04-27 11:58:48 -06:00
|
|
|
*/
|
|
|
|
|
2015-01-19 07:54:16 -07:00
|
|
|
#include <sys/types.h>
|
2009-12-14 21:10:42 -07:00
|
|
|
#include <sys/queue.h>
|
|
|
|
|
|
|
|
#include <err.h>
|
|
|
|
#include <errno.h>
|
2015-01-19 07:54:16 -07:00
|
|
|
#include <limits.h>
|
2012-11-08 20:52:02 -07:00
|
|
|
#include <stdio.h>
|
2009-12-14 21:10:42 -07:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2007-04-27 11:58:48 -06:00
|
|
|
#include "calmwm.h"
|
|
|
|
|
2013-10-19 20:00:02 -06:00
|
|
|
void
|
2020-02-27 07:56:39 -07:00
|
|
|
xu_ptr_get(Window win, int *x, int *y)
|
2013-10-19 20:00:02 -06:00
|
|
|
{
|
2014-01-03 08:29:06 -07:00
|
|
|
Window w0, w1;
|
|
|
|
int tmp0, tmp1;
|
|
|
|
unsigned int tmp2;
|
2013-10-19 20:00:02 -06:00
|
|
|
|
|
|
|
XQueryPointer(X_Dpy, win, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-27 07:56:39 -07:00
|
|
|
xu_ptr_set(Window win, int x, int y)
|
2013-10-19 20:00:02 -06:00
|
|
|
{
|
|
|
|
XWarpPointer(X_Dpy, None, win, 0, 0, 0, 0, x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2020-02-27 07:56:39 -07:00
|
|
|
xu_get_prop(Window win, Atom atm, Atom type, long len, unsigned char **p)
|
2007-04-27 11:58:48 -06:00
|
|
|
{
|
2014-01-03 08:29:06 -07:00
|
|
|
Atom realtype;
|
|
|
|
unsigned long n, extra;
|
|
|
|
int format;
|
2007-04-27 11:58:48 -06:00
|
|
|
|
2010-04-11 10:51:26 -06:00
|
|
|
if (XGetWindowProperty(X_Dpy, win, atm, 0L, len, False, type,
|
2008-05-15 16:18:00 -06:00
|
|
|
&realtype, &format, &n, &extra, p) != Success || *p == NULL)
|
2020-02-27 07:56:39 -07:00
|
|
|
return -1;
|
2007-04-27 11:58:48 -06:00
|
|
|
|
|
|
|
if (n == 0)
|
|
|
|
XFree(*p);
|
|
|
|
|
2020-02-27 07:56:39 -07:00
|
|
|
return n;
|
2007-04-27 11:58:48 -06:00
|
|
|
}
|
|
|
|
|
2010-05-22 16:10:31 -06:00
|
|
|
int
|
2020-02-27 07:56:39 -07:00
|
|
|
xu_get_strprop(Window win, Atom atm, char **text) {
|
2010-05-22 16:10:31 -06:00
|
|
|
XTextProperty prop;
|
|
|
|
char **list;
|
2010-05-22 16:32:08 -06:00
|
|
|
int nitems = 0;
|
2010-05-22 16:10:31 -06:00
|
|
|
|
|
|
|
*text = NULL;
|
|
|
|
|
|
|
|
XGetTextProperty(X_Dpy, win, &prop, atm);
|
2020-04-25 14:07:28 -06:00
|
|
|
if (!prop.nitems) {
|
|
|
|
XFree(prop.value);
|
2020-02-27 07:56:39 -07:00
|
|
|
return 0;
|
2020-04-25 14:07:28 -06:00
|
|
|
}
|
2010-05-22 16:10:31 -06:00
|
|
|
|
|
|
|
if (Xutf8TextPropertyToTextList(X_Dpy, &prop, &list,
|
|
|
|
&nitems) == Success && nitems > 0 && *list) {
|
|
|
|
if (nitems > 1) {
|
|
|
|
XTextProperty prop2;
|
|
|
|
if (Xutf8TextListToTextProperty(X_Dpy, list, nitems,
|
|
|
|
XUTF8StringStyle, &prop2) == Success) {
|
2012-11-08 13:18:19 -07:00
|
|
|
*text = xstrdup((const char *)prop2.value);
|
2010-05-22 16:10:31 -06:00
|
|
|
XFree(prop2.value);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*text = xstrdup(*list);
|
|
|
|
}
|
|
|
|
XFreeStringList(list);
|
|
|
|
}
|
|
|
|
XFree(prop.value);
|
|
|
|
|
2020-02-27 07:56:39 -07:00
|
|
|
return nitems;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xu_send_clientmsg(Window win, Atom proto, Time ts)
|
|
|
|
{
|
|
|
|
XClientMessageEvent cm;
|
|
|
|
|
|
|
|
(void)memset(&cm, 0, sizeof(cm));
|
|
|
|
cm.type = ClientMessage;
|
|
|
|
cm.window = win;
|
|
|
|
cm.message_type = cwmh[WM_PROTOCOLS];
|
|
|
|
cm.format = 32;
|
|
|
|
cm.data.l[0] = proto;
|
|
|
|
cm.data.l[1] = ts;
|
|
|
|
|
|
|
|
XSendEvent(X_Dpy, win, False, NoEventMask, (XEvent *)&cm);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xu_get_wm_state(Window win, long *state)
|
|
|
|
{
|
|
|
|
long *p;
|
|
|
|
|
|
|
|
*state = -1;
|
|
|
|
if (xu_get_prop(win, cwmh[WM_STATE], cwmh[WM_STATE], 2L,
|
|
|
|
(unsigned char **)&p) > 0) {
|
|
|
|
*state = *p;
|
|
|
|
XFree(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xu_set_wm_state(Window win, long state)
|
|
|
|
{
|
|
|
|
long data[] = { state, None };
|
|
|
|
|
|
|
|
XChangeProperty(X_Dpy, win, cwmh[WM_STATE], cwmh[WM_STATE], 32,
|
|
|
|
PropModeReplace, (unsigned char *)data, 2);
|
|
|
|
}
|
|
|
|
void
|
|
|
|
xu_xorcolor(XftColor a, XftColor b, XftColor *r)
|
|
|
|
{
|
|
|
|
r->pixel = a.pixel ^ b.pixel;
|
|
|
|
r->color.red = a.color.red ^ b.color.red;
|
|
|
|
r->color.green = a.color.green ^ b.color.green;
|
|
|
|
r->color.blue = a.color.blue ^ b.color.blue;
|
|
|
|
r->color.alpha = 0xffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xu_atom_init(void)
|
|
|
|
{
|
|
|
|
char *cwmhints[] = {
|
|
|
|
"WM_STATE",
|
|
|
|
"WM_DELETE_WINDOW",
|
|
|
|
"WM_TAKE_FOCUS",
|
|
|
|
"WM_PROTOCOLS",
|
|
|
|
"_MOTIF_WM_HINTS",
|
|
|
|
"UTF8_STRING",
|
|
|
|
"WM_CHANGE_STATE",
|
|
|
|
};
|
|
|
|
char *ewmhints[] = {
|
|
|
|
"_NET_SUPPORTED",
|
|
|
|
"_NET_SUPPORTING_WM_CHECK",
|
|
|
|
"_NET_ACTIVE_WINDOW",
|
|
|
|
"_NET_CLIENT_LIST",
|
|
|
|
"_NET_CLIENT_LIST_STACKING",
|
|
|
|
"_NET_NUMBER_OF_DESKTOPS",
|
|
|
|
"_NET_CURRENT_DESKTOP",
|
|
|
|
"_NET_DESKTOP_VIEWPORT",
|
|
|
|
"_NET_DESKTOP_GEOMETRY",
|
|
|
|
"_NET_VIRTUAL_ROOTS",
|
|
|
|
"_NET_SHOWING_DESKTOP",
|
|
|
|
"_NET_DESKTOP_NAMES",
|
|
|
|
"_NET_WORKAREA",
|
|
|
|
"_NET_WM_NAME",
|
|
|
|
"_NET_WM_DESKTOP",
|
|
|
|
"_NET_CLOSE_WINDOW",
|
|
|
|
"_NET_WM_STATE",
|
|
|
|
"_NET_WM_STATE_STICKY",
|
|
|
|
"_NET_WM_STATE_MAXIMIZED_VERT",
|
|
|
|
"_NET_WM_STATE_MAXIMIZED_HORZ",
|
|
|
|
"_NET_WM_STATE_HIDDEN",
|
|
|
|
"_NET_WM_STATE_FULLSCREEN",
|
|
|
|
"_NET_WM_STATE_DEMANDS_ATTENTION",
|
|
|
|
"_NET_WM_STATE_SKIP_PAGER",
|
|
|
|
"_NET_WM_STATE_SKIP_TASKBAR",
|
|
|
|
"_CWM_WM_STATE_FREEZE",
|
|
|
|
};
|
|
|
|
|
|
|
|
XInternAtoms(X_Dpy, cwmhints, nitems(cwmhints), False, cwmh);
|
|
|
|
XInternAtoms(X_Dpy, ewmhints, nitems(ewmhints), False, ewmh);
|
2010-05-22 16:10:31 -06:00
|
|
|
}
|
|
|
|
|
2012-07-03 07:49:03 -06:00
|
|
|
/* Root Window Properties */
|
2009-12-07 14:20:52 -07:00
|
|
|
void
|
2012-05-15 19:17:14 -06:00
|
|
|
xu_ewmh_net_supported(struct screen_ctx *sc)
|
2009-12-07 14:20:52 -07:00
|
|
|
{
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SUPPORTED],
|
2013-07-16 08:30:48 -06:00
|
|
|
XA_ATOM, 32, PropModeReplace, (unsigned char *)ewmh, EWMH_NITEMS);
|
2012-05-15 19:17:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xu_ewmh_net_supported_wm_check(struct screen_ctx *sc)
|
|
|
|
{
|
|
|
|
Window w;
|
|
|
|
|
|
|
|
w = XCreateSimpleWindow(X_Dpy, sc->rootwin, -1, -1, 1, 1, 0, 0, 0);
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SUPPORTING_WM_CHECK],
|
2012-05-15 19:17:14 -06:00
|
|
|
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, w, ewmh[_NET_SUPPORTING_WM_CHECK],
|
2012-05-15 19:17:14 -06:00
|
|
|
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, w, ewmh[_NET_WM_NAME],
|
2016-10-05 07:10:59 -06:00
|
|
|
cwmh[UTF8_STRING], 8, PropModeReplace,
|
|
|
|
(unsigned char *)Conf.wmname, strlen(Conf.wmname));
|
2012-07-03 07:49:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xu_ewmh_net_desktop_geometry(struct screen_ctx *sc)
|
|
|
|
{
|
2012-07-13 09:21:35 -06:00
|
|
|
long geom[2] = { sc->view.w, sc->view.h };
|
2012-07-03 07:49:03 -06:00
|
|
|
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_GEOMETRY],
|
2012-07-03 07:49:03 -06:00
|
|
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)geom , 2);
|
|
|
|
}
|
|
|
|
|
2019-03-04 07:48:59 -07:00
|
|
|
void
|
|
|
|
xu_ewmh_net_desktop_viewport(struct screen_ctx *sc)
|
|
|
|
{
|
|
|
|
long viewports[2] = {0, 0};
|
|
|
|
|
|
|
|
/* We don't support large desktops, so this is (0, 0). */
|
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_VIEWPORT],
|
|
|
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)viewports, 2);
|
|
|
|
}
|
|
|
|
|
2012-07-03 07:49:03 -06:00
|
|
|
void
|
|
|
|
xu_ewmh_net_workarea(struct screen_ctx *sc)
|
|
|
|
{
|
2016-10-04 09:18:20 -06:00
|
|
|
unsigned long *workarea;
|
|
|
|
int i, ngroups = Conf.ngroups;
|
|
|
|
|
|
|
|
workarea = xreallocarray(NULL, ngroups * 4, sizeof(unsigned long));
|
|
|
|
for (i = 0; i < ngroups; i++) {
|
|
|
|
workarea[4 * i + 0] = sc->work.x;
|
|
|
|
workarea[4 * i + 1] = sc->work.y;
|
|
|
|
workarea[4 * i + 2] = sc->work.w;
|
|
|
|
workarea[4 * i + 3] = sc->work.h;
|
2012-07-03 07:49:03 -06:00
|
|
|
}
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_WORKAREA],
|
2016-10-04 09:18:20 -06:00
|
|
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)workarea,
|
|
|
|
ngroups * 4);
|
|
|
|
free(workarea);
|
2012-07-03 07:49:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xu_ewmh_net_client_list(struct screen_ctx *sc)
|
|
|
|
{
|
|
|
|
struct client_ctx *cc;
|
|
|
|
Window *winlist;
|
|
|
|
int i = 0, j = 0;
|
|
|
|
|
2014-09-08 14:11:22 -06:00
|
|
|
TAILQ_FOREACH(cc, &sc->clientq, entry)
|
2012-07-03 07:49:03 -06:00
|
|
|
i++;
|
|
|
|
if (i == 0)
|
|
|
|
return;
|
|
|
|
|
2015-03-28 17:12:47 -06:00
|
|
|
winlist = xreallocarray(NULL, i, sizeof(*winlist));
|
2014-09-08 14:11:22 -06:00
|
|
|
TAILQ_FOREACH(cc, &sc->clientq, entry)
|
2012-07-03 07:49:03 -06:00
|
|
|
winlist[j++] = cc->win;
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST],
|
2012-07-03 07:49:03 -06:00
|
|
|
XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i);
|
2012-11-07 13:34:39 -07:00
|
|
|
free(winlist);
|
2012-07-03 07:49:03 -06:00
|
|
|
}
|
|
|
|
|
2015-08-24 09:42:57 -06:00
|
|
|
void
|
|
|
|
xu_ewmh_net_client_list_stacking(struct screen_ctx *sc)
|
|
|
|
{
|
|
|
|
struct client_ctx *cc;
|
|
|
|
Window *winlist;
|
|
|
|
int i = 0, j;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(cc, &sc->clientq, entry)
|
|
|
|
i++;
|
|
|
|
if (i == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
j = i;
|
|
|
|
winlist = xreallocarray(NULL, i, sizeof(*winlist));
|
|
|
|
TAILQ_FOREACH(cc, &sc->clientq, entry)
|
|
|
|
winlist[--j] = cc->win;
|
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST_STACKING],
|
|
|
|
XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i);
|
|
|
|
free(winlist);
|
|
|
|
}
|
|
|
|
|
2012-07-03 07:49:03 -06:00
|
|
|
void
|
|
|
|
xu_ewmh_net_active_window(struct screen_ctx *sc, Window w)
|
|
|
|
{
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_ACTIVE_WINDOW],
|
2012-07-03 07:49:03 -06:00
|
|
|
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-03-04 07:48:59 -07:00
|
|
|
xu_ewmh_net_number_of_desktops(struct screen_ctx *sc)
|
2012-07-03 07:49:03 -06:00
|
|
|
{
|
2016-10-04 09:18:20 -06:00
|
|
|
long ndesks = Conf.ngroups;
|
2012-07-03 07:49:03 -06:00
|
|
|
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_NUMBER_OF_DESKTOPS],
|
2012-07-03 07:49:03 -06:00
|
|
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&ndesks, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xu_ewmh_net_showing_desktop(struct screen_ctx *sc)
|
|
|
|
{
|
|
|
|
long zero = 0;
|
|
|
|
|
|
|
|
/* We don't support `showing desktop' mode, so this is zero.
|
|
|
|
* Note that when we hide all groups, or when all groups are
|
|
|
|
* hidden we could technically set this later on.
|
|
|
|
*/
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SHOWING_DESKTOP],
|
2012-07-03 07:49:03 -06:00
|
|
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&zero, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xu_ewmh_net_virtual_roots(struct screen_ctx *sc)
|
|
|
|
{
|
|
|
|
/* We don't support virtual roots, so delete if set by previous wm. */
|
2013-07-15 08:50:44 -06:00
|
|
|
XDeleteProperty(X_Dpy, sc->rootwin, ewmh[_NET_VIRTUAL_ROOTS]);
|
2012-07-03 07:49:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-09-23 08:25:08 -06:00
|
|
|
xu_ewmh_net_current_desktop(struct screen_ctx *sc)
|
2012-07-03 07:49:03 -06:00
|
|
|
{
|
2014-09-23 08:25:08 -06:00
|
|
|
long num = sc->group_active->num;
|
|
|
|
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CURRENT_DESKTOP],
|
2014-09-23 08:25:08 -06:00
|
|
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&num, 1);
|
2012-07-03 07:49:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-08-25 08:31:22 -06:00
|
|
|
xu_ewmh_net_desktop_names(struct screen_ctx *sc)
|
2012-07-03 07:49:03 -06:00
|
|
|
{
|
2014-09-06 10:08:58 -06:00
|
|
|
struct group_ctx *gc;
|
|
|
|
char *p, *q;
|
|
|
|
unsigned char *prop_ret;
|
|
|
|
int i = 0, j = 0, nstrings = 0, n = 0;
|
|
|
|
size_t len = 0, tlen, slen;
|
|
|
|
|
|
|
|
/* Let group names be overwritten if _NET_DESKTOP_NAMES is set. */
|
|
|
|
|
2020-02-27 07:56:39 -07:00
|
|
|
if ((j = xu_get_prop(sc->rootwin, ewmh[_NET_DESKTOP_NAMES],
|
2014-09-06 10:08:58 -06:00
|
|
|
cwmh[UTF8_STRING], 0xffffff, (unsigned char **)&prop_ret)) > 0) {
|
|
|
|
prop_ret[j - 1] = '\0'; /* paranoia */
|
|
|
|
while (i < j) {
|
|
|
|
if (prop_ret[i++] == '\0')
|
|
|
|
nstrings++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = (char *)prop_ret;
|
|
|
|
while (n < nstrings) {
|
|
|
|
TAILQ_FOREACH(gc, &sc->groupq, entry) {
|
|
|
|
if (gc->num == n) {
|
|
|
|
free(gc->name);
|
|
|
|
gc->name = xstrdup(p);
|
|
|
|
p += strlen(p) + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
if (prop_ret != NULL)
|
|
|
|
XFree(prop_ret);
|
2014-08-25 08:31:22 -06:00
|
|
|
|
2014-09-06 10:08:58 -06:00
|
|
|
TAILQ_FOREACH(gc, &sc->groupq, entry)
|
|
|
|
len += strlen(gc->name) + 1;
|
2015-03-28 17:12:47 -06:00
|
|
|
q = p = xreallocarray(NULL, len, sizeof(*p));
|
2014-08-25 08:31:22 -06:00
|
|
|
|
|
|
|
tlen = len;
|
2014-09-06 10:08:58 -06:00
|
|
|
TAILQ_FOREACH(gc, &sc->groupq, entry) {
|
|
|
|
slen = strlen(gc->name) + 1;
|
|
|
|
(void)strlcpy(q, gc->name, tlen);
|
2014-08-25 08:31:22 -06:00
|
|
|
tlen -= slen;
|
|
|
|
q += slen;
|
|
|
|
}
|
|
|
|
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_NAMES],
|
2014-08-25 08:31:22 -06:00
|
|
|
cwmh[UTF8_STRING], 8, PropModeReplace, (unsigned char *)p, len);
|
2015-03-28 15:55:48 -06:00
|
|
|
free(p);
|
2012-07-03 07:49:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Application Window Properties */
|
2020-02-27 07:56:39 -07:00
|
|
|
int
|
|
|
|
xu_ewmh_get_net_wm_desktop(struct client_ctx *cc, long *n)
|
|
|
|
{
|
|
|
|
long *p;
|
|
|
|
|
|
|
|
if (xu_get_prop(cc->win, ewmh[_NET_WM_DESKTOP], XA_CARDINAL, 1L,
|
|
|
|
(unsigned char **)&p) <= 0)
|
|
|
|
return 0;
|
|
|
|
*n = *p;
|
|
|
|
XFree(p);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-07-03 07:49:03 -06:00
|
|
|
void
|
2020-02-27 07:56:39 -07:00
|
|
|
xu_ewmh_set_net_wm_desktop(struct client_ctx *cc)
|
2012-07-03 07:49:03 -06:00
|
|
|
{
|
2014-08-22 13:04:00 -06:00
|
|
|
long num = 0xffffffff;
|
|
|
|
|
2015-08-27 12:53:14 -06:00
|
|
|
if (cc->gc)
|
|
|
|
num = cc->gc->num;
|
2012-07-03 07:49:03 -06:00
|
|
|
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_DESKTOP],
|
2014-08-20 09:15:29 -06:00
|
|
|
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&num, 1);
|
2009-12-07 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
2013-05-20 15:13:58 -06:00
|
|
|
Atom *
|
|
|
|
xu_ewmh_get_net_wm_state(struct client_ctx *cc, int *n)
|
|
|
|
{
|
|
|
|
Atom *state, *p = NULL;
|
|
|
|
|
2020-02-27 07:56:39 -07:00
|
|
|
if ((*n = xu_get_prop(cc->win, ewmh[_NET_WM_STATE], XA_ATOM, 64L,
|
2013-10-03 07:51:57 -06:00
|
|
|
(unsigned char **)&p)) <= 0)
|
2020-02-27 07:56:39 -07:00
|
|
|
return NULL;
|
2013-05-20 15:13:58 -06:00
|
|
|
|
2015-03-28 17:12:47 -06:00
|
|
|
state = xreallocarray(NULL, *n, sizeof(Atom));
|
2013-12-17 09:10:43 -07:00
|
|
|
(void)memcpy(state, p, *n * sizeof(Atom));
|
2013-05-20 15:13:58 -06:00
|
|
|
XFree((char *)p);
|
|
|
|
|
2020-02-27 07:56:39 -07:00
|
|
|
return state;
|
2013-05-20 15:13:58 -06:00
|
|
|
}
|
|
|
|
|
2013-05-20 18:29:20 -06:00
|
|
|
void
|
|
|
|
xu_ewmh_handle_net_wm_state_msg(struct client_ctx *cc, int action,
|
|
|
|
Atom first, Atom second)
|
|
|
|
{
|
2014-01-03 08:29:06 -07:00
|
|
|
unsigned int i;
|
2020-02-27 07:56:39 -07:00
|
|
|
struct handlers {
|
|
|
|
Atom atom;
|
|
|
|
int flag;
|
2013-05-20 18:29:20 -06:00
|
|
|
void (*toggle)(struct client_ctx *);
|
|
|
|
} handlers[] = {
|
2014-08-25 06:49:19 -06:00
|
|
|
{ _NET_WM_STATE_STICKY,
|
|
|
|
CLIENT_STICKY,
|
2014-09-17 12:41:44 -06:00
|
|
|
client_toggle_sticky },
|
2013-05-20 18:29:20 -06:00
|
|
|
{ _NET_WM_STATE_MAXIMIZED_VERT,
|
|
|
|
CLIENT_VMAXIMIZED,
|
2014-09-17 12:41:44 -06:00
|
|
|
client_toggle_vmaximize },
|
2013-05-20 18:29:20 -06:00
|
|
|
{ _NET_WM_STATE_MAXIMIZED_HORZ,
|
|
|
|
CLIENT_HMAXIMIZED,
|
2014-09-17 12:41:44 -06:00
|
|
|
client_toggle_hmaximize },
|
2014-09-17 10:00:44 -06:00
|
|
|
{ _NET_WM_STATE_HIDDEN,
|
|
|
|
CLIENT_HIDDEN,
|
2014-09-17 12:41:44 -06:00
|
|
|
client_toggle_hidden },
|
2013-12-16 12:02:17 -07:00
|
|
|
{ _NET_WM_STATE_FULLSCREEN,
|
|
|
|
CLIENT_FULLSCREEN,
|
2014-09-17 12:41:44 -06:00
|
|
|
client_toggle_fullscreen },
|
2013-12-13 07:40:52 -07:00
|
|
|
{ _NET_WM_STATE_DEMANDS_ATTENTION,
|
|
|
|
CLIENT_URGENCY,
|
|
|
|
client_urgency },
|
2017-12-19 07:30:53 -07:00
|
|
|
{ _NET_WM_STATE_SKIP_PAGER,
|
|
|
|
CLIENT_SKIP_PAGER,
|
|
|
|
client_toggle_skip_pager},
|
|
|
|
{ _NET_WM_STATE_SKIP_TASKBAR,
|
|
|
|
CLIENT_SKIP_TASKBAR,
|
|
|
|
client_toggle_skip_taskbar},
|
2015-08-24 08:56:10 -06:00
|
|
|
{ _CWM_WM_STATE_FREEZE,
|
|
|
|
CLIENT_FREEZE,
|
|
|
|
client_toggle_freeze },
|
2013-05-20 18:29:20 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
for (i = 0; i < nitems(handlers); i++) {
|
2013-07-15 08:50:44 -06:00
|
|
|
if (first != ewmh[handlers[i].atom] &&
|
|
|
|
second != ewmh[handlers[i].atom])
|
2013-05-20 18:29:20 -06:00
|
|
|
continue;
|
|
|
|
switch (action) {
|
|
|
|
case _NET_WM_STATE_ADD:
|
2020-02-27 07:56:39 -07:00
|
|
|
if (!(cc->flags & handlers[i].flag))
|
2013-05-20 18:29:20 -06:00
|
|
|
handlers[i].toggle(cc);
|
|
|
|
break;
|
|
|
|
case _NET_WM_STATE_REMOVE:
|
2020-02-27 07:56:39 -07:00
|
|
|
if (cc->flags & handlers[i].flag)
|
2013-05-20 18:29:20 -06:00
|
|
|
handlers[i].toggle(cc);
|
|
|
|
break;
|
|
|
|
case _NET_WM_STATE_TOGGLE:
|
|
|
|
handlers[i].toggle(cc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-20 15:13:58 -06:00
|
|
|
void
|
|
|
|
xu_ewmh_restore_net_wm_state(struct client_ctx *cc)
|
|
|
|
{
|
|
|
|
Atom *atoms;
|
|
|
|
int i, n;
|
|
|
|
|
|
|
|
atoms = xu_ewmh_get_net_wm_state(cc, &n);
|
|
|
|
for (i = 0; i < n; i++) {
|
2014-08-25 06:49:19 -06:00
|
|
|
if (atoms[i] == ewmh[_NET_WM_STATE_STICKY])
|
2014-09-17 12:41:44 -06:00
|
|
|
client_toggle_sticky(cc);
|
2013-07-15 08:50:44 -06:00
|
|
|
if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_VERT])
|
2014-09-17 12:41:44 -06:00
|
|
|
client_toggle_vmaximize(cc);
|
2015-08-24 08:56:10 -06:00
|
|
|
if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_HORZ])
|
|
|
|
client_toggle_hmaximize(cc);
|
2014-09-17 10:00:44 -06:00
|
|
|
if (atoms[i] == ewmh[_NET_WM_STATE_HIDDEN])
|
2014-09-17 12:41:44 -06:00
|
|
|
client_toggle_hidden(cc);
|
2013-12-16 12:02:17 -07:00
|
|
|
if (atoms[i] == ewmh[_NET_WM_STATE_FULLSCREEN])
|
2014-09-17 12:41:44 -06:00
|
|
|
client_toggle_fullscreen(cc);
|
2013-12-13 07:40:52 -07:00
|
|
|
if (atoms[i] == ewmh[_NET_WM_STATE_DEMANDS_ATTENTION])
|
|
|
|
client_urgency(cc);
|
2017-12-19 07:30:53 -07:00
|
|
|
if (atoms[i] == ewmh[_NET_WM_STATE_SKIP_PAGER])
|
|
|
|
client_toggle_skip_pager(cc);
|
|
|
|
if (atoms[i] == ewmh[_NET_WM_STATE_SKIP_TASKBAR])
|
|
|
|
client_toggle_skip_taskbar(cc);
|
2015-08-24 08:56:10 -06:00
|
|
|
if (atoms[i] == ewmh[_CWM_WM_STATE_FREEZE])
|
|
|
|
client_toggle_freeze(cc);
|
2013-05-20 15:13:58 -06:00
|
|
|
}
|
|
|
|
free(atoms);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xu_ewmh_set_net_wm_state(struct client_ctx *cc)
|
|
|
|
{
|
|
|
|
Atom *atoms, *oatoms;
|
|
|
|
int n, i, j;
|
|
|
|
|
|
|
|
oatoms = xu_ewmh_get_net_wm_state(cc, &n);
|
2015-03-28 17:12:47 -06:00
|
|
|
atoms = xreallocarray(NULL, (n + _NET_WM_STATES_NITEMS), sizeof(Atom));
|
2013-05-20 15:13:58 -06:00
|
|
|
for (i = j = 0; i < n; i++) {
|
2015-08-24 08:56:10 -06:00
|
|
|
if (oatoms[i] != ewmh[_NET_WM_STATE_STICKY] &&
|
2013-12-13 07:40:52 -07:00
|
|
|
oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_VERT] &&
|
2015-08-24 08:56:10 -06:00
|
|
|
oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_HORZ] &&
|
2014-09-17 10:00:44 -06:00
|
|
|
oatoms[i] != ewmh[_NET_WM_STATE_HIDDEN] &&
|
2013-12-16 12:02:17 -07:00
|
|
|
oatoms[i] != ewmh[_NET_WM_STATE_FULLSCREEN] &&
|
2015-08-24 08:56:10 -06:00
|
|
|
oatoms[i] != ewmh[_NET_WM_STATE_DEMANDS_ATTENTION] &&
|
2017-12-19 07:30:53 -07:00
|
|
|
oatoms[i] != ewmh[_NET_WM_STATE_SKIP_PAGER] &&
|
|
|
|
oatoms[i] != ewmh[_NET_WM_STATE_SKIP_TASKBAR] &&
|
2015-08-24 08:56:10 -06:00
|
|
|
oatoms[i] != ewmh[_CWM_WM_STATE_FREEZE])
|
2013-05-20 15:13:58 -06:00
|
|
|
atoms[j++] = oatoms[i];
|
|
|
|
}
|
|
|
|
free(oatoms);
|
2014-08-25 06:49:19 -06:00
|
|
|
if (cc->flags & CLIENT_STICKY)
|
|
|
|
atoms[j++] = ewmh[_NET_WM_STATE_STICKY];
|
2014-09-17 10:00:44 -06:00
|
|
|
if (cc->flags & CLIENT_HIDDEN)
|
|
|
|
atoms[j++] = ewmh[_NET_WM_STATE_HIDDEN];
|
2013-12-16 12:02:17 -07:00
|
|
|
if (cc->flags & CLIENT_FULLSCREEN)
|
|
|
|
atoms[j++] = ewmh[_NET_WM_STATE_FULLSCREEN];
|
|
|
|
else {
|
|
|
|
if (cc->flags & CLIENT_VMAXIMIZED)
|
|
|
|
atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_VERT];
|
2015-08-24 08:56:10 -06:00
|
|
|
if (cc->flags & CLIENT_HMAXIMIZED)
|
|
|
|
atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_HORZ];
|
2013-12-16 12:02:17 -07:00
|
|
|
}
|
2013-12-13 07:40:52 -07:00
|
|
|
if (cc->flags & CLIENT_URGENCY)
|
|
|
|
atoms[j++] = ewmh[_NET_WM_STATE_DEMANDS_ATTENTION];
|
2017-12-19 07:30:53 -07:00
|
|
|
if (cc->flags & CLIENT_SKIP_PAGER)
|
|
|
|
atoms[j++] = ewmh[_NET_WM_STATE_SKIP_PAGER];
|
|
|
|
if (cc->flags & CLIENT_SKIP_TASKBAR)
|
|
|
|
atoms[j++] = ewmh[_NET_WM_STATE_SKIP_TASKBAR];
|
2015-08-24 08:56:10 -06:00
|
|
|
if (cc->flags & CLIENT_FREEZE)
|
|
|
|
atoms[j++] = ewmh[_CWM_WM_STATE_FREEZE];
|
2013-05-20 15:13:58 -06:00
|
|
|
if (j > 0)
|
2013-07-15 08:50:44 -06:00
|
|
|
XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE],
|
2013-05-20 15:13:58 -06:00
|
|
|
XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, j);
|
|
|
|
else
|
2013-07-15 08:50:44 -06:00
|
|
|
XDeleteProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE]);
|
2013-05-20 15:13:58 -06:00
|
|
|
free(atoms);
|
|
|
|
}
|