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

« back to all changes in this revision

Viewing changes to src/fluxbox.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
 
// fluxbox.cc for Fluxbox Window Manager
2
 
// Copyright (c) 2001 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
3
 
//
4
 
// blackbox.cc for blackbox - an X11 Window manager
5
 
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
6
 
//
7
 
// Permission is hereby granted, free of charge, to any person obtaining a
8
 
// copy of this software and associated documentation files (the "Software"),
9
 
// to deal in the Software without restriction, including without limitation
10
 
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 
// and/or sell copies of the Software, and to permit persons to whom the
12
 
// Software is furnished to do so, subject to the following conditions:
13
 
//
14
 
// The above copyright notice and this permission notice shall be included in
15
 
// all copies or substantial portions of the Software.
16
 
//
17
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
 
// DEALINGS IN THE SOFTWARE.
24
 
 
25
 
// $Id: fluxbox.cc 4084 2005-07-20 18:29:01Z mathias $
26
 
 
27
 
#include "fluxbox.hh"
28
 
 
29
 
#include "Screen.hh"
30
 
#include "Window.hh"
31
 
#include "Workspace.hh"
32
 
#include "AtomHandler.hh"
33
 
#include "FbCommands.hh"
34
 
#include "WinClient.hh"
35
 
#include "Keys.hh"
36
 
#include "FbAtoms.hh"
37
 
#include "defaults.hh"
38
 
 
39
 
#include "FbTk/I18n.hh"
40
 
#include "FbTk/Image.hh"
41
 
#include "FbTk/FileUtil.hh"
42
 
#include "FbTk/KeyUtil.hh"
43
 
#include "FbTk/ImageControl.hh"
44
 
#include "FbTk/EventManager.hh"
45
 
#include "FbTk/StringUtil.hh"
46
 
#include "FbTk/Resource.hh"
47
 
#include "FbTk/SimpleCommand.hh"
48
 
#include "FbTk/XrmDatabaseHelper.hh"
49
 
#include "FbTk/Command.hh"
50
 
#include "FbTk/RefCount.hh"
51
 
#include "FbTk/SimpleCommand.hh"
52
 
#include "FbTk/CompareEqual.hh"
53
 
#include "FbTk/Transparent.hh"
54
 
#include "FbTk/Select2nd.hh"
55
 
#include "FbTk/Compose.hh"
56
 
 
57
 
//Use GNU extensions
58
 
#ifndef  _GNU_SOURCE
59
 
#define  _GNU_SOURCE
60
 
#endif // _GNU_SOURCE
61
 
 
62
 
#ifdef HAVE_CONFIG_H
63
 
#include "config.h"
64
 
#endif // HAVE_CONFIG_H
65
 
 
66
 
#ifdef SLIT
67
 
#include "Slit.hh"
68
 
#endif // SLIT
69
 
#ifdef USE_GNOME
70
 
#include "Gnome.hh"
71
 
#endif // USE_GNOME
72
 
#ifdef USE_NEWWMSPEC
73
 
#include "Ewmh.hh"
74
 
#endif // USE_NEWWMSPEC
75
 
#ifdef REMEMBER
76
 
#include "Remember.hh"
77
 
#endif // REMEMBER
78
 
#ifdef USE_TOOLBAR
79
 
#include "Toolbar.hh"
80
 
#else
81
 
class Toolbar { };
82
 
#endif // USE_TOOLBAR
83
 
 
84
 
// X headers
85
 
#include <X11/Xlib.h>
86
 
#include <X11/Xutil.h>
87
 
#include <X11/Xresource.h>
88
 
#include <X11/Xatom.h>
89
 
#include <X11/keysym.h>
90
 
 
91
 
// X extensions
92
 
#ifdef SHAPE
93
 
#include <X11/extensions/shape.h>
94
 
#endif // SHAPE
95
 
#ifdef HAVE_RANDR
96
 
#include <X11/extensions/Xrandr.h>
97
 
#endif // HAVE_RANDR
98
 
 
99
 
// system headers
100
 
 
101
 
#ifdef HAVE_CSTDIO
102
 
  #include <cstdio>
103
 
#else
104
 
  #include <stdio.h>
105
 
#endif
106
 
#ifdef HAVE_CSTDLIB
107
 
  #include <cstdlib>
108
 
#else
109
 
  #include <stdlib.h>
110
 
#endif
111
 
#ifdef HAVE_CSTRING
112
 
  #include <cstring>
113
 
#else
114
 
  #include <string.h>
115
 
#endif
116
 
 
117
 
#ifdef HAVE_UNISTD_H
118
 
#include <sys/types.h>
119
 
#include <unistd.h>
120
 
#endif // HAVE_UNISTD_H
121
 
 
122
 
#ifdef HAVE_SYS_PARAM_H
123
 
#include <sys/param.h>
124
 
#endif // HAVE_SYS_PARAM_H
125
 
 
126
 
#ifdef HAVE_SYS_SELECT_H
127
 
#include <sys/select.h>
128
 
#endif // HAVE_SYS_SELECT_H
129
 
 
130
 
#ifdef HAVE_SYS_STAT_H
131
 
#include <sys/types.h>
132
 
#include <sys/stat.h>
133
 
#endif // HAVE_SYS_STAT_H
134
 
 
135
 
#ifdef  TIME_WITH_SYS_TIME
136
 
#include <sys/time.h>
137
 
#include <time.h>
138
 
#else // !TIME_WITH_SYS_TIME
139
 
#ifdef HAVE_SYS_TIME_H
140
 
#include <sys/time.h>
141
 
#else // !HAVE_SYS_TIME_H
142
 
#include <time.h>
143
 
#endif // HAVE_SYS_TIME_H
144
 
#endif // TIME_WITH_SYS_TIME
145
 
 
146
 
#include <sys/wait.h>
147
 
 
148
 
#include <iostream>
149
 
#include <string>
150
 
#include <memory>
151
 
#include <algorithm>
152
 
#include <typeinfo>
153
 
 
154
 
using namespace std;
155
 
using namespace FbTk;
156
 
 
157
 
namespace {
158
 
 
159
 
Window last_bad_window = None;
160
 
 
161
 
// *** NOTE: if you want to debug here the X errors are 
162
 
//     coming from, you should turn on the XSynchronise call below
163
 
int handleXErrors(Display *d, XErrorEvent *e) {
164
 
    if (e->error_code == BadWindow)
165
 
        last_bad_window = e->resourceid;
166
 
#ifdef DEBUG
167
 
    else {
168
 
        // ignore bad window ones, they happen a lot
169
 
        // when windows close themselves
170
 
        char errtxt[128];
171
 
 
172
 
        XGetErrorText(d, e->error_code, errtxt, 128);
173
 
        cerr<<"Fluxbox: X Error: "<<errtxt<<"("<<(int)e->error_code<<") opcodes "<<
174
 
            (int)e->request_code<<"/"<<(int)e->minor_code<<" resource 0x"<<hex<<(int)e->resourceid<<dec<<endl;
175
 
    }
176
 
#endif // !DEBUG
177
 
 
178
 
    return False;
179
 
}
180
 
 
181
 
} // end anonymous
182
 
 
183
 
//static singleton var
184
 
Fluxbox *Fluxbox::s_singleton=0;
185
 
 
186
 
//default values for titlebar left and right
187
 
//don't forget to change last value in m_rc_titlebar_* if you add more to these
188
 
Fluxbox::Titlebar Fluxbox::s_titlebar_left[] = {STICK};
189
 
Fluxbox::Titlebar Fluxbox::s_titlebar_right[] = {MINIMIZE, MAXIMIZE, CLOSE};
190
 
 
191
 
Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfilename)
192
 
    : FbTk::App(dpy_name),
193
 
      m_fbatoms(new FbAtoms()),
194
 
      m_resourcemanager(rcfilename, true),
195
 
      // TODO: shouldn't need a separate one for screen
196
 
      m_screen_rm(m_resourcemanager),
197
 
      m_rc_tabs(m_resourcemanager, true, "session.tabs", "Session.Tabs"),
198
 
      m_rc_tabs_padding(m_resourcemanager, 0, "session.tabPadding", "Session.TabPadding"),
199
 
      m_rc_focused_tab_min_width(m_resourcemanager, 0, "session.focusTabMinWidth",
200
 
              "Session.FocusTabMinWidth"),
201
 
      m_rc_ignoreborder(m_resourcemanager, false, "session.ignoreBorder", "Session.IgnoreBorder"),
202
 
      m_rc_pseudotrans(m_resourcemanager, false, "session.forcePseudoTransparency", "Session.forcePseudoTransparency"),
203
 
      m_rc_colors_per_channel(m_resourcemanager, 4,
204
 
                              "session.colorsPerChannel", "Session.ColorsPerChannel"),
205
 
      m_rc_numlayers(m_resourcemanager, 13, "session.numLayers", "Session.NumLayers"),
206
 
      m_rc_double_click_interval(m_resourcemanager, 250, "session.doubleClickInterval", "Session.DoubleClickInterval"),
207
 
      m_rc_stylefile(m_resourcemanager, DEFAULTSTYLE, "session.styleFile", "Session.StyleFile"),
208
 
      m_rc_menufile(m_resourcemanager, DEFAULTMENU, "session.menuFile", "Session.MenuFile"),
209
 
      m_rc_keyfile(m_resourcemanager, DEFAULTKEYSFILE, "session.keyFile", "Session.KeyFile"),
210
 
      m_rc_slitlistfile(m_resourcemanager, "~/.fluxbox/slitlist", "session.slitlistFile", "Session.SlitlistFile"),
211
 
      m_rc_groupfile(m_resourcemanager, "~/.fluxbox/groups", "session.groupFile", "Session.GroupFile"),
212
 
      m_rc_appsfile(m_resourcemanager, "~/.fluxbox/apps", "session.appsFile", "Session.AppsFile"),
213
 
      m_rc_titlebar_left(m_resourcemanager, 
214
 
                         TitlebarList(&s_titlebar_left[0], &s_titlebar_left[1]), 
215
 
                         "session.titlebar.left", "Session.Titlebar.Left"),
216
 
      m_rc_titlebar_right(m_resourcemanager,
217
 
                          TitlebarList(&s_titlebar_right[0], &s_titlebar_right[3]),
218
 
                          "session.titlebar.right", "Session.Titlebar.Right"),
219
 
      m_rc_tabs_attach_area(m_resourcemanager, ATTACH_AREA_WINDOW, "session.tabsAttachArea", "Session.TabsAttachArea"),
220
 
      m_rc_cache_life(m_resourcemanager, 5, "session.cacheLife", "Session.CacheLife"),
221
 
      m_rc_cache_max(m_resourcemanager, 200, "session.cacheMax", "Session.CacheMax"),
222
 
      m_rc_auto_raise_delay(m_resourcemanager, 250, "session.autoRaiseDelay", "Session.AutoRaiseDelay"),
223
 
      m_rc_use_mod1(m_resourcemanager, true, "session.useMod1", "Session.UseMod1"),
224
 
      m_focused_window(0), m_masked_window(0),
225
 
      m_mousescreen(0),
226
 
      m_keyscreen(0),
227
 
      m_watching_screen(0), m_watch_keyrelease(0),
228
 
      m_last_time(0),
229
 
      m_masked(0),
