]> git.lizzy.rs Git - bspwm.git/blob - rules.c
Keep the *name* section straightforward
[bspwm.git] / rules.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <xcb/xcb_icccm.h>
4 #include <xcb/xcb_ewmh.h>
5 #include "types.h"
6 #include "bspwm.h"
7 #include "ewmh.h"
8 #include "rules.h"
9 #include "query.h"
10
11 void add_rule(rule_t *r)
12 {
13     if (rule_head == NULL) {
14         rule_head = rule_tail = r;
15     } else {
16         rule_tail->next = r;
17         r->prev = rule_tail;
18         rule_tail = r;
19     }
20 }
21
22 void remove_rule(rule_t *r)
23 {
24     if (r == NULL)
25         return;
26     rule_t *prev = r->prev;
27     rule_t *next = r->next;
28     if (prev != NULL)
29         prev->next = next;
30     if (next != NULL)
31         next->prev = prev;
32     if (r == rule_head)
33         rule_head = next;
34     if (r == rule_tail)
35         rule_tail = prev;
36     free(r);
37 }
38
39 void remove_rule_by_uid(unsigned int uid)
40 {
41     remove_rule(find_rule(uid));
42 }
43
44 rule_t *find_rule(unsigned int uid)
45 {
46     for (rule_t *r = rule_head; r != NULL; r = r->next)
47         if (r->uid == uid)
48             return r;
49     return NULL;
50 }
51
52 bool is_match(rule_t *r, xcb_window_t win)
53 {
54     xcb_icccm_get_wm_class_reply_t reply;
55     if (xcb_icccm_get_wm_class_reply(dpy, xcb_icccm_get_wm_class(dpy, win), &reply, NULL) == 1
56             && (streq(reply.class_name, r->cause.name)
57                 || streq(reply.instance_name, r->cause.name))) {
58         xcb_icccm_get_wm_class_reply_wipe(&reply);
59         return true;
60     }
61     return false;
62 }
63
64 void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, bool *floating, bool *follow, bool *transient, bool *fullscreen, bool *takes_focus, bool *manage)
65 {
66     xcb_ewmh_get_atoms_reply_t win_type;
67
68     if (xcb_ewmh_get_wm_window_type_reply(ewmh, xcb_ewmh_get_wm_window_type(ewmh, win), &win_type, NULL) == 1) {
69         for (unsigned int i = 0; i < win_type.atoms_len; i++) {
70             xcb_atom_t a = win_type.atoms[i];
71             if (a == ewmh->_NET_WM_WINDOW_TYPE_TOOLBAR
72                     || a == ewmh->_NET_WM_WINDOW_TYPE_UTILITY) {
73                 *takes_focus = false;
74             } else if (a == ewmh->_NET_WM_WINDOW_TYPE_DIALOG) {
75                 *floating = true;
76             } else if (a == ewmh->_NET_WM_WINDOW_TYPE_DOCK || a == ewmh->_NET_WM_WINDOW_TYPE_NOTIFICATION) {
77                 *manage = false;
78             }
79         }
80         xcb_ewmh_get_atoms_reply_wipe(&win_type);
81     }
82
83     xcb_size_hints_t size_hints;
84
85     if (xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, win), &size_hints, NULL) == 1) {
86         if (size_hints.min_width > 0 && size_hints.min_height > 0
87                 && size_hints.min_width == size_hints.max_width
88                 && size_hints.min_height == size_hints.max_height)
89             *floating = true;
90     }
91
92     xcb_ewmh_get_atoms_reply_t win_state;
93
94     if (xcb_ewmh_get_wm_state_reply(ewmh, xcb_ewmh_get_wm_state(ewmh, win), &win_state, NULL) == 1) {
95         for (unsigned int i = 0; i < win_state.atoms_len; i++) {
96             xcb_atom_t a = win_state.atoms[i];
97             if (a == ewmh->_NET_WM_STATE_FULLSCREEN) {
98                 *fullscreen = true;
99             }
100         }
101         xcb_ewmh_get_atoms_reply_wipe(&win_state);
102     }
103
104     xcb_window_t transient_for = XCB_NONE;
105     xcb_icccm_get_wm_transient_for_reply(dpy, xcb_icccm_get_wm_transient_for(dpy, win), &transient_for, NULL);
106     *transient = (transient_for == XCB_NONE ? false : true);
107     if (*transient)
108         *floating = true;
109
110     rule_t *rule = rule_head;
111
112     while (rule != NULL) {
113         if (is_match(rule, win)) {
114             rule_effect_t efc = rule->effect;
115             if (efc.floating)
116                 *floating = true;
117             if (efc.follow)
118                 *follow = true;
119             if (efc.focus)
120                 *takes_focus = true;
121             if (efc.desc[0] != '\0') {
122                 coordinates_t ref = {*m, *d, NULL};
123                 coordinates_t loc;
124                 if (desktop_from_desc(efc.desc, &ref, &loc)) {
125                     *m = loc.monitor;
126                     *d = loc.desktop;
127                 }
128             }
129         }
130         rule = rule->next;
131     }
132 }
133
134 void list_rules(char *pattern, char *rsp)
135 {
136     char line[MAXLEN];
137
138     for (rule_t *r = rule_head; r != NULL; r = r->next) {
139         if (pattern != NULL && !streq(pattern, r->cause.name))
140             continue;
141         snprintf(line, sizeof(line), "%2X %s", r->uid, r->cause.name);
142         strncat(rsp, line, REMLEN(rsp));
143         if (r->effect.floating)
144             strncat(rsp, " --floating", REMLEN(rsp));
145         if (r->effect.follow)
146             strncat(rsp, " --follow", REMLEN(rsp));
147         if (r->effect.focus)
148             strncat(rsp, " --focus", REMLEN(rsp));
149         if (r->effect.desc[0] != '\0') {
150             snprintf(line, sizeof(line), " -d %s", r->effect.desc);
151             strncat(rsp, line, REMLEN(rsp));
152         }
153         strncat(rsp, "\n", REMLEN(rsp));
154     }
155 }