mirror of
https://github.com/leahneukirchen/cwm.git
synced 2023-08-10 21:13:12 +03:00
Implement _NET_DESKTOP_NAMES, this one was a bit tricky since thespec
says that a pager can change the property at any time (most need a clientmessage). So deal with property updates. Needed to shuffle some of the other code around since we can't just use shortcut_to_name[] everywhere now. ok okan@
This commit is contained in:
parent
9b04930f24
commit
b35cbf81d8
17
calmwm.h
17
calmwm.h
@ -66,7 +66,6 @@ TAILQ_HEAD(client_ctx_q, client_ctx);
|
||||
struct group_ctx {
|
||||
TAILQ_ENTRY(group_ctx) entry;
|
||||
struct client_ctx_q clients;
|
||||
const char *name;
|
||||
int shortcut;
|
||||
int hidden;
|
||||
int nhidden;
|
||||
@ -101,6 +100,8 @@ struct screen_ctx {
|
||||
struct group_ctx groups[CALMWM_NGROUPS];
|
||||
int group_hideall;
|
||||
struct group_ctx_q groupq;
|
||||
char **group_names;
|
||||
int group_nonames;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(screen_ctx_q, screen_ctx);
|
||||
@ -178,11 +179,10 @@ extern const char *shortcut_to_name[];
|
||||
|
||||
/* Autogroups */
|
||||
struct autogroupwin {
|
||||
TAILQ_ENTRY(autogroupwin) entry;
|
||||
|
||||
char *class;
|
||||
char *name;
|
||||
char *group;
|
||||
TAILQ_ENTRY(autogroupwin) entry;
|
||||
char *class;
|
||||
char *name;
|
||||
int num;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(autogroupwin_q, autogroupwin);
|
||||
@ -475,6 +475,8 @@ void search_match_exec(struct menu_q *, struct menu_q *,
|
||||
char *);
|
||||
|
||||
void group_init(struct screen_ctx *);
|
||||
void group_make_autogroup(struct conf *, char *, int);
|
||||
void group_update_names(struct screen_ctx *);
|
||||
void group_hidetoggle(struct screen_ctx *, int);
|
||||
void group_only(struct screen_ctx *, int);
|
||||
void group_cycle(struct screen_ctx *, int);
|
||||
@ -538,7 +540,8 @@ extern struct conf Conf;
|
||||
#define _NET_DESKTOP_GEOMETRY cwm_atoms[15]
|
||||
#define _NET_VIRTUAL_ROOTS cwm_atoms[16]
|
||||
#define _NET_SHOWING_DESKTOP cwm_atoms[17]
|
||||
#define CWM_NO_ATOMS 18
|
||||
#define _NET_DESKTOP_NAMES cwm_atoms[18]
|
||||
#define CWM_NO_ATOMS 19
|
||||
#define CWM_NETWM_START 7
|
||||
|
||||
extern Atom cwm_atoms[CWM_NO_ATOMS];
|
||||
|
1
conf.c
1
conf.c
@ -225,7 +225,6 @@ conf_clear(struct conf *c)
|
||||
xfree(ag->class);
|
||||
if (ag->name)
|
||||
xfree(ag->name);
|
||||
xfree(ag->group);
|
||||
xfree(ag);
|
||||
}
|
||||
|
||||
|
125
group.c
125
group.c
@ -28,6 +28,7 @@ static void group_hide(struct screen_ctx *, struct group_ctx *);
|
||||
static void group_show(struct screen_ctx *, struct group_ctx *);
|
||||
static void group_fix_hidden_state(struct group_ctx *);
|
||||
static void group_setactive(struct screen_ctx *, int);
|
||||
static void group_set_names(struct screen_ctx *);
|
||||
|
||||
const char *shortcut_to_name[] = {
|
||||
"nogroup", "one", "two", "three", "four", "five", "six",
|
||||
@ -47,7 +48,8 @@ group_add(struct group_ctx *gc, struct client_ctx *cc)
|
||||
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
|
||||
|
||||
XChangeProperty(X_Dpy, cc->win, _CWM_GRP, XA_STRING,
|
||||
8, PropModeReplace, gc->name, strlen(gc->name));
|
||||
8, PropModeReplace, shortcut_to_name[gc->shortcut],
|
||||
strlen(shortcut_to_name[gc->shortcut]));
|
||||
|
||||
TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
|
||||
cc->group = gc;
|
||||
@ -131,12 +133,15 @@ group_init(struct screen_ctx *sc)
|
||||
|
||||
TAILQ_INIT(&sc->groupq);
|
||||
sc->group_hideall = 0;
|
||||
/* see if any group names have already been set and update the property
|
||||
* with ours if they'll have changed.
|
||||
*/
|
||||
group_update_names(sc);
|
||||
|
||||
for (i = 0; i < CALMWM_NGROUPS; i++) {
|
||||
TAILQ_INIT(&sc->groups[i].clients);
|
||||
sc->groups[i].hidden = 0;
|
||||
sc->groups[i].shortcut = i + 1;
|
||||
sc->groups[i].name = shortcut_to_name[sc->groups[i].shortcut];
|
||||
TAILQ_INSERT_TAIL(&sc->groupq, &sc->groups[i], entry);
|
||||
}
|
||||
|
||||
@ -160,6 +165,28 @@ group_init(struct screen_ctx *sc)
|
||||
group_setactive(sc, 0);
|
||||
}
|
||||
|
||||
void
|
||||
group_make_autogroup(struct conf *conf, char *class, int no)
|
||||
{
|
||||
struct autogroupwin *aw;
|
||||
char *p;
|
||||
|
||||
aw = xcalloc(1, sizeof(*aw));
|
||||
|
||||
if ((p = strchr(class, ',')) == NULL) {
|
||||
aw->name = NULL;
|
||||
aw->class = xstrdup(class);
|
||||
} else {
|
||||
*(p++) = '\0';
|
||||
aw->name = xstrdup(class);
|
||||
aw->class = xstrdup(p);
|
||||
}
|
||||
aw->num = no;
|
||||
|
||||
TAILQ_INSERT_TAIL(&conf->autogroupq, aw, entry);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
group_setactive(struct screen_ctx *sc, int idx)
|
||||
{
|
||||
@ -334,10 +361,10 @@ group_menu(XButtonEvent *e)
|
||||
mi = xcalloc(1, sizeof(*mi));
|
||||
if (gc->hidden)
|
||||
snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
|
||||
gc->shortcut, shortcut_to_name[gc->shortcut]);
|
||||
gc->shortcut, sc->group_names[i]);
|
||||
else
|
||||
snprintf(mi->text, sizeof(mi->text), "%d: %s",
|
||||
gc->shortcut, shortcut_to_name[gc->shortcut]);
|
||||
gc->shortcut, sc->group_names[i]);
|
||||
mi->ctx = gc;
|
||||
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
||||
}
|
||||
@ -382,31 +409,36 @@ group_autogroup(struct client_ctx *cc)
|
||||
struct screen_ctx *sc = cc->sc;
|
||||
struct autogroupwin *aw;
|
||||
struct group_ctx *gc;
|
||||
int no = -1, i;
|
||||
unsigned char *grpstr = NULL;
|
||||
char group[CALMWM_MAXNAMELEN];
|
||||
|
||||
if (cc->app_class == NULL || cc->app_name == NULL)
|
||||
return;
|
||||
if (xu_getprop(cc, _CWM_GRP, XA_STRING,
|
||||
(CALMWM_MAXNAMELEN - 1)/sizeof(long), &grpstr) > 0) {
|
||||
strlcpy(group, grpstr, sizeof(group));
|
||||
for (i = 0; i < sizeof(shortcut_to_name) /
|
||||
sizeof(shortcut_to_name[0]); i++) {
|
||||
if (strcmp(shortcut_to_name[i], grpstr) == 0)
|
||||
no = i;
|
||||
}
|
||||
XFree(grpstr);
|
||||
} else {
|
||||
TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
|
||||
if (strcmp(aw->class, cc->app_class) == 0 &&
|
||||
(aw->name == NULL ||
|
||||
strcmp(aw->name, cc->app_name) == 0)) {
|
||||
strlcpy(group, aw->group, sizeof(group));
|
||||
no = aw->num;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp("nogroup", group, 7) == 0)
|
||||
/* no group please */
|
||||
if (no == 0)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(gc, &sc->groupq, entry) {
|
||||
if (strcmp(shortcut_to_name[gc->shortcut], group) == 0) {
|
||||
if (gc->shortcut == no) {
|
||||
group_add(gc, cc);
|
||||
return;
|
||||
}
|
||||
@ -416,3 +448,78 @@ group_autogroup(struct client_ctx *cc)
|
||||
group_add(sc->group_active, cc);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
group_update_names(struct screen_ctx *sc)
|
||||
{
|
||||
char **strings, *p;
|
||||
unsigned char *prop_ret;
|
||||
Atom type_ret;
|
||||
int format_ret, i = 0, nstrings = 0, n, setnames = 0;
|
||||
unsigned long bytes_after, num_ret;
|
||||
|
||||
if (XGetWindowProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_NAMES, 0,
|
||||
0xffffff, False, UTF8_STRING, &type_ret, &format_ret,
|
||||
&num_ret, &bytes_after, &prop_ret) == Success &&
|
||||
prop_ret != NULL && format_ret == 8) {
|
||||
/* failure, just set defaults */
|
||||
prop_ret[num_ret - 1] = '\0'; /* paranoia */
|
||||
while (i < num_ret) {
|
||||
if (prop_ret[i++] == '\0')
|
||||
nstrings++;
|
||||
}
|
||||
}
|
||||
|
||||
strings = xmalloc((nstrings < CALMWM_NGROUPS ? CALMWM_NGROUPS :
|
||||
nstrings) * sizeof(*strings));
|
||||
|
||||
i = n = 0;
|
||||
p = prop_ret;
|
||||
while (n < nstrings) {
|
||||
strings[n++] = xstrdup(p);
|
||||
p += strlen(p) + 1;
|
||||
}
|
||||
/*
|
||||
* make sure we always set our defaults if nothing is there to
|
||||
* replace them.
|
||||
*/
|
||||
if (n < CALMWM_NGROUPS) {
|
||||
setnames = 1;
|
||||
i = 1;
|
||||
while (n < CALMWM_NGROUPS)
|
||||
strings[n++] = xstrdup(shortcut_to_name[i++]);
|
||||
}
|
||||
|
||||
if (prop_ret != NULL)
|
||||
XFree(prop_ret);
|
||||
if (sc->group_nonames != 0)
|
||||
free(sc->group_names);
|
||||
|
||||
sc->group_names = strings;
|
||||
sc->group_nonames = n;
|
||||
if (setnames)
|
||||
group_set_names(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
group_set_names(struct screen_ctx *sc)
|
||||
{
|
||||
unsigned char *p, *q;
|
||||
size_t len = 0, tlen, slen;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sc->group_nonames; i++)
|
||||
len += strlen(sc->group_names[i]) + 1;
|
||||
q = p = xcalloc(len, sizeof(*p));
|
||||
|
||||
tlen = len;
|
||||
for (i = 0; i < sc->group_nonames; i++) {
|
||||
slen = strlen(sc->group_names[i]) + 1;
|
||||
strlcpy(q, sc->group_names[i], tlen);
|
||||
tlen -= slen;
|
||||
q += slen;
|
||||
}
|
||||
|
||||
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_NAMES,
|
||||
UTF8_STRING, 8, PropModeReplace, p, len);
|
||||
}
|
||||
|
18
parse.y
18
parse.y
@ -123,29 +123,13 @@ main : FONTNAME STRING {
|
||||
free($3);
|
||||
}
|
||||
| AUTOGROUP NUMBER STRING {
|
||||
struct autogroupwin *aw;
|
||||
char *p;
|
||||
|
||||
if ($2 < 0 || $2 > 9) {
|
||||
free($3);
|
||||
yyerror("autogroup number out of range: %d", $2);
|
||||
YYERROR;
|
||||
}
|
||||
|
||||
aw = xcalloc(1, sizeof(*aw));
|
||||
|
||||
if ((p = strchr($3, ',')) == NULL) {
|
||||
aw->name = NULL;
|
||||
aw->class = xstrdup($3);
|
||||
} else {
|
||||
*(p++) = '\0';
|
||||
aw->name = xstrdup($3);
|
||||
aw->class = xstrdup(p);
|
||||
}
|
||||
aw->group = xstrdup(shortcut_to_name[$2]);
|
||||
|
||||
TAILQ_INSERT_TAIL(&conf->autogroupq, aw, entry);
|
||||
|
||||
group_make_autogroup(conf, $3, $2);
|
||||
free($3);
|
||||
}
|
||||
| IGNORE STRING {
|
||||
|
11
xevents.c
11
xevents.c
@ -170,6 +170,7 @@ static void
|
||||
xev_handle_propertynotify(XEvent *ee)
|
||||
{
|
||||
XPropertyEvent *e = &ee->xproperty;
|
||||
struct screen_ctx *sc;
|
||||
struct client_ctx *cc;
|
||||
|
||||
if ((cc = client_find(e->window)) != NULL) {
|
||||
@ -184,7 +185,17 @@ xev_handle_propertynotify(XEvent *ee)
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
TAILQ_FOREACH(sc, &Screenq, entry)
|
||||
if (sc->rootwin == e->window)
|
||||
goto test;
|
||||
return;
|
||||
|
||||
test:
|
||||
if (e->atom == _NET_DESKTOP_NAMES)
|
||||
group_update_names(sc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user