1
// fluxbox.cc for Fluxbox Window Manager
2
// Copyright (c) 2001 - 2005 Henrik Kinnunen (fluxgen at fluxbox dot org)
4
// blackbox.cc for blackbox - an X11 Window manager
5
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
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:
14
// The above copyright notice and this permission notice shall be included in
15
// all copies or substantial portions of the Software.
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.
25
// $Id: fluxbox.cc 4084 2005-07-20 18:29:01Z mathias $
31
#include "Workspace.hh"
32
#include "AtomHandler.hh"
33
#include "FbCommands.hh"
34
#include "WinClient.hh"
37
#include "defaults.hh"
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"
64
#endif // HAVE_CONFIG_H
74
#endif // USE_NEWWMSPEC
76
#include "Remember.hh"
86
#include <X11/Xutil.h>
87
#include <X11/Xresource.h>
88
#include <X11/Xatom.h>
89
#include <X11/keysym.h>
93
#include <X11/extensions/shape.h>
96
#include <X11/extensions/Xrandr.h>
118
#include <sys/types.h>
120
#endif // HAVE_UNISTD_H
122
#ifdef HAVE_SYS_PARAM_H
123
#include <sys/param.h>
124
#endif // HAVE_SYS_PARAM_H
126
#ifdef HAVE_SYS_SELECT_H
127
#include <sys/select.h>
128
#endif // HAVE_SYS_SELECT_H
130
#ifdef HAVE_SYS_STAT_H
131
#include <sys/types.h>
132
#include <sys/stat.h>
133
#endif // HAVE_SYS_STAT_H
135
#ifdef TIME_WITH_SYS_TIME
136
#include <sys/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
143
#endif // HAVE_SYS_TIME_H
144
#endif // TIME_WITH_SYS_TIME
146
#include <sys/wait.h>
155
using namespace FbTk;
159
Window last_bad_window = None;
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;
168
// ignore bad window ones, they happen a lot
169
// when windows close themselves
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;
183
//static singleton var
184
Fluxbox *Fluxbox::s_singleton=0;
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};
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),
227
m_watching_screen(0), m_watch_keyrelease(0),
230
m_rc_file(rcfilename ? rcfilename : ""),
231
m_argv(argv), m_argc(argc),
236
m_randr_event_type(0),
237
m_RC_PATH("fluxbox"),
238
m_RC_INIT_FILE("init") {
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!"));
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"));
250
Display *disp = FbTk::App::instance()->display();
251
// For KDE dock applets
253
m_kwm1_dockwindow = XInternAtom(disp,
254
"KWM_DOCKWINDOW", False);
256
m_kwm2_dockwindow = XInternAtom(disp,
257
"_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
258
// setup X error handler
259
XSetErrorHandler((XErrorHandler) handleXErrors);
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);
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));
281
m_reconfig_timer.setTimeout(to);
282
m_reconfig_timer.setCommand(reconfig_cmd);
283
m_reconfig_timer.fireOnce(true);
284
// XSynchronize(disp, True);
287
m_have_shape = false;
288
m_shape_eventbase = 0;
291
m_have_shape = XShapeQueryExtension(disp, &m_shape_eventbase, &shape_err);
295
// get randr event type
296
int randr_error_base;
297
XRRQueryExtension(disp, &m_randr_event_type, &randr_error_base);
301
// setup theme manager to have our style file ready to be scanned
302
FbTk::ThemeManager::instance().load(getStyleFilename());
304
// setup atom handlers before we create any windows
306
addAtomHandler(new Remember(), "remember"); // for remembering window attribs
309
addAtomHandler(new Ewmh(), "ewmh"); // for Extended window manager atom support
310
#endif // USE_NEWWMSPEC
312
addAtomHandler(new Gnome(), "gnome"); // for gnome 1 atom support
319
if (! XSupportsLocale())
320
cerr<<_FBTEXT(Fluxbox, WarningLocale, "Warning: X server does not support locale", "XSupportsLocale returned false")<<endl;
322
if (XSetLocaleModifiers("") == 0)
323
cerr<<_FBTEXT(Fluxbox, WarningLocaleModifiers, "Warning: cannot set locale modifiers", "XSetLocaleModifiers returned false")<<endl;
327
m_fluxbox_pid = XInternAtom(disp, "_BLACKBOX_PID", False);
328
#endif // HAVE_GETPID
334
// default is "use all screens"
335
for (i = 0; i < ScreenCount(disp); i++)
336
screens.push_back(i);
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";
347
if (! strcmp(m_argv[i], "all"))
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);
362
swap(scrtmp, screens);
366
// init all "screens"
367
for(i = 0; i < screens.size(); i++)
368
initScreen(screens[i]);
370
XAllowEvents(disp, ReplayPointer, CurrentTime);
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"));
379
m_keyscreen = m_mousescreen = m_screen_list.front();
381
// setup theme manager to have our style file ready to be scanned
382
FbTk::ThemeManager::instance().load(FbTk::StringUtil::expandFilename(getStyleFilename()));
384
//XSynchronize(disp, False);
387
m_reconfigure_wait = m_reread_menu_wait = false;
389
// Create keybindings handler and load keys file
390
m_key.reset(new Keys(StringUtil::expandFilename(*m_rc_keyfile).c_str()));
392
m_resourcemanager.unlock();
396
if (m_resourcemanager.lockDepth() != 0)
397
cerr<<"--- resource manager lockdepth = "<<m_resourcemanager.lockDepth()<<endl;
401
// For dumping theme items
402
// FbTk::ThemeManager::instance().listItems();
404
// m_resourcemanager.dump();
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
417
Fluxbox::~Fluxbox() {
420
while (!m_toolbars.empty()) {
421
delete m_toolbars.back();
422
m_toolbars.pop_back();
426
while (!m_screen_list.empty()) {
427
delete m_screen_list.back();
428
m_screen_list.pop_back();
431
// destroy atomhandlers
432
for (AtomHandlerContainerIt it= m_atomhandler.begin();
433
it != m_atomhandler.end();
437
m_atomhandler.clear();
439
clearMenuFilenames();
443
int Fluxbox::initScreen(int scrnr) {
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(),
451
scrnr, getNumberOfLayers());
454
if (! screen->isScreenManaged()) {
460
m_screen_list.push_back(screen);
462
// now we can create menus (which needs this screen to be in screen_list)
466
pid_t bpid = getpid();
468
screen->rootWindow().changeProperty(getFluxboxPidAtom(), XA_CARDINAL,
469
sizeof(pid_t) * 8, PropModeReplace,
470
(unsigned char *) &bpid, 1);
471
#endif // HAVE_GETPID
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);
480
XRRSelectInput(disp, screen->rootWindow().window(),
481
RRScreenChangeNotifyMask);
482
#endif // X_RRScreenChangeSelectInput
488
m_toolbars.push_back(new Toolbar(*screen,
489
*screen->layerManager().
490
getLayer(Fluxbox::instance()->getNormalLayer())));
491
#endif // USE_TOOLBAR
493
// must do this after toolbar is created
494
screen->initWindows();
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);
503
// initiate atomhandler for screen specific stuff
504
for (AtomHandlerContainerIt it= m_atomhandler.begin();
505
it != m_atomhandler.end();
507
(*it).first->initForScreen(*screen);
510
revertFocus(*screen); // make sure focus style is correct
513
screen->slit()->show();
520
void Fluxbox::eventLoop() {
521
Display *disp = display();
522
while (!m_shutdown) {
523
if (XPending(disp)) {
525
XNextEvent(disp, &e);
527
if (last_bad_window != None && e.xany.window == last_bad_window &&
528
e.type != DestroyNotify) { // we must let the actual destroys through
530
cerr<<"Fluxbox::eventLoop(): removing bad window from event queue"<<endl;
533
last_bad_window = None;
537
FbTk::Timer::updateTimers(ConnectionNumber(disp)); //handle all timers
542
bool Fluxbox::validateWindow(Window window) const {
544
if (XCheckTypedWindowEvent(display(), window, DestroyNotify, &event)) {
545
XPutBackEvent(display(), &event);
552
void Fluxbox::grab() {
553
if (! m_server_grabs++)
554
XGrabServer(display());
557
void Fluxbox::ungrab() {
558
if (! --m_server_grabs)
559
XUngrabServer(display());
561
if (m_server_grabs < 0)
566
setup the configutation files in
569
void Fluxbox::setupConfigFiles() {
571
bool create_init = false, create_keys = false, create_menu = false;
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";
581
// is file/dir already there?
582
if (! stat(dirname.c_str(), &buf)) {
584
// check if anything with those name exists, if not create new
585
if (stat(init_file.c_str(), &buf))
587
if (stat(keys_file.c_str(), &buf))
589
if (stat(menu_file.c_str(), &buf))
594
cerr <<__FILE__<<"("<<__LINE__<<"): Creating dir: " << dirname.c_str() << endl;
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"),
607
//mark creation of files
608
create_init = create_keys = create_menu = true;
612
// copy key configuration
614
FbTk::FileUtil::copyFile(DEFAULTKEYSFILE, keys_file.c_str());
616
// copy menu configuration
618
FbTk::FileUtil::copyFile(DEFAULTMENU, menu_file.c_str());
622
FbTk::FileUtil::copyFile(DEFAULT_INITFILE, init_file.c_str());
626
void Fluxbox::handleEvent(XEvent * const e) {
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);
637
} else if (e->type == ButtonRelease) {
638
e->xbutton.window = m_masked_window->fbWindow().window();
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;
653
m_last_time = e->xbutton.time;
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
664
BScreen *screen = searchScreen(e->xproperty.window);
666
FbTk::FbPixmap::rootwinPropertyNotify(screen->screenNumber(), e->xproperty.atom);
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) {
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()) {
688
break; // found the screen, no more search
693
revertFocus(*screen);
696
// try FbTk::EventHandler first
697
FbTk::EventManager::instance()->handleEvent(*e);
702
handleButtonEvent(e->xbutton);
704
case ConfigureRequest: {
706
if (!searchWindow(e->xconfigurerequest.window)) {
710
if (validateWindow(e->xconfigurerequest.window)) {
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;
721
XConfigureWindow(FbTk::App::instance()->display(),
722
e->xconfigurerequest.window,
723
e->xconfigurerequest.value_mask, &xwc);
727
} // else already handled in FluxboxWindow::handleEvent
734
cerr<<"MapRequest for 0x"<<hex<<e->xmaprequest.window<<dec<<endl;
738
WinClient *winclient = searchWindow(e->xmaprequest.window);
739
FluxboxWindow *win = 0;
744
XWindowAttributes attr;
746
if (XGetWindowAttributes(display(),
747
e->xmaprequest.window,
748
&attr) && attr.screen != 0) {
749
screen_num = XScreenNumberOfScreen(attr.screen);
752
ScreenList::iterator screen_it = find_if(m_screen_list.begin(),
754
FbTk::CompareEqual<BScreen>(&BScreen::screenNumber, screen_num));
755
if (screen_it != m_screen_list.end())
758
// try with parent if we failed to find screen num
760
screen = searchScreen(e->xmaprequest.parent);
763
cerr<<"Fluxbox "<<_FBTEXT(Fluxbox, CantMapWindow, "Warning! Could not find screen to map window on!", "")<<endl;
765
win = screen->createWindow(e->xmaprequest.window);
768
win = winclient->fbwindow();
771
// we don't handle MapRequest in FluxboxWindow::handleEvent
773
win->mapRequestEvent(e->xmaprequest);
777
// handled directly in FluxboxWindow::handleEvent
780
handleUnmapNotify(e->xunmap);
783
// Update stored modifier mapping
785
cerr<<__FILE__<<"("<<__FUNCTION__<<"): MappingNotify"<<endl;
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());
797
case DestroyNotify: {
798
WinClient *winclient = searchWindow(e->xdestroywindow.window);
799
if (winclient != 0) {
800
FluxboxWindow *win = winclient->fbwindow();
802
win->destroyNotifyEvent(e->xdestroywindow);
806
if (win && win->numClients() == 0)
813
m_last_time = e->xmotion.time;
815
case PropertyNotify: {
816
m_last_time = e->xproperty.time;
817
WinClient *winclient = searchWindow(e->xproperty.window);
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))
830
m_last_time = e->xcrossing.time;
833
if (e->xcrossing.mode == NotifyGrab)
836
if ((e->xcrossing.window == e->xcrossing.root) &&
837
(screen = searchScreen(e->xcrossing.window))) {
838
screen->imageControl().installRootColormap();
844
m_last_time = e->xcrossing.time;
850
handleKeyEvent(e->xkey);
852
case ColormapNotify: {
853
BScreen *screen = searchScreen(e->xcolormap.window);
856
screen->setRootColormapInstalled((e->xcolormap.state ==
857
ColormapInstalled) ? true : false);
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)
868
WinClient *winclient = searchWindow(e->xfocus.window);
869
if (winclient && m_focused_window != winclient)
870
setFocusedWindow(winclient);
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)
880
WinClient *winclient = searchWindow(e->xfocus.window);
881
if (winclient == 0 && FbTk::Menu::focused() == 0) {
883
cerr<<__FILE__<<"("<<__FUNCTION__<<") Focus out is not a FluxboxWindow !!"<<endl;
885
} else if (winclient && winclient == m_focused_window &&
886
(winclient->fbwindow() == 0
887
|| !winclient->fbwindow()->isMoving()))
888
// we don't unfocus a moving window
893
handleClientMessage(e->xclient);
898
if (e->type == m_randr_event_type) {
899
// update root window size in screen
900
BScreen *scr = searchScreen(e->xany.window);
911
void Fluxbox::handleButtonEvent(XButtonEvent &be) {
915
m_last_time = be.time;
917
BScreen *screen = searchScreen(be.window);
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)
930
if (be.button == 1) {
931
if (! screen->isRootColormapInstalled())
932
screen->imageControl().installRootColormap();
934
if (screen->rootMenu().isVisible())
935
screen->rootMenu().hide();
936
if (screen->workspaceMenu().isVisible())
937
screen->workspaceMenu().hide();
939
} else if (be.button == 2) {
940
FbCommands::ShowWorkspaceMenuCmd cmd;
942
} else if (be.button == 3) {
943
FbCommands::ShowRootMenuCmd cmd;
945
} else if (screen->isDesktopWheeling() && be.button == 4) {
946
screen->nextWorkspace(1);
947
} else if (screen->isDesktopWheeling() && be.button == 5) {
948
screen->prevWorkspace(1);
953
m_last_time = be.time;
960
void Fluxbox::handleUnmapNotify(XUnmapEvent &ue) {
962
BScreen *screen = searchScreen(ue.event);
964
if (ue.event != ue.window && (!screen || !ue.send_event)) {
968
WinClient *winclient = 0;
970
if ((winclient = searchWindow(ue.window)) != 0) {
972
if (winclient != 0) {
973
FluxboxWindow *win = winclient->fbwindow();
980
// this should delete client and adjust m_focused_window if necessary
981
win->unmapNotifyEvent(ue);
983
winclient = 0; // it's invalid now when win destroyed the client
985
// finally destroy window if empty
986
if (win->numClients() == 0) {
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);
1004
* Handles XClientMessageEvent
1006
void Fluxbox::handleClientMessage(XClientMessageEvent &ce) {
1010
if (ce.message_type)
1011
atom = XGetAtomName(FbTk::App::instance()->display(), ce.message_type);
1013
cerr<<__FILE__<<"("<<__LINE__<<"): ClientMessage. data.l[0]=0x"<<hex<<ce.data.l[0]<<
1014
" message_type=0x"<<ce.message_type<<dec<<" = \""<<atom<<"\""<<endl;
1016
if (ce.message_type && atom) XFree((char *) atom);
1020
if (ce.format != 32)
1023
if (ce.message_type == m_fbatoms->getWMChangeStateAtom()) {
1024
WinClient *winclient = searchWindow(ce.window);
1025
if (! winclient || !winclient->fbwindow() || ! winclient->validateClient())
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);
1035
if (screen && ce.data.l[0] >= 0 &&
1036
ce.data.l[0] < (signed)screen->numberOfWorkspaces())
1037
screen->changeWorkspaceID(ce.data.l[0]);
1039
} else if (ce.message_type == m_fbatoms->getFluxboxChangeWindowFocusAtom()) {
1040
WinClient *winclient = searchWindow(ce.window);
1042
FluxboxWindow *win = winclient->fbwindow();
1043
if (win && win->isVisible())
1044
win->setCurrentClient(*winclient, true);
1046
} else if (ce.message_type == m_fbatoms->getFluxboxCycleWindowFocusAtom()) {
1047
BScreen *screen = searchScreen(ce.window);
1051
screen->prevFocus();
1053
screen->nextFocus();
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);
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);
1081
Handles KeyRelease and KeyPress events
1083
void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
1085
if (keyScreen() == 0 || mouseScreen() == 0)
1090
m_key->doAction(ke);
1093
// we ignore most key releases unless we need to use
1094
// a release to stop something (e.g. window cycling).
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);
1103
if ((m_watch_keyrelease & state) == 0) {
1105
m_watching_screen->notifyReleasedKeys(ke);
1106
XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime);
1108
// once they are released, we drop the watch
1109
m_watching_screen = 0;
1110
m_watch_keyrelease = 0;
1121
/// handle system signals
1122
void Fluxbox::handleSignal(int signum) {
1125
static int re_enter = 0;
1128
case SIGCHLD: // we don't want the child process to kill us
1129
waitpid(-1, 0, WNOHANG | WUNTRACED);
1150
_FBTEXT(BaseDisplay, SignalCaught, "%s: signal %d caught\n", "signal catch debug message. Include %s for command and %d for signal number"),
1153
if (! m_starting && ! re_enter) {
1156
_FBTEXT(BaseDisplay, ShuttingDown, "Shutting Down\n", "Quitting because of signal, end with newline"));
1162
_FBTEXT(BaseDisplay, Aborting, "Aborting... dumping core\n", "Aboring and dumping core, end with newline"));
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);
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);
1186
// if window changed to iconic state
1188
if (win.isIconic()) {
1189
win.screen().addIcon(&win);
1190
Workspace *space = win.screen().getWorkspace(win.workspaceNumber());
1192
space->removeWindow(&win, true);
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(),
1205
} else if ((&(win.layerSig())) == changedsub) { // layer signal
1207
for (AtomHandlerContainerIt it= m_atomhandler.begin();
1208
it != m_atomhandler.end(); ++it) {
1209
if ((*it).first->update())
1210
(*it).first->updateLayer(win);
1212
} else if ((&(win.dieSig())) == changedsub) { // window death signal
1214
for (AtomHandlerContainerIt it= m_atomhandler.begin();
1215
it != m_atomhandler.end(); ++it) {
1216
if ((*it).first->update())
1217
(*it).first->updateFrameClose(win);
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;
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);
1234
cerr<<__FILE__<<"("<<__LINE__<<"): WINDOW uncought signal from "<<&win<<endl;
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);
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);
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);
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);
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);
1272
} else if (typeid(*changedsub) == typeid(WinClient::WinClientSubj)) {
1274
WinClient::WinClientSubj *subj = dynamic_cast<WinClient::WinClientSubj *>(changedsub);
1275
WinClient &client = subj->winClient();
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);
1284
BScreen &screen = client.screen();
1286
screen.removeClient(client);
1287
// finaly send notify signal
1288
screen.updateNetizenWindowDel(client.window());
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
1294
// This is where we revert focus on window close
1296
if (m_focused_window == &client)
1297
unfocusWindow(client);
1299
// failed to revert focus?
1300
if (m_focused_window == &client)
1301
m_focused_window = 0;
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);
1317
void Fluxbox::attachSignals(WinClient &winclient) {
1318
winclient.dieSig().attach(this);
1320
for (AtomHandlerContainerIt it= m_atomhandler.begin();
1321
it != m_atomhandler.end(); ++it) {
1322
(*it).first->setupClient(winclient);
1326
BScreen *Fluxbox::searchScreen(Window window) {
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)
1339
AtomHandler* Fluxbox::getAtomHandler(const std::string &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())
1351
void Fluxbox::addAtomHandler(AtomHandler *atomh, const std::string &name) {
1352
m_atomhandler[atomh]= name;;
1355
void Fluxbox::removeAtomHandler(AtomHandler *atomh) {
1356
for (AtomHandlerContainerIt it= m_atomhandler.begin();
1357
it != m_atomhandler.end();
1359
if ((*it).first == atomh) {
1360
m_atomhandler.erase(it);
1366
WinClient *Fluxbox::searchWindow(Window window) {
1367
WinClientMap::iterator it = m_window_search.find(window);
1368
if (it != m_window_search.end())
1371
WindowMap::iterator git = m_window_search_group.find(window);
1372
return git == m_window_search_group.end() ? 0 : &git->second->winClient();
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
1381
WinClient *Fluxbox::searchGroup(Window window) {
1385
void Fluxbox::saveWindowSearch(Window window, WinClient *data) {
1386
m_window_search[window] = data;
1389
/* some windows relate to the whole group */
1390
void Fluxbox::saveWindowSearchGroup(Window window, FluxboxWindow *data) {
1391
m_window_search_group[window] = data;
1394
void Fluxbox::saveGroupSearch(Window window, WinClient *data) {
1395
m_group_search.insert(pair<Window, WinClient *>(window, data));
1399
void Fluxbox::removeWindowSearch(Window window) {
1400
m_window_search.erase(window);
1403
void Fluxbox::removeWindowSearchGroup(Window window) {
1404
m_window_search_group.erase(window);
1407
void Fluxbox::removeGroupSearch(Window window) {
1408
m_group_search.erase(window);
1411
/// restarts fluxbox
1412
void Fluxbox::restart(const char *prog) {
1415
m_restarting = true;
1418
m_restart_argument = prog;
1422
/// prepares fluxbox for a shutdown
1423
void Fluxbox::shutdown() {
1429
XSetInputFocus(FbTk::App::instance()->display(), PointerRoot, None, CurrentTime);
1431
//send shutdown to all screens
1432
for_each(m_screen_list.begin(),
1433
m_screen_list.end(), mem_fun(&BScreen::shutdown));
1439
void Fluxbox::save_rc() {
1441
XrmDatabase new_blackboxrc = 0;
1443
char rc_string[1024];
1445
string dbfile(getRcFilename());
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());
1451
cerr<<_FBTEXT(Fluxbox, BadRCFile, "rc filename is invalid!", "Bad settings file")<<endl;
1453
ScreenList::iterator it = m_screen_list.begin();
1454
ScreenList::iterator it_end = m_screen_list.end();
1456
//Save screen resources
1458
for (; it != it_end; ++it) {
1459
BScreen *screen = *it;
1460
int screen_number = screen->screenNumber();
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
1467
// write out the users workspace names
1468
sprintf(rc_string, "session.screen%d.workspaceNames: ", screen_number);
1469
string workspaces_string(rc_string);
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());
1475
workspaces_string.append("Null");
1476
workspaces_string.append(",");
1479
XrmPutLineResource(&new_blackboxrc, workspaces_string.c_str());
1483
XrmDatabase old_blackboxrc = XrmGetFileDatabase(dbfile.c_str());
1485
XrmMergeDatabases(new_blackboxrc, &old_blackboxrc); //merge database together
1486
XrmPutFileDatabase(old_blackboxrc, dbfile.c_str());
1487
XrmDestroyDatabase(old_blackboxrc);
1489
cerr<<__FILE__<<"("<<__LINE__<<"): ------------ SAVING DONE"<<endl;
1493
/// @return filename of resource file
1494
string Fluxbox::getRcFilename() {
1496
if (m_rc_file.empty()) { // set default filename
1497
string defaultfile(getenv("HOME") + string("/.") + m_RC_PATH + string("/") + m_RC_INIT_FILE);
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);
1510
void Fluxbox::load_rc() {
1512
//get resource filename
1513
string dbfile(getRcFilename());
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;
1523
if (!m_resourcemanager.load(DEFAULT_INITFILE))
1524
cerr<<_FBTEXT(Fluxbox, CantLoadRCFile, "Failed to load database", "")<<": "<<DEFAULT_INITFILE<<endl;
1527
if (m_rc_menufile->empty())
1528
m_rc_menufile.setDefaultValue();
1530
if (FbTk::Transparent::haveComposite())
1531
FbTk::Transparent::usePseudoTransparent(*m_rc_pseudotrans);
1533
if (!m_rc_slitlistfile->empty()) {
1534
*m_rc_slitlistfile = StringUtil::expandFilename(*m_rc_slitlistfile);
1537
getDefaultDataFilename("slitlist", filename);
1538
m_rc_slitlistfile.setFromString(filename.c_str());
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;
1546
if (m_rc_stylefile->empty())
1547
*m_rc_stylefile = DEFAULTSTYLE;
1549
if (!Workspace::loadGroups(*m_rc_groupfile)) {
1551
cerr<<_FBTEXT(Fluxbox, CantLoadGroupFile, "Failed to load groupfile", "Couldn't load the groupfile")<<": "<<*m_rc_groupfile<<endl;
1556
void Fluxbox::load_rc(BScreen &screen) {
1557
//get resource filename
1559
string dbfile(getRcFilename());
1561
XrmDatabaseHelper database;
1563
database = XrmGetFileDatabase(dbfile.c_str());
1565
database = XrmGetFileDatabase(DEFAULT_INITFILE);
1568
char *value_type, name_lookup[1024], class_lookup[1024];
1569
int screen_number = screen.screenNumber();
1572
screen.removeWorkspaceNames();
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,
1579
string values(value.addr);
1580
BScreen::WorkspaceNames names;
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());
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]);
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;
1612
if (!m_screen_rm.load(DEFAULT_INITFILE))
1613
cerr<<_FBTEXT(Fluxbox, CantLoadRCFile, "Failed to load database", "")<<": "<<DEFAULT_INITFILE<<endl;
1617
void Fluxbox::loadRootCommand(BScreen &screen) {
1619
string dbfile(getRcFilename());
1621
XrmDatabaseHelper database(dbfile.c_str());
1623
database = XrmGetFileDatabase(DEFAULT_INITFILE);
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,
1631
screen.saveRootCommand(value.addr==0 ? "": value.addr);
1633
screen.saveRootCommand("");
1637
void Fluxbox::reload_rc() {
1643
void Fluxbox::reconfigure() {
1644
m_reconfigure_wait = true;
1645
m_reconfig_timer.start();
1649
void Fluxbox::real_reconfigure() {
1651
XrmDatabase new_fluxboxrc = (XrmDatabase) 0;
1653
string dbfile(getRcFilename());
1654
XrmDatabase old_fluxboxrc = XrmGetFileDatabase(dbfile.c_str());
1656
XrmMergeDatabases(new_fluxboxrc, &old_fluxboxrc);
1657
XrmPutFileDatabase(old_fluxboxrc, dbfile.c_str());
1660
XrmDestroyDatabase(old_fluxboxrc);
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));
1667
// reconfigure all screens
1668
for_each(m_screen_list.begin(), m_screen_list.end(), mem_fun(&BScreen::reconfigure));
1671
m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str());
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)
1683
if (it == m_screen_list.end())
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) {
1694
time_t timestamp = FbTk::FileUtil::getLastStatusChangeTimestamp((*it)->filename.c_str());
1696
if (timestamp >= 0) {
1697
if (timestamp != (*it)->timestamp)
1703
// no timestamp changed
1707
void Fluxbox::checkMenu() {
1708
if (menuTimestampsChanged())
1712
void Fluxbox::hideExtraMenus(BScreen &screen) {
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();
1721
#endif // USE_TOOLBAR
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();
1732
void Fluxbox::real_rereadMenu() {
1734
clearMenuFilenames();
1736
for_each(m_screen_list.begin(),
1737
m_screen_list.end(),
1738
mem_fun(&BScreen::rereadMenu));
1740
if(m_show_menu_after_reread) {
1742
FbCommands::ShowRootMenuCmd showcmd;
1745
m_show_menu_after_reread = false;
1749
void Fluxbox::saveMenuFilename(const char *filename) {
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) {
1765
time_t timestamp = FbTk::FileUtil::getLastStatusChangeTimestamp(filename);
1767
if (timestamp >= 0) {
1768
MenuTimestamp *ts = new MenuTimestamp;
1770
ts->filename = filename;
1771
ts->timestamp = timestamp;
1773
m_menu_timestamps.push_back(ts);
1778
void Fluxbox::clearMenuFilenames() {
1779
while(!m_menu_timestamps.empty()) {
1780
delete m_menu_timestamps.back();
1781
m_menu_timestamps.pop_back();
1785
void Fluxbox::timed_reconfigure() {
1786
if (m_reconfigure_wait)
1789
if (m_reread_menu_wait)
1792
m_reconfigure_wait = m_reread_menu_wait = false;
1795
// set focused window
1796
void Fluxbox::setFocusedWindow(WinClient *client) {
1798
if (m_focused_window == client) {
1800
cerr<<"Focused window already win"<<endl;
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;
1811
BScreen *old_screen = 0, *screen = 0;
1812
WinClient *old_client = 0;
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>()));
1822
if (it == m_window_search.end()) {
1823
m_focused_window = 0;
1825
old_client = m_focused_window;
1826
old_screen = &old_client->screen();
1828
if (old_client->fbwindow()) {
1829
FluxboxWindow *old_win = old_client->fbwindow();
1831
if (!client || client->fbwindow() != old_win)
1832
old_win->setFocusFlag(false);
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(),
1843
if (winscreen == m_screen_list.end()) {
1844
m_focused_window = 0; // the window pointer wasn't valid, mark no window focused
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
1853
m_focused_window = 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() :
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);
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).
1881
* ignore_event means that it ignores the given event until
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());
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);
1899
case BScreen::CLICKFOCUS:
1900
screen.rootWindow().setInputFocus(RevertToPointerRoot, CurrentTime);
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
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.
1917
* assumption: client has focus
1919
void Fluxbox::unfocusWindow(WinClient &client, bool full_revert, bool unfocus_frame) {
1920
// go up the transient tree looking for a focusable window
1922
FluxboxWindow *fbwin = client.fbwindow();
1924
unfocus_frame = false;
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)) {
1934
trans_parent = trans_parent->transientFor();
1938
return; // nothing more we can do
1940
BScreen &screen = fbwin->screen();
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)) {
1950
if (full_revert && m_focused_window == &client)
1951
revertFocus(screen);
1956
void Fluxbox::watchKeyRelease(BScreen &screen, unsigned int mods) {
1959
cerr<<"WARNING: attempt to grab without modifiers!"<<endl;
1962
m_watching_screen = &screen;
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);