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:
oga 2009-12-11 17:51:42 +00:00
parent 9b04930f24
commit b35cbf81d8
6 changed files with 139 additions and 34 deletions

View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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 {

View File

@ -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

View File

@ -189,6 +189,7 @@ char *atoms[CWM_NO_ATOMS] = {
"_NET_DESKTOP_GEOMETRY",
"_NET_VIRTUAL_ROOTS",
"_NET_SHOWING_DESKTOP",
"_NET_DESKTOP_NAMES",
};
void