230
 
      m_rc_file(rcfilename ? rcfilename : ""),
231
 
      m_argv(argv), m_argc(argc),
232
 
      m_starting(true),
233
 
      m_restarting(false),
234
 
      m_shutdown(false),
235
 
      m_server_grabs(0),
236
 
      m_randr_event_type(0),
237
 
      m_RC_PATH("fluxbox"),
238
 
      m_RC_INIT_FILE("init") {
239
 
 
240
 
    _FB_USES_NLS;
241
 
    if (s_singleton != 0)
242
 
        throw string(_FBTEXT(Fluxbox, FatalSingleton, "Fatal! There can only one instance of fluxbox class.", "Error displayed on weird error where an instance of the Fluxbox class already exists!"));
243
 
 
244
 
    if (display() == 0) {
245
 
        throw string(_FBTEXT(Fluxbox, NoDisplay,
246
 
                             "Can not connect to X server.\nMake sure you started X before you start Fluxbox.",
247
 
                             "Error message when no X display appears to exist"));
248
 
    }
249
 
 
250
 
    Display *disp = FbTk::App::instance()->display();
251
 
    // For KDE dock applets
252
 
    // KDE v1.x
253
 
    m_kwm1_dockwindow = XInternAtom(disp,
254
 
                                    "KWM_DOCKWINDOW", False);
255
 
    // KDE v2.x
256
 
    m_kwm2_dockwindow = XInternAtom(disp,
257
 
                                    "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
258
 
    // setup X error handler
259
 
    XSetErrorHandler((XErrorHandler) handleXErrors);
260
 
 
261
 
    //catch system signals
262
 
    SignalHandler &sigh = SignalHandler::instance();
263
 
    sigh.registerHandler(SIGSEGV, this);
264
 
    sigh.registerHandler(SIGFPE, this);
265
 
    sigh.registerHandler(SIGTERM, this);
266
 
    sigh.registerHandler(SIGINT, this);
267
 
    sigh.registerHandler(SIGCHLD, this);
268
 
    sigh.registerHandler(SIGHUP, this);
269
 
    sigh.registerHandler(SIGUSR1, this);
270
 
    sigh.registerHandler(SIGUSR2, this);
271
 
    //
272
 
    // setup timer
273
 
    // This timer is used to we can issue a safe reconfig command.
274
 
    // Because when the command is executed we shouldn't do reconfig directly
275
 
    // because it could affect ongoing menu stuff so we need to reconfig in
276
 
    // the next event "round".
277
 
    FbTk::RefCount<FbTk::Command> reconfig_cmd(new FbTk::SimpleCommand<Fluxbox>(*this, &Fluxbox::timed_reconfigure));
278
 
    timeval to;
279
 
    to.tv_sec = 0;
280
 
    to.tv_usec = 1;
281
 
    m_reconfig_timer.setTimeout(to);
282
 
    m_reconfig_timer.setCommand(reconfig_cmd);
283
 
    m_reconfig_timer.fireOnce(true);
284
 
    // XSynchronize(disp, True);
285
 
 
286
 
    s_singleton = this;
287
 
    m_have_shape = false;
288
 
    m_shape_eventbase = 0;
289
 
#ifdef SHAPE
290
 
    int shape_err;
291
 
    m_have_shape = XShapeQueryExtension(disp, &m_shape_eventbase, &shape_err);
292
 
#endif // SHAPE
293
 
 
294
 
#ifdef HAVE_RANDR
295
 
    // get randr event type
296
 
    int randr_error_base;
297
 
    XRRQueryExtension(disp, &m_randr_event_type, &randr_error_base);
298
 
#endif // HAVE_RANDR
299
 
 
300
 
    load_rc();
301
 
    // setup theme manager to have our style file ready to be scanned
302
 
    FbTk::ThemeManager::instance().load(getStyleFilename());
303
 
 
304
 
    // setup atom handlers before we create any windows
305
 
#ifdef REMEMBER
306
 
    addAtomHandler(new Remember(), "remember"); // for remembering window attribs
307
 
#endif // REMEMBER
308
 
#ifdef USE_NEWWMSPEC
309
 
    addAtomHandler(new Ewmh(), "ewmh"); // for Extended window manager atom support
310
 
#endif // USE_NEWWMSPEC
311
 
#ifdef USE_GNOME
312
 
    addAtomHandler(new Gnome(), "gnome"); // for gnome 1 atom support
313
 
#endif //USE_GNOME
314
 
 
315
 
    grab();
316
 
 
317
 
    setupConfigFiles();
318
 
 
319
 
    if (! XSupportsLocale())
320
 
        cerr<<_FBTEXT(Fluxbox, WarningLocale, "Warning: X server does not support locale", "XSupportsLocale returned false")<<endl;
321
 
 
322
 
    if (XSetLocaleModifiers("") == 0)
323
 
        cerr<<_FBTEXT(Fluxbox, WarningLocaleModifiers, "Warning: cannot set locale modifiers", "XSetLocaleModifiers returned false")<<endl;
324
 
 
325
 
 
326
 
#ifdef HAVE_GETPID
327
 
    m_fluxbox_pid = XInternAtom(disp, "_BLACKBOX_PID", False);
328
 
#endif // HAVE_GETPID
329
 
 
330
 
 
331
 
    vector<int> screens;
332
 
    int i;
333
 
 
334
 
    // default is "use all screens"
335
 
    for (i = 0; i < ScreenCount(disp); i++)
336
 
        screens.push_back(i);
337
 
 
338
 
    // find out, on what "screens" fluxbox should run
339
 
    for (i = 1; i < m_argc; i++) {
340
 
        if (! strcmp(m_argv[i], "-screen")) {
341
 
            if ((++i) >= m_argc) {
342
 
                cerr<<"error, -screen requires argument\n";
343
 
                exit(1);
344
 
            }
345
 
 
346
 
            // "all" is default
347
 
            if (! strcmp(m_argv[i], "all"))
348
 
                break;
349
 
 
350
 
            vector<string> vals;
351
 
            vector<int> scrtmp;
352
 
            int scrnr = 0;
353
 
            FbTk::StringUtil::stringtok(vals, m_argv[i], ",:");
354
 
            for (vector<string>::iterator scrit = vals.begin(); 
355
 
                 scrit != vals.end(); scrit++) {
356
 
                scrnr = atoi(scrit->c_str());
357
 
                if (scrnr >= 0 && scrnr < ScreenCount(disp))
358
 
                    scrtmp.push_back(scrnr);
359
 
            }
360
 
 
361
 
            if (!vals.empty())
362
 
                swap(scrtmp, screens);
363
 
        }
364
 
    }
365
 
    
366
 
    // init all "screens"
367
 
    for(i = 0; i < screens.size(); i++)
368
 
        initScreen(screens[i]);
369
 
    
370
 
    XAllowEvents(disp, ReplayPointer, CurrentTime);
371
 
 
372
 
 
373
 
    if (m_screen_list.empty()) {
374
 
        throw string(_FBTEXT(Fluxbox, ErrorNoScreens,
375
 
                             "Couldn't find screens to manage.\nMake sure you don't have another window manager running.", 
376
 
                             "Error message when no unmanaged screens found - usually means another window manager is running"));
377
 
    }
378
 
 
379
 
    m_keyscreen = m_mousescreen = m_screen_list.front();
380
 
   
381
 
    // setup theme manager to have our style file ready to be scanned
382
 
    FbTk::ThemeManager::instance().load(FbTk::StringUtil::expandFilename(getStyleFilename()));
383
 
 
384
 
    //XSynchronize(disp, False);
385
 
    sync(false);
386
 
 
387
 
    m_reconfigure_wait = m_reread_menu_wait = false;
388
 
 
389
 
    // Create keybindings handler and load keys file
390
 
    m_key.reset(new Keys(StringUtil::expandFilename(*m_rc_keyfile).c_str()));
391
 
 
392
 
    m_resourcemanager.unlock();
393
 
    ungrab();
394
 
 
395
 
#ifdef DEBUG
396
 
    if (m_resourcemanager.lockDepth() != 0)
397
 
        cerr<<"--- resource manager lockdepth = "<<m_resourcemanager.lockDepth()<<endl;
398
 
#endif //DEBUG
399
 
    m_starting = false;
400
 
    //
401
 
    // For dumping theme items
402
 
    // FbTk::ThemeManager::instance().listItems();
403
 
    //
404
 
    //    m_resourcemanager.dump();
405
 
 
406
 
#ifdef USE_TOOLBAR
407
 
    // finally, show toolbar
408
 
    Toolbars::iterator toolbar_it = m_toolbars.begin();
409
 
    Toolbars::iterator toolbar_it_end = m_toolbars.end();
410
 
    for (; toolbar_it != toolbar_it_end; ++toolbar_it)
411
 
        (*toolbar_it)->updateVisibleState();
412
 
#endif // USE_TOOLBAR
413
 
 
414
 
}
415
 
 
416
 
 
417
 
Fluxbox::~Fluxbox() {
418
 
 
419
 
    // destroy toolbars
420
 
    while (!m_toolbars.empty()) {
421
 
        delete m_toolbars.back();
422
 
        m_toolbars.pop_back();
423
 
    }
424
 
   
425
 
    // destroy screens
426
 
    while (!m_screen_list.empty()) {
427
 
        delete m_screen_list.back();
428
 
        m_screen_list.pop_back();
429
 
    }
430
 
 
431
 
    // destroy atomhandlers
432
 
    for (AtomHandlerContainerIt it= m_atomhandler.begin();
433
 
         it != m_atomhandler.end();
434
 
         it++) {
435
 
        delete (*it).first;
436
 
    }
437
 
    m_atomhandler.clear();
438
 
 
439
 
    clearMenuFilenames();
440
 
}
441
 
 
442
 
 
443
 
int Fluxbox::initScreen(int scrnr) {
444
 
    
445
 
    Display* disp = display();
446
 
    char scrname[128], altscrname[128];
447
 
    sprintf(scrname, "session.screen%d", scrnr);
448
 
    sprintf(altscrname, "session.Screen%d", scrnr);
449
 
    BScreen *screen = new BScreen(m_screen_rm.lock(),
450
 
                                  scrname, altscrname,
451
 
                                  scrnr, getNumberOfLayers());
452
 
 
453
 
    // already handled
454
 
    if (! screen->isScreenManaged()) {
455
 
        delete screen;
456
 
        return 0;
457
 
    }
458
 
    
459
 
    // add to our list
460
 
    m_screen_list.push_back(screen);
461
 
 
462
 
    // now we can create menus (which needs this screen to be in screen_list)
463
 
    screen->initMenus();
464
 
 
465
 
#ifdef HAVE_GETPID
466
 
    pid_t bpid = getpid();
467
 
 
468
 
    screen->rootWindow().changeProperty(getFluxboxPidAtom(), XA_CARDINAL,
469
 
                                        sizeof(pid_t) * 8, PropModeReplace,
470
 
                                        (unsigned char *) &bpid, 1);
471
 
#endif // HAVE_GETPID
472
 
 
473
 
#ifdef HAVE_RANDR
474
 
    // setup RANDR for this screens root window
475
 
    // we need to determine if we should use old randr select input function or not
476
 
#ifdef X_RRScreenChangeSelectInput
477
 
    // use old set randr event
478
 
    XRRScreenChangeSelectInput(disp, screen->rootWindow().window(), True);
479
 
#else
480
 
    XRRSelectInput(disp, screen->rootWindow().window(),
481
 
                   RRScreenChangeNotifyMask);
482
 
#endif // X_RRScreenChangeSelectInput
483
 
 
484
 
#endif // HAVE_RANDR
485
 
 
486
 
 
487
 
#ifdef USE_TOOLBAR
488
 
    m_toolbars.push_back(new Toolbar(*screen,
489
 
                                     *screen->layerManager().
490
 
                                     getLayer(Fluxbox::instance()->getNormalLayer())));
491
 
#endif // USE_TOOLBAR
492
 
 
493
 
    // must do this after toolbar is created
494
 
    screen->initWindows();
495
 
 
496
 
    // attach screen signals to this
497
 
    screen->currentWorkspaceSig().attach(this);
498
 
    screen->workspaceCountSig().attach(this);
499
 
    screen->workspaceNamesSig().attach(this);
500
 
    screen->workspaceAreaSig().attach(this);
501
 
    screen->clientListSig().attach(this);
502
 
 
503
 
    // initiate atomhandler for screen specific stuff
504
 
    for (AtomHandlerContainerIt it= m_atomhandler.begin();
505
 
         it != m_atomhandler.end();
506
 
         it++) {
507
 
        (*it).first->initForScreen(*screen);
508
 
    }
509
 
 
510
 
    revertFocus(*screen); // make sure focus style is correct
511
 
#ifdef SLIT
512
 
    if (screen->slit())
513
 
        screen->slit()->show();
514
 
#endif // SLIT
515
 
 
516
 
    return 1;
517
 
}
518
 
 
519
 
 
520
 
void Fluxbox::eventLoop() {
521
 
    Display *disp = display();
522
 
    while (!m_shutdown) {
523
 
        if (XPending(disp)) {
524
 
            XEvent e;
525
 
            XNextEvent(disp, &e);
526
 
 
527
 
            if (last_bad_window != None && e.xany.window == last_bad_window &&
528
 
                e.type != DestroyNotify) { // we must let the actual destroys through
529
 
#ifdef DEBUG
530
 
                cerr<<"Fluxbox::eventLoop(): removing bad window from event queue"<<endl;
531
 
#endif // DEBUG
532
 
            } else {
533
 
                last_bad_window = None;
534
 
                handleEvent(&e);
535
 
            }
536
 
        } else {
537
 
            FbTk::Timer::updateTimers(ConnectionNumber(disp)); //handle all timers
538
 
        }
539
 
    }
540
 
}
541
 
 
542
 
bool Fluxbox::validateWindow(Window window) const {
543
 
    XEvent event;
544
 
    if (XCheckTypedWindowEvent(display(), window, DestroyNotify, &event)) {
545
 
        XPutBackEvent(display(), &event);
546
 
        return false;
547
 
    }
548
 
 
549
 
    return true;
550
 
}
551
 
 
552
 
void Fluxbox::grab() {
553
 
    if (! m_server_grabs++)
554
 
       XGrabServer(display());
555
 
}
556
 
 
557
 
void Fluxbox::ungrab() {
558
 
    if (! --m_server_grabs)
559
 
        XUngrabServer(display());
560
 
 
561
 
    if (m_server_grabs < 0)
562
 
        m_server_grabs = 0;
563
 
}
564
 
 
565
 
/**
566
 
 setup the configutation files in
567
 
 home directory
568
 
*/
569
 
void Fluxbox::setupConfigFiles() {
570
 
 
571
 
    bool create_init = false, create_keys = false, create_menu = false;
572
 
 
573
 
    string dirname = getenv("HOME") + string("/.") + string(m_RC_PATH) + "/";
574
 
    string init_file, keys_file, menu_file, slitlist_file;
575
 
    init_file = dirname + m_RC_INIT_FILE;
576
 
    keys_file = dirname + "keys";
577
 
    menu_file = dirname + "menu";
578
 
 
579
 
    struct stat buf;
580
 
 
581
 
    // is file/dir already there?
582
 
    if (! stat(dirname.c_str(), &buf)) {
583
 
 
584
 
        // check if anything with those name exists, if not create new
585
 
        if (stat(init_file.c_str(), &buf))
586
 
            create_init = true;
587
 
        if (stat(keys_file.c_str(), &buf))
588
 
            create_keys = true;
589
 
        if (stat(menu_file.c_str(), &buf))
590
 
            create_menu = true;
591
 
 
592
 
    } else {
593
 
#ifdef DEBUG
594
 
        cerr <<__FILE__<<"("<<__LINE__<<"): Creating dir: " << dirname.c_str() << endl;
595
 
#endif // DEBUG
596
 
        _FB_USES_NLS;
597
 
        // create directory with perm 700
598
 
        if (mkdir(dirname.c_str(), 0700)) {
599
 
            fprintf(stderr, _FBTEXT(Fluxbox, ErrorCreatingDirectory,
600
 
                                    "Can't create %s directory", 
601
 
                                    "Can't create a directory, one %s for directory name"), 
602
 
                    dirname.c_str());
603
 
            cerr<<endl;
604
 
            return;
605
 
        }
606
 
 
607
 
        //mark creation of files
608
 
        create_init = create_keys = create_menu = true;
609
 
    }
610
 
 
611
 
 
612
 
    // copy key configuration
613
 
    if (create_keys)
614
 
        FbTk::FileUtil::copyFile(DEFAULTKEYSFILE, keys_file.c_str());
615
 
 
616
 
    // copy menu configuration
617
 
    if (create_menu)
618
 
        FbTk::FileUtil::copyFile(DEFAULTMENU, menu_file.c_str());
619
 
 
620
 
    // copy init file
621
 
    if (create_init)
622
 
        FbTk::FileUtil::copyFile(DEFAULT_INITFILE, init_file.c_str());
623
 
 
624
 
}
625
 
 
626
 
void Fluxbox::handleEvent(XEvent * const e) {
627
 
    _FB_USES_NLS;
628
 
    m_last_event = *e;
629
 
 
630
 
    // it is possible (e.g. during moving) for a window
631
 
    // to mask all events to go to it
632
 
    if ((m_masked == e->xany.window) && m_masked_window) {
633
 
        if (e->type == MotionNotify) {
634
 
            m_last_time = e->xmotion.time;
635
 
            m_masked_window->motionNotifyEvent(e->xmotion);
636
 
            return;
637
 
        } else if (e->type == ButtonRelease) {
638
 
            e->xbutton.window = m_masked_window->fbWindow().window();
639
 
        }
640
 
 
641
 
    }
642
 
 
643
 
    // update key/mouse screen and last time before we enter other eventhandlers
644
 
    if (e->type == KeyPress ||
645
 
        e->type == KeyRelease) {
646
 
        m_keyscreen = searchScreen(e->xkey.root);
647
 
    } else if (e->type == ButtonPress ||
648
 
               e->type == ButtonRelease ||
649
 
               e->type == MotionNotify ) {
650
 
        if (e->type == MotionNotify)
651
 
            m_last_time = e->xmotion.time;
652
 
        else
653
 
            m_last_time = e->xbutton.time;
654
 
 
655
 
        m_mousescreen = searchScreen(e->xbutton.root);
656
 
    } else if (e->type == EnterNotify ||
657
 
               e->type == LeaveNotify) {
658
 
        m_last_time = e->xcrossing.time;
659
 
        m_mousescreen = searchScreen(e->xcrossing.root);
660
 
    } else if (e->type == PropertyNotify) {
661
 
        m_last_time = e->xproperty.time;
662
 
        // check transparency atoms if it's a root pm
663
 
        
664
 
        BScreen *screen = searchScreen(e->xproperty.window);
665
 
        if (screen) {
666
 
            FbTk::FbPixmap::rootwinPropertyNotify(screen->screenNumber(), e->xproperty.atom);
667
 
        }
668
 
    }
669
 
 
670
 
    // we need to check focus out for menus before
671
 
    // we call FbTk eventhandler
672
 
    // so we can get FbTk::Menu::focused() before it sets to 0
673
 
    if (e->type == FocusOut &&
674
 
        e->xfocus.mode != NotifyGrab &&
675
 
        e->xfocus.detail != NotifyPointer &&
676
 
        e->xfocus.detail != NotifyInferior &&
677
 
        FbTk::Menu::focused() != 0 &&
678
 
        FbTk::Menu::focused()->window() == e->xfocus.window) {
679
 
 
680
 
        // find screen num
681
 
        BScreen *screen = 0;
682
 
        ScreenList::iterator it = m_screen_list.begin();
683
 
        ScreenList::iterator it_end = m_screen_list.end();
684
 
        for (; it != it_end; ++it) {
685
 
            if ( (*it)->screenNumber() ==
686
 
                 FbTk::Menu::focused()->fbwindow().screenNumber()) {
687
 
                screen = (*it);
688
 
                break; // found the screen, no more search
689
 
            }
690
 
        }
691
 
 
692
 
        if (screen != 0)
693
 
            revertFocus(*screen);
694
 
    }
695
 
 
696
 
    // try FbTk::EventHandler first
697
 
    FbTk::EventManager::instance()->handleEvent(*e);
698
 
 
699
 
    switch (e->type) {
700
 
    case ButtonRelease:
701
 
    case ButtonPress:
702
 
        handleButtonEvent(e->xbutton);
703
 
        break;
704
 
    case ConfigureRequest: {
705
 
 
706
 
        if (!searchWindow(e->xconfigurerequest.window)) {
707
 
 
708
 
            grab();
709
 
 
710
 
            if (validateWindow(e->xconfigurerequest.window)) {
711
 
                XWindowChanges xwc;
712
 
 
713
 
                xwc.x = e->xconfigurerequest.x;
714
 
                xwc.y = e->xconfigurerequest.y;
715
 
                xwc.width = e->xconfigurerequest.width;
716
 
                xwc.height = e->xconfigurerequest.height;
717
 
                xwc.border_width = e->xconfigurerequest.border_width;
718
 
                xwc.sibling = e->xconfigurerequest.above;
719
 
                xwc.stack_mode = e->xconfigurerequest.detail;
720
 
 
721
 
                XConfigureWindow(FbTk::App::instance()->display(),
722
 
                                 e->xconfigurerequest.window,
723
 
                                 e->xconfigurerequest.value_mask, &xwc);
724
 
            }
725
 
 
726
 
            ungrab();
727
 
        } // else already handled in FluxboxWindow::handleEvent
728
 
 
729
 
    }
730
 
        break;
731
 
    case MapRequest: {
732
 
 
733
 
#ifdef DEBUG
734
 
        cerr<<"MapRequest for 0x"<<hex<<e->xmaprequest.window<<dec<<endl;
735
 
 
736
 
#endif // DEBUG
737
 
 
738
 
        WinClient *winclient = searchWindow(e->xmaprequest.window);
739
 
        FluxboxWindow *win = 0;
740
 
 
741
 
        if (! winclient) {
742
 
            BScreen *screen = 0;
743
 
            int screen_num;
744
 
            XWindowAttributes attr;
745
 
            // find screen
746
 
            if (XGetWindowAttributes(display(),
747
 
                                     e->xmaprequest.window,
748
 
                                     &attr) && attr.screen != 0) {
749
 
                screen_num = XScreenNumberOfScreen(attr.screen);
750
 
 
751
 
                // find screen
752
 
                ScreenList::iterator screen_it = find_if(m_screen_list.begin(),
753
 
                                                         m_screen_list.end(),
754
 
                                                         FbTk::CompareEqual<BScreen>(&BScreen::screenNumber, screen_num));
755
 
                if (screen_it != m_screen_list.end())
756
 
                    screen = *screen_it;
757
 
            }
758
 
            // try with parent if we failed to find screen num
759
 
            if (screen == 0)
760
 
               screen = searchScreen(e->xmaprequest.parent);
761
 
 
762
 
            if (screen == 0) {
763
 
                cerr<<"Fluxbox "<<_FBTEXT(Fluxbox, CantMapWindow, "Warning! Could not find screen to map window on!", "")<<endl;
764
 
            } else
765
 
                win = screen->createWindow(e->xmaprequest.window);
766
 
 
767
 
        } else {
768
 
            win = winclient->fbwindow();
769
 
        }
770
 
 
771
 
        // we don't handle MapRequest in FluxboxWindow::handleEvent
772
 
        if (win)
773
 
            win->mapRequestEvent(e->xmaprequest);
774
 
    }
775
 
        break;
776
 
    case MapNotify:
777
 
        // handled directly in FluxboxWindow::handleEvent
778
 
        break;
779
 
    case UnmapNotify:
780
 
        handleUnmapNotify(e->xunmap);
781
 
        break;
782
 
    case MappingNotify:
783
 
        // Update stored modifier mapping
784
 
#ifdef DEBUG
785
 
        cerr<<__FILE__<<"("<<__FUNCTION__<<"): MappingNotify"<<endl;
786
 
#endif // DEBUG
787
 
        if (e->xmapping.request == MappingKeyboard
788
 
            || e->xmapping.request == MappingModifier) {
789
 
            XRefreshKeyboardMapping(&e->xmapping);
790
 
            FbTk::KeyUtil::instance().init(); // reinitialise the key utils
791
 
            // reconfigure keys (if the mapping changes, they don't otherwise update
792
 
            m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str());
793
 
        }
794
 
        break;
795
 
    case CreateNotify:
796
 
        break;
797
 
    case DestroyNotify: {
798
 
        WinClient *winclient = searchWindow(e->xdestroywindow.window);
799
 
        if (winclient != 0) {
800
 
            FluxboxWindow *win = winclient->fbwindow();
801
 
            if (win)
802
 
                win->destroyNotifyEvent(e->xdestroywindow);
803
 
 
804
 
            delete winclient;
805
 
 
806
 
            if (win && win->numClients() == 0)
807
 
                delete win;
808
 
        }
809
 
 
810
 
    }
811
 
        break;
812
 
    case MotionNotify:
813
 
        m_last_time = e->xmotion.time;
814
 
        break;
815
 
    case PropertyNotify: {
816
 
        m_last_time = e->xproperty.time;
817
 
        WinClient *winclient = searchWindow(e->xproperty.window);
818
 
        if (winclient == 0)
819
 
            break;
820
 
        // most of them are handled in FluxboxWindow::handleEvent
821
 
        // but some special cases like ewmh propertys needs to be checked
822
 
        for (AtomHandlerContainerIt it= m_atomhandler.begin();
823
 
             it != m_atomhandler.end(); it++) {
824
 
            if ( (*it).first->propertyNotify(*winclient, e->xproperty.atom))
825
 
                break;
826
 
        }
827
 
    } break;
828
 
    case EnterNotify: {
829
 
 
830
 
        m_last_time = e->xcrossing.time;
831
 
        BScreen *screen = 0;
832
 
 
833
 
        if (e->xcrossing.mode == NotifyGrab)
834
 
            break;
835
 
 
836
 
        if ((e->xcrossing.window == e->xcrossing.root) &&
837
 
            (screen = searchScreen(e->xcrossing.window))) {
838
 
            screen->imageControl().installRootColormap();
839
 
 
840
 
        }
841
 
 
842
 
    } break;
843
 
    case LeaveNotify:
844
 
        m_last_time = e->xcrossing.time;
845
 
        break;
846
 
    case Expose:
847
 
        break;
848
 
    case KeyRelease:
849
 
    case KeyPress:
850
 
        handleKeyEvent(e->xkey);
851
 
        break;
852
 
    case ColormapNotify: {
853
 
        BScreen *screen = searchScreen(e->xcolormap.window);
854
 
 
855
 
        if (screen != 0) {
856
 
            screen->setRootColormapInstalled((e->xcolormap.state ==
857
 
                                              ColormapInstalled) ? true : false);
858
 
        }
859
 
    } break;
860
 
    case FocusIn: {
861
 
 
862
 
        // a grab is something of a pseudo-focus event, so we ignore
863
 
        // them, here we ignore some window receiving it
864
 
        if (e->xfocus.mode == NotifyGrab ||
865
 
            e->xfocus.detail == NotifyPointer ||
866
 
            e->xfocus.detail == NotifyInferior)
867
 
            break;
868
 
        WinClient *winclient = searchWindow(e->xfocus.window);
869
 
        if (winclient && m_focused_window != winclient)
870
 
            setFocusedWindow(winclient);
871
 
 
872
 
    } break;
873
 
    case FocusOut:{
874
 
        // and here we ignore some window losing the special grab focus
875
 
        if (e->xfocus.mode == NotifyGrab ||
876
 
            e->xfocus.detail == NotifyPointer ||
877
 
            e->xfocus.detail == NotifyInferior)
878
 
            break;
879
 
 
880
 
        WinClient *winclient = searchWindow(e->xfocus.window);
881
 
        if (winclient == 0 && FbTk::Menu::focused() == 0) {
882
 
#ifdef DEBUG
883
 
            cerr<<__FILE__<<"("<<__FUNCTION__<<") Focus out is not a FluxboxWindow !!"<<endl;
884
 
#endif // DEBUG
885
 
        } else if (winclient && winclient == m_focused_window &&
886
 
                   (winclient->fbwindow() == 0
887
 
                    || !winclient->fbwindow()->isMoving()))
888
 
            // we don't unfocus a moving window
889
 
            setFocusedWindow(0);
890
 
    }
891
 
        break;
892
 
    case ClientMessage:
893
 
        handleClientMessage(e->xclient);
894
 
        break;
895
 
    default: {
896
 
 
897
 
#ifdef HAVE_RANDR
898
 
        if (e->type == m_randr_event_type) {
899
 
            // update root window size in screen
900
 
            BScreen *scr = searchScreen(e->xany.window);
901
 
            if (scr != 0)
902
 
                scr->updateSize();
903
 
        }
904
 
#endif // HAVE_RANDR
905
 
 
906
 
    }
907
 
 
908
 
    }
909
 
}
910
 
 
911
 
