Skip to content

Commit

Permalink
Merge pull request #454 from rdnvndr/net-wm-window-type
Browse files Browse the repository at this point in the history
Add a group of programs by window type (issue #453)
  • Loading branch information
joewing authored Mar 27, 2018
2 parents 663862b + 42889d9 commit e4b4341
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 6 deletions.
10 changes: 8 additions & 2 deletions jwm.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -749,8 +749,8 @@ output is the same as the main configuration file.
.B "GROUP SETTINGS"
.RS
Program groups allow one to specify options which apply to a group of
programs by name and/or class. A program group is created with the
\fBGroup\fP tag. As many program groups can be created as desired.
programs by name, class and window type. A program group is created with
the \fBGroup\fP tag. As many program groups can be created as desired.
If one or more \fBName\fP tags is specified, at least one name must
match. Likewise, if one or more \fBClass\fP tags is specified, at least
one class must match.
Expand All @@ -768,6 +768,12 @@ first string in WM_CLASS).
The window class for a program to match to be in this group (the
second string in WM_CLASS).
.RE
.B Type
.RS
The window type for a program to match to be in this group. Possible
values are desktop, dialog, dock, menu, normal, notification, splash,
toolbar, utility.
.RE
.B Option
.RS
An option for this group. Possible options are:
Expand Down
37 changes: 36 additions & 1 deletion src/group.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
typedef unsigned int MatchType;
#define MATCH_NAME 0 /**< Match the window name. */
#define MATCH_CLASS 1 /**< Match the window class. */
#define MATCH_TYPE 2 /**< Match the window type. */

/** List of match patterns for a group. */
typedef struct PatternListType {
Expand Down Expand Up @@ -127,6 +128,17 @@ void AddGroupName(GroupType *gp, const char *pattern)
}
}

/** Add a window type to a group. */
void AddGroupType(GroupType *gp, const char *pattern)
{
Assert(gp);
if(JLIKELY(pattern)) {
AddPattern(&gp->patterns, pattern, MATCH_TYPE);
} else {
Warning(_("invalid group type"));
}
}

