news download themes documentation links










Screen.cc

00001 // Screen.cc for Fluxbox Window Manager
00002 // Copyright (c) 2001 - 2004 Henrik Kinnunen (fluxgen at users.sourceforge.net)
00003 //
00004 // Screen.cc for Blackbox - an X11 Window manager
00005 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
00006 //
00007 // Permission is hereby granted, free of charge, to any person obtaining a
00008 // copy of this software and associated documentation files (the "Software"),
00009 // to deal in the Software without restriction, including without limitation
00010 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
00011 // and/or sell copies of the Software, and to permit persons to whom the
00012 // Software is furnished to do so, subject to the following conditions:
00013 //
00014 // The above copyright notice and this permission notice shall be included in
00015 // all copies or substantial portions of the Software.
00016 //
00017 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00020 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00022 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00023 // DEALINGS IN THE SOFTWARE.
00024 
00025 // $Id: Screen.cc,v 1.260 2004/01/11 16:06:22 fluxgen Exp $
00026 
00027 
00028 #include "Screen.hh"
00029 
00030 #include "I18n.hh"
00031 #include "fluxbox.hh"
00032 #include "Window.hh"
00033 #include "Workspace.hh"
00034 #include "Netizen.hh"
00035 #include "FbWinFrameTheme.hh"
00036 #include "MenuTheme.hh"
00037 #include "RootTheme.hh"
00038 #include "WinButtonTheme.hh"
00039 #include "FbCommands.hh"
00040 #include "BoolMenuItem.hh"
00041 #include "IntResMenuItem.hh"
00042 #include "FbMenu.hh"
00043 #include "LayerMenu.hh"
00044 #include "WinClient.hh"
00045 #include "FbWinFrame.hh"
00046 #include "FbWindow.hh"
00047 #include "Strut.hh"
00048 #include "SlitTheme.hh"
00049 #include "CommandParser.hh"
00050 #include "IconMenuItem.hh"
00051 
00052 #include "FbTk/Subject.hh"
00053 #include "FbTk/Directory.hh"
00054 #include "FbTk/SimpleCommand.hh"
00055 #include "FbTk/MultLayers.hh"
00056 #include "FbTk/XLayerItem.hh"
00057 #include "FbTk/MacroCommand.hh"
00058 #include "FbTk/StringUtil.hh"
00059 #include "FbTk/ImageControl.hh"
00060 
00061 //use GNU extensions
00062 #ifndef  _GNU_SOURCE
00063 #define  _GNU_SOURCE
00064 #endif // _GNU_SOURCE
00065 
00066 #ifdef HAVE_CONFIG_H
00067 #include "config.h"
00068 #endif // HAVE_CONFIG_H
00069 
00070 #ifdef SLIT
00071 #include "Slit.hh"
00072 #else
00073 // fill it in
00074 class Slit {};
00075 #endif // SLIT
00076 
00077 #ifdef STDC_HEADERS
00078 #include <sys/types.h>
00079 #endif // STDC_HEADERS
00080 
00081 #ifdef HAVE_CTYPE_H
00082 #include <ctype.h>
00083 #endif // HAVE_CTYPE_H
00084 
00085 #ifdef HAVE_UNISTD_H
00086 #include <sys/types.h>
00087 #include <unistd.h>
00088 #endif // HAVE_UNISTD_H
00089 
00090 #ifdef HAVE_STDARG_H
00091 #include <stdarg.h>
00092 #endif // HAVE_STDARG_H
00093 
00094 #ifdef TIME_WITH_SYS_TIME
00095 #include <sys/time.h>
00096 #include <time.h>
00097 #else // !TIME_WITH_SYS_TIME
00098 #ifdef  HAVE_SYS_TIME_H
00099 #include <sys/time.h>
00100 #else // !HAVE_SYS_TIME_H
00101 #include <time.h>
00102 #endif // HAVE_SYS_TIME_H
00103 #endif // TIME_WITH_SYS_TIME
00104 
00105 #include <X11/Xatom.h>
00106 #include <X11/keysym.h>
00107 #include <X11/cursorfont.h>
00108 
00109 #ifdef XINERAMA
00110 extern  "C" {
00111 #include <X11/extensions/Xinerama.h>
00112 }
00113 #endif // XINERAMA
00114 
00115 #include <iostream>
00116 #include <memory>
00117 #include <algorithm>
00118 #include <functional>
00119 
00120 using namespace std;
00121 
00122 static bool running = true;
00123 namespace {
00124 
00125 int anotherWMRunning(Display *display, XErrorEvent *) {
00126     cerr<<I18n::instance()->
00127         getMessage(FBNLS::ScreenSet, FBNLS::ScreenAnotherWMRunning,
00128                    "BScreen::BScreen: an error occured while querying the X server.\n"
00129                    "    another window manager already running on display ")<<DisplayString(display)<<endl;
00130 
00131     running = false;
00132 
00133     return -1;
00134 }
00135 
00136 class FocusModelMenuItem : public FbTk::MenuItem {
00137 public:
00138     FocusModelMenuItem(const char *label, BScreen &screen, 
00139                        BScreen::FocusModel model, 
00140                        FbTk::RefCount<FbTk::Command> &cmd):
00141         FbTk::MenuItem(label, cmd), m_screen(screen), m_focusmodel(model) {
00142     }
00143     bool isEnabled() const { return m_screen.getFocusModel() != m_focusmodel; }
00144     void click(int button, int time) {
00145         m_screen.saveFocusModel(m_focusmodel);
00146         FbTk::MenuItem::click(button, time);
00147     }
00148 
00149 private:
00150     BScreen &m_screen;
00151     BScreen::FocusModel m_focusmodel;
00152 };
00153 
00154 
00155 } // End anonymous namespace
00156 
00157 template <>
00158 void FbTk::Resource<BScreen::PlacementPolicy>::setDefaultValue() {
00159     *(*this) = BScreen::ROWSMARTPLACEMENT;
00160 }
00161 
00162 template <>
00163 void FbTk::Resource<BScreen::PlacementPolicy>::setFromString(const char *str) {
00164     if (strcasecmp("RowSmartPlacement", str) == 0)
00165         *(*this) = BScreen::ROWSMARTPLACEMENT;
00166     else if (strcasecmp("", str) == 0)
00167         *(*this) = BScreen::COLSMARTPLACEMENT;
00168     else if (strcasecmp("UnderMousePlacement", str) == 0)
00169         *(*this) = BScreen::UNDERMOUSEPLACEMENT;
00170     else if (strcasecmp("CascadePlacement", str) == 0)
00171         *(*this) = BScreen::CASCADEPLACEMENT;
00172     else
00173         setDefaultValue();
00174     
00175 }
00176 
00177 string FbTk::Resource<BScreen::PlacementPolicy>::getString() {
00178     switch (*(*this)) {
00179     case BScreen::ROWSMARTPLACEMENT:
00180         return "RowSmartPlacement";
00181     case BScreen::COLSMARTPLACEMENT:
00182         return "ColSmartPlacement";
00183     case BScreen::UNDERMOUSEPLACEMENT:
00184         return "UnderMousePlacement";
00185     case BScreen::CASCADEPLACEMENT:
00186         return "CascadePlacement";
00187     }
00188 
00189     return "RowSmartPlacement";
00190 }
00191 
00192 template <>
00193 void FbTk::Resource<BScreen::RowDirection>::setDefaultValue() {
00194     *(*this) = BScreen::LEFTRIGHT;
00195 }
00196 
00197 template <>
00198 void FbTk::Resource<BScreen::RowDirection>::setFromString(const char *str) {
00199     if (strcasecmp("LeftToRight", str) == 0)
00200         *(*this) = BScreen::LEFTRIGHT;
00201     else if (strcasecmp("RightToLeft", str) == 0)
00202         *(*this) = BScreen::RIGHTLEFT;
00203     else
00204         setDefaultValue();
00205     
00206 }
00207 
00208 string FbTk::Resource<BScreen::RowDirection>::getString() {
00209     switch (*(*this)) {
00210     case BScreen::LEFTRIGHT:
00211         return "LeftToRight";
00212     case BScreen::RIGHTLEFT:
00213         return "RightToLeft";
00214     }
00215 
00216     return "LeftToRight";
00217 }
00218 
00219 
00220 template <>
00221 void FbTk::Resource<BScreen::ColumnDirection>::setDefaultValue() {
00222     *(*this) = BScreen::TOPBOTTOM;
00223 }
00224 
00225 template <>
00226 void FbTk::Resource<BScreen::ColumnDirection>::setFromString(const char *str) {
00227     if (strcasecmp("TopToBottom", str) == 0)
00228         *(*this) = BScreen::TOPBOTTOM;
00229     else if (strcasecmp("BottomToTop", str) == 0)
00230         *(*this) = BScreen::BOTTOMTOP;
00231     else
00232         setDefaultValue();
00233     
00234 }
00235 
00236 string FbTk::Resource<BScreen::ColumnDirection>::getString() {
00237     switch (*(*this)) {
00238     case BScreen::TOPBOTTOM:
00239         return "TopToBottom";
00240     case BScreen::BOTTOMTOP:
00241         return "BottomToTop";
00242     }
00243 
00244     return "TopToBottom";
00245 }
00246 
00247 template <>
00248 void FbTk::Resource<FbTk::MenuTheme::MenuMode>::setDefaultValue() {
00249     *(*this) = FbTk::MenuTheme::DELAY_OPEN;
00250 }
00251 
00252 template <>
00253 string FbTk::Resource<FbTk::MenuTheme::MenuMode>::getString() {
00254     switch (*(*this)) {
00255     case FbTk::MenuTheme::DELAY_OPEN:
00256         return string("Delay");
00257     case FbTk::MenuTheme::CLICK_OPEN:
00258         return string("Click");
00259     }
00260     return string("Delay");
00261 }
00262 
00263 template <>
00264 void FbTk::Resource<FbTk::MenuTheme::MenuMode>::setFromString(const char *str) {
00265     if (strcasecmp(str, "Delay") == 0)
00266         *(*this) = FbTk::MenuTheme::DELAY_OPEN;
00267     else if (strcasecmp(str, "Click") == 0)
00268         *(*this) = FbTk::MenuTheme::CLICK_OPEN;
00269     else
00270         setDefaultValue();
00271 }
00272 
00273 template<>
00274 std::string FbTk::Resource<BScreen::FocusModel>::
00275 getString() {
00276     switch (m_value) {
00277     case BScreen::SLOPPYFOCUS:
00278         return string("SloppyFocus");
00279     case BScreen::SEMISLOPPYFOCUS:
00280         return string("SemiSloppyFocus");
00281     case BScreen::CLICKTOFOCUS:
00282         return string("ClickToFocus");
00283     }
00284     // default string
00285     return string("ClickToFocus");
00286 }
00287 
00288 template<>
00289 void FbTk::Resource<BScreen::FocusModel>::
00290 setFromString(char const *strval) {
00291     // auto raise options here for backwards read compatibility
00292     // they are not supported for saving purposes. Nor does the "AutoRaise" 
00293     // part actually do anything
00294     if (strcasecmp(strval, "SloppyFocus") == 0 
00295         || strcasecmp(strval, "AutoRaiseSloppyFocus") == 0) 
00296         m_value = BScreen::SLOPPYFOCUS;
00297     else if (strcasecmp(strval, "SemiSloppyFocus") == 0
00298         || strcasecmp(strval, "AutoRaiseSemiSloppyFocus") == 0) 
00299         m_value = BScreen::SEMISLOPPYFOCUS;
00300     else if (strcasecmp(strval, "ClickToFocus") == 0) 
00301         m_value = BScreen::CLICKTOFOCUS;
00302     else
00303         setDefaultValue();
00304 }
00305 
00306 namespace {
00307 
00308 class StyleMenuItem: public FbTk::MenuItem {
00309 public:
00310     StyleMenuItem(const std::string &label, const std::string &filename):
00311         FbTk::MenuItem(label.c_str()), 
00312         m_filename(FbTk::StringUtil::
00313                    expandFilename(filename)) {
00314         // perform shell style ~ home directory expansion
00315         // and insert style      
00316         FbTk::RefCount<FbTk::Command> 
00317             setstyle_cmd(new FbCommands::
00318                          SetStyleCmd(m_filename));
00319         setCommand(setstyle_cmd);
00320         setToggleItem(true);
00321     }
00322     bool isSelected() const {
00323         return Fluxbox::instance()->getStyleFilename() == m_filename;
00324     }
00325 private:
00326     const std::string m_filename;
00327 };
00328 
00329 void setupWorkspacemenu(BScreen &scr, FbTk::Menu &menu) {
00330     menu.removeAll(); // clear all items
00331     using namespace FbTk;
00332     menu.setLabel("Workspace");
00333     RefCount<Command> new_workspace(new FbTk::SimpleCommand<BScreen, int>(scr, &BScreen::addWorkspace));
00334     RefCount<Command> remove_last(new FbTk::SimpleCommand<BScreen, int>(scr, &BScreen::removeLastWorkspace));
00336     menu.insert("New Workspace", new_workspace);
00337     menu.insert("Remove Last", remove_last);
00338     // for each workspace add workspace name and it's menu to our workspace menu
00339     for (size_t workspace = 0; workspace < scr.getCount(); ++workspace) {
00340         Workspace *wkspc = scr.getWorkspace(workspace);
00341         menu.insert(wkspc->name().c_str(), &wkspc->menu());
00342     }
00343 
00344     // update graphics
00345     menu.update();
00346 }
00347 
00348 };
00349 
00350 
00351 BScreen::ScreenResource::ScreenResource(FbTk::ResourceManager &rm, 
00352                                         const std::string &scrname, 
00353                                         const std::string &altscrname):
00354     image_dither(rm, false, scrname+".imageDither", altscrname+".ImageDither"),
00355     opaque_move(rm, false, scrname + ".opaqueMove", altscrname+".OpaqueMove"),
00356     full_max(rm, true, scrname+".fullMaximization", altscrname+".FullMaximization"),
00357     sloppy_window_grouping(rm, true, 
00358                            scrname+".sloppywindowgrouping", altscrname+".SloppyWindowGrouping"),
00359     workspace_warping(rm, true, scrname+".workspacewarping", altscrname+".WorkspaceWarping"),
00360     desktop_wheeling(rm, true, scrname+".desktopwheeling", altscrname+".DesktopWheeling"),
00361     show_window_pos(rm, true, scrname+".showwindowposition", altscrname+".ShowWindowPosition"),
00362     focus_last(rm, true, scrname+".focusLastWindow", altscrname+".FocusLastWindow"),
00363     focus_new(rm, true, scrname+".focusNewWindows", altscrname+".FocusNewWindows"),
00364     antialias(rm, false, scrname+".antialias", altscrname+".Antialias"),
00365     auto_raise(rm, false, scrname+".autoRaise", altscrname+".AutoRaise"),
00366     click_raises(rm, true, scrname+".clickRaises", altscrname+".ClickRaises"),
00367     rootcommand(rm, "", scrname+".rootCommand", altscrname+".RootCommand"),
00368     resizemode(rm, "", scrname+".resizeMode", altscrname+".ResizeMode"),
00369     focus_model(rm, CLICKTOFOCUS, scrname+".focusModel", altscrname+".FocusModel"),
00370     workspaces(rm, 1, scrname+".workspaces", altscrname+".Workspaces"),
00371     edge_snap_threshold(rm, 0, scrname+".edgeSnapThreshold", altscrname+".EdgeSnapThreshold"),
00372     menu_alpha(rm, 255, scrname+".menuAlpha", altscrname+".MenuAlpha"),
00373     menu_delay(rm, 0, scrname + ".menuDelay", altscrname+".MenuDelay"),
00374     menu_delay_close(rm, 0, scrname + ".menuDelayClose", altscrname+".MenuDelayClose"),
00375     menu_mode(rm, FbTk::MenuTheme::DELAY_OPEN, scrname+".menuMode", altscrname+".MenuMode"),
00376     placement_policy(rm, ROWSMARTPLACEMENT, scrname+".windowPlacement", altscrname+".WindowPlacement"),
00377     row_direction(rm, LEFTRIGHT, scrname+".rowPlacementDirection", altscrname+".RowPlacementDirection"),
00378     col_direction(rm, TOPBOTTOM, scrname+".colPlacementDirection", altscrname+".ColPlacementDirection") {
00379 
00380 }
00381 
00382 BScreen::BScreen(FbTk::ResourceManager &rm,
00383                  const string &screenname, const string &altscreenname,
00384                  int scrn, int num_layers) : 
00385     m_clientlist_sig(*this),  // client signal
00386     m_iconlist_sig(*this), // icon list signal
00387     m_workspacecount_sig(*this), // workspace count signal
00388     m_workspacenames_sig(*this), // workspace names signal 
00389     m_currentworkspace_sig(*this), // current workspace signal
00390     m_reconfigure_sig(*this), // reconfigure signal
00391     m_resize_sig(*this),
00392     m_layermanager(num_layers),
00393     cycling_focus(false),
00394     cycling_last(0),
00395     m_windowtheme(new FbWinFrameTheme(scrn)), 
00396     // the order of windowtheme and winbutton theme is important
00397     // because winbutton need to rescale the pixmaps in winbutton theme
00398     // after fbwinframe have resized them
00399     m_winbutton_theme(new WinButtonTheme(scrn, *m_windowtheme)),
00400     m_menutheme(new MenuTheme(scrn)),
00401     m_root_theme(new 
00402                  RootTheme(scrn, 
00403                            *resource.rootcommand)),
00404     m_root_window(scrn),
00405     resource(rm, screenname, altscreenname),
00406     m_name(screenname),
00407     m_altname(altscreenname),
00408     m_resource_manager(rm),
00409     m_available_workspace_area(new Strut(0, 0, 0, 0)),
00410     m_xinerama_headinfo(0),
00411     m_shutdown(false) {
00412 
00413 
00414     Display *disp = FbTk::App::instance()->display();
00415 
00416     initXinerama();
00417 
00418     // setup error handler to catch "screen already managed by other wm"
00419     XErrorHandler old = XSetErrorHandler((XErrorHandler) anotherWMRunning);
00420 
00421     rootWindow().setEventMask(ColormapChangeMask | EnterWindowMask | PropertyChangeMask |
00422                               SubstructureRedirectMask | KeyPressMask | KeyReleaseMask |
00423                               ButtonPressMask | ButtonReleaseMask| SubstructureNotifyMask);
00424 
00425     FbTk::App::instance()->sync(false);
00426 
00427     XSetErrorHandler((XErrorHandler) old);
00428 
00429     managed = running;
00430     if (! managed)
00431         return;
00432     
00433     I18n *i18n = I18n::instance();
00434     
00435     fprintf(stderr, i18n->getMessage(FBNLS::ScreenSet, FBNLS::ScreenManagingScreen,
00436                                      "BScreen::BScreen: managing screen %d "
00437                                      "using visual 0x%lx, depth %d\n"),
00438             screenNumber(), XVisualIDFromVisual(rootWindow().visual()),
00439             rootWindow().depth());
00440 
00441     cycling_window = focused_list.end();
00442     
00443     rootWindow().setCursor(XCreateFontCursor(disp, XC_left_ptr));
00444 
00445     Fluxbox *fluxbox = Fluxbox::instance();
00446     // load this screens resources
00447     fluxbox->load_rc(*this);
00448 
00449     // setup image cache engine
00450     m_image_control.reset(new FbTk::ImageControl(scrn, true, fluxbox->colorsPerChannel(),
00451                                                  fluxbox->getCacheLife(), fluxbox->getCacheMax()));
00452     imageControl().installRootColormap();
00453     root_colormap_installed = true;
00454 
00455 
00456 
00457     m_menutheme->setAlpha(*resource.menu_alpha);
00458     m_menutheme->setMenuMode(*resource.menu_mode);
00459     // clamp values
00460     if (*resource.menu_delay > 5000)
00461         *resource.menu_delay = 5000;
00462     if (*resource.menu_delay < 0)
00463         *resource.menu_delay = 0;
00464 
00465     if (*resource.menu_delay_close > 5000)
00466         *resource.menu_delay_close = 5000;
00467     if (*resource.menu_delay_close < 0)
00468         *resource.menu_delay_close = 0;
00469 
00470     m_menutheme->setDelayOpen(*resource.menu_delay);
00471     m_menutheme->setDelayClose(*resource.menu_delay_close);
00472 
00473     imageControl().setDither(*resource.image_dither);
00474 
00475     // setup windowtheme for antialias
00476     // before we load the theme
00477 
00478     winFrameTheme().font().setAntialias(*resource.antialias);
00479     menuTheme().titleFont().setAntialias(*resource.antialias);
00480     menuTheme().frameFont().setAntialias(*resource.antialias);
00481 
00482 
00483     // create geometry window 
00484 
00485     int geom_h = 10;
00486     int geom_w = 100; // just initial, will be fixed in render
00487 
00488     XSetWindowAttributes attrib;
00489     unsigned long mask = CWBorderPixel | CWColormap | CWSaveUnder;
00490     attrib.border_pixel = winFrameTheme().border().color().pixel();
00491     attrib.colormap = rootWindow().colormap();
00492     attrib.save_under = true;
00493 
00494     winFrameTheme().reconfigSig().attach(this);// for geom window
00495 
00496     m_geom_window = 
00497         XCreateWindow(disp, rootWindow().window(),
00498                       0, 0, geom_w, geom_h, winFrameTheme().border().width(), rootWindow().depth(),
00499                       InputOutput, rootWindow().visual(), mask, &attrib);
00500     geom_visible = false;
00501     geom_pixmap = 0;
00502 
00503     renderGeomWindow();
00504 
00505     // setup workspaces and workspace menu
00506 
00507     workspacemenu.reset(createMenu(""));
00508     workspacemenu->setInternalMenu();
00510     m_iconmenu.reset(createMenu("Icons"));
00511     m_iconmenu->setInternalMenu();
00512 
00513     if (*resource.workspaces != 0) {
00514         for (int i = 0; i < *resource.workspaces; ++i) {
00515             Workspace *wkspc = new Workspace(*this, m_layermanager, 
00516                                              getNameOfWorkspace(m_workspaces_list.size()),
00517                                              m_workspaces_list.size());
00518             m_workspaces_list.push_back(wkspc);
00519         }
00520     } else { // create at least one workspace
00521         Workspace *wkspc = new Workspace(*this, m_layermanager, 
00522                                          getNameOfWorkspace(m_workspaces_list.size()),
00523                                          m_workspaces_list.size());
00524         m_workspaces_list.push_back(wkspc);
00525     }
00526 
00527     setupWorkspacemenu(*this, *workspacemenu);
00529     workspacemenu->insert("Icons", m_iconmenu.get());
00530     workspacemenu->update();
00531 
00532     m_current_workspace = m_workspaces_list.front();
00533 
00534 #ifdef SLIT
00535     m_slit.reset(new Slit(*this, *layerManager().getLayer(Fluxbox::instance()->getDesktopLayer()),
00536                  Fluxbox::instance()->getSlitlistFilename().c_str()));
00537 #endif // SLIT
00538 
00540     // own resources we must do this.
00541     fluxbox->load_rc(*this);
00542 
00543     // TODO: nls
00544     m_configmenu.reset(createMenu("Configuration"));
00545     setupConfigmenu(*m_configmenu.get());
00546     m_configmenu->setInternalMenu();
00547 
00548     workspacemenu->setItemSelected(2, true);
00549     // create and initiate rootmenu
00550     rereadMenu();
00551     
00552     m_configmenu->update();
00553 
00554     // start with workspace 0
00555     changeWorkspaceID(0);
00556     updateNetizenWorkspaceCount();
00557 
00558     // we need to load win frame theme before we create any fluxbox window
00559     // and after we've load the resources
00560     // else we get some bad handle/grip height/width
00561     //    FbTk::ThemeManager::instance().loadTheme(*m_windowtheme.get());
00563     // else the focus label doesn't get updated
00564     // So we lock root theme temporary so it doesn't uses RootTheme::reconfigTheme
00565     // This must be fixed in the future.
00566     m_root_theme->lock(true);
00567     FbTk::ThemeManager::instance().load(Fluxbox::instance()->getStyleFilename());
00568     m_root_theme->lock(false);
00569 
00570     int i;
00571     unsigned int nchild;
00572     Window r, p, *children;
00573     XQueryTree(disp, rootWindow().window(), &r, &p, &children, &nchild);
00574 
00575     // preen the window list of all icon windows... for better dockapp support
00576     for (i = 0; i < (int) nchild; i++) {
00577         
00578         if (children[i] == None) continue;
00579 
00580         XWMHints *wmhints = XGetWMHints(FbTk::App::instance()->display(),
00581                                         children[i]);
00582 
00583         if (wmhints) {
00584             if ((wmhints->flags & IconWindowHint) &&
00585                 (wmhints->icon_window != children[i]))
00586                 for (int j = 0; j < (int) nchild; j++) {
00587                     if (children[j] == wmhints->icon_window) {
00588                         children[j] = None;
00589                         break;
00590                     }
00591                 }
00592             XFree(wmhints);
00593         }
00594     }
00595 
00596     // manage shown windows
00597     for (i = 0; i < (int) nchild; ++i) {
00598         if (children[i] == None || (! fluxbox->validateWindow(children[i])))
00599             continue;
00600 
00601         XWindowAttributes attrib;
00602         if (XGetWindowAttributes(disp, children[i],
00603                                  &attrib)) {
00604             if (attrib.override_redirect) 
00605                 continue;
00606 
00607             if (attrib.map_state != IsUnmapped) {
00608                 FluxboxWindow *win = createWindow(children[i]);
00609 
00610                 if (win) {
00611                     XMapRequestEvent mre;
00612                     mre.window = children[i];
00613                     win->mapRequestEvent(mre);
00614                 }
00615             }
00616         }
00617     }
00618 
00619     rm.unlock();
00620 
00621     XFree(children);
00622 
00623     XFlush(disp);
00624 }
00625 
00626 BScreen::~BScreen() {
00627     if (! managed)
00628         return;
00629 
00630     if (m_rootmenu.get() != 0)
00631         m_rootmenu->removeAll();
00632 
00633     if (geom_pixmap != None)
00634         imageControl().removeImage(geom_pixmap);
00635 
00636     removeWorkspaceNames();
00637 
00638     Workspaces::iterator w_it = m_workspaces_list.begin();
00639     Workspaces::iterator w_it_end = m_workspaces_list.end();
00640     for(; w_it != w_it_end; ++w_it) {
00641         delete (*w_it);
00642     }
00643     m_workspaces_list.clear();
00644     
00645     Icons::iterator i_it = m_icon_list.begin();
00646     Icons::iterator i_it_end = m_icon_list.end();
00647     for(; i_it != i_it_end; ++i_it) {
00648         delete (*i_it);
00649     }
00650     m_icon_list.clear();
00651     
00652     Netizens::iterator n_it = m_netizen_list.begin();
00653     Netizens::iterator n_it_end = m_netizen_list.end();
00654     for(; n_it != n_it_end; ++n_it) {
00655         delete (*n_it);
00656     }
00657 
00658     m_netizen_list.clear();
00659 
00660     if (hasXinerama() && m_xinerama_headinfo) {
00661         delete [] m_xinerama_headinfo;
00662     }
00663 }
00664 
00665 unsigned int BScreen::currentWorkspaceID() const { 
00666     return m_current_workspace->workspaceID(); 
00667 }
00668 
00669 Pixmap BScreen::rootPixmap() const {
00670 
00671     Pixmap root_pm = 0;
00672     Display *disp = FbTk::App::instance()->display();
00673     Atom real_type;
00674     int real_format;
00675     unsigned long items_read, items_left;
00676     unsigned int *data;
00677     if (rootWindow().property(XInternAtom(disp, "_XROOTPMAP_ID", false),
00678                               0L, 1L, 
00679                               false, XA_PIXMAP, &real_type,
00680                               &real_format, &items_read, &items_left, 
00681                               (unsigned char **) &data) && 
00682         items_read) { 
00683         root_pm = (Pixmap) (*data);                  
00684         XFree(data);
00685     }
00686 
00687     return root_pm;
00688 
00689 }
00690     
00691 unsigned int BScreen::maxLeft(int head) const {
00692     // we ignore strut if we're doing full maximization
00693     if (hasXinerama())
00694         return doFullMax() ? getHeadX(head) : 
00695             getHeadX(head) + m_available_workspace_area->left();
00696     else
00697         return doFullMax() ? 0 : m_available_workspace_area->left();
00698 }
00699 
00700 unsigned int BScreen::maxRight(int head) const {
00701     // we ignore strut if we're doing full maximization
00702     if (hasXinerama())
00703         return doFullMax() ? getHeadX(head) + getHeadWidth(head) : 
00704             getHeadX(head) + getHeadWidth(head) - m_available_workspace_area->right();
00705     else
00706         return doFullMax() ? width() : width() - m_available_workspace_area->right();
00707 }
00708 
00709 unsigned int BScreen::maxTop(int head) const {
00710 
00711     // we ignore strut if we're doing full maximization
00712 
00713     if (hasXinerama())
00714         return doFullMax() ? getHeadY(head) : getHeadY(head) + m_available_workspace_area->top();
00715     else
00716         return doFullMax() ? 0 : m_available_workspace_area->top();
00717 }
00718 
00719 unsigned int BScreen::maxBottom(int head) const {
00720     // we ignore strut if we're doing full maximization
00721 
00722     if (hasXinerama())
00723         return doFullMax() ? getHeadY(head) + getHeadHeight(head) :
00724             getHeadY(head) + getHeadHeight(head) - m_available_workspace_area->bottom();
00725     else
00726         return doFullMax() ? height() : height() - m_available_workspace_area->bottom();
00727 }
00728 
00729 void BScreen::update(FbTk::Subject *subj) {
00730     // for now we're only listening to the theme sig, so no object check
00731     // if another signal is added later, will need to differentiate here
00732 
00733     renderGeomWindow();
00734 }
00735 
00736 FbTk::Menu *BScreen::createMenu(const std::string &label) {
00737     FbTk::Menu *menu = new FbMenu(menuTheme(), 
00738                                   imageControl(), 
00739                                   *layerManager().getLayer(Fluxbox::instance()->getMenuLayer()));
00740     if (!label.empty())
00741         menu->setLabel(label.c_str());
00742 
00743     return menu;
00744 }
00745 
00746 void BScreen::hideMenus() {
00747     // hide extra menus
00748     Fluxbox::instance()->hideExtraMenus(*this);
00749 
00750 #ifdef SLIT
00751     // hide slit menu
00752     if (slit())
00753         slit()->menu().hide();
00754 #endif // SLIT
00755 
00756     // hide icon menus
00757     if (getIconList().size()) {
00758         Icons::iterator it = getIconList().begin();
00759         const Icons::iterator it_end = getIconList().end();
00760         for (; it != it_end; ++it)
00761             (*it)->menu().hide();
00762     }
00763     // hide all client menus
00764     Workspaces::iterator w_it = getWorkspacesList().begin();
00765     const Workspaces::iterator w_it_end = getWorkspacesList().end();
00766     for (; w_it != w_it_end; ++w_it) {
00767         if ((*w_it)->windowList().size()) {
00768             Workspace::Windows::iterator win_it = (*w_it)->windowList().begin();
00769             const Workspace::Windows::iterator win_it_end = (*w_it)->windowList().end();
00770             for (; win_it != win_it_end; ++win_it) {
00771                 (*win_it)->menu().hide();
00772             }
00773         }
00774     }
00775 
00776 
00777 }
00778 
00779 void BScreen::reconfigure() {
00780     m_menutheme->setAlpha(*resource.menu_alpha);
00781     m_menutheme->setMenuMode(*resource.menu_mode);
00782 
00783     // clamp values
00784     if (*resource.menu_delay > 5000)
00785         *resource.menu_delay = 5000;
00786     if (*resource.menu_delay < 0)
00787         *resource.menu_delay = 0;
00788 
00789     if (*resource.menu_delay_close > 5000)
00790         *resource.menu_delay_close = 5000;
00791     if (*resource.menu_delay_close < 0)
00792         *resource.menu_delay_close = 0;
00793 
00794     m_menutheme->setDelayOpen(*resource.menu_delay);
00795     m_menutheme->setDelayClose(*resource.menu_delay_close);
00796 
00797     // setup windowtheme, toolbartheme for antialias
00798     winFrameTheme().font().setAntialias(*resource.antialias);
00799     m_menutheme->titleFont().setAntialias(*resource.antialias);
00800     m_menutheme->frameFont().setAntialias(*resource.antialias);
00801 
00802     renderGeomWindow();
00803 
00804     //reconfigure menus
00805     workspacemenu->reconfigure();
00806     m_configmenu->reconfigure();
00807 
00808     // We need to check to see if the timestamps
00809     // changed before we actually can restore the menus 
00810     // in the same way, since we can't really say if
00811     // any submenu is in the same place as before if the
00812     // menu changed.
00813 
00814     // if timestamp changed then no restoring
00815     bool restore_menus = ! Fluxbox::instance()->menuTimestampsChanged();
00816 
00817     // destroy old timestamps
00818     Fluxbox::instance()->clearMenuFilenames();
00819 
00820     // save submenu index so we can restore them afterwards
00821     vector<int> remember_sub;
00822     if (restore_menus) {
00823         FbTk::Menu *menu = m_rootmenu.get();
00824         while (menu) {
00825             int r = menu->currentSubmenu();
00826             if (r < 0) break;
00827             remember_sub.push_back(r);
00828             menu = menu->find(r)->submenu();
00829         }
00830     }
00831 
00832     rereadMenu();
00833 
00834     if (restore_menus) {
00835         // restore submenus, no timestamp changed
00836         FbTk::Menu *menu = m_rootmenu.get();
00837         for (int i = 0; i < (int)remember_sub.size(); i++ ) {
00838             int sub = remember_sub[i];
00839             if (!menu || sub < 0) 
00840                 break;
00841             FbTk::MenuItem *item = menu->find(sub);
00842             if (item != 0) {
00843                 menu->drawSubmenu(sub);
00844                 menu = item->submenu();
00845             } else
00846                 menu = 0;
00847 
00848         }
00849     }
00850 
00851     // reconfigure workspaces
00852     for_each(m_workspaces_list.begin(),
00853              m_workspaces_list.end(),
00854              mem_fun(&Workspace::reconfigure));
00855 
00856     // reconfigure Icons
00857     for_each(m_icon_list.begin(),
00858              m_icon_list.end(),
00859              mem_fun(&FluxboxWindow::reconfigure));
00860 
00861     imageControl().cleanCache();
00862     // notify objects that the screen is reconfigured
00863     m_reconfigure_sig.notify();
00864 }
00865 
00866 
00867 void BScreen::rereadMenu() {
00868     initMenu();
00869     m_rootmenu->reconfigure();
00870 }
00871 
00872 
00873 void BScreen::removeWorkspaceNames() {
00874     m_workspace_names.clear();
00875 }
00876 
00877 void BScreen::updateWorkspaceNamesAtom() {
00878     m_workspacenames_sig.notify();
00879 }
00880 
00881 void BScreen::addIcon(FluxboxWindow *w) {
00882     if (! w) return;
00883 
00884     m_icon_list.push_back(w);
00885     updateIconMenu();
00886 
00887     m_iconlist_sig.notify();
00888 }
00889 
00890 
00891 void BScreen::removeIcon(FluxboxWindow *w) {
00892     if (! w)
00893         return;
00894     
00895     Icons::iterator erase_it = remove_if(m_icon_list.begin(),
00896                                          m_icon_list.end(),
00897                                          bind2nd(equal_to<FluxboxWindow *>(), w));
00898     if (erase_it != m_icon_list.end())
00899         m_icon_list.erase(erase_it);
00900 
00901     updateIconMenu();
00902 
00903     m_iconlist_sig.notify();
00904 }
00905 
00906 
00907 void BScreen::updateIconMenu() {
00908     m_iconmenu->removeAll();
00909     Icons::iterator it = m_icon_list.begin();
00910     Icons::iterator it_end = m_icon_list.end();
00911     for (; it != it_end; ++it) {
00912         FluxboxWindow::ClientList::iterator client_it = (*it)->clientList().begin();
00913         FluxboxWindow::ClientList::iterator client_it_end = (*it)->clientList().end();
00914         for (; client_it != client_it_end; ++client_it)
00915             m_iconmenu->insert(new IconMenuItem(**client_it));
00916     }
00917     m_iconmenu->update();
00918 }
00919 
00920 void BScreen::removeWindow(FluxboxWindow *win) {
00921     if (win->isIconic())
00922         removeIcon(win);
00923     else
00924         getWorkspace(win->workspaceNumber())->removeWindow(win);
00925 }
00926 
00927 
00928 void BScreen::removeClient(WinClient &client) {
00929 
00930     WinClient *cyc = 0;
00931     if (cycling_window != focused_list.end())
00932         cyc = *cycling_window;
00933 
00934     WinClient *focused = Fluxbox::instance()->getFocusedWindow();
00935     focused_list.remove(&client);
00936     if (cyc == &client) {
00937         cycling_window = focused_list.end();
00938     } else if (focused == &client) {
00939         // if we are focused, then give our focus to our transient parent
00940         // or revert normally
00941         if (client.transientFor() && client.transientFor()->fbwindow())
00942             client.transientFor()->fbwindow()->setInputFocus();
00943         else
00944             Fluxbox::instance()->revertFocus(focused->screen());
00945     }
00946 
00947     if (cycling_last == &client)
00948         cycling_last = 0;
00949 
00950     for_each(getWorkspacesList().begin(), getWorkspacesList().end(),
00951              mem_fun(&Workspace::updateClientmenu));
00952 
00953     // remove any grouping this is expecting
00954     Groupables::iterator it = m_expecting_groups.begin();
00955     Groupables::iterator it_end = m_expecting_groups.end();
00956     for (; it != it_end; ++it) {
00957         if (it->second == &client) {
00958             m_expecting_groups.erase(it);
00959             // it should only be in there a maximum of once
00960             break;
00961         }
00962     }
00963     // the client could be on icon menu so we update it
00964     updateIconMenu();
00965 
00966 }
00967 
00968 void BScreen::setAntialias(bool value) {
00969     if (*resource.antialias == value)
00970         return;
00971     resource.antialias = value;
00972     reconfigure();
00973 }
00974 
00975 int BScreen::addWorkspace() {
00976     Workspace *wkspc = new Workspace(*this, m_layermanager, 
00977                                      "",
00978                                      m_workspaces_list.size());
00979     m_workspaces_list.push_back(wkspc);
00980     addWorkspaceName(wkspc->name().c_str()); // update names
00981     //add workspace to workspacemenu
00982     workspacemenu->insert(wkspc->name().c_str(), &wkspc->menu(),
00983                           wkspc->workspaceID() + 2); //+2 so we add it after "remove last" item
00984         
00985     workspacemenu->update();
00986     saveWorkspaces(m_workspaces_list.size());
00987     
00988     updateNetizenWorkspaceCount();  
00989     
00990     return m_workspaces_list.size();
00991     
00992 }
00993 
00996 int BScreen::removeLastWorkspace() {
00997     if (m_workspaces_list.size() <= 1)
00998         return 0;
00999     Workspace *wkspc = m_workspaces_list.back();
01000 
01001     if (m_current_workspace->workspaceID() == wkspc->workspaceID())
01002         changeWorkspaceID(m_current_workspace->workspaceID() - 1);
01003 
01004     wkspc->removeAll();
01005 
01006     workspacemenu->remove(wkspc->workspaceID()+2); // + 2 is where workspaces starts
01007     workspacemenu->update();
01008     
01009     //remove last workspace
01010     m_workspaces_list.pop_back();       
01011     delete wkspc;
01012 
01013 
01014     updateNetizenWorkspaceCount();
01015     saveWorkspaces(m_workspaces_list.size());
01016 
01017     return m_workspaces_list.size();
01018 }
01019 
01020 
01021 void BScreen::changeWorkspaceID(unsigned int id) {
01022 
01023     if (! m_current_workspace || id >= m_workspaces_list.size() ||
01024         id == m_current_workspace->workspaceID())
01025         return;
01026 
01027     FbTk::App::instance()->sync(true);
01028 
01029     WinClient *focused_client = Fluxbox::instance()->getFocusedWindow();
01030     FluxboxWindow *focused = 0;
01031     if (focused_client)
01032         focused = focused_client->fbwindow();
01033         
01034     if (focused && focused->isMoving()) {
01035         if (doOpaqueMove())
01036             reassociateWindow(focused, id, true);
01037         // don't reassociate if not opaque moving
01038         focused->pauseMoving();
01039     }
01040 
01041     // reassociate all windows that are stuck to the new workspace
01042     Workspace *wksp = currentWorkspace();
01043     Workspace::Windows wins = wksp->windowList();
01044     Workspace::Windows::iterator it = wins.begin();
01045     for (; it != wins.end(); ++it) {
01046         if ((*it)->isStuck()) {
01047             reassociateWindow(*it, id, true);
01048         }
01049     }
01050 
01051     currentWorkspace()->hideAll();
01052 
01053     workspacemenu->setItemSelected(currentWorkspace()->workspaceID() + 2, false);
01054 
01055     // set new workspace
01056     m_current_workspace = getWorkspace(id);
01057 
01058     workspacemenu->setItemSelected(currentWorkspace()->workspaceID() + 2, true);
01059     // This is a little tricks to reduce flicker 
01060     // this way we can set focus pixmap on frame before we show it
01061     // and using ExposeEvent to redraw without flicker
01062     /*
01063       WinClient *win = getLastFocusedWindow(currentWorkspaceID());
01064       if (win && win->fbwindow())
01065       win->fbwindow()->setFocusFlag(true);
01066     */
01067 
01068     currentWorkspace()->showAll();
01069 
01070     if (focused && (focused->isStuck() || focused->isMoving()))
01071         focused->setInputFocus();
01072     else
01073         Fluxbox::instance()->revertFocus(*this);
01074 
01075     if (focused && focused->isMoving())
01076         focused->resumeMoving();
01077 
01078     updateNetizenCurrentWorkspace();
01079 
01080 }
01081 
01082 
01083 void BScreen::sendToWorkspace(unsigned int id, FluxboxWindow *win, bool changeWS) {
01084     if (! m_current_workspace || id >= m_workspaces_list.size())
01085         return;
01086 
01087     if (!win) {
01088         WinClient *client = Fluxbox::instance()->getFocusedWindow();
01089         if (client) 
01090             win = client->fbwindow();
01091     }
01092 
01093 
01094     FbTk::App::instance()->sync(true);
01095 
01096     if (win && &win->screen() == this &&
01097         (! win->isStuck())) {
01098 
01099         // if iconified, deiconify it before we send it somewhere
01100         if (win->isIconic())
01101             win->deiconify();
01102 
01103         // if the window isn't on current workspace, hide it
01104         if (id != currentWorkspace()->workspaceID())
01105             win->withdraw();
01106 
01107         reassociateWindow(win, id, true);
01108 
01109         // if the window is on current workspace, show it.
01110         if (id == currentWorkspace()->workspaceID())
01111             win->deiconify(false, false);
01112 
01113         // change workspace ?
01114         if (changeWS && id != currentWorkspace()->workspaceID()) {
01115             changeWorkspaceID(id);
01116             win->setInputFocus();
01117         }
01118 
01119     }
01120 
01121 }
01122 
01123 
01124 void BScreen::addNetizen(Window win) {
01125     Netizen *net = new Netizen(*this, win);
01126     m_netizen_list.push_back(net);
01127 
01128     net->sendWorkspaceCount();
01129     net->sendCurrentWorkspace();
01130 
01131     // send all windows to netizen
01132     Workspaces::iterator it = m_workspaces_list.begin();
01133     Workspaces::iterator it_end = m_workspaces_list.end();
01134     for (; it != it_end; ++it) {
01135         Workspace::Windows::iterator win_it = (*it)->windowList().begin();
01136         Workspace::Windows::iterator win_it_end = (*it)->windowList().end();
01137         for (; win_it != win_it_end; ++win_it) {
01138             net->sendWindowAdd((*win_it)->clientWindow(), 
01139                                (*it)->workspaceID());
01140         }
01141     }
01142 
01143     Window f = ((Fluxbox::instance()->getFocusedWindow()) ?
01144         Fluxbox::instance()->getFocusedWindow()->window() : None);
01145     net->sendWindowFocus(f);
01146 }
01147 
01148 void BScreen::removeNetizen(Window w) {
01149     Netizens::iterator it = m_netizen_list.begin();
01150     Netizens::iterator it_end = m_netizen_list.end();
01151     for (; it != it_end; ++it) {
01152         if ((*it)->window() == w) {
01153             Netizen *n = *it;
01154             delete n;
01155             m_netizen_list.erase(it);           
01156             break;
01157         }
01158     }
01159 }
01160 
01161 
01162 void BScreen::updateNetizenCurrentWorkspace() {
01163     m_currentworkspace_sig.notify();
01164     for_each(m_netizen_list.begin(),
01165              m_netizen_list.end(),
01166              mem_fun(&Netizen::sendCurrentWorkspace));
01167 }
01168 
01169 
01170 void BScreen::updateNetizenWorkspaceCount() {
01171     for_each(m_netizen_list.begin(),
01172              m_netizen_list.end(),
01173              mem_fun(&Netizen::sendWorkspaceCount));
01174 
01175     m_workspacecount_sig.notify();  
01176 }
01177 
01178 
01179 void BScreen::updateNetizenWindowFocus() {
01180     Window f = ((Fluxbox::instance()->getFocusedWindow()) ?
01181                 Fluxbox::instance()->getFocusedWindow()->window() : None);
01182     for_each(m_netizen_list.begin(),
01183              m_netizen_list.end(),
01184              bind2nd(mem_fun(&Netizen::sendWindowFocus), f));
01185 }
01186 
01187 
01188 void BScreen::updateNetizenWindowAdd(Window w, unsigned long p) {
01189     Netizens::iterator it = m_netizen_list.begin();
01190     Netizens::iterator it_end = m_netizen_list.end();
01191     for (; it != it_end; ++it) {
01192         (*it)->sendWindowAdd(w, p);
01193     }
01194 
01195     m_clientlist_sig.notify();
01196     
01197 }
01198 
01199 
01200 void BScreen::updateNetizenWindowDel(Window w) {
01201     for_each(m_netizen_list.begin(),
01202              m_netizen_list.end(),
01203              bind2nd(mem_fun(&Netizen::sendWindowDel), w));
01204     
01205     m_clientlist_sig.notify();
01206 }
01207 
01208 
01209 void BScreen::updateNetizenWindowRaise(Window w) {
01210     for_each(m_netizen_list.begin(),
01211              m_netizen_list.end(),
01212              bind2nd(mem_fun(&Netizen::sendWindowRaise), w));
01213 }
01214 
01215 
01216 void BScreen::updateNetizenWindowLower(Window w) {
01217     for_each(m_netizen_list.begin(),
01218              m_netizen_list.end(),
01219              bind2nd(mem_fun(&Netizen::sendWindowLower), w));
01220 }
01221 
01222 void BScreen::updateNetizenConfigNotify(XEvent &e) {
01223     Netizens::iterator it = m_netizen_list.begin();
01224     Netizens::iterator it_end = m_netizen_list.end();
01225     for (; it != it_end; ++it)
01226         (*it)->sendConfigNotify(e);
01227 }
01228 
01229 FluxboxWindow *BScreen::createWindow(Window client) {
01230     FbTk::App::instance()->sync(false);
01231 
01232 #ifdef SLIT
01233 #ifdef KDE
01234         //Check and see if client is KDE dock applet.
01235         //If so add to Slit
01236         bool iskdedockapp = false;
01237         Atom ajunk;
01238         int ijunk;
01239         unsigned long *data = 0, uljunk;
01240         Display *disp = FbTk::App::instance()->display();
01241         // Check if KDE v2.x dock applet
01242         if (XGetWindowProperty(disp, client,
01243                                XInternAtom(FbTk::App::instance()->display(), 
01244                                            "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False),
01245                                0l, 1l, False,
01246                                XA_WINDOW, &ajunk, &ijunk, &uljunk,
01247                                &uljunk, (unsigned char **) &data) == Success) {
01248                     
01249             if (data)
01250                 iskdedockapp = True;
01251             XFree((void *) data);
01252             data = 0;
01253         }
01254 
01255         // Check if KDE v1.x dock applet
01256         if (!iskdedockapp) {
01257             Atom kwm1 = XInternAtom(FbTk::App::instance()->display(), 
01258                                     "KWM_DOCKWINDOW", False);
01259             if (XGetWindowProperty(disp, client,
01260                                    kwm1, 0l, 1l, False,
01261                                    kwm1, &ajunk, &ijunk, &uljunk,
01262                                    &uljunk, (unsigned char **) &data) == Success && data) {
01263                 iskdedockapp = (data && data[0] != 0);
01264                 XFree((void *) data);
01265                 data = 0;
01266             }
01267         }
01268 
01269         if (iskdedockapp) {
01270             XSelectInput(disp, client, StructureNotifyMask);
01271 
01272             if (slit())
01273                 slit()->addClient(client);
01274 
01275             return 0; // dont create a FluxboxWindow for this one
01276         }
01277 #endif // KDE
01278 #endif // SLIT
01279 
01280     WinClient *winclient = new WinClient(client, *this);
01281 
01282     if (winclient->initial_state == WithdrawnState) {
01283         delete winclient;
01284 #ifdef SLIT
01285         slit()->addClient(client);
01286 #endif // SLIT
01287         return 0;
01288     }
01289 
01290     bool new_win = false;
01291 
01292     // check if it should be grouped with something else
01293     FluxboxWindow *win;
01294     if ((win = findGroupLeft(*winclient)) != 0) {
01295         win->attachClient(*winclient);
01296         Fluxbox::instance()->attachSignals(*winclient);
01297     } else {
01298 
01299         Fluxbox::instance()->attachSignals(*winclient);
01300         if (winclient->fbwindow()) // may have been set in an atomhandler
01301             win = winclient->fbwindow();
01302         else {
01303             win = new FluxboxWindow(*winclient,
01304                                     winFrameTheme(),
01305                                     *layerManager().getLayer(Fluxbox::instance()->getNormalLayer()));
01306             
01307             new_win = true;
01308 
01309             if (!win->isManaged()) {
01310                 delete win;
01311                 return 0;
01312             } 
01313         }
01314     }
01315                 
01316     // always put on end of focused list, if it gets focused it'll get pushed up
01317     // there is only the one win client at this stage
01318     if (doFocusNew())
01319         focused_list.push_front(&win->winClient());
01320     else
01321         focused_list.push_back(&win->winClient());
01322     
01323     if (new_win) {
01324         Fluxbox::instance()->attachSignals(*win);
01325     }
01326 
01327     // we also need to check if another window expects this window to the left
01328     // and if so, then join it.
01329     FluxboxWindow *otherwin = 0;
01330     // TODO: does this do the right stuff focus-wise?
01331     if ((otherwin = findGroupRight(*winclient)) && otherwin != win) {
01332         win->attachClient(otherwin->winClient());
01333     }
01334 
01335     if (!win->isIconic() && (win->workspaceNumber() == currentWorkspaceID() || win->isStuck())) {
01336         win->show();
01337     }
01338 
01339     FbTk::App::instance()->sync(false);
01340     return win;
01341 }
01342 
01343 FluxboxWindow *BScreen::createWindow(WinClient &client) {
01344     FluxboxWindow *win = new FluxboxWindow(client,
01345                                            winFrameTheme(),
01346                                            *layerManager().getLayer(Fluxbox::instance()->getNormalLayer()));
01347 #ifdef SLIT
01348     if (win->initialState() == WithdrawnState)
01349         slit()->addClient(win->clientWindow());
01350 #endif // SLIT
01351     if (!win->isManaged()) {
01352         delete win;
01353         return 0;
01354     }
01355     // don't add to focused_list, as it should already be in there (since the
01356     // WinClient already exists).
01357     
01358     Fluxbox::instance()->attachSignals(*win);
01359     // winclient actions should have been setup when the WinClient was created
01360     if (win->workspaceNumber() == currentWorkspaceID() || win->isStuck())
01361         win->show();      
01362 
01363     return win;
01364 }
01365 
01366 Strut *BScreen::requestStrut(int left, int right, int top, int bottom) {
01367     Strut *str = new Strut(left, right, top, bottom);
01368     m_strutlist.push_back(str);
01369     return str;
01370 }
01371 
01372 void BScreen::clearStrut(Strut *str) {
01373     if (str == 0)
01374         return;
01375     // find strut and erase it
01376     std::list<Strut *>::iterator pos = find(m_strutlist.begin(),
01377                                             m_strutlist.end(),
01378                                             str);
01379     if (pos == m_strutlist.end())
01380         return;
01381     m_strutlist.erase(pos);
01382     delete str;
01383 }
01384 
01386 namespace {
01387 class MaxArea {
01388 public:
01389     MaxArea(Strut &max_area):m_max_area(max_area) { }
01390     void operator ()(const Strut *str) {
01391         static int left, right, bottom, top;
01392         left = std::max(m_max_area.left(), str->left());
01393         right = std::max(m_max_area.right(), str->right());
01394         bottom = std::max(m_max_area.bottom(), str->bottom());
01395         top = std::max(m_max_area.top(), str->top());
01396         m_max_area = Strut(left, right, top, bottom);
01397     }
01398 private:
01399     Strut &m_max_area;
01400 };
01401 
01402 }; // end anonymous namespace
01403 
01404 void BScreen::updateAvailableWorkspaceArea() {
01405     // find max of left, right, top and bottom and set avaible workspace area
01406 
01407     // clear old area
01408     m_available_workspace_area.reset(new Strut(0, 0, 0, 0));
01409     
01410     // calculate max area
01411     for_each(m_strutlist.begin(),
01412              m_strutlist.end(),
01413              MaxArea(*m_available_workspace_area.get()));
01414 }
01415 
01416 void BScreen::addWorkspaceName(const char *name) {
01417     m_workspace_names.push_back(name);
01418 }
01419 
01420 
01421 string BScreen::getNameOfWorkspace(unsigned int workspace) const {
01422     if (workspace < m_workspace_names.size())
01423         return m_workspace_names[workspace];
01424     else
01425         return "";
01426 }
01427 
01428 void BScreen::reassociateWindow(FluxboxWindow *w, unsigned int wkspc_id, 
01429                                 bool ignore_sticky) {
01430     if (w == 0)
01431         return;
01432 
01433     if (wkspc_id >= getCount())
01434         wkspc_id = currentWorkspace()->workspaceID();
01435 
01436     if (!w->isIconic() && w->workspaceNumber() == wkspc_id)
01437         return;
01438 
01439 
01440     if (w->isIconic()) {
01441         removeIcon(w);
01442         getWorkspace(wkspc_id)->addWindow(*w);
01443     } else if (ignore_sticky || ! w->isStuck()) {
01444         getWorkspace(w->workspaceNumber())->removeWindow(w);
01445         getWorkspace(wkspc_id)->addWindow(*w);
01446     }
01447 }
01448 
01449 
01450 void BScreen::nextFocus(int opts) {
01451     const int num_windows = currentWorkspace()->numberOfWindows();
01452 
01453     if (num_windows < 1)
01454         return;
01455 
01456     if (!(opts & CYCLELINEAR)) {
01457         if (!cycling_focus) {
01458             cycling_focus = True;
01459             cycling_window = focused_list.begin();
01460             cycling_last = 0;
01461         } else {
01462             // already cycling, so restack to put windows back in their proper order
01463             m_layermanager.restack();
01464         }
01465         // if it is stacked, we want the highest window in the focused list
01466         // that is on the same workspace
01467         FocusedWindows::iterator it = cycling_window;
01468         const FocusedWindows::iterator it_end = focused_list.end();
01469 
01470         while (true) {
01471             ++it;
01472             if (it == it_end) {
01473                 it = focused_list.begin();
01474             }
01475             // give up [do nothing] if we reach the current focused again
01476             if ((*it) == (*cycling_window)) {
01477                 break;
01478             }
01479 
01480             FluxboxWindow *fbwin = (*it)->m_win;
01481             if (fbwin && !fbwin->isIconic() &&
01482                 (fbwin->isStuck() 
01483                  || fbwin->workspaceNumber() == currentWorkspaceID())) {
01484                 // either on this workspace, or stuck
01485 
01486                 // keep track of the originally selected window in a set
01487                 WinClient &last_client = fbwin->winClient();
01488 
01489                 if (! (doSkipWindow(**it, opts) || !fbwin->setCurrentClient(**it)) ) {
01490                     // moved onto a new fbwin
01491                     if (!cycling_last || cycling_last->fbwindow() != fbwin) {
01492                         if (cycling_last)
01493                             // set back to orig current Client in that fbwin
01494                             cycling_last->fbwindow()->setCurrentClient(*cycling_last, false);
01495                         cycling_last = &last_client;
01496                     }
01497                     fbwin->tempRaise();
01498                     break;
01499                 }
01500             }
01501         }
01502         cycling_window = it;
01503     } else { // not stacked cycling
01504         // I really don't like this, but evidently some people use it(!)
01505         Workspace *wksp = currentWorkspace();
01506         Workspace::Windows &wins = wksp->windowList();
01507         Workspace::Windows::iterator it = wins.begin();
01508 
01509         FluxboxWindow *focused_group = 0;
01510         // start from the focused window
01511         bool have_focused = false;
01512         WinClient *focused = Fluxbox::instance()->getFocusedWindow();
01513         if (focused != 0) {
01514             if (focused->screen().screenNumber() == screenNumber()) {
01515                 have_focused = true;
01516                 focused_group = focused->fbwindow();
01517             }
01518         }
01519 
01520         if (!have_focused) {
01521             focused_group = (*it);
01522         } else {
01523             // get focused window iterator
01524             for (; it != wins.end() && (*it) != focused_group; ++it) 
01525                 continue;
01526         }
01527 
01528         do {
01529             ++it;
01530             if (it == wins.end())
01531                 it = wins.begin();
01532             // see if the window should be skipped
01533             if (! (doSkipWindow((*it)->winClient(), opts) || !(*it)->setInputFocus()) )
01534                 break;
01535         } while ((*it) != focused_group);
01536 
01537         if ((*it) != focused_group && it != wins.end())
01538             (*it)->raise();
01539     }
01540 
01541 }
01542 
01543 
01544 void BScreen::prevFocus(int opts) {
01545     int num_windows = currentWorkspace()->numberOfWindows();
01546     
01547     if (num_windows < 1)
01548         return;
01549 
01550     if (!(opts & CYCLELINEAR)) {
01551         if (!cycling_focus) {
01552             cycling_focus = true;
01553             cycling_window = focused_list.end();
01554             cycling_last = 0;
01555         } else {
01556             // already cycling, so restack to put windows back in their proper order
01557             m_layermanager.restack();
01558         }
01559         // if it is stacked, we want the highest window in the focused list
01560         // that is on the same workspace
01561         FocusedWindows::iterator it = cycling_window;
01562         FocusedWindows::iterator it_end = focused_list.end();
01563 
01564         while (true) {
01565             --it;
01566             if (it == it_end) {
01567                 it = focused_list.end();
01568                 --it;
01569             }
01570             // give up [do nothing] if we reach the current focused again
01571             if ((*it) == (*cycling_window)) {
01572                 break;
01573             }
01574 
01575             FluxboxWindow *fbwin = (*it)->m_win;
01576             if (fbwin && !fbwin->isIconic() &&
01577                 (fbwin->isStuck() 
01578                  || fbwin->workspaceNumber() == currentWorkspaceID())) {
01579                 // either on this workspace, or stuck
01580 
01581                 // keep track of the originally selected window in a set
01582                 WinClient &last_client = fbwin->winClient();
01583 
01584 
01585                 if (! (doSkipWindow(**it, opts) || !fbwin->setCurrentClient(**it)) ) {
01586                     // moved onto a new fbwin
01587                     if (!cycling_last || cycling_last->fbwindow() != fbwin) {
01588                         if (cycling_last)
01589                             // set back to orig current Client in that fbwin
01590                             cycling_last->fbwindow()->setCurrentClient(*cycling_last, false);
01591                         cycling_last = &last_client;
01592                     }
01593                     fbwin->tempRaise();
01594                     break;
01595                 }
01596             }
01597         }
01598         cycling_window = it;
01599     } else { // not stacked cycling
01600             
01601         Workspace *wksp = currentWorkspace();
01602         Workspace::Windows &wins = wksp->windowList();
01603         Workspace::Windows::iterator it = wins.begin();
01604             
01605         FluxboxWindow *focused_group = 0;
01606         // start from the focused window
01607         bool have_focused = false;
01608         WinClient *focused = Fluxbox::instance()->getFocusedWindow();
01609         if (focused != 0) {
01610             if (focused->screen().screenNumber() == screenNumber()) {
01611                 have_focused = true;
01612                 focused_group = focused->fbwindow();
01613             }
01614         }
01615 
01616         if (!have_focused) {
01617             focused_group = (*it);
01618         } else {
01619             //get focused window iterator
01620             for (; it != wins.end() && (*it) != focused_group; ++it) 
01621                 continue;
01622         }
01623 
01624         do {
01625             if (it == wins.begin())
01626                 it = wins.end();
01627             --it;
01628             // see if the window should be skipped
01629             if (! (doSkipWindow((*it)->winClient(), opts) || !(*it)->setInputFocus()) )
01630                 break;
01631         } while ((*it) != focused_group);
01632             
01633         if ((*it) != focused_group && it != wins.end())
01634             (*it)->raise();
01635     }
01636 }
01637 
01638 
01639 void BScreen::raiseFocus() {
01640     bool have_focused = false;
01641     Fluxbox &fb = *Fluxbox::instance();
01642     // set have_focused if the currently focused window 
01643     // is on this screen
01644     if (fb.getFocusedWindow()) {
01645         if (fb.getFocusedWindow()->screen().screenNumber() == screenNumber()) {
01646             have_focused = true;
01647         }
01648     }
01649 
01650     // if we have a focused window on this screen and
01651     // number of windows is greater than one raise the focused window
01652     if (currentWorkspace()->numberOfWindows() > 1 && have_focused)
01653         fb.getFocusedWindow()->raise();
01654 }
01655 
01656 void BScreen::setFocusedWindow(WinClient &winclient) {
01657     // raise newly focused window to the top of the focused list
01658     if (!cycling_focus) { // don't change the order if we're cycling
01659         focused_list.remove(&winclient);
01660         focused_list.push_front(&winclient);
01661         cycling_window = focused_list.begin();
01662     }
01663 }
01664 
01665 void BScreen::dirFocus(FluxboxWindow &win, FocusDir dir) {
01666     // change focus to the window in direction dir from the given window
01667 
01668     // we scan through the list looking for the window that is "closest"
01669     // in the given direction
01670 
01671     FluxboxWindow *foundwin = 0;
01672     int weight = 999999, exposure = 0; // extreme values
01673     int borderW = winFrameTheme().border().width(),
01674         top = win.y(), 
01675         bottom = win.y() + win.height() + 2*borderW,
01676         left = win.x(),
01677         right = win.x() + win.width() + 2*borderW;
01678 
01679     Workspace::Windows &wins = currentWorkspace()->windowList();
01680     Workspace::Windows::iterator it = wins.begin();
01681     for (; it != wins.end(); ++it) {
01682         if ((*it) == &win) continue; // skip slef
01683         
01684         // we check things against an edge, and within the bounds (draw a picture)
01685         int edge=0, upper=0, lower=0, oedge=0, oupper=0, olower=0;
01686 
01687         int otop = (*it)->y(), 
01688             obottom = (*it)->y() + (*it)->height() + 2*borderW,
01689             oleft = (*it)->x(),
01690             oright = (*it)->x() + (*it)->width() + 2*borderW;
01691         // check if they intersect
01692         switch (dir) {
01693         case FOCUSUP:
01694             edge = obottom;
01695             oedge = bottom;
01696             upper = left;
01697             oupper = oleft;
01698             lower = right;
01699             olower = oright;
01700             break;
01701         case FOCUSDOWN:
01702             edge = top;
01703             oedge = otop;
01704             upper = left;
01705             oupper = oleft;
01706             lower = right;
01707             olower = oright;
01708             break;
01709         case FOCUSLEFT:
01710             edge = oright;
01711             oedge = right;
01712             upper = top;
01713             oupper = otop;
01714             lower = bottom;
01715             olower = obottom;
01716             break;
01717         case FOCUSRIGHT:
01718             edge = left;
01719             oedge = oleft;
01720             upper = top;
01721             oupper = otop;
01722             lower = bottom;
01723             olower = obottom;
01724             break;
01725         }
01726 
01727         if (oedge < edge) continue; // not in the right direction
01728         if (olower <= upper || oupper >= lower) {
01729             // outside our horz bounds, get a heavy weight penalty
01730             int myweight = 100000 + oedge - edge + abs(upper-oupper)+abs(lower-olower);
01731             if (myweight < weight) {
01732                 foundwin = *it;
01733                 exposure = 0;
01734                 weight = myweight;
01735             }
01736         } else if ((oedge - edge) < weight) {
01737             foundwin = *it;
01738             weight = oedge - edge;
01739             exposure = ((lower < olower)?lower:olower) - ((upper > oupper)?upper:oupper);
01740         } else if (foundwin && oedge - edge == weight) {
01741             int myexp = ((lower < olower)?lower:olower) - ((upper > oupper)?upper:oupper);
01742             if (myexp > exposure) {
01743                 foundwin = *it;
01744                 // weight is same
01745                 exposure = myexp;
01746             }
01747         } // else not improvement
01748     }
01749 
01750     if (foundwin) 
01751         foundwin->setInputFocus();
01752 }
01753 
01754 void BScreen::initMenu() {
01755     I18n *i18n = I18n::instance();
01756     
01757     if (m_rootmenu.get()) {
01758         // since all menus in root is submenus in m_rootmenu
01759         // just remove every item in m_rootmenu and then clear m_rootmenu_list
01760         while (m_rootmenu->numberOfItems())
01761             m_rootmenu->remove(0); 
01762         m_rootmenu_list.clear();
01763 
01764     } else
01765         m_rootmenu.reset(createMenu(""));
01766 
01767     bool defaultMenu = true;
01768     Fluxbox * const fb = Fluxbox::instance();
01769     if (fb->getMenuFilename().size() > 0) {
01770         std::string menufilestr = fb->getMenuFilename();
01771         menufilestr = FbTk::StringUtil::expandFilename(menufilestr);
01772         ifstream menu_file(menufilestr.c_str());
01773 
01774         if (!menu_file.fail()) {
01775             if (! menu_file.eof()) {
01776                 string line;
01777                 int row = 0;
01778                 while (getline(menu_file, line) && ! menu_file.eof()) {
01779                     row++;
01780                     if (line[0] != '#') {
01781                         string key;
01782                         int pos=0;
01783                         int err = FbTk::StringUtil::
01784                             getStringBetween(key, 
01785                                              line.c_str(), 
01786                                              '[', ']');
01787                         
01788                         if (key == "begin") {
01789                             pos += err;
01790                             string label;
01791                             err = FbTk::StringUtil::
01792                                 getStringBetween(label, 
01793                                                  line.c_str()+pos, 
01794                                                  '(', ')');
01795                             if (err>0) {
01796                                 m_rootmenu->setLabel(label.c_str());
01797                                 defaultMenu = parseMenuFile(menu_file, *m_rootmenu.get(), row);
01798                             } else
01799                                 cerr<<"Error in menufile. Line("<<row<<")"<<endl;
01800                             break;
01801                         }
01802                     }
01803                 }
01804             } else {
01805                 fprintf(stderr,
01806                         i18n->getMessage(
01807                                          FBNLS::ScreenSet, FBNLS::ScreenEmptyMenuFile,
01808                                          "%s: Empty menu file"),
01809                         menufilestr.c_str());
01810             }
01811             menu_file.close();
01812         } else
01813             perror(menufilestr.c_str());
01814     }
01815 
01816     if (defaultMenu) {
01817         FbTk::RefCount<FbTk::Command> restart_fb(new FbCommands::RestartFluxboxCmd(""));
01818         FbTk::RefCount<FbTk::Command> exit_fb(new FbCommands::ExitFluxboxCmd());
01819         FbTk::RefCount<FbTk::Command> execute_xterm(new FbCommands::ExecuteCmd("xterm", screenNumber()));
01820         m_rootmenu->setInternalMenu();
01821         m_rootmenu->insert(i18n->getMessage(FBNLS::ScreenSet, FBNLS::Screenxterm,
01822                                             "xterm"),
01823                            execute_xterm);
01824         m_rootmenu->insert(i18n->getMessage(FBNLS::ScreenSet, FBNLS::ScreenRestart,
01825                                             "Restart"),
01826                            restart_fb);
01827         m_rootmenu->insert(i18n->getMessage(FBNLS::ScreenSet, FBNLS::ScreenExit,
01828                                             "Exit"),
01829                            exit_fb