~ubuntu-branches/ubuntu/trusty/fluxbox/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/30-try-to-fix-532094/src/ClientPattern.cc

  • Committer: Package Import Robot
  • Author(s): Paul Tagliamonte
  • Date: 2010-08-12 21:16:02 UTC
  • mfrom: (0.1.1) (1.1.10)
  • Revision ID: package-import@ubuntu.com-20100812211602-3tsmzl9in5nmwz7z
Tags: 1.1.1+git20100807.0cc08f9-1
* debian/ dir has been cleaned out, complete repackage
  of most files.
* pulled new archive from git.fluxbox.org HEAD, saved as
  tar.gz.
* Added in fluxbox.* files from the old dfsg tree.
* Added in system.fluxbox-menu file from the old dfsg tree
* Added the source/format file to bump package source
  version from 1.0 to 3.0 (quilt). 
* Changed rules file to match the old dfsg setup so that
  fluxbox behaves nicely.
* Removed entries from copyright that no longer apply.
* Added theme based on Denis Brand ( naran )'s old theme.
* Added a background I whipped up.
* Changed compile flags to point to debian theme by default
* Adding a patch to have fluxbox use x-terminal-emulator
  over xterm. Closes: #591694 (LP: #580485)
* Adding a patch to allow titlebar-window dragging.
* Changed the flags in rules to pull from a script. This script
  lets us un-hardcode what theme is default. Be sure there
  is a theme pack!
* Added comments to my patches.
* Removing debian/docs, empty file.
* Fixing fluxbox.desktop to remove all the warnings from
  desktop-file-validate
* Fixing libtool issue by running an update before
  configure in the rules script.
* Added a compile flag script to auto-detect what platform
  we are running on, and apply the correct theme. This
  should solve Ubuntnu issues later on.
* adding in a get-orig-source rule
* fixing the upstream version number to pinpoint
  the commit ( thanks, lfaraone ).
* adding a rule for get-orig-source. ( thanks again,
  lfaraone ).
* Updated rules to actually allow us to do a build from it
* Removed Denis from the uploaders ( as per an email
  conversation )
* Removing madduck from the uploaders ( thanks for asking,
  lfaraone. ). Thanks for your hard work, madduck.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// ClientPattern.cc for Fluxbox Window Manager
2
 
// Copyright (c) 2003 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org)
3
 
//                and Simon Bowden    (rathnor at users.sourceforge.net)
4
 
//
5
 
// Permission is hereby granted, free of charge, to any person obtaining a
6
 
// copy of this software and associated documentation files (the "Software"),
7
 
// to deal in the Software without restriction, including without limitation
8
 
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
 
// and/or sell copies of the Software, and to permit persons to whom the
10
 
// Software is furnished to do so, subject to the following conditions:
11
 
//
12
 
// The above copyright notice and this permission notice shall be included in
13
 
// all copies or substantial portions of the Software.
14
 
//
15
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 
// DEALINGS IN THE SOFTWARE.
22
 
 
23
 
#include "ClientPattern.hh"
24
 
 
25
 
#include "fluxbox.hh"
26
 
#include "FocusControl.hh"
27
 
#include "Layer.hh"
28
 
#include "Screen.hh"
29
 
#include "WinClient.hh"
30
 
#include "Workspace.hh"
31
 
 
32
 
#include "FbTk/StringUtil.hh"
33
 
#include "FbTk/App.hh"
34
 
#include "FbTk/stringstream.hh"
35
 
 
36
 
// use GNU extensions
37
 
#ifndef _GNU_SOURCE
38
 
#define _GNU_SOURCE
39
 
#endif // _GNU_SOURCE
40
 
 
41
 
#include <fstream>
42
 
#include <string>
43
 
#include <memory>
44
 
#ifdef HAVE_CSTDIO
45
 
  #include <cstdio>
46
 
#else
47
 
  #include <stdio.h>
48
 
#endif
49
 
 
50
 