void Fluxbox::handleButtonEvent(XButtonEvent &be) {
912
 
 
913
 
    switch (be.type) {
914
 
    case ButtonPress: {
915
 
        m_last_time = be.time;
916
 
 
917
 
        BScreen *screen = searchScreen(be.window);
918
 
        if (screen == 0)
919
 
            break; // end case
920
 
 
921
 
        screen->hideMenus();
922
 
 
923
 
        // strip num/caps/scroll-lock and
924
 
        // see if we're using any other modifier,
925
 
        // if we're we shouldn't show the root menu
926
 
        // this could happen if we're resizing aterm for instance
927
 
        if (FbTk::KeyUtil::instance().cleanMods(be.state) != 0)
928
 
            return;
929
 
 
930
 
        if (be.button == 1) {
931
 
            if (! screen->isRootColormapInstalled())
932
 
                screen->imageControl().installRootColormap();
933
 
            // hide menus
934
 
            if (screen->rootMenu().isVisible())
935
 
                screen->rootMenu().hide();
936
 
            if (screen->workspaceMenu().isVisible())
937
 
                screen->workspaceMenu().hide();
938
 
 
939
 
        } else if (be.button == 2) {
940
 
            FbCommands::ShowWorkspaceMenuCmd cmd;
941
 
            cmd.execute();
942
 
        } else if (be.button == 3) {
943
 
            FbCommands::ShowRootMenuCmd cmd;
944
 
            cmd.execute();
945
 
        } else if (screen->isDesktopWheeling() && be.button == 4) {
946
 
            screen->nextWorkspace(1);
947
 
        } else if (screen->isDesktopWheeling() && be.button == 5) {
948
 
            screen->prevWorkspace(1);
949
 
        }
950
 
 
951
 
    } break;
952
 
    case ButtonRelease:
953
 
        m_last_time = be.time;
954
 
        break;
955
 
    default:
956
 
        break;
957
 
    }
958
 
}
959
 
 
960
 