/** Add a pattern to a pattern list. */
void AddPattern(PatternListType **lp, const char *pattern, MatchType match)
{
Expand Down Expand Up @@ -199,15 +211,31 @@ void ApplyGroups(ClientNode *np)
GroupType *gp;
char hasClass;
char hasName;
char hasType;
char matchesClass;
char matchesName;
char matchesType;

static const StringMappingType windowTypeMapping[] = {
{ "desktop", WINDOW_TYPE_DESKTOP },
{ "dialog", WINDOW_TYPE_DIALOG },
{ "dock", WINDOW_TYPE_DOCK },
{ "menu", WINDOW_TYPE_MENU },
{ "normal", WINDOW_TYPE_NORMAL },
{ "notification", WINDOW_TYPE_NOTIFICATION },
{ "splash", WINDOW_TYPE_SPLASH },
{ "toolbar", WINDOW_TYPE_TOOLBAR },
{ "utility", WINDOW_TYPE_UTILITY }
};

Assert(np);
for(gp = groups; gp; gp = gp->next) {
hasClass = 0;
hasName = 0;
hasType = 0;
matchesClass = 0;
matchesName = 0;
matchesType = 0;
for(lp = gp->patterns; lp; lp = lp->next) {
if(lp->match == MATCH_CLASS) {
if(Match(lp->pattern, np->className)) {
Expand All @@ -219,11 +247,18 @@ void ApplyGroups(ClientNode *np)
matchesName = 1;
}
hasName = 1;
} else if(lp->match == MATCH_TYPE) {
if(FindValue(windowTypeMapping, WINDOW_TYPE_COUNT, lp->pattern)
== np->state.windowType) {
matchesType = 1;
}
hasType = 1;
} else {
Debug("invalid match in ApplyGroups: %d", lp->match);
}
}
if(hasName == matchesName && hasClass == matchesClass) {
if(hasName == matchesName && hasClass == matchesClass
&& hasType == matchesType) {
ApplyGroup(gp, np);
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/group.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ void AddGroupClass(struct GroupType *gp, const char *pattern);
*/
void AddGroupName(struct GroupType *gp, const char *pattern);

/** Add a window type to a group.
* @param gp The group.
* @param pattern A pattern to match with the window type.
*/
void AddGroupType(struct GroupType *gp, const char *pattern);

/** Add a group option that doesn't take a value.
* @param gp The group.
* @param option The option.
Expand Down
15 changes: 12 additions & 3 deletions src/hint.c
Original file line number Diff line number Diff line change
Expand Up @@ -639,42 +639,51 @@ ClientState ReadWindowState(Window win, char alreadyMapped)
state = (Atom*)temp;
for(x = 0; x < count; x++) {
if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_NORMAL]) {
result.windowType = WINDOW_TYPE_NORMAL;
break;
} else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_DESKTOP]) {
result.defaultLayer = LAYER_DESKTOP;
result.border = BORDER_NONE;
result.status |= STAT_STICKY;
result.status |= STAT_NOLIST;
result.status |= STAT_NOFOCUS;
result.windowType = WINDOW_TYPE_DESKTOP;
break;
} else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_DOCK]) {
result.border = BORDER_NONE;
result.defaultLayer = LAYER_ABOVE;
result.status |= STAT_NOFOCUS;
result.windowType = WINDOW_TYPE_DOCK;
break;
} else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_SPLASH]) {
result.border = BORDER_NONE;
result.border = BORDER_NONE;
result.windowType = WINDOW_TYPE_SPLASH;
break;
} else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_DIALOG]) {
result.border &= ~BORDER_MIN;
result.border &= ~BORDER_MAX;
result.border &= ~BORDER_MIN;
result.border &= ~BORDER_MAX;
result.windowType = WINDOW_TYPE_DIALOG;
break;
} else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_MENU]) {
result.border &= ~BORDER_MAX;
result.status |= STAT_NOLIST;
result.windowType = WINDOW_TYPE_MENU;
} else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION]) {
result.border = BORDER_NONE;
result.status |= STAT_NOLIST;
result.status |= STAT_NOFOCUS;
result.windowType = WINDOW_TYPE_NOTIFICATION;
} else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_TOOLBAR]) {
result.border &= ~BORDER_MAX;
result.defaultLayer = LAYER_ABOVE;
result.status |= STAT_STICKY;
result.status |= STAT_NOLIST;
result.status |= STAT_NOFOCUS;
result.windowType = WINDOW_TYPE_TOOLBAR;
} else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_UTILITY]) {
result.border &= ~BORDER_MAX;
result.status |= STAT_NOFOCUS;
result.windowType = WINDOW_TYPE_UTILITY;
} else {
Debug("Unknown _NET_WM_WINDOW_TYPE: %lu", state[x]);
}
Expand Down
14 changes: 14 additions & 0 deletions src/hint.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@ typedef unsigned char WinLayerType;
#define LAST_LAYER LAYER_ABOVE
#define DEFAULT_TRAY_LAYER LAYER_ABOVE

/** Enumeration of window type. */
typedef unsigned char WindowType;
#define WINDOW_TYPE_DESKTOP 0
#define WINDOW_TYPE_DOCK 1
#define WINDOW_TYPE_SPLASH 2
#define WINDOW_TYPE_DIALOG 3
#define WINDOW_TYPE_NORMAL 4
#define WINDOW_TYPE_MENU 5
#define WINDOW_TYPE_NOTIFICATION 6
#define WINDOW_TYPE_TOOLBAR 7
#define WINDOW_TYPE_UTILITY 8
#define WINDOW_TYPE_COUNT 9

/** Client state information. */
typedef struct ClientState {
unsigned int status; /**< Status bit mask. */
Expand All @@ -154,6 +167,7 @@ typedef struct ClientState {
unsigned char maxFlags; /**< Maximization status. */
unsigned char layer; /**< Current window layer. */
unsigned char defaultLayer; /**< Default window layer. */
unsigned char windowType; /**< Window type. */
} ClientState;

extern Atom atoms[ATOM_COUNT];
Expand Down
1 change: 1 addition & 0 deletions src/lex.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ static const StringMappingType TOKEN_MAP[] = {
{ "TrayButton", TOK_TRAYBUTTON },
{ "TrayButtonStyle", TOK_TRAYBUTTONSTYLE },
{ "TrayStyle", TOK_TRAYSTYLE },
{ "Type", TOK_TYPE },
{ "Width", TOK_WIDTH },
{ "WindowStyle", TOK_WINDOWSTYLE }
};
Expand Down
1 change: 1 addition & 0 deletions src/lex.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ typedef enum {
TOK_TRAYBUTTON,
TOK_TRAYBUTTONSTYLE,
TOK_TRAYSTYLE,
TOK_TYPE,
TOK_WIDTH,
TOK_WINDOWSTYLE

Expand Down
3 changes: 3 additions & 0 deletions src/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1810,6 +1810,9 @@ void ParseGroup(const TokenNode *tp)
case TOK_NAME:
AddGroupName(group, np->value);
break;
case TOK_TYPE:
AddGroupType(group, np->value);
break;
case TOK_OPTION:
ParseGroupOption(np, group, np->value);
break;
Expand Down

0 comments on commit e4b4341

Please sign in to comment.