// needed as well for index on some systems (e.g. solaris)
51
 
#include <strings.h>
52
 
 
53
 
using std::string;
54
 
 
55
 
 
56
 
ClientPattern::ClientPattern():
57
 
    m_matchlimit(0),
58
 
    m_nummatches(0) {}
59
 
 
60
 
// parse the given pattern (to end of line)
61
 
ClientPattern::ClientPattern(const char *str):
62
 
    m_matchlimit(0),
63
 
    m_nummatches(0)
64
 
{
65
 
    /* A rough grammar of a pattern is:
66
 
       PATTERN ::= MATCH+ LIMIT?
67
 
       MATCH ::= '(' word ')'
68
 
                 | '(' propertyname '=' word ')'
69
 
       LIMIT ::= '{' number '}'
70
 
 
71
 
       i.e. one or more match definitions, followed by
72
 
            an optional limit on the number of apps to match to
73
 
 
74
 
       Match definitions are enclosed in parentheses, and if no
75
 
       property name is given, then CLASSNAME is assumed.
76
 
       If no limit is specified, no limit is applied (i.e. limit = infinity)
77
 
    */
78
 
 
79
 
    bool had_error = false;
80
 
 
81
 
    int pos = 0;
82
 
    string match;
83
 
    int err = 1; // for starting first loop
84
 
    while (!had_error && err > 0) {
85
 
        err = FbTk::StringUtil::getStringBetween(match,
86
 
                                                 str + pos,
87
 
                                                 '(', ')', " \t\n", true);
88
 
        if (err > 0) {
89
 
            // need to determine the property used
90
 
            string memstr, expr;
91
 
            WinProperty prop;
92
 
            string::size_type eq = match.find_first_of('=');
93
 
            if (eq == match.npos) {
94
 
                memstr = match;
95
 
                expr = "[current]";
96
 
            } else {
97
 
                memstr.assign(match, 0, eq); // memstr = our identifier
98
 
                expr.assign(match, eq+1, match.length());
99
 
            }
100
 
            bool negate = false;
101
 
            if (!memstr.empty() && memstr[memstr.length()-1] == '!') {
102
 
                negate = true;
103
 
                memstr.assign(memstr, 0, memstr.length()-1);
104
 
            }
105
 
            if (strcasecmp(memstr.c_str(), "name") == 0) {
106
 
                prop = NAME;
107
 
            } else if (strcasecmp(memstr.c_str(), "class") == 0) {
108
 
                prop = CLASS;
109
 
            } else if (strcasecmp(memstr.c_str(), "title") == 0) {
110
 
                prop = TITLE;
111
 
            } else if (strcasecmp(memstr.c_str(), "role") == 0) {
112
 
                prop = ROLE;
113
 
            } else if (strcasecmp(memstr.c_str(), "transient") == 0) {
114
 
                prop = TRANSIENT;
115
 
            } else if (strcasecmp(memstr.c_str(), "maximized") == 0) {
116
 
                prop = MAXIMIZED;
117
 
            } else if (strcasecmp(memstr.c_str(), "minimized") == 0) {
118
 
                prop = MINIMIZED;
119
 
            } else if (strcasecmp(memstr.c_str(), "shaded") == 0) {
120
 
                prop = SHADED;
121
 
            } else if (strcasecmp(memstr.c_str(), "stuck") == 0) {
122
 
                prop = STUCK;
123
 
            } else if (strcasecmp(memstr.c_str(), "focushidden") == 0) {
124
 
                prop = FOCUSHIDDEN;
125
 
            } else if (strcasecmp(memstr.c_str(), "iconhidden") == 0) {
126
 
                prop = ICONHIDDEN;
127
 
            } else if (strcasecmp(memstr.c_str(), "workspace") == 0) {
128
 
                prop = WORKSPACE;
129
 
            } else if (strcasecmp(memstr.c_str(), "workspacename") == 0) {
130
 
                prop = WORKSPACENAME;
131
 
            } else if (strcasecmp(memstr.c_str(), "head") == 0) {
132
 
                prop = HEAD;
133
 
            } else if (strcasecmp(memstr.c_str(), "layer") == 0) {
134
 
                prop = LAYER;
135
 
            } else if (strcasecmp(memstr.c_str(), "urgent") == 0) {
136
 
                prop = URGENT;
137
 
            } else {
138
 
                prop = NAME;
139
 
                expr = match;
140
 
            }
141
 
            had_error = !addTerm(expr, prop, negate);
142
 
            pos += err;
143
 
        }
144
 
    }
145
 
    if (pos == 0 && !had_error) {
146
 
        // no match terms given, this is not allowed
147
 
        had_error = true;
148
 
    }
149
 
 
150
 
    if (!had_error) {
151
 
        // otherwise, we check for a number
152
 
        string number;
153
 
        err = FbTk::StringUtil::getStringBetween(number,
154
 
                                             str+pos,
155
 
                                             '{', '}');
156
 
        if (err > 0) {
157
 
            FbTk_istringstream iss(number.c_str());
158
 
            iss >> m_matchlimit;
159
 
            pos+=err;
160
 
        }
161
 
        // we don't care if there isn't one
162
 
 
163
 
        // there shouldn't be anything else on the line
164
 
        match = str + pos;
165
 
        size_t uerr;// need a special type here
166
 
        uerr = match.find_first_not_of(" \t\n", pos);
167
 
        if (uerr != match.npos) {
168
 
            // found something, not good
169
 
            had_error = true;
170
 
        }
171
 
    }
172
 
 
173
 
    if (had_error) {
174
 
        // delete all the terms
175
 
        while (!m_terms.empty()) {
176
 
            Term * term = m_terms.back();
177
 
            delete term;
178
 
            m_terms.pop_back();
179
 
        }
180
 
    }
181
 
}
182
 
 
183
 
