aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/asciidoc/client-patterns.txt9
-rw-r--r--doc/asciidoc/fluxbox-keys.txt8
-rw-r--r--src/ClientPattern.cc188
-rw-r--r--src/ClientPattern.hh7
-rw-r--r--src/CurrentWindowCmd.cc69
-rw-r--r--src/Focusable.hh2
-rw-r--r--src/WinClient.hh1
-rw-r--r--src/Window.cc4
-rw-r--r--src/Window.hh1
9 files changed, 206 insertions, 83 deletions
diff --git a/doc/asciidoc/client-patterns.txt b/doc/asciidoc/client-patterns.txt
index 85dac7b..5b00e0c 100644
--- a/doc/asciidoc/client-patterns.txt
+++ b/doc/asciidoc/client-patterns.txt
@@ -64,6 +64,9 @@ The following values are accepted for 'propertyname':::
64*Layer*;; 64*Layer*;;
65 The string name of the window's layer, which is one of 65 The string name of the window's layer, which is one of
66 *AboveDock*, *Dock*, *Top*, *Normal*, *Bottom*, *Desktop* 66 *AboveDock*, *Dock*, *Top*, *Normal*, *Bottom*, *Desktop*
67*@XPROP*;;
68 A string, corresponding to any xproperty (Use either the *xprop(1)*
69 utility or the 'SetXProp' command to set a xproperty to a window)
67 70
68.Matches any windows with the CLASSNAME of "xterm" 71.Matches any windows with the CLASSNAME of "xterm"
69.......... 72..........
@@ -79,3 +82,9 @@ The following values are accepted for 'propertyname':::
79........... 82...........
80(Head=[mouse]) (Layer!=[current]) 83(Head=[mouse]) (Layer!=[current])
81........... 84...........
85
86.Matches any windows having a xproperty named FOO with "bar" in it
87..............
88(@FOO=.*bar.*)
89..............
90
diff --git a/doc/asciidoc/fluxbox-keys.txt b/doc/asciidoc/fluxbox-keys.txt
index 41ad1e2..16bc18c 100644
--- a/doc/asciidoc/fluxbox-keys.txt
+++ b/doc/asciidoc/fluxbox-keys.txt
@@ -327,6 +327,10 @@ two arguments;;
327 heads. If this takes the window beyond the total number of heads, it 327 heads. If this takes the window beyond the total number of heads, it
328 will wrap around to the beginning. 328 will wrap around to the beginning.
329 329
330*SetXProp* 'PROP=value'::
331 Sets the xproperty 'PROP' of the current window to 'value'. Delete the
332 content of 'PROP' by using 'PROP='.
333
330Workspace Commands 334Workspace Commands
331~~~~~~~~~~~~~~~~~~ 335~~~~~~~~~~~~~~~~~~
332These commands affect the entire workspace (or "desktop" as it is sometimes 336These commands affect the entire workspace (or "desktop" as it is sometimes
@@ -643,8 +647,12 @@ Mod4 t :If {Some Matches (xterm)} {NextWindow (xterm)} {Exec xterm}
643 647
644# Set a different wallpaper on every workspace: 648# Set a different wallpaper on every workspace:
645ChangeWorkspace :Exec fbsetbg ~/.fluxbox/bg$(xprop -root _NET_CURRENT_DESKTOP | awk '{print $3}').png 649ChangeWorkspace :Exec fbsetbg ~/.fluxbox/bg$(xprop -root _NET_CURRENT_DESKTOP | awk '{print $3}').png
650
651# Focusses the next window with it's xproperty 'PROP' set to 'foo'
652Mod4 p Mod4 Tab :NextWindow (@PROP=foo)
646.................. 653..................
647 654
655
648AUTHORS 656AUTHORS
649------- 657-------
650- Jim Ramsay <i.am at jimramsay com> (>fluxbox-1.0.0) 658- Jim Ramsay <i.am at jimramsay com> (>fluxbox-1.0.0)
diff --git a/src/ClientPattern.cc b/src/ClientPattern.cc
index 7e7e715..71725fb 100644
--- a/src/ClientPattern.cc
+++ b/src/ClientPattern.cc
@@ -66,7 +66,7 @@ struct Name2WinProperty {
66 ClientPattern::WinProperty prop; 66 ClientPattern::WinProperty prop;
67}; 67};
68 68
69Name2WinProperty name_2_winproperties[] = { // sorted for 'bsearch' 69const Name2WinProperty name_2_winproperties[] = { // sorted for 'bsearch'
70 { "class", ClientPattern::CLASS }, 70 { "class", ClientPattern::CLASS },
71 { "focushidden", ClientPattern::FOCUSHIDDEN }, 71 { "focushidden", ClientPattern::FOCUSHIDDEN },
72 { "head", ClientPattern::HEAD }, 72 { "head", ClientPattern::HEAD },
@@ -92,29 +92,43 @@ int name_2_winproperty_cmp(const void* a, const void* b) {
92 reinterpret_cast<const Name2WinProperty*>(b)->name); 92 reinterpret_cast<const Name2WinProperty*>(b)->name);
93} 93}
94 94
95const Name2WinProperty* find_winproperty_by_name(const FbTk::FbString& name) {
96
97 const Name2WinProperty key = { name.c_str(), ClientPattern::CLASS };
98 const Name2WinProperty* result = reinterpret_cast<Name2WinProperty*>(
99 bsearch(&key, name_2_winproperties,
100 sizeof(name_2_winproperties) / sizeof(Name2WinProperty),
101 sizeof(Name2WinProperty),
102 name_2_winproperty_cmp));
103
104 return result;
105}
106
107
95struct Prop2String { 108struct Prop2String {
96 ClientPattern::WinProperty prop; 109 ClientPattern::WinProperty prop;
97 const char* str; 110 const char* str;
98}; 111};
99 112
100Prop2String property_2_strings[] = { // sorted by 'prop' 113Prop2String property_2_strings[] = { // sorted by 'prop'
101 { ClientPattern::TITLE, "title=" }, 114 { ClientPattern::TITLE, "title" },
102 { ClientPattern::CLASS, "class=" }, 115 { ClientPattern::CLASS, "class" },
103 { ClientPattern::NAME, "name=" }, 116 { ClientPattern::NAME, "name" },
104 { ClientPattern::ROLE, "role=" }, 117 { ClientPattern::ROLE, "role" },
105 { ClientPattern::TRANSIENT, "transient=" }, 118 { ClientPattern::TRANSIENT, "transient" },
106 { ClientPattern::MAXIMIZED, "maximized=" }, 119 { ClientPattern::MAXIMIZED, "maximized" },
107 { ClientPattern::MINIMIZED, "minimized=" }, 120 { ClientPattern::MINIMIZED, "minimized" },
108 { ClientPattern::SHADED, "shaded=" }, 121 { ClientPattern::SHADED, "shaded" },
109 { ClientPattern::STUCK, "stuck=" }, 122 { ClientPattern::STUCK, "stuck" },
110 { ClientPattern::FOCUSHIDDEN, "focushidden=" }, 123 { ClientPattern::FOCUSHIDDEN, "focushidden" },
111 { ClientPattern::ICONHIDDEN, "iconhidden=" }, 124 { ClientPattern::ICONHIDDEN, "iconhidden" },
112 { ClientPattern::WORKSPACE, "workspace=" }, 125 { ClientPattern::WORKSPACE, "workspace" },
113 { ClientPattern::WORKSPACENAME, "workspacename=" }, 126 { ClientPattern::WORKSPACENAME, "workspacename" },
114 { ClientPattern::HEAD, "head=" }, 127 { ClientPattern::HEAD, "head" },
115 { ClientPattern::LAYER, "layer=" }, 128 { ClientPattern::LAYER, "layer" },
116 { ClientPattern::URGENT, "urgent=" }, 129 { ClientPattern::URGENT, "urgent" },
117 { ClientPattern::SCREEN, "screen=" } 130 { ClientPattern::SCREEN, "screen" },
131 { ClientPattern::XPROP, "@" },
118}; 132};
119 133
120 134
@@ -129,16 +143,21 @@ Prop2String property_2_strings[] = { // sorted by 'prop'
129 */ 143 */
130struct ClientPattern::Term { 144struct ClientPattern::Term {
131 145
132 Term(const FbTk::FbString& _regstr, WinProperty _prop, bool _negate) : 146 Term(const FbTk::FbString& _regstr, WinProperty _prop, bool _negate, const FbTk::FbString& _xprop) :
133 orig(_regstr), 147 regstr(_regstr),
148 xpropstr(_xprop),
134 regexp(_regstr, true), 149 regexp(_regstr, true),
135 prop(_prop), 150 prop(_prop),
136 negate(_negate) { 151 negate(_negate) {
137 152
153 xprop = XInternAtom(FbTk::App::instance()->display(), xpropstr.c_str(), False);
138 } 154 }
139 155
140 FbTk::FbString orig; 156 // (title=.*bar) or (@FOO=.*bar)
141 FbTk::RegExp regexp; 157 FbTk::FbString regstr; // .*bar
158 FbTk::FbString xpropstr; // @FOO=.*bar
159 Atom xprop; // Atom of 'FOO'
160 FbTk::RegExp regexp; // compiled version of '.*bar'
142 WinProperty prop; 161 WinProperty prop;
143 bool negate; 162 bool negate;
144}; 163};
@@ -175,51 +194,65 @@ ClientPattern::ClientPattern(const char *str):
175 err = FbTk::StringUtil::getStringBetween(match, 194 err = FbTk::StringUtil::getStringBetween(match,
176 str + pos, 195 str + pos,
177 '(', ')', " \t\n", true); 196 '(', ')', " \t\n", true);
197
178 if (err > 0) { 198 if (err > 0) {
179 // need to determine the property used 199
180 string memstr, expr; 200 WinProperty prop = NAME;
181 WinProperty prop; 201 std::string expr;
182 string::size_type eq = match.find_first_of('='); 202 std::string xprop;
183 if (eq == match.npos) {
184 memstr = match;
185 expr = "[current]";
186 } else {
187 memstr.assign(match, 0, eq); // memstr = our identifier
188 expr.assign(match, eq+1, match.length());
189 }
190 bool negate = false; 203 bool negate = false;
191 if (!memstr.empty() && memstr[memstr.length()-1] == '!') { 204
192 negate = true; 205 // need to determine the property used, potential patterns:
193 memstr.assign(memstr, 0, memstr.length()-1); 206 //
207 // A) foo (short for 'title=foo')
208 // B) foo=bar
209 // C) foo!=bar
210 //
211 // D) @foo=bar (xproperty 'foo' equal to 'bar')
212 //
213
214 string propstr = match;
215 string::size_type eq = propstr.find_first_of('=');
216
217 if (eq == propstr.npos) { // A
218 expr = "[current]";
219 } else { // B or C, so strip away the '='
220
221 // 'bar'
222 expr.assign(propstr.begin() + eq + 1, propstr.end());
223
224 // 'foo' or 'foo!'
225 propstr.resize(eq);
226 if (propstr.rfind("!", propstr.npos, 1) != propstr.npos) { // C 'foo!'
227 negate = true;
228 propstr.resize(propstr.size()-1);
229 }
194 } 230 }
195 231
196 memstr = FbTk::StringUtil::toLower(memstr); 232 if (propstr[0] != '@') { // not D
197 233
198 Name2WinProperty key = { memstr.c_str(), CLASS }; 234 const Name2WinProperty* p = find_winproperty_by_name(FbTk::StringUtil::toLower(propstr));
199 Name2WinProperty* i = reinterpret_cast<Name2WinProperty*>(
200 bsearch(&key, name_2_winproperties,
201 sizeof(name_2_winproperties) / sizeof(Name2WinProperty),
202 sizeof(Name2WinProperty),
203 name_2_winproperty_cmp));
204 235
205 if (i) { 236 if (p) {
206 prop = i->prop; 237 prop = p->prop;
207 } else { 238 } else {
208 prop = NAME; 239 expr = match;
209 expr = match; 240 }
241 } else { // D
242 prop = XPROP;
243 xprop.assign(propstr, 1, propstr.size());
210 } 244 }
211 245
212 had_error = !addTerm(expr, prop, negate); 246 had_error = !addTerm(expr, prop, negate, xprop);
213 pos += err; 247 pos += err;
214 } 248 }
215 } 249 }
216 if (pos == 0 && !had_error) { 250 if (pos == 0 && !had_error) { // no match terms given, this is not allowed
217 // no match terms given, this is not allowed
218 had_error = true; 251 had_error = true;
219 } 252 }
220 253
221 if (!had_error) { 254 if (!had_error) { // otherwise, we check for a number
222 // otherwise, we check for a number 255
223 string number; 256 string number;
224 err = FbTk::StringUtil::getStringBetween(number, 257 err = FbTk::StringUtil::getStringBetween(number,
225 str+pos, 258 str+pos,
@@ -251,23 +284,26 @@ ClientPattern::~ClientPattern() {
251 284
252// return a string representation of this pattern 285// return a string representation of this pattern
253string ClientPattern::toString() const { 286string ClientPattern::toString() const {
254 string pat; 287 string result;
255 Terms::const_iterator it = m_terms.begin(); 288 Terms::const_iterator it = m_terms.begin();
256 Terms::const_iterator it_end = m_terms.end(); 289 Terms::const_iterator it_end = m_terms.end();
257 for (; it != it_end; ++it) { 290 for (; it != it_end; ++it) {
258 291 const Term& term = *(*it);
259 pat.append(" ("); 292 result.append(" (");
260 pat.append(property_2_strings[(*it)->prop].str); 293 result.append(property_2_strings[term.prop].str);
261 pat.append((*it)->orig); 294 if (term.prop == XPROP)
262 pat.append(")"); 295 result.append(term.xpropstr);
296 result.append(term.negate ? "!=" : "=");
297 result.append(term.regstr);
298 result.append(")");
263 } 299 }
264 300
265 if (m_matchlimit > 0) { 301 if (m_matchlimit > 0) {
266 pat.append(" {"); 302 result.append(" {");
267 pat.append(FbTk::StringUtil::number2String(m_matchlimit)); 303 result.append(FbTk::StringUtil::number2String(m_matchlimit));
268 pat.append("}"); 304 result.append("}");
269 } 305 }
270 return pat; 306 return result;
271} 307}
272 308
273// does this client match this pattern? 309// does this client match this pattern?
@@ -282,7 +318,10 @@ bool ClientPattern::match(const Focusable &win) const {
282 Terms::const_iterator it_end = m_terms.end(); 318 Terms::const_iterator it_end = m_terms.end();
283 for (; it != it_end; ++it) { 319 for (; it != it_end; ++it) {
284 const Term& term = *(*it); 320 const Term& term = *(*it);
285 if (term.orig == "[current]") { 321 if (term.prop == XPROP) {
322 if (!term.negate ^ (term.regexp.match(win.getTextProperty(term.xprop))))
323 return false;
324 } else if (term.regstr == "[current]") {
286 WinClient *focused = FocusControl::focusedWindow(); 325 WinClient *focused = FocusControl::focusedWindow();
287 if (term.prop == WORKSPACE) { 326 if (term.prop == WORKSPACE) {
288 if (!term.negate ^ (getProperty(term.prop, win) == FbTk::StringUtil::number2String(win.screen().currentWorkspaceID()))) 327 if (!term.negate ^ (getProperty(term.prop, win) == FbTk::StringUtil::number2String(win.screen().currentWorkspaceID())))
@@ -293,7 +332,7 @@ bool ClientPattern::match(const Focusable &win) const {
293 return false; 332 return false;
294 } else if (!focused || (!term.negate ^ (getProperty(term.prop, win) == getProperty(term.prop, *focused)))) 333 } else if (!focused || (!term.negate ^ (getProperty(term.prop, win) == getProperty(term.prop, *focused))))
295 return false; 334 return false;
296 } else if (term.prop == HEAD && term.orig == "[mouse]") { 335 } else if (term.prop == HEAD && term.regstr == "[mouse]") {
297 if (!term.negate ^ (getProperty(term.prop, win) == FbTk::StringUtil::number2String(win.screen().getCurrHead()))) 336 if (!term.negate ^ (getProperty(term.prop, win) == FbTk::StringUtil::number2String(win.screen().getCurrHead())))
298 return false; 337 return false;
299 338
@@ -307,7 +346,7 @@ bool ClientPattern::dependsOnFocusedWindow() const {
307 Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end(); 346 Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end();
308 for (; it != it_end; ++it) { 347 for (; it != it_end; ++it) {
309 if ((*it)->prop != WORKSPACE && (*it)->prop != WORKSPACENAME && 348 if ((*it)->prop != WORKSPACE && (*it)->prop != WORKSPACENAME &&
310 (*it)->orig == "[current]") 349 (*it)->regstr == "[current]")
311 return true; 350 return true;
312 } 351 }
313 return false; 352 return false;
@@ -317,7 +356,7 @@ bool ClientPattern::dependsOnCurrentWorkspace() const {
317 Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end(); 356 Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end();
318 for (; it != it_end; ++it) { 357 for (; it != it_end; ++it) {
319 if (((*it)->prop == WORKSPACE || (*it)->prop == WORKSPACENAME) && 358 if (((*it)->prop == WORKSPACE || (*it)->prop == WORKSPACENAME) &&
320 (*it)->orig == "[current]") 359 (*it)->regstr == "[current]")
321 return true; 360 return true;
322 } 361 }
323 return false; 362 return false;
@@ -326,17 +365,16 @@ bool ClientPattern::dependsOnCurrentWorkspace() const {
326// add an expression to match against 365// add an expression to match against
327// The first argument is a regular expression, the second is the member 366// The first argument is a regular expression, the second is the member
328// function that we wish to match against. 367// function that we wish to match against.
329bool ClientPattern::addTerm(const FbTk::FbString &str, WinProperty prop, bool negate) { 368bool ClientPattern::addTerm(const FbTk::FbString &str, WinProperty prop, bool negate, const FbTk::FbString& xprop) {
330 369
331 bool rc = false; 370 bool rc = false;
332 Term* term = new Term(str, prop, negate); 371 Term* term = new Term(str, prop, negate, xprop);
333 372
334 if (!term) 373 if (!term)
335 return rc; 374 return rc;
336 375
337 if (!term->regexp.error()) { 376 if (rc = !term->regexp.error()) {
338 m_terms.push_back(term); 377 m_terms.push_back(term);
339 rc = true;
340 } else { 378 } else {
341 delete term; 379 delete term;
342 } 380 }
@@ -424,8 +462,11 @@ bool ClientPattern::operator ==(const ClientPattern &pat) const {
424 Terms::const_iterator other_it = pat.m_terms.begin(); 462 Terms::const_iterator other_it = pat.m_terms.begin();
425 Terms::const_iterator other_it_end = pat.m_terms.end(); 463 Terms::const_iterator other_it_end = pat.m_terms.end();
426 for (; it != it_end && other_it != other_it_end; ++it, ++other_it) { 464 for (; it != it_end && other_it != other_it_end; ++it, ++other_it) {
427 if ((*it)->orig != (*other_it)->orig || 465 const Term& i = *(*it);
428 (*it)->negate != (*other_it)->negate) 466 const Term& o = *(*other_it);
467 if (i.regstr != o.regstr ||
468 i.negate != o.negate ||
469 i.xpropstr != o.xpropstr)
429 return false; 470 return false;
430 } 471 }
431 if (it != it_end || other_it != other_it_end) 472 if (it != it_end || other_it != other_it_end)
@@ -433,3 +474,4 @@ bool ClientPattern::operator ==(const ClientPattern &pat) const {
433 474
434 return true; 475 return true;
435} 476}
477
diff --git a/src/ClientPattern.hh b/src/ClientPattern.hh
index 6aa2e11..315edb1 100644
--- a/src/ClientPattern.hh
+++ b/src/ClientPattern.hh
@@ -54,7 +54,8 @@ public:
54 enum WinProperty { 54 enum WinProperty {
55 TITLE = 0, CLASS, NAME, ROLE, TRANSIENT, 55 TITLE = 0, CLASS, NAME, ROLE, TRANSIENT,
56 MAXIMIZED, MINIMIZED, SHADED, STUCK, FOCUSHIDDEN, ICONHIDDEN, 56 MAXIMIZED, MINIMIZED, SHADED, STUCK, FOCUSHIDDEN, ICONHIDDEN,
57 WORKSPACE, WORKSPACENAME, HEAD, LAYER, URGENT, SCREEN 57 WORKSPACE, WORKSPACENAME, HEAD, LAYER, URGENT, SCREEN,
58 XPROP
58 }; 59 };
59 60
60 /// Does this client match this pattern? 61 /// Does this client match this pattern?
@@ -70,9 +71,11 @@ public:
70 * Add an expression to match against 71 * Add an expression to match against
71 * @param str is a regular expression 72 * @param str is a regular expression
72 * @param prop is the member function that we wish to match against 73 * @param prop is the member function that we wish to match against
74 * @param negate is if the term should be negated
75 * @param xprop is the name of the prop if prop is XPROP
73 * @return false if the regexp wasn't valid 76 * @return false if the regexp wasn't valid
74 */ 77 */
75 bool addTerm(const FbTk::FbString &str, WinProperty prop, bool negate = false); 78 bool addTerm(const FbTk::FbString &str, WinProperty prop, bool negate = false, const FbTk::FbString& xprop = FbTk::FbString());
76 79
77 void addMatch() { ++m_nummatches; } 80 void addMatch() { ++m_nummatches; }
78 void removeMatch() { --m_nummatches; } 81 void removeMatch() { --m_nummatches; }
diff --git a/src/CurrentWindowCmd.cc b/src/CurrentWindowCmd.cc
index e2fdb94..1851f2d 100644
--- a/src/CurrentWindowCmd.cc
+++ b/src/CurrentWindowCmd.cc
@@ -227,23 +227,75 @@ REGISTER_COMMAND_PARSER(focus, parseFocusCmd, void);
227 227
228class ActivateTabCmd: public WindowHelperCmd { 228class ActivateTabCmd: public WindowHelperCmd {
229public: 229public:
230 ActivateTabCmd() { } 230 explicit ActivateTabCmd() { }
231protected: 231protected:
232 void real_execute(); 232 void real_execute() {
233 WinClient* winclient = fbwindow().winClientOfLabelButtonWindow(
234 Fluxbox::instance()->lastEvent().xany.window);
235
236 if (winclient && winclient != &fbwindow().winClient()) {
237 fbwindow().setCurrentClient(*winclient, true);
238 }
239
240 }
241};
242
243
244REGISTER_COMMAND(activatetab, ActivateTabCmd, void);
245
246class SetXPropCmd: public WindowHelperCmd {
247public:
248 explicit SetXPropCmd(const FbTk::FbString& name, const FbTk::FbString& value) :
249 m_name(name), m_value(value) { }
250
251protected:
252 void real_execute() {
253
254 WinClient& client = fbwindow().winClient();
255 Atom prop = XInternAtom(client.display(), m_name.c_str(), False);
256
257 client.changeProperty(prop, XInternAtom(client.display(), "UTF8_STRING", False), 8,
258 PropModeReplace, (unsigned char*)m_value.c_str(), m_value.size());
259 }
260
261private:
262 FbTk::FbString m_name;
263 FbTk::FbString m_value;
233}; 264};
234 265
266FbTk::Command<void> *parseSetXPropCmd(const string &command, const string &args, bool trusted) {
267
268 SetXPropCmd* cmd = 0;
269
270 if (trusted) {
271
272 FbTk::FbString name = args;
273
274 FbTk::StringUtil::removeFirstWhitespace(name);
275 FbTk::StringUtil::removeTrailingWhitespace(name);
276
277 if (name.size() > 1 && name[0] != '=') { // the smallest valid argument is 'X='
278
279 FbTk::FbString value;
235 280
236void ActivateTabCmd::real_execute() { 281 size_t eq = name.find('=');
282 if (eq != name.npos && eq != name.size()) {
237 283
238 WinClient* winclient = fbwindow().winClientOfLabelButtonWindow( 284 value.assign(name, eq + 1, name.size());
239 Fluxbox::instance()->lastEvent().xany.window); 285 name.resize(eq);
286 }
240 287
241 if (winclient && winclient != &fbwindow().winClient()) { 288 cmd = new SetXPropCmd(name, value);
242 fbwindow().setCurrentClient(*winclient, true); 289
290 }
243 } 291 }
292
293 return cmd;
244} 294}
245 295
246REGISTER_COMMAND(activatetab, ActivateTabCmd, void); 296REGISTER_COMMAND_PARSER(setxprop, parseSetXPropCmd, void);
297
298
247 299
248} // end anonymous namespace 300} // end anonymous namespace
249 301
@@ -677,6 +729,7 @@ void SetAlphaCmd::real_execute() {
677 : m_unfocus); 729 : m_unfocus);
678} 730}
679 731
732
680REGISTER_COMMAND_WITH_ARGS(matches, MatchCmd, bool); 733REGISTER_COMMAND_WITH_ARGS(matches, MatchCmd, bool);
681 734
682bool MatchCmd::real_execute() { 735bool MatchCmd::real_execute() {
diff --git a/src/Focusable.hh b/src/Focusable.hh
index 47f14d3..4583a62 100644
--- a/src/Focusable.hh
+++ b/src/Focusable.hh
@@ -88,6 +88,8 @@ public:
88 /// @return wm role string (for pattern matching) 88 /// @return wm role string (for pattern matching)
89 virtual std::string getWMRole() const { return "Focusable"; } 89 virtual std::string getWMRole() const { return "Focusable"; }
90 90
91 virtual FbTk::FbString getTextProperty(Atom prop) const { return ""; }
92
91 /// @return whether this window is a transient (for pattern matching) 93 /// @return whether this window is a transient (for pattern matching)
92 virtual bool isTransient() const { return false; } 94 virtual bool isTransient() const { return false; }
93 95
diff --git a/src/WinClient.hh b/src/WinClient.hh
index ebe61a5..157278e 100644
--- a/src/WinClient.hh
+++ b/src/WinClient.hh
@@ -96,6 +96,7 @@ public:
96 std::string getWMRole() const; 96 std::string getWMRole() const;
97 WindowState::WindowType getWindowType() const { return m_window_type; } 97 WindowState::WindowType getWindowType() const { return m_window_type; }
98 void setWindowType(WindowState::WindowType type) { m_window_type = type; } 98 void setWindowType(WindowState::WindowType type) { m_window_type = type; }
99 FbTk::FbString getTextProperty(Atom prop) const { return FbTk::FbWindow::textProperty(prop); }
99 100
100 WinClient *transientFor() { return transient_for; } 101 WinClient *transientFor() { return transient_for; }
101 const WinClient *transientFor() const { return transient_for; } 102 const WinClient *transientFor() const { return transient_for; }
diff --git a/src/Window.cc b/src/Window.cc
index 5f64705..1837cee 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -3363,6 +3363,10 @@ FbTk::FbString FluxboxWindow::getWMRole() const {
3363 return (m_client ? m_client->getWMRole() : "FluxboxWindow"); 3363 return (m_client ? m_client->getWMRole() : "FluxboxWindow");
3364} 3364}
3365 3365
3366FbTk::FbString FluxboxWindow::getTextProperty(Atom prop) const {
3367 return (m_client ? m_client->getTextProperty(prop) : Focusable::getTextProperty(prop));
3368}
3369
3366bool FluxboxWindow::isTransient() const { 3370bool FluxboxWindow::isTransient() const {
3367 return (m_client && m_client->isTransient()); 3371 return (m_client && m_client->isTransient());
3368} 3372}
diff --git a/src/Window.hh b/src/Window.hh
index 080ceac..7f8133e 100644
--- a/src/Window.hh
+++ b/src/Window.hh
@@ -422,6 +422,7 @@ public:
422 const FbTk::FbString &getWMClassName() const; 422 const FbTk::FbString &getWMClassName() const;
423 const FbTk::FbString &getWMClassClass() const; 423 const FbTk::FbString &getWMClassClass() const;
424 std::string getWMRole() const; 424 std::string getWMRole() const;
425 FbTk::FbString getTextProperty(Atom prop) const;
425 void setWindowType(WindowState::WindowType type); 426 void setWindowType(WindowState::WindowType type);
426 bool isTransient() const; 427 bool isTransient() const;
427 428