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

« back to all changes in this revision

Viewing changes to src/Remember.cc

  • Committer: Bazaar Package Importer
  • Author(s): Dmitry E. Oboukhov
  • Date: 2008-07-01 10:38:14 UTC
  • mfrom: (2.1.12 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080701103814-khx2b6il152x9p93
Tags: 1.0.0+deb1-8
* x-dev has been removed from build-depends (out-of-date package).
* Standards-Version bumped to 3.8.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Remember.cc for Fluxbox Window Manager
2
 
// Copyright (c) 2003 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
3
 
//                     and Simon Bowden    (rathnor at users.sourceforge.net)
4
 
// Copyright (c) 2002 Xavier Brouckaert
5
 
// 
6
 
// Permission is hereby granted, free of charge, to any person obtaining a
7
 
// copy of this software and associated documentation files (the "Software"),
8
 
// to deal in the Software without restriction, including without limitation
9
 
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 
// and/or sell copies of the Software, and to permit persons to whom the
11
 
// Software is furnished to do so, subject to the following conditions:
12
 
//
13
 
// The above copyright notice and this permission notice shall be included in
14
 
// all copies or substantial portions of the Software.
15
 
//
16
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
 
// DEALINGS IN THE SOFTWARE.
23
 
 
24
 
// $Id: Remember.cc 4066 2005-06-23 09:22:11Z mathias $
25
 
 
26
 
#include "Remember.hh"
27
 
#include "ClientPattern.hh"
28
 
#include "Screen.hh"
29
 
#include "Window.hh"
30
 
#include "WinClient.hh"
31
 
#include "FbMenu.hh"
32
 
#include "FbCommands.hh"
33
 
#include "fluxbox.hh"
34
 
#include "WindowCmd.hh"
35
 
 
36
 
#include "FbTk/I18n.hh"
37
 
#include "FbTk/StringUtil.hh"
38
 
#include "FbTk/MenuItem.hh"
39
 
#include "FbTk/App.hh"
40
 
#include "FbTk/stringstream.hh"
41
 
 
42
 
 
43
 
#include <X11/Xlib.h>
44
 
 
45
 
//use GNU extensions
46
 
#ifndef  _GNU_SOURCE
47
 
#define  _GNU_SOURCE
48
 
#endif // _GNU_SOURCE
49
 
 
50
 
 
51
 
#include <iostream>
52
 
#include <fstream>
53
 
#include <string>
54
 
#include <memory>
55
 
#include <set>
56
 
 
57
 
 
58
 
using namespace std;
59
 
 
60
 
namespace {
61
 
 
62
 
class RememberMenuItem : public FbTk::MenuItem {
63
 
public:
64
 
    RememberMenuItem(const char *label,
65
 
                     Remember::Attribute attrib) :
66
 
        FbTk::MenuItem(label),
67
 
        m_attrib(attrib) {
68
 
        setToggleItem(true);
69
 
    }
70
 
 
71
 
    bool isSelected() const {
72
 
        if (WindowCmd<void>::window() == 0)
73
 
            return false;
74
 
 
75
 
        if (WindowCmd<void>::window()->numClients()) // ensure it HAS clients
76
 
            return Remember::instance().isRemembered(WindowCmd<void>::window()->winClient(), m_attrib);
77
 
        else
78
 
            return false;
79
 
    }
80
 
 
81
 
    bool isEnabled() const {
82
 
        if (WindowCmd<void>::window() == 0)
83
 
            return false;
84
 
 
85
 
        if (m_attrib != Remember::REM_JUMPWORKSPACE)
86
 
            return true;
87
 
        else if (WindowCmd<void>::window()->numClients())
88
 
            return (Remember::instance().isRemembered(WindowCmd<void>::window()->winClient(), Remember::REM_WORKSPACE));
89
 
        else
90
 
            return false;
91
 
    }
92
 
 
93
 
    void click(int button, int time) {
94
 
        if (WindowCmd<void>::window() != 0) {
95
 
            if (isSelected()) {
96
 
                Remember::instance().forgetAttrib(WindowCmd<void>::window()->winClient(), m_attrib);
97
 
            } else {
98
 
                Remember::instance().rememberAttrib(WindowCmd<void>::window()->winClient(), m_attrib);
99
 
            }
100
 
        }
101
 
        Remember::instance().save();
102
 
        FbTk::MenuItem::click(button, time);
103
 
    }
104
 
 
105
 
private:
106
 
    Remember::Attribute m_attrib;
107
 
};
108
 
 
109
 
FbTk::Menu *createRememberMenu(BScreen &screen) {
110
 
    // each fluxboxwindow has its own windowmenu
111
 
    // so we also create a remember menu just for it...
112
 
    FbTk::Menu *menu = screen.createMenu("");
113
 
 
114
 
    // if enabled, then we want this to be a unavailable menu
115
 
    /*
116
 
    if (!enabled) {
117
 
        FbTk::MenuItem *item = new FbTk::MenuItem("unavailable");
118
 
        item->setEnabled(false);
119
 
        menu->insert(item);
120
 
        menu->updateMenu();
121
 
        return menu;
122
 
    }
123
 
    */
124
 
    _FB_USES_NLS;
125
 
    menu->insert(new RememberMenuItem(_FBTEXT(Remember, Workspace, "Workspace", "Remember Workspace"),
126
 
                                      Remember::REM_WORKSPACE));
127
 
    menu->insert(new RememberMenuItem(_FBTEXT(Remember, JumpToWorkspace, "Jump to workspace", "Change active workspace to remembered one on open"),
128
 
                                      Remember::REM_JUMPWORKSPACE));
129
 
    menu->insert(new RememberMenuItem(_FBTEXT(Remember, Head, "Head", "Remember Head"),
130
 
                                      Remember::REM_HEAD));
131
 
    menu->insert(new RememberMenuItem(_FBTEXT(Remember, Dimensions, "Dimensions", "Remember Dimensions - with width and height"),
132
 
                                      Remember::REM_DIMENSIONS));
133
 
    menu->insert(new RememberMenuItem(_FBTEXT(Remember, Position, "Position", "Remember position - window co-ordinates"),
134
 
                                      Remember::REM_POSITION));
135
 
    menu->insert(new RememberMenuItem(_FBTEXT(Remember, Sticky, "Sticky", "Remember Sticky"),
136
 
                                      Remember::REM_STUCKSTATE));
137
 
    menu->insert(new RememberMenuItem(_FBTEXT(Remember, Decorations, "Decorations", "Remember window decorations"),
138
 
                                      Remember::REM_DECOSTATE));
139
 
    menu->insert(new RememberMenuItem(_FBTEXT(Remember, Shaded, "Shaded", "Remember shaded"),
140
 
                                      Remember::REM_SHADEDSTATE));
141
 
    menu->insert(new RememberMenuItem(_FBTEXT(Remember, Layer, "Layer", "Remember Layer"),
142
 
                                      Remember::REM_LAYER));
143
 
    menu->insert(new RememberMenuItem(_FBTEXT(Remember, SaveOnClose, "Save on close", "Save remembered attributes on close"),
144
 
                                      Remember::REM_SAVEONCLOSE));
145
 
 
146
 
    menu->updateMenu();
147
 
    return menu;
148
 
};
149
 
 
150
 
// offset is the offset in the string that we start looking from
151
 
// return true if all ok, false on error
152
 
bool handleStartupItem(const string &line, int offset) {
153
 
    int next = 0;
154
 
    string str;
155
 
    int screen = 0;
156
 
 
157
 
    // accept some options, for now only "screen=NN"
158
 
    // these option are given in parentheses before the command
159
 
    next = FbTk::StringUtil::getStringBetween(str,
160
 
                                              line.c_str() + offset,
161
 
                                              '(', ')');
162
 
    if (next > 0) {
163
 
        // there are some options
164
 
        string option;
165
 
        int pos = str.find('=');
166
 
        bool error = false;
167
 
        if (pos > 0) {
168
 
            option = str.substr(0, pos);
169
 
            if (option == "screen") {
170
 
                FbTk_istringstream iss(str.c_str() + pos + 1);
171
 
                iss >> screen;
172
 
            } else {
173
 
                error = true;
174
 
            }
175
 
        } else {
176
 
            error = true;
177
 
        }
178
 
        if (error) {
179
 
            cerr<<"Error parsing startup options."<<endl;
180
 
            return false;
181
 
        }
182
 
    } else {
183
 
        next = 0;
184
 
    }
185
 
 
186
 
    next = FbTk::StringUtil::getStringBetween(str,
187
 
                                              line.c_str() + offset + next,
188
 
                                              '{', '}');
189
 
 
190
 
    if (next <= 0) {
191
 
        cerr<<"Error parsing [startup] at column "<<offset<<" - expecting {command}."<<endl;
192
 
        return false;
193
 
    } else {
194
 
        FbCommands::ExecuteCmd *tmp_exec_cmd = new FbCommands::ExecuteCmd(str, screen);
195
 
#ifdef DEBUG
196
 
        cerr<<"Executing startup command '"<<str<<"' on screen "<<screen<<endl;
197
 
#endif // DEBUG
198
 
        tmp_exec_cmd->execute();
199
 
        delete tmp_exec_cmd;
200
 
        return true;
201
 
    }
202
 
};
203
 
 
204
 
}; // end anonymous namespace
205
 
 
206
 
 
207
 
Application::Application(bool grouped)
208
 
    : is_grouped(grouped),
209
 
      group(0)
210
 
{
211
 
    decostate_remember =
212
 
        dimensions_remember =
213
 
        focushiddenstate_remember =
214
 
        iconhiddenstate_remember =
215
 
        jumpworkspace_remember =
216
 
        layer_remember  =
217
 
        position_remember =
218
 
        shadedstate_remember =
219
 
        stuckstate_remember =
220
 
        tabstate_remember =
221
 
        workspace_remember =
222
 
        head_remember =
223
 
        save_on_close_remember = false;
224
 
}
225
 
 
226
 
/************
227
 
 * Remember *
228
 
 ************/
229
 
 
230
 
Remember *Remember::s_instance = 0;
231
 
 
232
 
Remember::Remember() {
233
 
    if (s_instance != 0)
234
 
        throw string("Can not create more than one instance of Remember");
235
 
 
236
 
    s_instance = this;
237
 
    enableUpdate();
238
 
    load();
239
 
}
240
 
 
241
 
Remember::~Remember() {
242
 
 
243
 
    // free our resources
244
 
 
245
 
    // the patterns free the "Application"s
246
 
    // the client mapping shouldn't need cleaning
247
 
    Patterns::iterator it;
248
 
    std::set<Application *> all_apps; // no duplicates
249
 
    while (!m_pats.empty()) {
250
 
        it = m_pats.begin();
251
 
        delete it->first; // ClientPattern
252
 
        all_apps.insert(it->second); // Application, not necessarily unique
253
 
        m_pats.erase(it);
254
 
    }
255
 
 
256
 
    std::set<Application *>::iterator ait = all_apps.begin(); // no duplicates
257
 
    while (ait != all_apps.end()) {
258
 
        delete (*ait);
259
 
        ++ait;
260
 
    }
261
 
 
262
 
    s_instance = 0;
263
 
}
264
 
 
265
 
Application* Remember::find(WinClient &winclient) {
266
 
    // if it is already associated with a application, return that one
267
 
    // otherwise, check it against every pattern that we've got
268
 
    Clients::iterator wc_it = m_clients.find(&winclient);
269
 
    if (wc_it != m_clients.end())
270
 
        return wc_it->second;
271
 
    else {
272
 
        Patterns::iterator it = m_pats.begin();
273
 
        for (; it != m_pats.end(); it++)
274
 
            if (it->first->match(winclient)) {
275
 
                it->first->addMatch();
276
 
                m_clients[&winclient] = it->second;
277
 
                return it->second;
278
 
            }
279
 
    }
280
 
    // oh well, no matches
281
 
    return 0;
282
 
}
283
 
 
284
 
Application * Remember::add(WinClient &winclient) {
285
 
    ClientPattern *p = new ClientPattern();
286
 
    Application *app = new Application(false);
287
 
    // by default, we match against the WMClass of a window.
288
 
    p->addTerm(p->getProperty(ClientPattern::NAME, winclient), ClientPattern::NAME);
289
 
    m_clients[&winclient] = app;
290
 
    p->addMatch();
291
 
    m_pats.push_back(make_pair(p, app));
292
 
    return app;
293
 
}
294
 
 
295
 
int Remember::parseApp(ifstream &file, Application &app, string *first_line) {
296
 
    string line;
297
 
    _FB_USES_NLS;
298
 
    int row = 0;
299
 
    while (! file.eof()) {
300
 
        if (first_line || getline(file, line)) {
301
 
            if (first_line) {
302
 
                line = *first_line;
303
 
                first_line = 0;
304
 
            }
305
 
 
306
 
            row++;
307
 
            FbTk::StringUtil::removeFirstWhitespace(line);
308
 
            FbTk::StringUtil::removeTrailingWhitespace(line);
309
 
            if (line.size() == 0 || line[0] == '#')
310
 
                continue;  //the line is commented or blank
311
 
            int parse_pos = 0, err = 0;
312
 
            string str_key, str_option, str_label;
313
 
            err = FbTk::StringUtil::getStringBetween(str_key,
314
 
                                                     line.c_str(),
315
 
                                                     '[', ']');
316
 
            if (err > 0) {
317
 
                int tmp;
318
 
                tmp= FbTk::StringUtil::getStringBetween(str_option,
319
 
                                                        line.c_str() + err,
320
 
                                                        '(', ')');
321
 
                if (tmp>0)
322
 
                    err += tmp;
323
 
            }
324
 
            if (err > 0 ) {
325
 
                parse_pos += err;
326
 
                err = FbTk::StringUtil::getStringBetween(str_label,
327
 
                                                         line.c_str() + parse_pos,
328
 
                                                         '{', '}');
329
 
                if (err>0) {
330
 
                    parse_pos += err;
331
 
                }
332
 
            } else
333
 
                continue; //read next line
334
 
 
335
 
            if (!str_key.size())
336
 
                continue; //read next line
337
 
            if (str_key == "Workspace") {
338
 
                unsigned int w;
339
 
                FbTk_istringstream iss(str_label.c_str());
340
 
                iss >> w;
341
 
                app.rememberWorkspace(w);
342
 
            } else if (str_key == "Head") {
343
 
                int h = atoi(str_label.c_str());
344
 
                app.rememberHead(h);
345
 
            } else if (str_key == "Layer") {
346
 
                unsigned int l;
347
 
                if (str_label == "DESKTOP") {
348
 
                    l = Fluxbox::instance()->getDesktopLayer();
349
 
                } else if (str_label == "BOTTOM") {
350
 
                    l = Fluxbox::instance()->getBottomLayer();
351
 
                } else if (str_label == "NORMAL") {
352
 
                    l = Fluxbox::instance()->getNormalLayer();
353
 
                } else if (str_label == "TOP") {
354
 
                    l = Fluxbox::instance()->getTopLayer();
355
 
                } else if (str_label == "DOCK") {
356
 
                    l = Fluxbox::instance()->getDockLayer();
357
 
                } else if (str_label == "ABOVEDOCK") {
358
 
                    l = Fluxbox::instance()->getAboveDockLayer();
359
 
                } else if (str_label == "MENU") {
360
 
                    l = Fluxbox::instance()->getMenuLayer();
361
 
                } else {
362
 
                    FbTk_istringstream iss(str_label.c_str());
363
 
                    iss >> l;
364
 
                }
365
 
                app.rememberLayer(l);
366
 
            } else if (str_key == "Dimensions") {
367
 
                unsigned int h,w;
368
 
                FbTk_istringstream iss(str_label.c_str());
369
 
                iss >> w >> h;
370
 
                app.rememberDimensions(w,h);
371
 
            } else if (str_key == "Position") {
372
 
                unsigned int r= 0;
373
 
                unsigned int x= 0;
374
 
                unsigned int y= 0;
375
 
                // more info about the parameter
376
 
                // in ::rememberPosition
377
 
 
378
 
                if ( str_option.length() )
379
 
                    {
380
 
                        if      ( str_option == "UPPERLEFT"  ) r= POS_UPPERLEFT;
381
 
                        else if ( str_option == "UPPERRIGHT" ) r= POS_UPPERRIGHT;
382
 
                        else if ( str_option == "LOWERLEFT"  ) r= POS_LOWERLEFT;
383
 
                        else if ( str_option == "LOWERRIGHT" ) r= POS_LOWERRIGHT;
384
 
                        else if ( str_option == "CENTER" )     r= POS_CENTER;
385
 
                        else if ( str_option == "WINCENTER" )  r= POS_WINCENTER;
386
 
                        else {
387
 
                            FbTk_istringstream iss_r(str_option.c_str());
388
 
                            iss_r >> r;
389
 
                        }
390
 
                    }
391
 
 
392
 
                FbTk_istringstream iss_xy(str_label.c_str());
393
 
                iss_xy >> x >> y;
394
 
                app.rememberPosition(x, y, r);
395
 
            } else if (str_key == "Shaded") {
396
 
                app.rememberShadedstate((str_label=="yes"));
397
 
            } else if (str_key == "Tab") {
398
 
                app.rememberTabstate((str_label=="yes"));
399
 
            } else if (str_key == "FocusHidden") {
400
 
                app.rememberFocusHiddenstate((str_label=="yes"));
401
 
            } else if (str_key == "IconHidden") {
402
 
                app.rememberIconHiddenstate((str_label=="yes"));
403
 
            } else if (str_key == "Hidden") {
404
 
                app.rememberIconHiddenstate((str_label=="yes"));
405
 
                app.rememberFocusHiddenstate((str_label=="yes"));
406
 
            } else if (str_key == "Deco") {
407
 
                if (str_label == "NONE") {
408
 
                    app.rememberDecostate((unsigned int) 0);
409
 
                } else if (str_label == "NORMAL") {
410
 
                    app.rememberDecostate((unsigned int) 0xfffffff);
411
 
                } else if (str_label == "TINY") {
412
 
                    app.rememberDecostate((unsigned int)
413
 
                                          FluxboxWindow::DECORM_TITLEBAR
414
 
                                          | FluxboxWindow::DECORM_ICONIFY
415
 
                                          | FluxboxWindow::DECORM_MENU
416
 
                                          );
417
 
                } else if (str_label == "TOOL") {
418
 
                    app.rememberDecostate((unsigned int)
419
 
                                          FluxboxWindow::DECORM_TITLEBAR
420
 
                                          | FluxboxWindow::DECORM_MENU
421
 
                                          );
422
 
                } else if (str_label == "BORDER") {
423
 
                    app.rememberDecostate((unsigned int)
424
 
                                          FluxboxWindow::DECORM_BORDER
425
 
                                          | FluxboxWindow::DECORM_MENU
426
 
                                          );
427
 
                } else {
428
 
                    unsigned int mask;
429
 
                    const char * str = str_label.c_str();
430
 
                    // it'll have at least one char and \0, so this is safe
431
 
                    FbTk_istringstream iss(str);
432
 
                    // check for hex
433
 
                    if (str[0] == '0' && str[1] == 'x') {
434
 
                        iss.seekg(2);
435
 
                        iss >> hex;
436
 
                    }
437
 
                    iss >> mask ;
438
 
                    app.rememberDecostate(mask);
439
 
                }
440
 
            } else if (str_key == "Sticky") {
441
 
                app.rememberStuckstate((str_label=="yes"));
442
 
            } else if (str_key == "Jump") {
443
 
                app.rememberJumpworkspace((str_label=="yes"));
444
 
            } else if (str_key == "Close") {
445
 
                app.rememberSaveOnClose((str_label=="yes"));
446
 
            } else if (str_key == "end") {
447
 
                return row;
448
 
            } else {
449
 
                cerr << _FBTEXT(Remember, Unknown, "Unknown apps key", "apps entry type not known")<<" = " << str_key << endl;
450
 
            }
451
 
        }
452
 
    }
453
 
    return row;
454
 
}
455
 
 
456
 
void Remember::load() {
457
 
 
458
 
    string apps_string = FbTk::StringUtil::expandFilename(Fluxbox::instance()->getAppsFilename());
459
 
 
460
 
#ifdef DEBUG
461
 
    cerr<<__FILE__<<"("<<__FUNCTION__<<"): Loading apps file ["<<apps_string<<"]"<<endl;
462
 
#endif // DEBUG
463
 
    ifstream apps_file(apps_string.c_str());
464
 
 
465
 
    if (!apps_file.fail()) {
466
 
        if (!apps_file.eof()) {
467
 
            string line;
468
 
            int row = 0;
469
 
            bool in_group = false;
470
 
            std::list<ClientPattern *> grouped_pats;
471
 
            while (getline(apps_file, line) && ! apps_file.eof()) {
472
 
                row++;
473
 
                FbTk::StringUtil::removeFirstWhitespace(line);
474
 
                FbTk::StringUtil::removeTrailingWhitespace(line);
475
 
                if (line.size() == 0 || line[0] == '#')
476
 
                    continue;
477
 
                string key;
478
 
                int err=0;
479
 
                int pos = FbTk::StringUtil::getStringBetween(key,
480
 
                                                             line.c_str(),
481
 
                                                             '[', ']');
482
 
 
483
 
                if (pos > 0 && key == "app") {
484
 
                    ClientPattern *pat = new ClientPattern(line.c_str() + pos);
485
 
                    if (!in_group) {
486
 
                        if ((err = pat->error()) == 0) {
487
 
                            Application *app = new Application(false);
488
 
                            m_pats.push_back(make_pair(pat, app));
489
 
                            row += parseApp(apps_file, *app);
490
 
                        } else {
491
 
                            cerr<<"Error reading apps file at line "<<row<<", column "<<(err+pos)<<"."<<endl;
492
 
                            delete pat; // since it didn't work
493
 
                        }
494
 
                    } else {
495
 
                        grouped_pats.push_back(pat);
496
 
                    }
497
 
                } else if (pos > 0 && key == "startup") {
498
 
                    if (!handleStartupItem(line, pos)) {
499
 
                        cerr<<"Error reading apps file at line "<<row<<"."<<endl;
500
 
                    }
501
 
                    // save the item even if it was bad (aren't we nice)
502
 
                    m_startups.push_back(line.substr(pos));
503
 
                } else if (pos > 0 && key == "group") {
504
 
                    in_group = true;
505
 
                } else if (in_group) {
506
 
                    // otherwise assume that it is the start of the attributes
507
 
                    Application *app = new Application(true);
508
 
                    while (!grouped_pats.empty()) {
509
 
                        // associate all the patterns with this app
510
 
                        m_pats.push_back(make_pair(grouped_pats.front(), app));
511
 
                        grouped_pats.pop_front();
512
 
                    }
513
 
 
514
 
                    // we hit end... probably don't have attribs for the group
515
 
                    // so finish it off with an empty application
516
 
                    // otherwise parse the app
517
 
                    if (!(pos>0 && key == "end")) {
518
 
                        row += parseApp(apps_file, *app, &line);
519
 
                    }
520
 
                    in_group = false;
521
 
                } else
522
 
                    cerr<<"Error in apps file on line "<<row<<"."<<endl;
523
 
 
524
 
            }
525
 
        } else {
526
 
#ifdef DEBUG
527
 
            cerr<<__FILE__<<"("<<__FUNCTION__<< ") Empty apps file" << endl;
528
 
#endif
529
 
        }
530
 
    } else {
531
 
        cerr << "apps file failure" << endl;
532
 
    }
533
 
}
534
 
 
535
 
void Remember::save() {
536
 
#ifdef DEBUG
537
 
    cerr<<__FILE__<<"("<<__FUNCTION__<<"): Saving apps file..."<<endl;
538
 
#endif // DEBUG
539
 
    string apps_string;
540
 
    Fluxbox::instance()->getDefaultDataFilename("apps", apps_string);
541
 
    ofstream apps_file(apps_string.c_str());
542
 
 
543
 
    // first of all we output all the startup commands
544
 
    Startups::iterator sit = m_startups.begin();
545
 
    Startups::iterator sit_end = m_startups.end();
546
 
    for (; sit != sit_end; ++sit) {
547
 
        apps_file<<"[startup] "<<(*sit)<<endl;
548
 
    }
549
 
 
550
 
    Patterns::iterator it = m_pats.begin();
551
 
    Patterns::iterator it_end = m_pats.end();
552
 
 
553
 
    std::set<Application *> grouped_apps; // no duplicates
554
 
 
555
 
    for (; it != it_end; ++it) {
556
 
        Application &a = *it->second;
557
 
        if (a.is_grouped) {
558
 
            // if already processed
559
 
            if (grouped_apps.find(&a) != grouped_apps.end())
560
 
                continue;
561
 
            grouped_apps.insert(&a);
562
 
            // otherwise output this whole group
563
 
            apps_file << "[group]" << endl;
564
 
            Patterns::iterator git = m_pats.begin();
565
 
            Patterns::iterator git_end = m_pats.end();
566
 
            for (; git != git_end; git++) {
567
 
                if (git->second == &a) {
568
 
                    apps_file << " [app]"<<git->first->toString()<<endl;
569
 
                }
570
 
            }
571
 
        } else {
572
 
            apps_file << "[app]"<<it->first->toString()<<endl;
573
 
        }
574
 
        if (a.workspace_remember) {
575
 
            apps_file << "  [Workspace]\t{" << a.workspace << "}" << endl;
576
 
        }
577
 
        if (a.head_remember) {
578
 
            apps_file << "  [Head]\t{" << a.head << "}" << endl;
579
 
        }
580
 
        if (a.dimensions_remember) {
581
 
            apps_file << "  [Dimensions]\t{" << a.w << " " << a.h << "}" << endl;
582
 
        }
583
 
        if (a.position_remember) {
584
 
            apps_file << "  [Position]\t(";
585
 
            switch(a.refc) {
586
 
            case POS_WINCENTER:
587
 
                apps_file << "WINCENTER";
588
 
                break;
589
 
            case POS_CENTER:
590
 
                apps_file << "CENTER";
591
 
                break;
592
 
            case POS_LOWERLEFT:
593
 
                apps_file << "LOWERLEFT";
594
 
                break;
595
 
            case POS_LOWERRIGHT:
596
 
                apps_file << "LOWERRIGHT";
597
 
                break;
598
 
            case POS_UPPERRIGHT:
599
 
                apps_file << "UPPERRIGHT";
600
 
                break;
601
 
            default:
602
 
                apps_file << "UPPERLEFT";
603
 
            }
604
 
            apps_file << ")\t{" << a.x << " " << a.y << "}" << endl;
605
 
        }
606
 
        if (a.shadedstate_remember) {
607
 
            apps_file << "  [Shaded]\t{" << ((a.shadedstate)?"yes":"no") << "}" << endl;
608
 
        }
609
 
        if (a.tabstate_remember) {
610
 
            apps_file << "  [Tab]\t\t{" << ((a.tabstate)?"yes":"no") << "}" << endl;
611
 
        }
612
 
        if (a.decostate_remember) {
613
 
            switch (a.decostate) {
614
 
            case (0) :
615
 
                apps_file << "  [Deco]\t{NONE}" << endl;
616
 
                break;
617
 
            case (0xffffffff):
618
 
            case (FluxboxWindow::DECORM_LAST - 1):
619
 
                apps_file << "  [Deco]\t{NORMAL}" << endl;
620
 
                break;
621
 
            case (FluxboxWindow::DECORM_TITLEBAR
622
 
                  | FluxboxWindow::DECORM_ICONIFY
623
 
                  | FluxboxWindow::DECORM_MENU):
624
 
                apps_file << "  [Deco]\t{TOOL}" << endl;
625
 
                break;
626
 
            case (FluxboxWindow::DECORM_TITLEBAR
627
 
                  | FluxboxWindow::DECORM_MENU):
628
 
                apps_file << "  [Deco]\t{TINY}" << endl;
629
 
                break;
630
 
            case (FluxboxWindow::DECORM_BORDER
631
 
                  | FluxboxWindow::DECORM_MENU):
632
 
                apps_file << "  [Deco]\t{BORDER}" << endl;
633
 
                break;
634
 
            default:
635
 
                apps_file << "  [Deco]\t{0x"<<hex<<a.decostate<<dec<<"}"<<endl;
636
 
                break;
637
 
            }
638
 
        }
639
 
 
640
 
        if (a.focushiddenstate_remember || a.iconhiddenstate_remember) {
641
 
            if (a.focushiddenstate_remember && a.iconhiddenstate_remember &&
642
 
                a.focushiddenstate && a.iconhiddenstate)
643
 
                apps_file << "  [Hidden]\t{" << ((a.focushiddenstate)?"yes":"no") << "}" << endl;
644
 
            else if (a.focushiddenstate_remember) {
645
 
                apps_file << "  [FocusHidden]\t{" << ((a.focushiddenstate)?"yes":"no") << "}" << endl;
646
 
            } else if (a.iconhiddenstate_remember) {
647
 
                apps_file << "  [IconHidden]\t{" << ((a.iconhiddenstate)?"yes":"no") << "}" << endl;
648
 
            }
649
 
        }
650
 
        if (a.stuckstate_remember) {
651
 
            apps_file << "  [Sticky]\t{" << ((a.stuckstate)?"yes":"no") << "}" << endl;
652
 
        }
653
 
        if (a.jumpworkspace_remember) {
654
 
            apps_file << "  [Jump]\t{" << ((a.jumpworkspace)?"yes":"no") << "}" << endl;
655
 
        }
656
 
        if (a.layer_remember) {
657
 
            apps_file << "  [Layer]\t{" << a.layer << "}" << endl;
658
 
        }
659
 
        if (a.save_on_close_remember) {
660
 
            apps_file << "  [Close]\t{" << ((a.save_on_close)?"yes":"no") << "}" << endl;
661
 
        }
662
 
        apps_file << "[end]" << endl;
663
 
    }
664
 
}
665
 
 
666
 
bool Remember::isRemembered(WinClient &winclient, Attribute attrib) {
667
 
    Application *app = find(winclient);
668
 
    if (!app) return false;
669
 
    switch (attrib) {
670
 
    case REM_WORKSPACE:
671
 
        return app->workspace_remember;
672
 
        break;
673
 
    case REM_HEAD:
674
 
        return app->head_remember;
675
 
        break;
676
 
    case REM_DIMENSIONS:
677
 
        return app->dimensions_remember;
678
 
        break;
679
 
    case REM_POSITION:
680
 
        return app->position_remember;
681
 
        break;
682
 
    case REM_FOCUSHIDDENSTATE:
683
 
        return app->focushiddenstate_remember;
684
 
        break;
685
 
    case REM_ICONHIDDENSTATE:
686
 
        return app->iconhiddenstate_remember;
687
 
        break;
688
 
    case REM_STUCKSTATE:
689
 
        return app->stuckstate_remember;
690
 
        break;
691
 
    case REM_DECOSTATE:
692
 
        return app->decostate_remember;
693
 
        break;
694
 
    case REM_SHADEDSTATE:
695
 
        return app->shadedstate_remember;
696
 
        break;
697
 
        //    case REM_TABSTATE:
698
 
        //        return app->tabstate_remember;
699
 
        //        break;
700
 
    case REM_JUMPWORKSPACE:
701
 
        return app->jumpworkspace_remember;
702
 
        break;
703
 
    case REM_LAYER:
704
 
        return app->layer_remember;
705
 
        break;
706
 
    case REM_SAVEONCLOSE:
707
 
        return app->save_on_close_remember;
708
 
        break;
709
 
    case REM_LASTATTRIB:
710
 
    default:
711
 
        return false; // should never get here
712
 
    }
713
 
}
714
 
 
715
 
void Remember::rememberAttrib(WinClient &winclient, Attribute attrib) {
716
 
    FluxboxWindow *win = winclient.fbwindow();
717
 
    if (!win) return;
718
 
    Application *app = find(winclient);
719
 
    if (!app) {
720
 
        app = add(winclient);
721
 
        if (!app) return;
722
 
    }
723
 
    switch (attrib) {
724
 
    case REM_WORKSPACE:
725
 
        app->rememberWorkspace(win->workspaceNumber());
726
 
        break;
727
 
    case REM_HEAD:
728
 
        app->rememberHead(win->screen().getHead(win->fbWindow()));
729
 
        break;
730
 
    case REM_DIMENSIONS:
731
 
        app->rememberDimensions(win->width(), win->height());
732
 
        break;
733
 
    case REM_POSITION:
734
 
        app->rememberPosition(win->x(), win->y());
735
 
        break;
736
 
    case REM_FOCUSHIDDENSTATE:
737
 
        app->rememberFocusHiddenstate(win->isFocusHidden());
738
 
        break;
739
 
    case REM_ICONHIDDENSTATE:
740
 
        app->rememberIconHiddenstate(win->isIconHidden());
741
 
        break;
742
 
    case REM_SHADEDSTATE:
743
 
        app->rememberShadedstate(win->isShaded());
744
 
        break;
745
 
    case REM_DECOSTATE:
746
 
        app->rememberDecostate(win->decorationMask());
747
 
        break;
748
 
    case REM_STUCKSTATE:
749
 
        app->rememberStuckstate(win->isStuck());
750
 
        break;
751
 
        //    case REM_TABSTATE:
752
 
        //        break;
753
 
    case REM_JUMPWORKSPACE:
754
 
        app->rememberJumpworkspace(true);
755
 
        break;
756
 
    case REM_LAYER:
757
 
        app->rememberLayer(win->layerNum());
758
 
        break;
759
 
    case REM_SAVEONCLOSE:
760
 
        app->rememberSaveOnClose(true);
761
 
        break;
762
 
    case REM_LASTATTRIB:
763
 
    default:
764
 
        // nothing
765
 
        break;
766
 
    }
767
 
}
768
 
 
769
 
void Remember::forgetAttrib(WinClient &winclient, Attribute attrib) {
770
 
    FluxboxWindow *win = winclient.fbwindow();
771
 
    if (!win) return;
772
 
    Application *app = find(winclient);
773
 
    if (!app) {
774
 
        app = add(winclient);
775
 
        if (!app) return;
776
 
    }
777
 
    switch (attrib) {
778
 
    case REM_WORKSPACE:
779
 
        app->forgetWorkspace();
780
 
        break;
781
 
    case REM_HEAD:
782
 
        app->forgetHead();
783
 
        break;
784
 
    case REM_DIMENSIONS:
785
 
        app->forgetDimensions();
786
 
        break;
787
 
    case REM_POSITION:
788
 
        app->forgetPosition();
789
 
        break;
790
 
    case REM_FOCUSHIDDENSTATE:
791
 
        app->forgetFocusHiddenstate();
792
 
        break;
793
 
    case REM_ICONHIDDENSTATE:
794
 
        app->forgetIconHiddenstate();
795
 
        break;
796
 
    case REM_STUCKSTATE:
797
 
        app->forgetStuckstate();
798
 
        break;
799
 
    case REM_DECOSTATE:
800
 
        app->forgetDecostate();
801
 
        break;
802
 
    case REM_SHADEDSTATE:
803
 
        app->forgetShadedstate();
804
 
        break;
805
 
//    case REM_TABSTATE:
806
 
//        break;
807
 
    case REM_JUMPWORKSPACE:
808
 
        app->forgetJumpworkspace();
809
 
        break;
810
 
    case REM_LAYER:
811
 
        app->forgetLayer();
812
 
        break;
813
 
    case REM_SAVEONCLOSE:
814
 
        app->forgetSaveOnClose();
815
 
        break;
816
 
    case REM_LASTATTRIB:
817
 
    default:
818
 
        // nothing
819
 
        break;
820
 
    }
821
 
}
822
 
 
823
 
void Remember::setupFrame(FluxboxWindow &win) {
824
 
    WinClient &winclient = win.winClient();
825
 
    _FB_USES_NLS;
826
 
    // we don't touch the window if it is a transient
827
 
    // of something else
828
 
 
829
 
 
830
 
    if (winclient.transientFor())
831
 
        return;
832
 
 
833
 
    Application *app = find(winclient);
834
 
    if (app == 0)
835
 
        return; // nothing to do
836
 
 
837
 
    if (app->is_grouped && app->group == 0)
838
 
        app->group = &win;
839
 
 
840
 
    BScreen &screen = winclient.screen();
841
 
 
842
 
    if (app->workspace_remember) {
843
 
        // we use setWorkspace and not reassoc because we're still initialising
844
 
        win.setWorkspace(app->workspace);
845
 
        if (app->jumpworkspace_remember)
846
 
            screen.changeWorkspaceID(app->workspace);
847
 
    }
848
 
 
849
 
    if (app->head_remember) {
850
 
        win.screen().setOnHead<FluxboxWindow>(win, app->head);
851
 
    }
852
 
 
853
 
    if (app->decostate_remember)
854
 
        win.setDecorationMask(app->decostate);
855
 
 
856
 
 
857
 
    if (app->dimensions_remember)
858
 
        win.resize(app->w, app->h);
859
 
 
860
 
    int head = screen.getHead(win.fbWindow());
861
 
 
862
 
    if (app->position_remember) {
863
 
 
864
 
        switch (app->refc) {
865
 
          default:
866
 
          case POS_UPPERLEFT: // upperleft corner
867
 
              win.move(screen.getHeadX(head) + app->x,
868
 
                       screen.getHeadY(head) + app->y);
869
 
              break;
870
 
          case POS_UPPERRIGHT: // upperright corner
871
 
              win.move(screen.getHeadX(head) + screen.getHeadWidth(head) - win.width() - app->x,
872
 
                       screen.getHeadY(head) + app->y);
873
 
              break;
874
 
          case POS_LOWERLEFT: // lowerleft corner
875
 
              win.move(screen.getHeadX(head) + app->x,
876
 
                       screen.getHeadHeight(head) - win.height() - app->y);
877
 
              break;
878
 
          case POS_LOWERRIGHT: // lowerright corner
879
 
              win.move(screen.getHeadWidth(head) - win.width() - app->x,
880
 
                       screen.getHeadHeight(head) - win.height() - app->y);
881
 
              break;
882
 
          case POS_CENTER: // center of the screen, windows topleft corner is on the center
883
 
                win.move((screen.getHeadWidth(head) / 2) + app->x,
884
 
                         (screen.getHeadHeight(head) / 2) + app->y);
885
 
              break;
886
 
          case POS_WINCENTER: // the window is centered REALLY upon the center
887
 
                win.move((screen.getHeadWidth(head) / 2) - ( win.width() / 2 ) + app->x,
888
 
                         (screen.getHeadHeight(head) / 2) - ( win.height() / 2 ) + app->y);
889
 
              break;
890
 
        };
891
 
    }
892
 
 
893
 
    if (app->shadedstate_remember)
894
 
        // if inconsistent...
895
 
        if (win.isShaded() && !app->shadedstate ||
896
 
            !win.isShaded() && app->shadedstate)
897
 
            win.shade(); // toggles
898
 
 
899
 
    // external tabs aren't available atm...
900
 
    //if (app->tabstate_remember) ...
901
 
 
902
 
    if (app->stuckstate_remember)
903
 
        // if inconsistent...
904
 
        if (win.isStuck() && !app->stuckstate ||
905
 
            !win.isStuck() && app->stuckstate)
906
 
            win.stick(); // toggles
907
 
    if (app->focushiddenstate_remember)
908
 
        win.setFocusHidden(true);
909
 
    if (app->iconhiddenstate_remember)
910
 
        win.setIconHidden(true);
911
 
 
912
 
    if (app->layer_remember)
913
 
        win.moveToLayer(app->layer);
914
 
 
915
 
}
916
 
 
917
 
void Remember::setupClient(WinClient &winclient) {
918
 
 
919
 
    Application *app = find(winclient);
920
 
    if (app == 0)
921
 
        return; // nothing to do
922
 
 
923
 
    if (winclient.fbwindow() == 0 && app->is_grouped && app->group) {
924
 
        app->group->attachClient(winclient);
925
 
    }
926
 
}
927
 
 
928
 
void Remember::updateClientClose(WinClient &winclient) {
929
 
    Application *app = find(winclient);
930
 
 
931
 
    if (app && (app->save_on_close_remember && app->save_on_close)) {
932
 
 
933
 
        for (int attrib = 0; attrib <= REM_LASTATTRIB; attrib++) {
934
 
            if (isRemembered(winclient, (Attribute) attrib)) {
935
 
                rememberAttrib(winclient, (Attribute) attrib);
936
 
            }
937
 
        }
938
 
 
939
 
        save();
940
 
    }
941
 
 
942
 
    // we need to get rid of references to this client
943
 
    Clients::iterator wc_it = m_clients.find(&winclient);
944
 
 
945
 
    if (wc_it != m_clients.end()) {
946
 
        m_clients.erase(wc_it);
947
 
    }
948
 
 
949
 
}
950
 
 
951
 
void Remember::initForScreen(BScreen &screen) {
952
 
    // All windows get the remember menu.
953
 
    _FB_USES_NLS;
954
 
    screen.addExtraWindowMenu(_FBTEXT(Remember, MenuItemName, "Remember...", "Remember item in menu"),
955
 
                              createRememberMenu(screen));
956
 
 
957
 
}
958
 
 
959
 
void Remember::updateFrameClose(FluxboxWindow &win) {
960
 
    // scan all applications and remove this fbw if it is a recorded group
961
 
    Patterns::iterator it = m_pats.begin();
962
 
    while (it != m_pats.end()) {
963
 
        if (&win == it->second->group)
964
 
            it->second->group = 0;
965
 
        ++it;
966
 
    }
967
 
}