ClientPattern::~ClientPattern() {
184
 
    // delete all the terms
185
 
    while (!m_terms.empty()) {
186
 
        delete m_terms.back();
187
 
        m_terms.pop_back();
188
 
    }
189
 
}
190
 
 
191
 
// return a string representation of this pattern
192
 
string ClientPattern::toString() const {
193
 
    string pat;
194
 
    Terms::const_iterator it = m_terms.begin();
195
 
    Terms::const_iterator it_end = m_terms.end();
196
 
    for (; it != it_end; ++it) {
197
 
 
198
 
        pat.append(" (");
199
 
 
200
 
        switch ((*it)->prop) {
201
 
        case NAME:
202
 
            pat.append("name=");
203
 
            break;
204
 
        case CLASS:
205
 
            pat.append("class=");
206
 
            break;
207
 
        case TITLE:
208
 
            pat.append("title=");
209
 
            break;
210
 
        case ROLE:
211
 
            pat.append("role=");
212
 
            break;
213
 
        case TRANSIENT:
214
 
            pat.append("transient=");
215
 
            break;
216
 
        case MAXIMIZED:
217
 
            pat.append("maximized=");
218
 
            break;
219
 
        case MINIMIZED:
220
 
            pat.append("minimized=");
221
 
            break;
222
 
        case SHADED:
223
 
            pat.append("shaded=");
224
 
            break;
225
 
        case STUCK:
226
 
            pat.append("stuck=");
227
 
            break;
228
 
        case FOCUSHIDDEN:
229
 
            pat.append("focushidden=");
230
 
            break;
231
 
        case ICONHIDDEN:
232
 
            pat.append("iconhidden=");
233
 
            break;
234
 
        case WORKSPACE:
235
 
            pat.append("workspace=");
236
 
            break;
237
 
        case WORKSPACENAME:
238
 
            pat.append("workspacename=");
239
 
            break;
240
 
        case HEAD:
241
 
            pat.append("head=");
242
 
            break;
243
 
        case LAYER:
244
 
            pat.append("layer=");
245
 
            break;
246
 
        case URGENT:
247
 
            pat.append("urgent=");
248
 
        }
249
 
 
250
 
        pat.append((*it)->orig);
251
 
        pat.append(")");
252
 
    }
253
 
 
254
 
    if (m_matchlimit > 0) {
255
 
        char num[20];
256
 
        sprintf(num, " {%d}", m_matchlimit);
257
 
        pat.append(num);
258
 
    }
259
 
    return pat;
260
 
}
261
 
 
262
 
