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