void Fluxbox::handleUnmapNotify(XUnmapEvent &ue) {
961
 
 
962
 
    BScreen *screen = searchScreen(ue.event);
963
 
    
964
 
    if (ue.event != ue.window && (!screen || !ue.send_event)) {
965
 
        return;
966
 
    }
967
 
 
968
 
    WinClient *winclient = 0;
969
 
 
970
 
    if ((winclient = searchWindow(ue.window)) != 0) {
971
 
 
972
 
        if (winclient != 0) {
973
 
            FluxboxWindow *win = winclient->fbwindow();
974
 
 
975
 
            if (!win) {
976
 
                delete winclient;
977
 
                return;
978
 
            }
979
 
 
980
 
            // this should delete client and adjust m_focused_window if necessary
981
 
            win->unmapNotifyEvent(ue);
982
 
 
983
 
            winclient = 0; // it's invalid now when win destroyed the client
984
 
 
985
 
            // finally destroy window if empty
986
 
            if (win->numClients() == 0) {
987
 
                delete win;
988
 
                win = 0;
989
 
            }
990
 
        }
991
 
 
992
 
    // according to http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.4
993
 
    // a XWithdrawWindow is 
994
 
    //   1) unmapping the window (which leads to the upper branch
995
 
    //   2) sends an synthetic unampevent (which is handled below)
996
 
    } else if (screen && ue.send_event) {
997
 
        XDeleteProperty(display(), ue.window, FbAtoms::instance()->getWMStateAtom());
998
 
        XUngrabButton(display(), AnyButton, AnyModifier, ue.window);
999
 
    }
1000
 
 
1001
 
}
1002
 
 
1003
 
/**
1004
 
 * Handles XClientMessageEvent
1005
 
 */
1006
 