// does this client match this pattern?
263
 
bool ClientPattern::match(const Focusable &win) const {
264
 
    if (m_matchlimit != 0 && m_nummatches >= m_matchlimit)
265
 
        return false; // already matched out
266
 
 
267
 
    // regmatch everything
268
 
    // currently, we use an "AND" policy for multiple terms
269
 
    // changing to OR would require minor modifications in this function only
270
 
    Terms::const_iterator it = m_terms.begin();
271
 
    Terms::const_iterator it_end = m_terms.end();
272
 
    for (; it != it_end; ++it) {
273
 
        if ((*it)->orig == "[current]") {
274
 
            WinClient *focused = FocusControl::focusedWindow();
275
 
            if ((*it)->prop == WORKSPACE) {
276
 
                char tmpstr[128];
277
 
                sprintf(tmpstr, "%d", win.screen().currentWorkspaceID());
278
 
                if (!(*it)->negate ^ (getProperty((*it)->prop, win) == tmpstr))
279
 
                    return false;
280
 
            } else if ((*it)->prop == WORKSPACENAME) {
281
 
                const Workspace *w = win.screen().currentWorkspace();
282
 
                if (!w || (!(*it)->negate ^
283
 
                           (getProperty((*it)->prop, win) == w->name())))
284
 
                    return false;
285
 
            } else if (!focused || (!(*it)->negate ^
286
 
                                    (getProperty((*it)->prop, win) ==
287
 
                                     getProperty((*it)->prop, *focused))))
288
 
                return false;
289
 
        } else if ((*it)->prop == HEAD &&
290
 
                   (*it)->orig == "[mouse]") {
291
 
            int mouse_head = win.screen().getCurrHead();
292
 
            char num[32];
293
 
            sprintf(num, "%d", mouse_head);
294
 
            if (!(*it)->negate ^ (getProperty((*it)->prop, win) == num))
295
 
                return false;
296
 
 
297
 
        } else if (!(*it)->negate ^
298
 
                   (*it)->regexp.match(getProperty((*it)->prop, win)))
299
 
            return false;
300
 
    }
301
 
    return true;
302
 
}
303
 
 
304
 
bool ClientPattern::dependsOnFocusedWindow() const {
305
 
    Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end();
306
 
    for (; it != it_end; ++it) {
307
 
        if ((*it)->prop != WORKSPACE && (*it)->prop != WORKSPACENAME &&
308
 
            (*it)->orig == "[current]")
309
 
            return true;
310
 
    }
311
 
    return false;
312
 
}
313
 
 
314
 
bool ClientPattern::dependsOnCurrentWorkspace() const {
315
 
    Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end();
316
 
    for (; it != it_end; ++it) {
317
 
        if (((*it)->prop == WORKSPACE || (*it)->prop == WORKSPACENAME) &&
318
 
            (*it)->orig == "[current]")
319
 
            return true;
320
 
    }
321
 
    return false;
322
 
}
323
 
 
324
 
// add an expression to match against
325
 
// The first argument is a regular expression, the second is the member
326
 
// function that we wish to match against.
327
 
bool ClientPattern::addTerm(const string &str, WinProperty prop, bool negate) {
328
 
 
329
 
    Term *term = new Term(str, true);
330
 
    term->orig = str;
331
 
    term->prop = prop;
332
 
    term->negate = negate;
333
 
 
334
 
    if (term->regexp.error()) {
335
 
        delete term;
336
 
        return false;
337
 
    }
338
 
    m_terms.push_back(term);
339
 
    return true;
340
 
}
341
 
 
342
 
