summaryrefslogtreecommitdiff
path: root/src/ClientPattern.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/ClientPattern.cc')
-rw-r--r--src/ClientPattern.cc175
1 files changed, 136 insertions, 39 deletions
diff --git a/src/ClientPattern.cc b/src/ClientPattern.cc
index d644767..9324bee 100644
--- a/src/ClientPattern.cc
+++ b/src/ClientPattern.cc
@@ -24,7 +24,12 @@
24 24
25#include "ClientPattern.hh" 25#include "ClientPattern.hh"
26#include "RegExp.hh" 26#include "RegExp.hh"
27
28#include "FocusControl.hh"
29#include "Layer.hh"
30#include "Screen.hh"
27#include "WinClient.hh" 31#include "WinClient.hh"
32#include "Workspace.hh"
28 33
29#include "FbTk/StringUtil.hh" 34#include "FbTk/StringUtil.hh"
30#include "FbTk/App.hh" 35#include "FbTk/App.hh"
@@ -73,54 +78,67 @@ ClientPattern::ClientPattern(const char *str):
73 If no limit is specified, no limit is applied (i.e. limit = infinity) 78 If no limit is specified, no limit is applied (i.e. limit = infinity)
74 */ 79 */
75 80
76 int had_error = 0; 81 bool had_error = false;
77 82
78 int pos = 0; 83 int pos = 0;
79 string match; 84 string match;
80 int err = 1; // for starting first loop 85 int err = 1; // for starting first loop
81 while (had_error == 0 && err > 0) { 86 while (!had_error && err > 0) {
82 err = FbTk::StringUtil::getStringBetween(match, 87 err = FbTk::StringUtil::getStringBetween(match,
83 str + pos, 88 str + pos,
84 '(', ')', " \t\n", true); 89 '(', ')', " \t\n", true);
85 if (err > 0) { 90 if (err > 0) {
86 size_t eq = match.find_first_of('='); 91 // need to determine the property used
92 string memstr, expr;
93 WinProperty prop;
94 string::size_type eq = match.find_first_of('=');
87 if (eq == match.npos) { 95 if (eq == match.npos) {
88 if (!addTerm(match, NAME)) { 96 memstr = match;
89 had_error = pos + match.find_first_of('(') + 1; 97 expr = "[current]";
90 break;
91 }
92 } else { 98 } else {
93 // need to determine the property used
94 string memstr, expr;
95 WinProperty prop;
96 memstr.assign(match, 0, eq); // memstr = our identifier 99 memstr.assign(match, 0, eq); // memstr = our identifier
97 expr.assign(match, eq+1, match.length()); 100 expr.assign(match, eq+1, match.length());
98 if (strcasecmp(memstr.c_str(), "name") == 0) {
99 prop = NAME;
100 } else if (strcasecmp(memstr.c_str(), "class") == 0) {
101 prop = CLASS;
102 } else if (strcasecmp(memstr.c_str(), "title") == 0) {
103 prop = TITLE;
104 } else if (strcasecmp(memstr.c_str(), "role") == 0) {
105 prop = ROLE;
106 } else {
107 had_error = pos + match.find_first_of('(') + 1;
108 break;
109 }
110 if (!addTerm(expr, prop)) {
111 had_error = pos + ((str+pos) - index(str+pos, '=')) + 1;
112 break;
113 }
114 } 101 }
102 if (strcasecmp(memstr.c_str(), "name") == 0) {
103 prop = NAME;
104 } else if (strcasecmp(memstr.c_str(), "class") == 0) {
105 prop = CLASS;
106 } else if (strcasecmp(memstr.c_str(), "title") == 0) {
107 prop = TITLE;
108 } else if (strcasecmp(memstr.c_str(), "role") == 0) {
109 prop = ROLE;
110 } else if (strcasecmp(memstr.c_str(), "maximized") == 0) {
111 prop = MAXIMIZED;
112 } else if (strcasecmp(memstr.c_str(), "minimized") == 0) {
113 prop = MINIMIZED;
114 } else if (strcasecmp(memstr.c_str(), "shaded") == 0) {
115 prop = SHADED;
116 } else if (strcasecmp(memstr.c_str(), "stuck") == 0) {
117 prop = STUCK;
118 } else if (strcasecmp(memstr.c_str(), "focushidden") == 0) {
119 prop = FOCUSHIDDEN;
120 } else if (strcasecmp(memstr.c_str(), "iconhidden") == 0) {
121 prop = ICONHIDDEN;
122 } else if (strcasecmp(memstr.c_str(), "workspace") == 0) {
123 prop = WORKSPACE;
124 } else if (strcasecmp(memstr.c_str(), "head") == 0) {
125 prop = HEAD;
126 } else if (strcasecmp(memstr.c_str(), "layer") == 0) {
127 prop = LAYER;
128 } else {
129 prop = NAME;
130 expr = match;
131 }
132 had_error = !addTerm(expr, prop);
115 pos += err; 133 pos += err;
116 } 134 }
117 } 135 }
118 if (pos == 0 && had_error == 0) { 136 if (pos == 0 && !had_error) {
119 // no match terms given, this is not allowed 137 // no match terms given, this is not allowed
120 had_error = 1; 138 had_error = true;
121 } 139 }
122 140
123 if (had_error == 0) { 141 if (!had_error) {
124 // otherwise, we check for a number 142 // otherwise, we check for a number
125 string number; 143 string number;
126 err = FbTk::StringUtil::getStringBetween(number, 144 err = FbTk::StringUtil::getStringBetween(number,
@@ -139,12 +157,11 @@ ClientPattern::ClientPattern(const char *str):
139 uerr = match.find_first_not_of(" \t\n", pos); 157 uerr = match.find_first_not_of(" \t\n", pos);
140 if (uerr != match.npos) { 158 if (uerr != match.npos) {
141 // found something, not good 159 // found something, not good
142 had_error++; 160 had_error = true;
143 } 161 }
144 } 162 }
145 163
146 if (had_error > 0) { 164 if (had_error) {
147 m_matchlimit = had_error;
148 // delete all the terms 165 // delete all the terms
149 while (!m_terms.empty()) { 166 while (!m_terms.empty()) {
150 Term * term = m_terms.back(); 167 Term * term = m_terms.back();
@@ -183,6 +200,34 @@ string ClientPattern::toString() const {
183 break; 200 break;
184 case ROLE: 201 case ROLE:
185 pat.append("role="); 202 pat.append("role=");
203 break;
204 case MAXIMIZED:
205 pat.append("maximized=");
206 break;
207 case MINIMIZED:
208 pat.append("minimized=");
209 break;
210 case SHADED:
211 pat.append("shaded=");
212 break;
213 case STUCK:
214 pat.append("stuck=");
215 break;
216 case FOCUSHIDDEN:
217 pat.append("focushidden=");
218 break;
219 case ICONHIDDEN:
220 pat.append("iconhidden=");
221 break;
222 case WORKSPACE:
223 pat.append("workspace=");
224 break;
225 case HEAD:
226 pat.append("head=");
227 break;
228 case LAYER:
229 pat.append("layer=");
230 break;
186 } 231 }
187 232
188 pat.append((*it)->orig); 233 pat.append((*it)->orig);
@@ -198,9 +243,8 @@ string ClientPattern::toString() const {
198} 243}
199 244
200// does this client match this pattern? 245// does this client match this pattern?
201bool ClientPattern::match(const WinClient &win) const { 246bool ClientPattern::match(const Focusable &win) const {
202 if (m_matchlimit != 0 && m_nummatches >= m_matchlimit || 247 if (m_matchlimit != 0 && m_nummatches >= m_matchlimit)
203 m_terms.empty())
204 return false; // already matched out 248 return false; // already matched out
205 249
206 // regmatch everything 250 // regmatch everything
@@ -209,7 +253,20 @@ bool ClientPattern::match(const WinClient &win) const {
209 Terms::const_iterator it = m_terms.begin(); 253 Terms::const_iterator it = m_terms.begin();
210 Terms::const_iterator it_end = m_terms.end(); 254 Terms::const_iterator it_end = m_terms.end();
211 for (; it != it_end; ++it) { 255 for (; it != it_end; ++it) {
212 if (!(*it)->regexp.match(getProperty((*it)->prop, win))) 256 if ((*it)->orig == "[current]") {
257 // workspaces don't necessarily have unique names, so we want to
258 // compare numbers instead of strings
259 if ((*it)->prop == WORKSPACE && (!win.fbwindow() ||
260 win.fbwindow()->workspaceNumber() !=
261 win.screen().currentWorkspaceID()))
262 return false;
263 else {
264 WinClient *focused = FocusControl::focusedWindow();
265 if (!focused || getProperty((*it)->prop, win) !=
266 getProperty((*it)->prop, *focused))
267 return false;
268 }
269 } else if (!(*it)->regexp.match(getProperty((*it)->prop, win)))
213 return false; 270 return false;
214 } 271 }
215 return true; 272 return true;
@@ -232,7 +289,11 @@ bool ClientPattern::addTerm(const string &str, WinProperty prop) {
232 return true; 289 return true;
233} 290}
234 291
235string ClientPattern::getProperty(WinProperty prop, const WinClient &client) const { 292string ClientPattern::getProperty(WinProperty prop,
293 const Focusable &client) const {
294 // we need this for some of the window properties
295 const FluxboxWindow *fbwin = client.fbwindow();
296
236 switch (prop) { 297 switch (prop) {
237 case TITLE: 298 case TITLE:
238 return client.title(); 299 return client.title();
@@ -244,8 +305,44 @@ string ClientPattern::getProperty(WinProperty prop, const WinClient &client) con
244 return client.getWMClassName(); 305 return client.getWMClassName();
245 break; 306 break;
246 case ROLE: 307 case ROLE:
247 Atom wm_role = XInternAtom(FbTk::App::instance()->display(), "WM_WINDOW_ROLE", False); 308 return client.getWMRole();
248 return client.textProperty(wm_role); 309 break;
310 case MAXIMIZED:
311 return (fbwin && fbwin->isMaximized()) ? "yes" : "no";
312 break;
313 case MINIMIZED:
314 return (fbwin && fbwin->isIconic()) ? "yes" : "no";
315 break;
316 case SHADED:
317 return (fbwin && fbwin->isShaded()) ? "yes" : "no";
318 break;
319 case STUCK:
320 return (fbwin && fbwin->isStuck()) ? "yes" : "no";
321 break;
322 case FOCUSHIDDEN:
323 return (fbwin && fbwin->isFocusHidden()) ? "yes" : "no";
324 break;
325 case ICONHIDDEN:
326 return (fbwin && fbwin->isIconHidden()) ? "yes" : "no";
327 break;
328 case WORKSPACE: {
329 if (!fbwin)
330 return "";
331 const Workspace *w = client.screen().getWorkspace(fbwin->workspaceNumber());
332 return w ? w->name() : "";
333 break;
334 }
335 case HEAD: {
336 if (!fbwin)
337 return "";
338 int head = client.screen().getHead(fbwin->fbWindow());
339 char tmpstr[128];
340 sprintf(tmpstr, "%d", head);
341 return std::string(tmpstr);
342 break;
343 }
344 case LAYER:
345 return fbwin ? ::Layer::getString(fbwin->layerNum()) : "";
249 break; 346 break;
250 } 347 }
251 return client.getWMClassName(); 348 return client.getWMClassName();