void Fluxbox::handleClientMessage(XClientMessageEvent &ce) {
1007
 
 
1008
 
#ifdef DEBUG
1009
 
    char * atom = 0;
1010
 
    if (ce.message_type)
1011
 
        atom = XGetAtomName(FbTk::App::instance()->display(), ce.message_type);
1012
 
 
1013
 
    cerr<<__FILE__<<"("<<__LINE__<<"): ClientMessage. data.l[0]=0x"<<hex<<ce.data.l[0]<<
1014
 
        "  message_type=0x"<<ce.message_type<<dec<<" = \""<<atom<<"\""<<endl;
1015
 
 
1016
 
    if (ce.message_type && atom) XFree((char *) atom);
1017
 
#endif // DEBUG
1018
 
 
1019
 
 
1020
 
    if (ce.format != 32)
1021
 
        return;
1022
 
 
1023
 
    if (ce.message_type == m_fbatoms->getWMChangeStateAtom()) {
1024
 
        WinClient *winclient = searchWindow(ce.window);
1025
 
        if (! winclient || !winclient->fbwindow() || ! winclient->validateClient())
1026
 
            return;
1027
 
 
1028
 
        if (ce.data.l[0] == IconicState)
1029
 
            winclient->fbwindow()->iconify();
1030
 
        if (ce.data.l[0] == NormalState)
1031
 
            winclient->fbwindow()->deiconify();
1032
 
    } else if (ce.message_type == m_fbatoms->getFluxboxChangeWorkspaceAtom()) {
1033
 
        BScreen *screen = searchScreen(ce.window);
1034
 
 
1035
 
        if (screen && ce.data.l[0] >= 0 &&
1036
 
            ce.data.l[0] < (signed)screen->numberOfWorkspaces())
1037
 
            screen->changeWorkspaceID(ce.data.l[0]);
1038
 
 
1039
 
    } else if (ce.message_type == m_fbatoms->getFluxboxChangeWindowFocusAtom()) {
1040
 
        WinClient *winclient = searchWindow(ce.window);
1041
 
        if (winclient) {
1042
 
            FluxboxWindow *win = winclient->fbwindow();
1043
 
            if (win && win->isVisible())
1044
 
                win->setCurrentClient(*winclient, true);
1045
 
        }
1046
 
    } else if (ce.message_type == m_fbatoms->getFluxboxCycleWindowFocusAtom()) {
1047
 
        BScreen *screen = searchScreen(ce.window);
1048
 
 
1049
 
        if (screen) {
1050
 
            if (! ce.data.l[0])
1051
 
                screen->prevFocus();
1052
 
            else
1053
 
                screen->nextFocus();
1054
 
        }
1055
 
    } else if (ce.message_type == m_fbatoms->getFluxboxChangeAttributesAtom()) {
1056
 
        WinClient *winclient = searchWindow(ce.window);
1057
 
        FluxboxWindow *win = 0;
1058
 
        if (winclient && (win = winclient->fbwindow()) && winclient->validateClient()) {
1059
 
            FluxboxWindow::BlackboxHints net;
1060
 
            net.flags = ce.data.l[0];
1061
 
            net.attrib = ce.data.l[1];
1062
 
            net.workspace = ce.data.l[2];
1063
 
            net.stack = ce.data.l[3];
1064
 
            net.decoration = static_cast<int>(ce.data.l[4]);
1065
 
            win->changeBlackboxHints(net);
1066
 
        }
1067
 
    } else {
1068
 
        WinClient *winclient = searchWindow(ce.window);
1069
 
        BScreen *screen = searchScreen(ce.window);
1070
 
        // note: we dont need screen nor winclient to be non-null,
1071
 
        // it's up to the atomhandler to check that
1072
 
        for (AtomHandlerContainerIt it= m_atomhandler.begin();
1073
 
             it != m_atomhandler.end(); it++) {
1074
 
            (*it).first->checkClientMessage(ce, screen, winclient);
1075
 
        }
1076
 
 
1077
 
    }
1078
 
}
1079
 
 
1080
 
/**
1081
 
 Handles KeyRelease and KeyPress events
1082
 
*/
1083
 
void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
1084
 
 
1085
 
    if (keyScreen() == 0 || mouseScreen() == 0)
1086
 
        return;
1087
 
 
1088
 
    switch (ke.type) {
1089
 
    case KeyPress:
1090
 
        m_key->doAction(ke);
1091
 
        break;
1092
 
    case KeyRelease: {
1093
 
        // we ignore most key releases unless we need to use
1094
 
        // a release to stop something (e.g. window cycling).
1095
 
 
1096
 
        // we notify if _all_ of the watched modifiers are released
1097
 
        if (m_watching_screen && m_watch_keyrelease) {
1098
 
            // mask the mod of the released key out
1099
 
            // won't mask anything if it isn't a mod
1100
 
            unsigned int state = FbTk::KeyUtil::instance().isolateModifierMask(ke.state);
1101
 
            state &= ~FbTk::KeyUtil::instance().keycodeToModmask(ke.keycode);
1102
 
            
1103
 
            if ((m_watch_keyrelease & state) == 0) {
1104
 
 
1105
 
                m_watching_screen->notifyReleasedKeys(ke);
1106
 
                XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime);
1107
 
 
1108
 
                // once they are released, we drop the watch
1109
 
                m_watching_screen = 0;
1110
 
                m_watch_keyrelease = 0;
1111
 
            }
1112
 
        }
1113
 
 
1114
 
        break;
1115
 
    }
1116
 
    default:
1117
 
        break;
1118
 
    }
1119
 
}
1120
 
 
1121
 
/// handle system signals
1122
 
void Fluxbox::handleSignal(int signum) {
1123
 
    _FB_USES_NLS;
1124
 
 
1125
 
    static int re_enter = 0;
1126
 
 
1127
 
    switch (signum) {
1128
 
    case SIGCHLD: // we don't want the child process to kill us
1129
 
        waitpid(-1, 0, WNOHANG | WUNTRACED);
1130
 
        break;
1131
 
    case SIGHUP:
1132
 
        restart();
1133
 
        break;
1134
 
    case SIGUSR1:
1135
 
        load_rc();
1136
 
        break;
1137
 
    case SIGUSR2:
1138
 
        reload_rc();
1139
 
        break;
1140
 
    case SIGSEGV:
1141
 
        abort();
1142
 
        break;
1143
 
    case SIGFPE:
1144
 
    case SIGINT:
1145
 
    case SIGTERM:
1146
 
        shutdown();
1147
 
        break;
1148
 
    default:
1149
 
        fprintf(stderr,
1150
 
                _FBTEXT(BaseDisplay, SignalCaught, "%s:      signal %d caught\n", "signal catch debug message. Include %s for command and %d for signal number"),
1151
 
                m_argv[0], signum);
1152
 
 
1153
 
        if (! m_starting && ! re_enter) {
1154
 
            re_enter = 1;
1155
 
            fprintf(stderr,
1156
 
                    _FBTEXT(BaseDisplay, ShuttingDown, "Shutting Down\n", "Quitting because of signal, end with newline"));
1157
 
            shutdown();
1158
 
        }
1159
 
 
1160
 
 
1161
 
        fprintf(stderr,
1162
 
                _FBTEXT(BaseDisplay, Aborting, "Aborting... dumping core\n", "Aboring and dumping core, end with newline"));
1163
 
        abort();
1164
 
        break;
1165
 
    }
1166
 
}
1167
 
 
1168
 
 
1169
 
void Fluxbox::update(FbTk::Subject *changedsub) {
1170
 
    //TODO: fix signaling, this does not look good
1171
 
    if (typeid(*changedsub) == typeid(FluxboxWindow::WinSubject)) {
1172
 
        FluxboxWindow::WinSubject *winsub = dynamic_cast<FluxboxWindow::WinSubject *>(changedsub);
1173
 
        FluxboxWindow &win = winsub->win();
1174
 
        if ((&(win.hintSig())) == changedsub) { // hint signal
1175
 
            for (AtomHandlerContainerIt it= m_atomhandler.begin();
1176
 
                 it != m_atomhandler.end(); ++it) {
1177
 
                if ( (*it).first->update())
1178
 
                    (*it).first->updateHints(win);
1179
 
            }
1180
 
        } else if ((&(win.stateSig())) == changedsub) { // state signal
1181
 
            for (AtomHandlerContainerIt it= m_atomhandler.begin();
1182
 
                 it != m_atomhandler.end(); ++it) {
1183
 
                if ((*it).first->update())
1184
 
                    (*it).first->updateState(win);
1185
 
            }
1186
 
            // if window changed to iconic state
1187
 
            // add to icon list
1188
 
            if (win.isIconic()) {
1189
 
                win.screen().addIcon(&win);
1190
 
                Workspace *space = win.screen().getWorkspace(win.workspaceNumber());
1191
 
                if (space != 0)
1192
 
                    space->removeWindow(&win, true);
1193
 
            }
1194
 
 
1195
 
            if (win.isStuck()) {
1196
 
                // if we're sticky then reassociate window
1197
 
                // to all workspaces
1198
 
                BScreen &scr = win.screen();
1199
 
                if (scr.currentWorkspaceID() != win.workspaceNumber()) {
1200
 
                    scr.reassociateWindow(&win,
1201
 
                                          scr.currentWorkspaceID(),
1202
 
                                          true);
1203
 
                }
1204
 
            }
1205
 
        } else if ((&(win.layerSig())) == changedsub) { // layer signal
1206
 
 
1207
 
            for (AtomHandlerContainerIt it= m_atomhandler.begin();
1208
 
                 it != m_atomhandler.end(); ++it) {
1209
 
                if ((*it).first->update())
1210
 
                    (*it).first->updateLayer(win);
1211
 
            }
1212
 
        } else if ((&(win.dieSig())) == changedsub) { // window death signal
1213
 
            
1214
 
            for (AtomHandlerContainerIt it= m_atomhandler.begin();
1215
 
                it != m_atomhandler.end(); ++it) {
1216
 
                if ((*it).first->update())
1217
 
                    (*it).first->updateFrameClose(win);
1218
 
            }
1219
 
 
1220
 
            // make sure each workspace get this
1221
 
            BScreen &scr = win.screen();
1222
 
            scr.removeWindow(&win);
1223
 
            if (m_focused_window == &win.winClient())
1224
 
                m_focused_window = 0;
1225
 
 
1226
 
        } else if ((&(win.workspaceSig())) == changedsub) {  // workspace signal
1227
 
            for (AtomHandlerContainerIt it= m_atomhandler.begin();
1228
 
                 it != m_atomhandler.end(); ++it) {
1229
 
                if ((*it).first->update())
1230
 
                    (*it).first->updateWorkspace(win);
1231
 
            }
1232
 
        } else {
1233
 
#ifdef DEBUG
1234
 
            cerr<<__FILE__<<"("<<__LINE__<<"): WINDOW uncought signal from "<<&win<<endl;
1235
 
#endif // DEBUG
1236
 
        }
1237
 
 
1238
 
    } else if (typeid(*changedsub) == typeid(BScreen::ScreenSubject)) {
1239
 
        BScreen::ScreenSubject *subj = dynamic_cast<BScreen::ScreenSubject *>(changedsub);
1240
 
        BScreen &screen = subj->screen();
1241
 
        if ((&(screen.workspaceCountSig())) == changedsub) {
1242
 
            for (AtomHandlerContainerIt it= m_atomhandler.begin();
1243
 
                 it != m_atomhandler.end(); ++it) {
1244
 
                if ((*it).first->update())
1245
 
                    (*it).first->updateWorkspaceCount(screen);
1246
 
            }
1247
 
        } else if ((&(screen.workspaceNamesSig())) == changedsub) {
1248
 
            for (AtomHandlerContainerIt it= m_atomhandler.begin();
1249
 
                 it != m_atomhandler.end(); ++it) {
1250
 
                if ((*it).first->update())
1251
 
                    (*it).first->updateWorkspaceNames(screen);
1252
 
            }
1253
 
        } else if ((&(screen.currentWorkspaceSig())) == changedsub) {
1254
 
            for (AtomHandlerContainerIt it= m_atomhandler.begin();
1255
 
                 it != m_atomhandler.end(); ++it) {
1256
 
                if ((*it).first->update())
1257
 
                    (*it).first->updateCurrentWorkspace(screen);
1258
 
            }
1259
 
        } else if ((&(screen.workspaceAreaSig())) == changedsub) {
1260
 
            for (AtomHandlerContainerIt it= m_atomhandler.begin();
1261
 
                 it != m_atomhandler.end(); ++it) {
1262
 
                if ((*it).first->update())
1263
 
                    (*it).first->updateWorkarea(screen);
1264
 
            }
1265
 
        } else if ((&(screen.clientListSig())) == changedsub) {
1266
 
            for (AtomHandlerContainerIt it= m_atomhandler.begin();
1267
 
                 it != m_atomhandler.end(); ++it) {
1268
 
                if ((*it).first->update())
1269
 
                    (*it).first->updateClientList(screen);
1270
 
            }
1271
 
        }
1272
 
    } else if (typeid(*changedsub) == typeid(WinClient::WinClientSubj)) {
1273
 
 
1274
 
        WinClient::WinClientSubj *subj = dynamic_cast<WinClient::WinClientSubj *>(changedsub);
1275
 
        WinClient &client = subj->winClient();
1276
 
 
1277
 
        // TODO: don't assume it is diesig (need to fix as soon as another signal appears)
1278
 
        for (AtomHandlerContainerIt it= m_atomhandler.begin();
1279
 
             it != m_atomhandler.end(); ++it) {
1280
 
            if ((*it).first->update())
1281
 
                (*it).first->updateClientClose(client);
1282
 
        }
1283
 
 
1284
 
        BScreen &screen = client.screen();
1285
 
 
1286
 
        screen.removeClient(client);
1287
 
        // finaly send notify signal
1288
 
        screen.updateNetizenWindowDel(client.window());
1289
 
 
1290
 
        // At this point, we trust that this client is no longer in the
1291
 
        // client list of its frame (but it still has reference to the frame)
1292
 
        // We also assume that any remaining active one is the last focused one
1293
 
 
1294
 
        // This is where we revert focus on window close
1295
 
        // NOWHERE ELSE!!!
1296
 
        if (m_focused_window == &client)
1297
 
            unfocusWindow(client);
1298
 
 
1299
 
        // failed to revert focus?
1300
 
        if (m_focused_window == &client)
1301
 
            m_focused_window = 0;
1302
 
    }
1303
 
}
1304
 
 
1305
 