string ClientPattern::getProperty(WinProperty prop, const Focusable &client) {
343
 
    // we need this for some of the window properties
344
 
    const FluxboxWindow *fbwin = client.fbwindow();
345
 
 
346
 
    switch (prop) {
347
 
    case TITLE:
348
 
        return client.title();
349
 
        break;
350
 
    case CLASS:
351
 
        return client.getWMClassClass();
352
 
        break;
353
 
    case NAME:
354
 
        return client.getWMClassName();
355
 
        break;
356
 
    case ROLE:
357
 
        return client.getWMRole();
358
 
        break;
359
 
    case TRANSIENT:
360
 
        return client.isTransient() ? "yes" : "no";
361
 
        break;
362
 
    case MAXIMIZED:
363
 
        return (fbwin && fbwin->isMaximized()) ? "yes" : "no";
364
 
        break;
365
 
    case MINIMIZED:
366
 
        return (fbwin && fbwin->isIconic()) ? "yes" : "no";
367
 
        break;
368
 
    case SHADED:
369
 
        return (fbwin && fbwin->isShaded()) ? "yes" : "no";
370
 
        break;
371
 
    case STUCK:
372
 
        return (fbwin && fbwin->isStuck()) ? "yes" : "no";
373
 
        break;
374
 
    case FOCUSHIDDEN:
375
 
        return (fbwin && fbwin->isFocusHidden()) ? "yes" : "no";
376
 
        break;
377
 
    case ICONHIDDEN:
378
 
        return (fbwin && fbwin->isIconHidden()) ? "yes" : "no";
379
 
        break;
380
 
    case WORKSPACE: {
381
 
        if (!fbwin)
382
 
            return "";
383
 
        char tmpstr[128];
384
 
        sprintf(tmpstr, "%d", fbwin->workspaceNumber());
385
 
        return std::string(tmpstr);
386
 
        break;
387
 
    }
388
 
    case WORKSPACENAME: {
389
 
        if (!fbwin)
390
 
            return "";
391
 
        const Workspace *w = client.screen().getWorkspace(fbwin->workspaceNumber());
392
 
        return w ? w->name() : "";
393
 
        break;
394
 
    }
395
 
    case HEAD: {
396
 
        if (!fbwin)
397
 
            return "";
398
 
        int head = client.screen().getHead(fbwin->fbWindow());
399
 
        char tmpstr[128];
400
 
        sprintf(tmpstr, "%d", head);
401
 
        return std::string(tmpstr);
402
 
        break;
403
 
    }
404
 
    case LAYER:
405
 
        return fbwin ? ::Layer::getString(fbwin->layerNum()) : "";
406
 
        break;
407
 
    case URGENT:
408
 
        return Fluxbox::instance()->attentionHandler()
409
 
                .isDemandingAttention(client) ? "yes" : "no";
410
 
        break;
411
 
    }
412
 
    return client.getWMClassName();
413
 
}
414
 
 
415
 
bool ClientPattern::operator ==(const ClientPattern &pat) const {
416
 
    // we require the terms to be identical (order too)
417
 
    Terms::const_iterator it = m_terms.begin();
418
 
    Terms::const_iterator it_end = m_terms.end();
419
 
    Terms::const_iterator other_it = pat.m_terms.begin();
420
 
    Terms::const_iterator other_it_end = pat.m_terms.end();
421
 
    for (; it != it_end && other_it != other_it_end; ++it, ++other_it) {
422
 
        if ((*it)->orig != (*other_it)->orig ||
423
 
            (*it)->negate != (*other_it)->negate)
424
 
            return false;
425
 
    }
426
 
    if (it != it_end || other_it != other_it_end)
427
 
        return false;
428
 
 
429
 
    return true;
430
 
}