void Fluxbox::attachSignals(FluxboxWindow &win) {
1306
 
    win.hintSig().attach(this);
1307
 
    win.stateSig().attach(this);
1308
 
    win.workspaceSig().attach(this);
1309
 
    win.layerSig().attach(this);
1310
 
    win.dieSig().attach(this);
1311
 
    for (AtomHandlerContainerIt it= m_atomhandler.begin();
1312
 
         it != m_atomhandler.end(); ++it) {
1313
 
        (*it).first->setupFrame(win);
1314
 
    }
1315
 
}
1316
 
 
1317
 
void Fluxbox::attachSignals(WinClient &winclient) {
1318
 
    winclient.dieSig().attach(this);
1319
 
 
1320
 
    for (AtomHandlerContainerIt it= m_atomhandler.begin();
1321
 
         it != m_atomhandler.end(); ++it) {
1322
 
        (*it).first->setupClient(winclient);
1323
 
    }
1324
 
}
1325
 
 
1326
 
BScreen *Fluxbox::searchScreen(Window window) {
1327
 
 
1328
 
    ScreenList::iterator it = m_screen_list.begin();
1329
 
    ScreenList::iterator it_end = m_screen_list.end();
1330
 
    for (; it != it_end; ++it) {
1331
 
        if (*it && (*it)->rootWindow() == window)
1332
 
            return *it;
1333
 
    }
1334
 
 
1335
 
    return 0;
1336
 
}
1337
 
 
1338
 
 
1339
 
AtomHandler* Fluxbox::getAtomHandler(const std::string &name) {
1340
 
    if ( name != "" ) {
1341
 
        using namespace FbTk;
1342
 
        AtomHandlerContainerIt it = find_if(m_atomhandler.begin(),
1343
 
                                            m_atomhandler.end(),
1344
 
                                            Compose(bind2nd(equal_to<string>(), name),
1345
 
                                                    Select2nd<AtomHandlerContainer::value_type>()));
1346
 
        if (it != m_atomhandler.end())
1347
 
            return (*it).first;
1348
 
    }
1349
 
    return 0;
1350
 
}
1351
 
void Fluxbox::addAtomHandler(AtomHandler *atomh, const std::string &name) {
1352
 
    m_atomhandler[atomh]= name;;
1353
 
}
1354
 
 
1355
 
void Fluxbox::removeAtomHandler(AtomHandler *atomh) {
1356
 
    for (AtomHandlerContainerIt it= m_atomhandler.begin();
1357
 
         it != m_atomhandler.end();
1358
 
         ++it) {
1359
 
        if ((*it).first == atomh) {
1360
 
            m_atomhandler.erase(it);
1361
 
            return;
1362
 
        }
1363
 
    }
1364
 
}
1365
 
 
1366
 
WinClient *Fluxbox::searchWindow(Window window) {
1367
 
    WinClientMap::iterator it = m_window_search.find(window);
1368
 
    if (it != m_window_search.end())
1369
 
        return it->second;
1370
 
 
1371
 
    WindowMap::iterator git = m_window_search_group.find(window);
1372
 
    return git == m_window_search_group.end() ? 0 : &git->second->winClient();
1373
 
}
1374
 
 
1375
 
 
1376
 
/* Not implemented until we know how it'll be used
1377
 
 * Recall that this refers to ICCCM groups, not fluxbox tabgroups
1378
 
 * See ICCCM 4.1.11 for details
1379
 
 */
1380
 
/*
1381
 
WinClient *Fluxbox::searchGroup(Window window) {
1382
 
}
1383
 
*/
1384
 
 
1385
 
void Fluxbox::saveWindowSearch(Window window, WinClient *data) {
1386
 
    m_window_search[window] = data;
1387
 
}
1388
 
 
1389
 
/* some windows relate to the whole group */
1390
 
void Fluxbox::saveWindowSearchGroup(Window window, FluxboxWindow *data) {
1391
 
    m_window_search_group[window] = data;
1392
 
}
1393
 
 
1394
 
void Fluxbox::saveGroupSearch(Window window, WinClient *data) {
1395
 
    m_group_search.insert(pair<Window, WinClient *>(window, data));
1396
 
}
1397
 
 
1398
 
 
1399
 
void Fluxbox::removeWindowSearch(Window window) {
1400
 
    m_window_search.erase(window);
1401
 
}
1402
 
 
1403
 
void Fluxbox::removeWindowSearchGroup(Window window) {
1404
 
    m_window_search_group.erase(window);
1405
 
}
1406
 
 
1407
 
void Fluxbox::removeGroupSearch(Window window) {
1408
 
    m_group_search.erase(window);
1409
 
}
1410
 
 
1411
 
/// restarts fluxbox
1412
 
void Fluxbox::restart(const char *prog) {
1413
 
    shutdown();
1414
 
 
1415
 
    m_restarting = true;
1416
 
 
1417
 
    if (prog) {
1418
 
        m_restart_argument = prog;
1419
 
    }
1420
 
}
1421
 
 
1422
 
/// prepares fluxbox for a shutdown
1423
 
void Fluxbox::shutdown() {
1424
 
    if (m_shutdown)
1425
 
        return;
1426
 
 
1427
 
    m_shutdown = true;
1428
 
 
1429
 
    XSetInputFocus(FbTk::App::instance()->display(), PointerRoot, None, CurrentTime);
1430
 
 
1431
 
    //send shutdown to all screens
1432
 
    for_each(m_screen_list.begin(),
1433
 
             m_screen_list.end(), mem_fun(&BScreen::shutdown));
1434
 
 
1435
 
    sync(false);
1436
 
}
1437
 
 
1438
 
/// saves resources
1439
 
void Fluxbox::save_rc() {
1440
 
    _FB_USES_NLS;
1441
 
    XrmDatabase new_blackboxrc = 0;
1442
 
 
1443
 
    char rc_string[1024];
1444
 
 
1445
 
    string dbfile(getRcFilename());
1446
 
 
1447
 
    if (!dbfile.empty()) {
1448
 
        m_resourcemanager.save(dbfile.c_str(), dbfile.c_str());
1449
 
        m_screen_rm.save(dbfile.c_str(), dbfile.c_str());
1450
 
    } else
1451
 
        cerr<<_FBTEXT(Fluxbox, BadRCFile, "rc filename is invalid!", "Bad settings file")<<endl;
1452
 
 
1453
 
    ScreenList::iterator it = m_screen_list.begin();
1454
 
    ScreenList::iterator it_end = m_screen_list.end();
1455
 
 
1456
 
    //Save screen resources
1457
 
 
1458
 
    for (; it != it_end; ++it) {
1459
 
        BScreen *screen = *it;
1460
 
        int screen_number = screen->screenNumber();
1461
 
 
1462
 
        // these are static, but may not be saved in the users resource file,
1463
 
        // writing these resources will allow the user to edit them at a later
1464
 
        // time... but loading the defaults before saving allows us to rewrite the
1465
 
        // users changes...
1466
 
 
1467
 
        // write out the users workspace names
1468
 
        sprintf(rc_string, "session.screen%d.workspaceNames: ", screen_number);
1469
 
        string workspaces_string(rc_string);
1470
 
 
1471
 
        for (unsigned int workspace=0; workspace < screen->numberOfWorkspaces(); workspace++) {
1472
 
            if (screen->getWorkspace(workspace)->name().size()!=0)
1473
 
                workspaces_string.append(screen->getWorkspace(workspace)->name());
1474
 
            else
1475
 
                workspaces_string.append("Null");
1476
 
            workspaces_string.append(",");
1477
 
        }
1478
 
 
1479
 
        XrmPutLineResource(&new_blackboxrc, workspaces_string.c_str());
1480
 
 
1481
 
    }
1482
 
 
1483
 
    XrmDatabase old_blackboxrc = XrmGetFileDatabase(dbfile.c_str());
1484
 
 
1485
 
    XrmMergeDatabases(new_blackboxrc, &old_blackboxrc); //merge database together
1486
 
    XrmPutFileDatabase(old_blackboxrc, dbfile.c_str());
1487
 
    XrmDestroyDatabase(old_blackboxrc);
1488
 
#ifdef DEBUG
1489
 
    cerr<<__FILE__<<"("<<__LINE__<<"): ------------ SAVING DONE"<<endl;
1490
 
#endif // DEBUG
1491
 
}
1492
 
 
1493
 
/// @return filename of resource file
1494
 
string Fluxbox::getRcFilename() {
1495
 
 
1496
 
    if (m_rc_file.empty()) { // set default filename
1497
 
        string defaultfile(getenv("HOME") + string("/.") + m_RC_PATH + string("/") + m_RC_INIT_FILE);
1498
 
        return defaultfile;
1499
 
    }
1500
 
 
1501
 
    return m_rc_file;
1502
 
}
1503
 
 
1504
 
/// Provides default filename of data file
1505
 
void Fluxbox::getDefaultDataFilename(char *name, string &filename) {
1506
 
    filename = string(getenv("HOME") + string("/.") + m_RC_PATH + string("/") + name);
1507
 
}
1508
 
 
1509
 
/// loads resources
1510
 
void Fluxbox::load_rc() {
1511
 
    _FB_USES_NLS;
1512
 
    //get resource filename
1513
 
    string dbfile(getRcFilename());
1514
 
 
1515
 
    if (!dbfile.empty()) {
1516
 
        if (!m_resourcemanager.load(dbfile.c_str())) {
1517
 
            cerr<<_FBTEXT(Fluxbox, CantLoadRCFile, "Failed to load database", "Failed trying to read rc file")<<":"<<dbfile<<endl;
1518
 
            cerr<<_FBTEXT(Fluxbox, CantLoadRCFileTrying, "Retrying with", "Retrying rc file loading with (the following file)")<<": "<<DEFAULT_INITFILE<<endl;
1519
 
            if (!m_resourcemanager.load(DEFAULT_INITFILE))
1520
 
                cerr<<_FBTEXT(Fluxbox, CantLoadRCFile, "Failed to load database", "")<<": "<<DEFAULT_INITFILE<<endl;
1521
 
        }
1522
 
    } else {
1523
 
        if (!m_resourcemanager.load(DEFAULT_INITFILE))
1524
 
            cerr<<_FBTEXT(Fluxbox, CantLoadRCFile, "Failed to load database", "")<<": "<<DEFAULT_INITFILE<<endl;
1525
 
    }
1526
 
 
1527
 
    if (m_rc_menufile->empty())
1528
 
        m_rc_menufile.setDefaultValue();
1529
 
 
1530
 
    if (FbTk::Transparent::haveComposite())
1531
 
        FbTk::Transparent::usePseudoTransparent(*m_rc_pseudotrans);
1532
 
 
1533
 
    if (!m_rc_slitlistfile->empty()) {
1534
 
        *m_rc_slitlistfile = StringUtil::expandFilename(*m_rc_slitlistfile);
1535
 
    } else {
1536
 
        string filename;
1537
 
        getDefaultDataFilename("slitlist", filename);
1538
 
        m_rc_slitlistfile.setFromString(filename.c_str());
1539
 
    }
1540
 
 
1541
 
    if (*m_rc_colors_per_channel < 2)
1542
 
        *m_rc_colors_per_channel = 2;
1543
 
    else if (*m_rc_colors_per_channel > 6)
1544
 
        *m_rc_colors_per_channel = 6;
1545
 
 
1546
 
    if (m_rc_stylefile->empty())
1547
 
        *m_rc_stylefile = DEFAULTSTYLE;
1548
 
 
1549
 
    if (!Workspace::loadGroups(*m_rc_groupfile)) {
1550
 
#ifdef DEBUG
1551
 
        cerr<<_FBTEXT(Fluxbox, CantLoadGroupFile, "Failed to load groupfile", "Couldn't load the groupfile")<<": "<<*m_rc_groupfile<<endl;
1552
 
#endif // DEBUG
1553
 
    }
1554
 
}
1555
 
 
1556
 
void Fluxbox::load_rc(BScreen &screen) {
1557
 
    //get resource filename
1558
 
    _FB_USES_NLS;
1559
 
    string dbfile(getRcFilename());
1560
 
 
1561
 
    XrmDatabaseHelper database;
1562
 
 
1563
 
    database = XrmGetFileDatabase(dbfile.c_str());
1564
 
    if (database==0)
1565
 
        database = XrmGetFileDatabase(DEFAULT_INITFILE);
1566
 
 
1567
 
    XrmValue value;
1568
 
    char *value_type, name_lookup[1024], class_lookup[1024];
1569
 
    int screen_number = screen.screenNumber();
1570
 
 
1571
 
 
1572
 
    screen.removeWorkspaceNames();
1573
 
 
1574
 
    sprintf(name_lookup, "session.screen%d.workspaceNames", screen_number);
1575
 
    sprintf(class_lookup, "Session.Screen%d.WorkspaceNames", screen_number);
1576
 
    if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
1577
 
                       &value)) {
1578
 
 
1579
 
        string values(value.addr);
1580
 
        BScreen::WorkspaceNames names;
1581
 
        
1582
 
        StringUtil::removeTrailingWhitespace(values);
1583
 
        StringUtil::removeFirstWhitespace(values);
1584
 
        StringUtil::stringtok<BScreen::WorkspaceNames>(names, values, ",");
1585
 
        BScreen::WorkspaceNames::iterator it;
1586
 
        for(it = names.begin(); it != names.end(); it++) {
1587
 
            if (!(*it).empty() && (*it) != "")
1588
 
            screen.addWorkspaceName((*it).c_str());
1589
 
        }
1590
 
        
1591
 
    }
1592
 
 
1593
 
    FbTk::Image::removeAllSearchPaths();
1594
 
    sprintf(name_lookup, "session.screen%d.imageSearchPath", screen_number);
1595
 
    sprintf(class_lookup, "Session.Screen%d.imageSearchPath", screen_number);
1596
 
    if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
1597
 
                       &value) && value.addr) {
1598
 
        std::vector<std::string> paths;
1599
 
        StringUtil::stringtok(paths, value.addr, ", ");
1600
 
        for (unsigned int i=0; i<paths.size(); ++i)
1601
 
            FbTk::Image::addSearchPath(paths[i]);
1602
 
    }
1603
 
 
1604
 
    if (!dbfile.empty()) {
1605
 
        if (!m_screen_rm.load(dbfile.c_str())) {
1606
 
            cerr<<_FBTEXT(Fluxbox, CantLoadRCFile, "Failed to load database", "Failed trying to read rc file")<<":"<<dbfile<<endl;
1607
 
            cerr<<_FBTEXT(Fluxbox, CantLoadRCFileTrying, "Retrying with", "Retrying rc file loading with (the following file)")<<": "<<DEFAULT_INITFILE<<endl;
1608
 
            if (!m_screen_rm.load(DEFAULT_INITFILE))
1609
 
                cerr<<_FBTEXT(Fluxbox, CantLoadRCFile, "Failed to load database", "")<<": "<<DEFAULT_INITFILE<<endl;
1610
 
        }
1611
 
    } else {
1612
 
        if (!m_screen_rm.load(DEFAULT_INITFILE))
1613
 
            cerr<<_FBTEXT(Fluxbox, CantLoadRCFile, "Failed to load database", "")<<": "<<DEFAULT_INITFILE<<endl;
1614
 
    }
1615
 
}
1616
 
 
1617
 
void Fluxbox::loadRootCommand(BScreen &screen)  {
1618
 
 
1619
 
    string dbfile(getRcFilename());
1620
 
 
1621
 
    XrmDatabaseHelper database(dbfile.c_str());
1622
 
    if (!*database)
1623
 
        database = XrmGetFileDatabase(DEFAULT_INITFILE);
1624
 
 
1625
 
    XrmValue value;
1626
 
    char *value_type, name_lookup[1024], class_lookup[1024];
1627
 
    sprintf(name_lookup, "session.screen%d.rootCommand", screen.screenNumber());
1628
 
    sprintf(class_lookup, "Session.Screen%d.RootCommand", screen.screenNumber());
1629
 
    if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
1630
 
                       &value)) {
1631
 
        screen.saveRootCommand(value.addr==0 ? "": value.addr);
1632
 
    } else
1633
 
        screen.saveRootCommand("");
1634
 
 
1635
 
}
1636
 
 
1637
 
void Fluxbox::reload_rc() {
1638
 
    load_rc();
1639
 
    reconfigure();
1640
 
}
1641
 
 
1642
 
 
1643
 
void Fluxbox::reconfigure() {
1644
 
    m_reconfigure_wait = true;
1645
 
    m_reconfig_timer.start();
1646
 
}
1647
 
 
1648
 
 
1649
 
void Fluxbox::real_reconfigure() {
1650
 
 
1651
 
    XrmDatabase new_fluxboxrc = (XrmDatabase) 0;
1652
 
 
1653
 
    string dbfile(getRcFilename());
1654
 
    XrmDatabase old_fluxboxrc = XrmGetFileDatabase(dbfile.c_str());
1655
 
 
1656
 
    XrmMergeDatabases(new_fluxboxrc, &old_fluxboxrc);
1657
 
    XrmPutFileDatabase(old_fluxboxrc, dbfile.c_str());
1658
 
 
1659
 
    if (old_fluxboxrc)
1660
 
        XrmDestroyDatabase(old_fluxboxrc);
1661
 
 
1662
 
    ScreenList::iterator screen_it = m_screen_list.begin();
1663
 
    ScreenList::iterator screen_it_end = m_screen_list.end();
1664
 
    for (; screen_it != screen_it_end; ++screen_it)
1665
 
        load_rc(*(*screen_it));
1666
 
 
1667
 
    // reconfigure all screens
1668
 
    for_each(m_screen_list.begin(), m_screen_list.end(), mem_fun(&BScreen::reconfigure));
1669
 
 
1670
 
    //reconfigure keys
1671
 
    m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str());
1672
 
 
1673
 
}
1674
 
 
1675
 
BScreen *Fluxbox::findScreen(int id) {
1676
 
    ScreenList::iterator it = m_screen_list.begin();
1677
 
    ScreenList::iterator it_end = m_screen_list.end();
1678
 
    for (; it != it_end; ++it) {
1679
 
        if ((*it)->screenNumber() == id)
1680
 
            break;
1681
 
    }
1682
 
 
1683
 
    if (it == m_screen_list.end())
1684
 
        return 0;
1685
 
 
1686
 
    return *it;
1687
 
}
1688
 
 
1689
 
bool Fluxbox::menuTimestampsChanged() const {
1690
 
    std::list<MenuTimestamp *>::const_iterator it = m_menu_timestamps.begin();
1691
 
    std::list<MenuTimestamp *>::const_iterator it_end = m_menu_timestamps.end();
1692
 
    for (; it != it_end; ++it) {
1693
 
        
1694
 
        time_t timestamp = FbTk::FileUtil::getLastStatusChangeTimestamp((*it)->filename.c_str());
1695
 
 
1696
 
        if (timestamp >= 0) {
1697
 
            if (timestamp != (*it)->timestamp)
1698
 
                return true;
1699
 
        } else
1700
 
            return true;
1701
 
    }
1702
 
 
1703
 
    // no timestamp changed
1704
 
    return false;
1705
 
}
1706
 
 
1707
 
void Fluxbox::checkMenu() {
1708
 
    if (menuTimestampsChanged())
1709
 
        rereadMenu();
1710
 
}
1711
 
 
1712
 
void Fluxbox::hideExtraMenus(BScreen &screen) {
1713
 
 
1714
 
#ifdef USE_TOOLBAR
1715
 
        // hide toolbar that matches screen
1716
 
        for (size_t toolbar = 0; toolbar < m_toolbars.size(); ++toolbar) {
1717
 
            if (&(m_toolbars[toolbar]->screen()) == &screen)
1718
 
                m_toolbars[toolbar]->menu().hide();
1719
 
        }
1720
 
 
1721
 
#endif // USE_TOOLBAR
1722
 
 
1723
 
}
1724
 
 
1725
 
void Fluxbox::rereadMenu(bool show_after_reread) {
1726
 
    m_reread_menu_wait = true;
1727
 
    m_show_menu_after_reread = show_after_reread;
1728
 
    m_reconfig_timer.start();
1729
 
}
1730
 
 
1731
 
 
1732
 
void Fluxbox::real_rereadMenu() {
1733
 
    
1734
 
    clearMenuFilenames();
1735
 
    
1736
 
    for_each(m_screen_list.begin(), 
1737
 
             m_screen_list.end(), 
1738
 
             mem_fun(&BScreen::rereadMenu));
1739
 
 
1740
 
    if(m_show_menu_after_reread) {
1741
 
 
1742
 
        FbCommands::ShowRootMenuCmd showcmd;
1743
 
        showcmd.execute();
1744
 
 
1745
 
        m_show_menu_after_reread = false;
1746
 
    }
1747
 
}
1748
 
 
1749
 
void Fluxbox::saveMenuFilename(const char *filename) {
1750
 
    if (filename == 0)
1751
 
        return;
1752
 
 
1753
 
    bool found = false;
1754
 
 
1755
 
    std::list<MenuTimestamp *>::iterator it = m_menu_timestamps.begin();
1756
 
    std::list<MenuTimestamp *>::iterator it_end = m_menu_timestamps.end();
1757
 
    for (; it != it_end; ++it) {
1758
 
        if ((*it)->filename == filename) {
1759
 
            found = true;
1760
 
            break;
1761
 
        }
1762
 
    }
1763
 
 
1764
 
    if (! found) {
1765
 
        time_t timestamp = FbTk::FileUtil::getLastStatusChangeTimestamp(filename);
1766
 
 
1767
 
        if (timestamp >= 0) {
1768
 
            MenuTimestamp *ts = new MenuTimestamp;
1769
 
 
1770
 
            ts->filename = filename;
1771
 
            ts->timestamp = timestamp;
1772
 
 
1773
 
            m_menu_timestamps.push_back(ts);
1774
 
        }
1775
 
    }
1776
 
}
1777
 
 
1778
 
void Fluxbox::clearMenuFilenames() {
1779
 
    while(!m_menu_timestamps.empty()) {
1780
 
        delete m_menu_timestamps.back();
1781
 
        m_menu_timestamps.pop_back();
1782
 
    }
1783
 
}
1784
 
 
1785
 
void Fluxbox::timed_reconfigure() {
1786
 
    if (m_reconfigure_wait)
1787
 
        real_reconfigure();
1788
 
 
1789
 
    if (m_reread_menu_wait)
1790
 
        real_rereadMenu();
1791
 
 
1792
 
    m_reconfigure_wait = m_reread_menu_wait = false;
1793
 
}
1794
 
 
1795
 
// set focused window
1796
 
void Fluxbox::setFocusedWindow(WinClient *client) {
1797
 
    // already focused
1798
 
    if (m_focused_window == client) {
1799
 
#ifdef DEBUG
1800
 
        cerr<<"Focused window already win"<<endl;
1801
 
#endif // DEBUG
1802
 
        return;
1803
 
    }
1804
 
#ifdef DEBUG
1805
 
    cerr<<"Setting Focused window = "<<client<<endl;
1806
 
    if (client != 0 && client->fbwindow() != 0)
1807
 
        cerr<<"title: "<<client->fbwindow()->title()<<endl;
1808
 
    cerr<<"Current Focused window = "<<m_focused_window<<endl;
1809
 
    cerr<<"------------------"<<endl;
1810
 
#endif // DEBUG
1811
 
    BScreen *old_screen = 0, *screen = 0;
1812
 
    WinClient *old_client = 0;
1813
 
 
1814
 
    if (m_focused_window != 0) {
1815
 
        // check if m_focused_window is valid
1816
 
        WinClientMap::iterator it = find_if(m_window_search.begin(),
1817
 
                                            m_window_search.end(),
1818
 
                                            Compose(bind2nd(equal_to<WinClient *>(), m_focused_window),
1819
 
                                                    Select2nd<WinClientMap::value_type>()));
1820
 
                
1821
 
        // if not found...
1822
 
        if (it == m_window_search.end()) {
1823
 
            m_focused_window = 0;
1824
 
        } else {
1825
 
            old_client = m_focused_window;
1826
 
            old_screen = &old_client->screen();
1827
 
 
1828
 
            if (old_client->fbwindow()) {
1829
 
                FluxboxWindow *old_win = old_client->fbwindow();
1830
 
 
1831
 
                if (!client || client->fbwindow() != old_win)
1832
 
                    old_win->setFocusFlag(false);
1833
 
            }
1834
 
        }
1835
 
    }
1836
 
 
1837
 
    if (client && client->fbwindow() && !client->fbwindow()->isIconic()) {
1838
 
        FluxboxWindow *win = client->fbwindow();
1839
 
        // make sure we have a valid win pointer with a valid screen
1840
 
        ScreenList::iterator winscreen =
1841
 
            std::find(m_screen_list.begin(), m_screen_list.end(),
1842
 
                      &client->screen());
1843
 
        if (winscreen == m_screen_list.end()) {
1844
 
            m_focused_window = 0; // the window pointer wasn't valid, mark no window focused
1845
 
        } else {
1846
 
            screen = *winscreen;
1847
 
            m_focused_window = client;     // update focused window
1848
 
            win->setCurrentClient(*client, false); // don't setinputfocus
1849
 
            win->setFocusFlag(true); // set focus flag
1850
 
        }
1851
 
 
1852
 
    } else
1853
 
        m_focused_window = 0;
1854
 
 
1855
 
 
1856
 
    if (screen != 0) {
1857
 
        screen->updateNetizenWindowFocus();
1858
 
        for (AtomHandlerContainerIt it= m_atomhandler.begin();
1859
 
             it != m_atomhandler.end(); it++) {
1860
 
            (*it).first->updateFocusedWindow(*screen, (m_focused_window ?
1861
 
                                                       m_focused_window->window() :
1862
 
                                                       0));
1863
 
        }
1864
 
    }
1865
 
 
1866
 
    if (old_screen && old_screen != screen) {
1867
 
        old_screen->updateNetizenWindowFocus();
1868
 
        for (AtomHandlerContainerIt it= m_atomhandler.begin();
1869
 
             it != m_atomhandler.end(); it++)
1870
 
            (*it).first->updateFocusedWindow(*old_screen, 0);
1871
 
    }
1872
 
}
1873
 
 
1874
 
/**
1875
 
 * This function is called whenever we aren't quite sure what
1876
 
 * focus is meant to be, it'll make things right ;-)
1877
 
 * last_focused is set to something if we want to make use of the
1878
 
 * previously focused window (it must NOT be set focused now, it
1879
 
 *   is probably dying).
1880
 
 *
1881
 
 * ignore_event means that it ignores the given event until
1882
 
 * it gets a focusIn
1883
 
 */
1884
 
void Fluxbox::revertFocus(BScreen &screen) {
1885
 
    // Relevant resources:
1886
 
    // resource.focus_last = whether we focus last focused when changing workspace
1887
 
    // BScreen::FocusModel = sloppy, click, whatever
1888
 
    WinClient *next_focus = screen.getLastFocusedWindow(screen.currentWorkspaceID());
1889
 
 
1890
 
    // if setting focus fails, or isn't possible, fallback correctly
1891
 
    if (!(next_focus && next_focus->fbwindow() &&
1892
 
          next_focus->fbwindow()->setCurrentClient(*next_focus, true))) {
1893
 
        setFocusedWindow(0); // so we don't get dangling m_focused_window pointer
1894
 
        switch (screen.getFocusModel()) {
1895
 
        case BScreen::MOUSEFOCUS:
1896
 
            XSetInputFocus(FbTk::App::instance()->display(),
1897
 
                           PointerRoot, None, CurrentTime);
1898
 
            break;
1899
 
        case BScreen::CLICKFOCUS:
1900
 
            screen.rootWindow().setInputFocus(RevertToPointerRoot, CurrentTime);
1901
 
            break;
1902
 
        }
1903
 
    }
1904
 
}
1905
 
 
1906
 
/*
1907
 
 * Like revertFocus, but specifically related to this window (transients etc)
1908
 
 * if full_revert, we fallback to a full revertFocus if we can't find anything
1909
 
 * local to the client.
1910
 
 * If unfocus_frame is true, we won't focus anything in the same frame
1911
 
 * as the client.
1912
 
 *
1913
 
 * So, we first prefer to choose a transient parent, then the last
1914
 
 * client in this window, and if no luck (or unfocus_frame), then
1915
 
 * we just use the normal revertFocus on the screen.
1916
 
 *
1917
 
 * assumption: client has focus
1918
 
 */
1919
 
void Fluxbox::unfocusWindow(WinClient &client, bool full_revert, bool unfocus_frame) {
1920
 
    // go up the transient tree looking for a focusable window
1921
 
 
1922
 
    FluxboxWindow *fbwin = client.fbwindow();
1923
 
    if (fbwin == 0)
1924
 
        unfocus_frame = false;
1925
 
 
1926
 
    WinClient *trans_parent = client.transientFor();
1927
 
    while (trans_parent) {
1928
 
        if (trans_parent->fbwindow() && // can't focus if no fbwin
1929
 
            (!unfocus_frame || trans_parent->fbwindow() != fbwin) && // can't be this window
1930
 
            trans_parent->fbwindow()->isVisible() &&
1931
 
            trans_parent->fbwindow()->setCurrentClient(*trans_parent, m_focused_window == &client)) {
1932
 
            return;
1933
 
        }
1934
 
        trans_parent = trans_parent->transientFor();
1935
 
    }
1936
 
 
1937
 
    if (fbwin == 0)
1938
 
        return; // nothing more we can do
1939
 
 
1940
 
    BScreen &screen = fbwin->screen();
1941
 
 
1942
 
    if (!unfocus_frame) {
1943
 
        WinClient *last_focus = screen.getLastFocusedWindow(*fbwin, &client);
1944
 
        if (last_focus != 0 &&
1945
 
            fbwin->setCurrentClient(*last_focus, m_focused_window == &client)) {
1946
 
            return;
1947
 
        }
1948
 
    }
1949
 
 
1950
 
    if (full_revert && m_focused_window == &client)
1951
 
        revertFocus(screen);
1952
 
 
1953
 
}
1954
 
 
1955
 
 
1956
 
void Fluxbox::watchKeyRelease(BScreen &screen, unsigned int mods) {
1957
 
    
1958
 
    if (mods == 0) {
1959
 
        cerr<<"WARNING: attempt to grab without modifiers!"<<endl;
1960
 
        return;
1961
 
    }
1962
 
    m_watching_screen = &screen;
1963
 
 
1964
 
    // just make sure we are saving the mods with any other flags (xkb)
1965
 
    m_watch_keyrelease = FbTk::KeyUtil::instance().isolateModifierMask(mods);
1966
 
    XGrabKeyboard(FbTk::App::instance()->display(),
1967
 
                  screen.rootWindow().window(), True,
1968
 
                  GrabModeAsync, GrabModeAsync, CurrentTime);
1969
 
}