// // WindowManager.cc for pekwm // Copyright (C) 2002-2005 Claes Nasten // // windowmanager.cc for aewm++ // Copyright (C) 2000 Frank Hale // http://sapphire.sourceforge.net/ // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "../config.h" #include "PWinObj.hh" #include "PDecor.hh" #include "Frame.hh" #include "Client.hh" #include "WindowManager.hh" #include "PScreen.hh" #include "ScreenResources.hh" #include "ActionHandler.hh" #include "AutoProperties.hh" #include "Config.hh" #include "Theme.hh" #include "PFont.hh" #include "PTexture.hh" #include "ColorHandler.hh" #include "FontHandler.hh" #include "PixmapHandler.hh" #include "TextureHandler.hh" #include "Viewport.hh" #include "Workspaces.hh" #include "Util.hh" #include "RegexString.hh" #include "KeyGrabber.hh" #ifdef HARBOUR #include "Harbour.hh" #include "DockApp.hh" #endif // HARBOUR #include "CmdDialog.hh" #include "StatusWindow.hh" #include "PMenu.hh" // we need this for the "Alt+Tabbing" #ifdef MENUS #include "WORefMenu.hh" #include "ActionMenu.hh" #include "FrameListMenu.hh" #include "DecorMenu.hh" #ifdef HARBOUR #include "HarbourMenu.hh" #endif // HARBOUR #endif // MENUS #include #include #include #include #include extern "C" { #include #include #include #include #include #include #ifdef HAVE_XRANDR #include #endif // HAVE_XRANDR } using std::cout; using std::cerr; using std::endl; using std::string; using std::list; using std::vector; using std::map; using std::mem_fun; using std::find; const string WindowManager::_wm_name = string("pekwm"); WindowManager *wm; //! @brief void sigHandler(int signal) { switch (signal) { case SIGHUP: wm->reload(); break; case SIGINT: case SIGTERM: wm->shutdown(); break; case SIGCHLD: wait(NULL); break; } } //! @brief int handleXError(Display *dpy, XErrorEvent *e) { if ((e->error_code == BadAccess) && (e->resourceid == (RootWindow(dpy, DefaultScreen(dpy))))) { cerr << "pekwm: root window unavailable, can't start!" << endl; exit(1); } #ifdef DEBUG else { char error_buf[256]; XGetErrorText(dpy, e->error_code, error_buf, 256); cerr << "XError: " << error_buf << " id: " << e->resourceid << endl; } #endif // DEBUG return 0; } // WindowManager::EdgeWO //! @brief EdgeWO constructor WindowManager::EdgeWO::EdgeWO(Display *dpy, Window root, EdgeType edge) : PWinObj(dpy), _edge(edge) { _type = WO_SCREEN_EDGE; _layer = LAYER_NONE; // hack, goes over LAYER_MENU _sticky = true; // don't map/unmap _iconified = true; // hack, to be ignored when placing _focusable = false; // focusing input only windows crashes X XSetWindowAttributes sattr; sattr.override_redirect = True; sattr.event_mask = EnterWindowMask|LeaveWindowMask|ButtonPressMask|ButtonReleaseMask; _window = XCreateWindow(_dpy, root, 0, 0, 1, 1, 0, CopyFromParent, InputOnly, CopyFromParent, CWOverrideRedirect|CWEventMask, &sattr); _wo_list.push_back(this); } //! @brief EdgeWO destructor WindowManager::EdgeWO::~EdgeWO(void) { _wo_list.remove(this); XDestroyWindow(_dpy, _window); } //! @brief void WindowManager::EdgeWO::mapWindow(void) { if (_mapped) return; PWinObj::mapWindow(); _iconified = true; } //! @brief ActionEvent* WindowManager::EdgeWO::handleEnterEvent(XCrossingEvent *ev) { return ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_ENTER, Config::instance()->getEdgeListFromPosition(_edge)); } //! @brief ActionEvent* WindowManager::EdgeWO::handleButtonPress(XButtonEvent *ev) { return ActionHandler::findMouseAction(ev->button, ev->state, MOUSE_EVENT_PRESS, Config::instance()->getEdgeListFromPosition(_edge)); } //! @brief ActionEvent* WindowManager::EdgeWO::handleButtonRelease(XButtonEvent *ev) { MouseEventType mb = MOUSE_EVENT_RELEASE; // first we check if it's a double click if (PScreen::instance()->isDoubleClick(ev->window, ev->button - 1, ev->time, Config::instance()->getDoubleClickTime())) { PScreen::instance()->setLastClickID(ev->window); PScreen::instance()->setLastClickTime(ev->button - 1, 0); mb = MOUSE_EVENT_DOUBLE; } else { PScreen::instance()->setLastClickID(ev->window); PScreen::instance()->setLastClickTime(ev->button - 1, ev->time); } return ActionHandler::findMouseAction(ev->button, ev->state, mb, Config::instance()->getEdgeListFromPosition(_edge)); } // WindowManager::RootWO //! @brief RootWO constructor WindowManager::RootWO::RootWO(Display *dpy, Window root) : PWinObj(dpy) { _type = WO_SCREEN_ROOT; _layer = LAYER_NONE; _mapped = true; _window = root; _gm.width = PScreen::instance()->getWidth(); _gm.height = PScreen::instance()->getHeight(); _wo_list.push_back(this); } //! @brief RootWO destructor WindowManager::RootWO::~RootWO(void) { _wo_list.remove(this); } //! @brief ActionEvent* WindowManager::RootWO::handleButtonPress(XButtonEvent *ev) { return ActionHandler::findMouseAction(ev->button, ev->state, MOUSE_EVENT_PRESS, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_ROOT)); } //! @brief ActionEvent* WindowManager::RootWO::handleButtonRelease(XButtonEvent *ev) { MouseEventType mb = MOUSE_EVENT_RELEASE; // first we check if it's a double click if (PScreen::instance()->isDoubleClick(ev->window, ev->button - 1, ev->time, Config::instance()->getDoubleClickTime())) { PScreen::instance()->setLastClickID(ev->window); PScreen::instance()->setLastClickTime(ev->button - 1, 0); mb = MOUSE_EVENT_DOUBLE; } else { PScreen::instance()->setLastClickID(ev->window); PScreen::instance()->setLastClickTime(ev->button - 1, ev->time); } return ActionHandler::findMouseAction(ev->button, ev->state, mb, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_ROOT)); } //! @brief ActionEvent* WindowManager::RootWO::handleMotionEvent(XMotionEvent *ev) { uint button = PScreen::instance()->getButtonFromState(ev->state); return ActionHandler::findMouseAction(button, ev->state, MOUSE_EVENT_MOTION, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_ROOT)); } //! @brief ActionEvent* WindowManager::RootWO::handleEnterEvent(XCrossingEvent *ev) { return ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_ENTER, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_ROOT)); } //! @brief ActionEvent* WindowManager::RootWO::handleLeaveEvent(XCrossingEvent *ev) { return ActionHandler::findMouseAction(BUTTON_ANY, ev->state, MOUSE_EVENT_LEAVE, Config::instance()->getMouseActionList(MOUSE_ACTION_LIST_ROOT)); } // WindowManager //! @brief Constructor for WindowManager class WindowManager::WindowManager(const std::string &command_line, const std::string &config_file) : _screen(NULL), _screen_resources(NULL), _keygrabber(NULL), _config(NULL), _color_handler(NULL), _font_handler(NULL), _texture_handler(NULL), _theme(NULL), _action_handler(NULL), _autoproperties(NULL), _workspaces(NULL), #ifdef HARBOUR _harbour(NULL), #endif // HARBOUR _cmd_dialog(NULL), _status_window(NULL), _command_line(command_line), _startup(false), _shutdown(false), _tagged_frame(NULL), _tag_activate(true), _allow_grouping(true), _root_wo(NULL), _pekwm_atoms(NULL), _icccm_atoms(NULL), _ewmh_atoms(NULL) { ::wm = this; struct sigaction act; // Set up the signal handlers. act.sa_handler = sigHandler; act.sa_mask = sigset_t(); act.sa_flags = SA_NOCLDSTOP | SA_NODEFER; sigaction(SIGTERM, &act, NULL); sigaction(SIGINT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGCHLD, &act, NULL); // construct _config = new Config(); _config->load(config_file); setupDisplay(); scanWindows(); setupFrameIds(); // add all frames to the MRU list _mru_list.resize (_frame_list.size ()); copy (_frame_list.begin (), _frame_list.end (), _mru_list.begin ()); // make sure windows are inside the virtual viewports for (uint i = 0; i < _workspaces->size(); ++i) { _workspaces->getViewport(i)->makeAllInsideVirtual(); } execStartFile(); doEventLoop(); } //! @brief WindowManager destructor WindowManager::~WindowManager(void) { cleanup(); if (_root_wo != NULL) delete _root_wo; #ifdef HARBOUR if (_harbour) { delete _harbour; } #endif // HARBOUR if (_cmd_dialog) delete _cmd_dialog; if (_status_window) delete _status_window; if (_action_handler) delete _action_handler; if (_autoproperties) delete _autoproperties; #ifdef MENUS map::iterator it(_menus.begin()); for (; it != _menus.end(); ++it) delete it->second; _menus.clear(); #endif // MENUS if (_pekwm_atoms != NULL) delete _pekwm_atoms; if (_icccm_atoms != NULL) delete _icccm_atoms; if (_ewmh_atoms != NULL) delete _ewmh_atoms; if (_keygrabber != NULL) delete _keygrabber; if (_workspaces != NULL) delete _workspaces; if (_config != NULL) delete _config; if (_theme != NULL) delete _theme; if (_color_handler != NULL) delete _color_handler; if (_font_handler != NULL) delete _font_handler; if (_texture_handler != NULL) delete _texture_handler; if (_screen_resources != NULL) delete _screen_resources; if (_screen != NULL) { Display *dpy = _screen->getDpy(); delete _screen; XCloseDisplay(dpy); } } //! @brief Checks if the start file is executable then execs it. void WindowManager::execStartFile(void) { string start_file(_config->getStartFile()); bool exec = Util::isExecutable(start_file); if (!exec) { start_file = SYSCONFDIR "/start"; exec = Util::isExecutable(start_file); } if (exec) Util::forkExec(start_file); } //! @brief Cleans up, Maps windows etc. void WindowManager::cleanup(void) { // update all nonactive clients properties list::iterator it_f(_frame_list.begin()); for (; it_f != _frame_list.end(); ++it_f) { (*it_f)->updateInactiveChildInfo(); } // make sure windows are inside the real screen for (uint i = 0; i < _workspaces->size(); ++i) { _workspaces->getViewport(i)->makeAllInsideReal(); } // remove all dockapps #ifdef HARBOUR _harbour->removeAllDockApps(); #endif // HARBOUR // To preserve stacking order when destroying the frames, we go through // the PWinObj list from the Workspaces and put all Frames into our own // list, then we delete the frames in order. list frame_list; list::iterator it_w(_workspaces->begin()); for (; it_w != _workspaces->end(); ++it_w) { if ((*it_w)->getType() == PWinObj::WO_FRAME) frame_list.push_back(static_cast(*it_w)); } // Delete all Frames. This reparents the Clients. for (it_f = frame_list.begin(); it_f != frame_list.end(); ++it_f) delete *it_f; // Delete all Clients. list client_list(_client_list); list::iterator it_c(client_list.begin()); for (; it_c != client_list.end(); ++it_c) delete *it_c; #ifdef DEBUG if (_frame_list.size()) { cerr << __FILE__ << "@" << __LINE__ << ": " << "WindowManager::cleanup()" << endl << " *** _frame_list.size() > 0: " << _frame_list.size() << endl; } if (_client_list.size()) { cerr << __FILE__ << "@" << __LINE__ << ": " << "WindowManager::cleanup()" << endl << " *** _client_list.size() > 0: " << _client_list.size() << endl; } #endif // DEBUG _keygrabber->ungrabKeys(_screen->getRoot()); // destroy screen edge screenEdgeDestroy(); // destroy atom windows XDestroyWindow(_screen->getDpy(), _extended_hints_win); XInstallColormap(_screen->getDpy(), _screen->getColormap()); XSetInputFocus(_screen->getDpy(), PointerRoot, RevertToPointerRoot, CurrentTime); } //! @brief void WindowManager::setupDisplay(void) { Display *dpy = XOpenDisplay(NULL); if (!dpy) { cerr << "Can not open display!" << endl << "Your DISPLAY variable currently is set to: " << getenv("DISPLAY") << endl; exit(1); } XSetErrorHandler(handleXError); _screen = new PScreen(dpy); _color_handler = new ColorHandler(dpy); _font_handler = new FontHandler(); _texture_handler = new TextureHandler(); _action_handler = new ActionHandler(this); // setup the font trimming PFont::setTrimString(_config->getTrimTitle()); // load colors, fonts _screen_resources = new ScreenResources(); _theme = new Theme(_screen); _autoproperties = new AutoProperties(); _autoproperties->load(); _pekwm_atoms = new PekwmAtoms(); _icccm_atoms = new IcccmAtoms(); _ewmh_atoms = new EwmhAtoms(); _workspaces = new Workspaces(_config->getWorkspaces()); // set initial values of hints initHints(); #ifdef HARBOUR _harbour = new Harbour(_screen, _theme, _workspaces); #endif // HARBOUR _cmd_dialog = new CmdDialog(_screen->getDpy(), _theme, "CmdDialog"); _status_window = new StatusWindow(_screen->getDpy(), _theme); XDefineCursor(dpy, _screen->getRoot(), _screen_resources->getCursor(ScreenResources::CURSOR_ARROW)); // select root window events XSetWindowAttributes sattr; sattr.event_mask = SubstructureRedirectMask|SubstructureNotifyMask| ColormapChangeMask|FocusChangeMask| EnterWindowMask| PropertyChangeMask| ButtonPressMask|ButtonReleaseMask|ButtonMotionMask; XChangeWindowAttributes(dpy, _screen->getRoot(), CWEventMask, &sattr); #ifdef HAVE_XRANDR #ifdef X_RRScreenChangeSelectInput XRRScreenChangeSelectInput(dpy, _screen->getRoot(), True); #else //! X_RRScreenChangeSelectInput XRRSelectInput(dpy, _screen->getRoot(), RRScreenChangeNotifyMask); #endif // X_RRScreenChangeSelectInput #endif // HAVE_XRANDR _keygrabber = new KeyGrabber(_screen); _keygrabber->load(_config->getKeyFile()); _keygrabber->grabKeys(_screen->getRoot()); #ifdef MENUS _menus[WINDOWMENU_TYPE] = new ActionMenu(this, WINDOWMENU_TYPE, ""); _menus[ROOTMENU_TYPE] = new ActionMenu(this, ROOTMENU_TYPE, ""); _menus[GOTOMENU_TYPE] = new FrameListMenu(_screen, _theme, _frame_list, GOTOMENU_TYPE); _menus[GOTOCLIENTMENU_TYPE] = new FrameListMenu(_screen, _theme, _frame_list, GOTOCLIENTMENU_TYPE); _menus[ICONMENU_TYPE] = new FrameListMenu(_screen, _theme, _frame_list, ICONMENU_TYPE); _menus[ATTACH_CLIENT_TYPE] = new FrameListMenu(_screen, _theme, _frame_list, ATTACH_CLIENT_TYPE); _menus[ATTACH_FRAME_TYPE] = new FrameListMenu(_screen, _theme, _frame_list, ATTACH_FRAME_TYPE); _menus[ATTACH_CLIENT_IN_FRAME_TYPE] = new FrameListMenu(_screen, _theme, _frame_list, ATTACH_CLIENT_IN_FRAME_TYPE); _menus[ATTACH_FRAME_IN_FRAME_TYPE] = new FrameListMenu(_screen, _theme, _frame_list, ATTACH_FRAME_IN_FRAME_TYPE); _menus[DECORMENU_TYPE] = new DecorMenu(_screen, _theme, _action_handler); _menus[WINDOWMENU_TYPE]->reload(); _menus[ROOTMENU_TYPE]->reload(); _menus[DECORMENU_TYPE]->reload(); #endif // MENUS // Create screen edge windows screenEdgeCreate(); screenEdgeMapUnmap(); // Create root PWinObj _root_wo = new RootWO(dpy, _screen->getRoot()); PWinObj::setRootPWinObj(_root_wo); } //! @brief Goes through the window and creates Clients/DockApps. void WindowManager::scanWindows(void) { if (_startup) // only done once when we start return; uint num_wins; Window d_win1, d_win2, *wins; XWindowAttributes attr; // Lets create a list of windows on the display XQueryTree(_screen->getDpy(), _screen->getRoot(), &d_win1, &d_win2, &wins, &num_wins); list win_list(wins, wins + num_wins); XFree(wins); list::iterator it(win_list.begin()); #ifdef HARBOUR // If we have the Harbour on, we filter out all windows with the // the IconWindowHint set not pointing to themself, making DockApps // work as they are supposed to. for (; it != win_list.end(); ++it) { if (*it == None) continue; XWMHints *wm_hints = XGetWMHints(_screen->getDpy(), *it); if (wm_hints) { if ((wm_hints->flags&IconWindowHint) && (wm_hints->icon_window != *it)) { list::iterator i_it(find(win_list.begin(), win_list.end(), wm_hints->icon_window)); if (i_it != win_list.end()) *i_it = None; } XFree(wm_hints); } } #endif // HARBOUR Client *client; for (it = win_list.begin(); it != win_list.end(); ++it) { if (*it == None) continue; XGetWindowAttributes(_screen->getDpy(), *it, &attr); if (!attr.override_redirect && (attr.map_state != IsUnmapped)) { #ifdef HARBOUR XWMHints *wm_hints = XGetWMHints(_screen->getDpy(), *it); if (wm_hints) { if ((wm_hints->flags&StateHint) && (wm_hints->initial_state == WithdrawnState)) { _harbour->addDockApp(new DockApp(_screen, _theme, *it)); } else { client = new Client(this, *it); if (!client->isAlive()) delete client; } XFree(wm_hints); } else #endif // HARBOUR { client = new Client(this, *it); if (!client->isAlive()) delete client; } } } // Try to focus the ontop window, if no window we give root focus PWinObj *wo = _workspaces->getTopWO(PWinObj::WO_FRAME); if ((wo != NULL) && wo->isMapped()) { wo->giveInputFocus(); } else { _root_wo->giveInputFocus(); } // We won't be needing these anymore until next restart _autoproperties->removeApplyOnStart(); _startup = true; } //! @brief Creates and places screen edge void WindowManager::screenEdgeCreate(void) { if (_screen_edge_list.size() != 0) { return; } _screen_edge_list.push_back(new EdgeWO(_screen->getDpy(), _screen->getRoot(), SCREEN_EDGE_LEFT)); _screen_edge_list.push_back(new EdgeWO(_screen->getDpy(), _screen->getRoot(), SCREEN_EDGE_RIGHT)); _screen_edge_list.push_back(new EdgeWO(_screen->getDpy(), _screen->getRoot(), SCREEN_EDGE_TOP)); _screen_edge_list.push_back(new EdgeWO(_screen->getDpy(), _screen->getRoot(), SCREEN_EDGE_BOTTOM)); // make sure the edge stays ontop list::iterator it(_screen_edge_list.begin()); for (; it != _screen_edge_list.end(); ++it) { _workspaces->insert(*it); } screenEdgeResize(); } //! @brief void WindowManager::screenEdgeDestroy(void) { if (_screen_edge_list.size() == 0) { return; } list::iterator it(_screen_edge_list.begin()); for (; it != _screen_edge_list.end(); ++it) { _workspaces->remove(*it); delete *it; } } //! @brief void WindowManager::screenEdgeResize(void) { if (_screen_edge_list.size() != 4) return; uint size = _config->getScreenEdgeSize(); // convenience if (size == 0) size = 1; list::iterator it(_screen_edge_list.begin()); // left edge (*it)->move(0, 0); (*it)->resize(size, _screen->getHeight()); ++it; // right edge (*it)->move(_screen->getWidth() - size, 0); (*it)->resize(size, _screen->getHeight()); ++it; // top edge (*it)->move(size, 0); (*it)->resize(_screen->getWidth() - (size * 2), size); ++it; // bottom edge (*it)->move(size, _screen->getHeight() - size); (*it)->resize(_screen->getWidth() - (size * 2), size); } void WindowManager::screenEdgeMapUnmap(void) { if (_screen_edge_list.size() != 4) { return; } list::iterator it(_screen_edge_list.begin()); for (; it != _screen_edge_list.end(); ++it) { if ((_config->getScreenEdgeSize() > 0) && (_config->getEdgeListFromPosition((*it)->getEdge())->size() > 0)) { (*it)->mapWindow(); } else { (*it)->unmapWindow(); } } } //! @brief Reloads configuration and updates states. void WindowManager::doReload(void) { // unique client names state bool old_client_unique_name = _config->getClientUniqueName(); string old_client_unique_name_pre = _config->getClientUniqueNamePre(); string old_client_unique_name_post = _config->getClientUniqueNamePost(); #ifdef HARBOUR // I do not want to restack or rearrange if nothing has changed. uint old_harbour_placement = _config->getHarbourPlacement(); bool old_harbour_stacking = _config->isHarbourOntop(); #ifdef HAVE_XINERAMA int old_harbour_head_nr = _config->getHarbourHead(); #endif // HAVE_XINERAMA #endif // HARBOUR _config->load(_config->getConfigFile()); // reload the config _autoproperties->load(); // reload autoprops config // update what might have changed in the cfg toouching the hints _workspaces->setSize(_config->getWorkspaces()); // flush pixmap cache and set size _screen_resources->getPixmapHandler()->setCacheSize(_config->getScreenPixmapCacheSize()); // set the font title trim before reloading the themes PFont::setTrimString(_config->getTrimTitle()); // update the ClientUniqueNames if needed if ((old_client_unique_name != _config->getClientUniqueName()) || (old_client_unique_name_pre != _config->getClientUniqueNamePre()) || (old_client_unique_name_post != _config->getClientUniqueNamePost())) { for_each(_client_list.begin(), _client_list.end(), mem_fun(&Client::getXClientName)); } // reload the theme _theme->load(_config->getThemeFile()); // resize the viewports for (uint i = 0; i < _workspaces->size(); ++i) { _workspaces->getViewport(i)->reload(); } // resize the screen edge screenEdgeResize(); screenEdgeMapUnmap(); // regrab the buttons on the client windows for_each(_client_list.begin(), _client_list.end(), mem_fun(&Client::grabButtons)); // reload the keygrabber _keygrabber->load(_config->getKeyFile()); _keygrabber->ungrabKeys(_screen->getRoot()); _keygrabber->grabKeys(_screen->getRoot()); // regrab keys list::iterator c_it(_client_list.begin()); for (; c_it != _client_list.end(); ++c_it) { _keygrabber->ungrabKeys((*c_it)->getWindow()); _keygrabber->grabKeys((*c_it)->getWindow()); } // update the status window and cmd dialog theme _cmd_dialog->loadDecor(); _status_window->loadDecor(); // reload the themes on the frames for_each(_frame_list.begin(), _frame_list.end(), mem_fun(&PDecor::loadDecor)); // NOTE: we need to load autoproperties after decor have been updated // as otherwise old theme data pointer will be used and sig 11 pekwm. list::iterator f_it(_frame_list.begin()); for (; f_it != _frame_list.end(); ++f_it) { (*f_it)->readAutoprops(); } #ifdef HARBOUR _harbour->loadTheme(); if (old_harbour_placement != _config->getHarbourPlacement()) _harbour->rearrange(); if (old_harbour_stacking != _config->isHarbourOntop()) _harbour->restack(); #ifdef HAVE_XINERAMA if (old_harbour_head_nr != _config->getHarbourHead()) _harbour->rearrange(); #endif // HAVE_XINERAMA _harbour->updateHarbourSize(); #endif // HARBOUR #ifdef MENUS map::iterator pm_it(_menus.begin()); for (; pm_it != _menus.end(); ++pm_it) { pm_it->second->loadDecor(); pm_it->second->reload(); } #ifdef HARBOUR _harbour->getHarbourMenu()->loadDecor(); _harbour->getHarbourMenu()->reload(); #endif // HARBOUR #endif // MENUS _screen->updateStrut(); _reload = false; } //! @brief Exit pekwm and restart with the command command void WindowManager::restart(std::string command) { if (command.size() == 0) { command = _command_line; } _restart_command = command; _shutdown = true; } // Event handling routins beneath this ===================================== void WindowManager::doEventLoop(void) { Display *dpy = _screen->getDpy(); #ifdef HAVE_SHAPE Client *client = NULL; // used for shape events #endif // HAVE_SHAPE XEvent ev; while (!_shutdown) { if (_reload) doReload(); XNextEvent(dpy, &ev); switch (ev.type) { case MapRequest: handleMapRequestEvent(&ev.xmaprequest); break; case UnmapNotify: handleUnmapEvent(&ev.xunmap); break; case DestroyNotify: handleDestroyWindowEvent(&ev.xdestroywindow); break; case ConfigureRequest: handleConfigureRequestEvent(&ev.xconfigurerequest); break; case ClientMessage: handleClientMessageEvent(&ev.xclient); break; case ColormapNotify: handleColormapEvent(&ev.xcolormap); break; case PropertyNotify: handlePropertyEvent(&ev.xproperty); break; case Expose: handleExposeEvent(&ev.xexpose); break; case KeyPress: case KeyRelease: handleKeyEvent(&ev.xkey); break; case ButtonPress: handleButtonPressEvent(&ev.xbutton); break; case ButtonRelease: handleButtonReleaseEvent(&ev.xbutton); break; case MotionNotify: handleMotionEvent(&ev.xmotion); break; case EnterNotify: handleEnterNotify(&ev.xcrossing); break; case LeaveNotify: handleLeaveNotify(&ev.xcrossing); break; case FocusIn: handleFocusInEvent(&ev.xfocus); break; case FocusOut: handleFocusOutEvent(&ev.xfocus); break; default: #ifdef HAVE_SHAPE if (_screen->hasExtensionShape() && (ev.type == _screen->getEventShape())) { client = findClient(ev.xany.window); if ((client != NULL) && (client->getParent() != NULL)) { static_cast(client->getParent())->handleShapeEvent(&ev.xany); } } #endif // HAVE_SHAPE #ifdef HAVE_XRANDR if (_screen->hasExtensionXRandr() && (ev.type == _screen->getEventXRandr())) { handleXRandrEvent((XRRScreenChangeNotifyEvent*) &ev); } #endif // HAVE_XRANDR break; } } } //! @brief Handle XKeyEvents void WindowManager::handleKeyEvent(XKeyEvent *ev) { ActionEvent *ae = NULL; PWinObj *wo = PWinObj::getFocusedPWinObj(); PWinObj::Type type = (wo == NULL) ? PWinObj::WO_SCREEN_ROOT : wo->getType(); switch (type) { case PWinObj::WO_CLIENT: case PWinObj::WO_FRAME: case PWinObj::WO_SCREEN_ROOT: case PWinObj::WO_MENU: if (ev->type == KeyPress) { ae = _keygrabber->findAction(ev, type); } break; case PWinObj::WO_CMD_DIALOG: if (ev->type == KeyPress) { ae = wo->handleKeyPress(ev); } else { ae = wo->handleKeyRelease(ev); } wo = static_cast(wo)->getWORef(); break; default: if (wo != NULL) { if (ev->type == KeyPress) { ae = wo->handleKeyPress(ev); } else { ae = wo->handleKeyRelease(ev); } } break; } if (ae != NULL) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.key = ev; _action_handler->handleAction(ap); } // flush Enter events caused by keygrabbing XEvent e; while (XCheckTypedEvent(_screen->getDpy(), EnterNotify, &e)); } //! @brief void WindowManager::handleButtonPressEvent(XButtonEvent *ev) { // Clear event queue while (XCheckTypedEvent(_screen->getDpy(), ButtonPress, (XEvent *) ev)); ActionEvent *ae = NULL; PWinObj *wo = NULL; wo = PWinObj::findPWinObj(ev->window); if (wo != NULL) { ae = wo->handleButtonPress(ev); if (wo->getType() == PWinObj::WO_FRAME) { // this is done so that clicking the titlebar executes action on // the client clicked on, doesn't apply when subwindow is set (meaning // a titlebar button beeing pressed) if ((ev->subwindow == None) && (ev->window == static_cast(wo)->getTitleWindow())) { wo = static_cast(wo)->getChildFromPos(ev->x); } else { wo = static_cast(wo)->getActiveChild(); } } } if (ae != NULL) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.button = ev; _action_handler->handleAction(ap); } #ifdef HARBOUR else { DockApp *da = _harbour->findDockAppFromFrame(ev->window); if (da) { _harbour->handleButtonEvent(ev, da); } } #endif // HARBOUR } //! @brief void WindowManager::handleButtonReleaseEvent(XButtonEvent *ev) { // Flush ButtonReleases while (XCheckTypedEvent(_screen->getDpy(), ButtonRelease, (XEvent *) ev)); ActionEvent *ae = NULL; PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo != NULL) { ae = wo->handleButtonRelease(ev); if (wo->getType() == PWinObj::WO_FRAME) { // this is done so that clicking the titlebar executes action on // the client clicked on, doesn't apply when subwindow is set (meaning // a titlebar button beeing pressed) if ((ev->subwindow == None) && (ev->window == static_cast(wo)->getTitleWindow())) { wo = static_cast(wo)->getChildFromPos(ev->x); } else { wo = static_cast(wo)->getActiveChild(); } } if (ae != NULL) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.button = ev; _action_handler->handleAction(ap); } } #ifdef HARBOUR else { DockApp *da = _harbour->findDockAppFromFrame(ev->window); if (da) { _harbour->handleButtonEvent(ev, da); } } #endif // HARBOUR } void WindowManager::handleConfigureRequestEvent(XConfigureRequestEvent *ev) { Client *client = findClientFromWindow(ev->window); if (client) { ((Frame*) client->getParent())->handleConfigureRequest(ev, client); } else { #ifdef HARBOUR DockApp *da = _harbour->findDockApp(ev->window); if (da) { _harbour->handleConfigureRequestEvent(ev, da); } else #endif // HARBOUR { // Since this window isn't yet a client lets delegate // the configure request back to the window so it can use it. XWindowChanges wc; wc.x = ev->x; wc.y = ev->y; wc.width = ev->width; wc.height = ev->height; wc.sibling = ev->above; wc.stack_mode = ev->detail; XConfigureWindow(_screen->getDpy(), ev->window, ev->value_mask, &wc); } } } //! @brief void WindowManager::handleMotionEvent(XMotionEvent *ev) { ActionEvent *ae = NULL; PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo != NULL) { if (wo->getType() == PWinObj::WO_CLIENT) { ae = wo->getParent()->handleMotionEvent(ev); } else if (wo->getType() == PWinObj::WO_FRAME) { ae = wo->handleMotionEvent(ev); // this is done so that clicking the titlebar executes action on // the client clicked on if (ev->subwindow != None) { wo = static_cast(wo)->getActiveChild(); } else { wo = static_cast(wo)->getChildFromPos(ev->x); } } else { ae = wo->handleMotionEvent(ev); } if (ae != NULL) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.motion = ev; _action_handler->handleAction(ap); } } #ifdef HARBOUR else { DockApp *da = _harbour->findDockAppFromFrame(ev->window); if (da) { _harbour->handleMotionNotifyEvent(ev, da); } } #endif // HARBOUR } //! @brief void WindowManager::handleMapRequestEvent(XMapRequestEvent *ev) { PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo != NULL) { wo->handleMapRequest(ev); } else { XWindowAttributes attr; XGetWindowAttributes(_screen->getDpy(), ev->window, &attr); if (!attr.override_redirect) { // if we have the harbour enabled, we need to figure out wheter or // not this is a dockapp. #ifdef HARBOUR XWMHints *wm_hints = XGetWMHints(_screen->getDpy(), ev->window); if (wm_hints != NULL) { if ((wm_hints->flags&StateHint) && (wm_hints->initial_state == WithdrawnState)) { _harbour->addDockApp(new DockApp(_screen, _theme, ev->window)); } else { Client *client = new Client(this, ev->window, true); if (client->isAlive() == false) { delete client; } } XFree(wm_hints); } else #endif // HARBOUR { Client *client = new Client(this, ev->window, true); if (client->isAlive() == false) { delete client; } } } } } //! @brief void WindowManager::handleUnmapEvent(XUnmapEvent *ev) { PWinObj *wo = PWinObj::findPWinObj(ev->window); PWinObj *wo_search = NULL; PWinObj::Type wo_type = PWinObj::WO_NO_TYPE; if (wo != NULL) { wo_type = wo->getType(); if (wo_type == PWinObj::WO_CLIENT) { wo_search = wo->getParent(); } wo->handleUnmapEvent(ev); if (wo == PWinObj::getFocusedPWinObj()) { PWinObj::setFocusedPWinObj(NULL); } } #ifdef HARBOUR else { DockApp *da = _harbour->findDockApp(ev->window); if (da) { if (ev->window == ev->event) { _harbour->removeDockApp(da); } } } #endif // HARBOUR if ((wo_type != PWinObj::WO_MENU) && (PWinObj::getFocusedPWinObj() == NULL)) { findWOAndFocus(wo_search); } } void WindowManager::handleDestroyWindowEvent(XDestroyWindowEvent *ev) { Client *client = findClientFromWindow(ev->window); if (client) { PWinObj *wo_search = client->getParent(); client->handleDestroyEvent(ev); if (PWinObj::getFocusedPWinObj() == NULL) { findWOAndFocus(wo_search); } } #ifdef HARBOUR else { DockApp *da = _harbour->findDockApp(ev->window); if (da) { da->setAlive(false); _harbour->removeDockApp(da); } } #endif // HARBOUR } void WindowManager::handleEnterNotify(XCrossingEvent *ev) { // Clear event queue while (XCheckTypedEvent(_screen->getDpy(), EnterNotify, (XEvent *) ev)); if ((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab)) { return; } PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo != NULL) { if (wo->getType() == PWinObj::WO_CLIENT) { wo = wo->getParent(); } ActionEvent *ae = wo->handleEnterEvent(ev); if (ae != NULL) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.crossing = ev; _action_handler->handleAction(ap); } } } void WindowManager::handleLeaveNotify(XCrossingEvent *ev) { // Clear event queue while (XCheckTypedEvent(_screen->getDpy(), LeaveNotify, (XEvent *) ev)); if ((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab)) { return; } PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo != NULL) { ActionEvent *ae = wo->handleLeaveEvent(ev); if (ae != NULL) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.crossing = ev; _action_handler->handleAction(ap); } } } //! @brief Handles FocusIn Events. void WindowManager::handleFocusInEvent(XFocusChangeEvent *ev) { // Get the last focus in event, no need to go through them all. while (XCheckTypedEvent(_screen->getDpy(), FocusIn, (XEvent *) ev)); if ((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab)) return; PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo) { // To simplify logic, changing client in frame wouldn't update the // focused window because wo != focused_wo woule be true. if (wo->getType() == PWinObj::WO_FRAME) wo = static_cast(wo)->getActiveChild(); if (!wo->isFocusable() || !wo->isMapped()) { findWOAndFocus(NULL); } else if (wo != PWinObj::getFocusedPWinObj()) { // If it's a valid FocusIn event with accepatable target lets flush // all EnterNotify and LeaveNotify as they can interfere with // focusing if Sloppy or Follow like focus model is used. XEvent e_flush; while (XCheckTypedEvent(_screen->getDpy(), EnterNotify, &e_flush)); while (XCheckTypedEvent(_screen->getDpy(), LeaveNotify, &e_flush)); PWinObj *focused_wo = PWinObj::getFocusedPWinObj(); // convenience // unfocus last window if (focused_wo != NULL) { if (focused_wo->getType() == PWinObj::WO_CLIENT) { focused_wo->getParent()->setFocused(false); } else { focused_wo->setFocused(false); } _workspaces->setLastFocused(_workspaces->getActive(), focused_wo); } PWinObj::setFocusedPWinObj(wo); if (wo->getType() == PWinObj::WO_CLIENT) { wo->getParent()->setFocused(true); setEwmhActiveWindow(wo->getWindow()); } else { wo->setFocused(true); setEwmhActiveWindow(None); } // update the MRU list if (wo->getType() == PWinObj::WO_CLIENT) { _mru_list.remove(wo->getParent()); _mru_list.push_back(wo->getParent()); } } } } //! @brief Handles FocusOut Events. void WindowManager::handleFocusOutEvent(XFocusChangeEvent *ev) { // Get the last focus in event, no need to go through them all. while (XCheckTypedEvent(_screen->getDpy(), FocusOut, (XEvent *) ev)); if ((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab)) return; // Match against focusd PWinObj if any, if matches we see if // there are any FocusIn events in the queue, if not we give focus to // the root window as we don't want to get left without focus. if (PWinObj::getFocusedPWinObj() && (*PWinObj::getFocusedPWinObj() == ev->window)) { if (XCheckTypedEvent(_screen->getDpy(), FocusIn, (XEvent *) ev)) { // We found a Event, put it back and handle it later on. XPutBackEvent(_screen->getDpy(), (XEvent *) ev); } else { // No event found, give the root PWinObj focus. PWinObj::getRootPWinObj()->giveInputFocus(); } } } void WindowManager::handleClientMessageEvent(XClientMessageEvent *ev) { if (ev->window == _screen->getRoot()) { // root window messages if (ev->format == 32) { if (ev->message_type == _ewmh_atoms->getAtom(NET_CURRENT_DESKTOP)) { _workspaces->setWorkspace(ev->data.l[0], true); } else if (ev->message_type == _ewmh_atoms->getAtom(NET_NUMBER_OF_DESKTOPS)) { if (ev->data.l[0] > 0) { _workspaces->setSize(ev->data.l[0]); } } else if (ev->message_type == _ewmh_atoms->getAtom(NET_DESKTOP_VIEWPORT)) { _workspaces->getActiveViewport()->move(ev->data.l[0], ev->data.l[1]); } } } else { // client messages Client *client = findClientFromWindow(ev->window); if (client) { static_cast(client->getParent())->handleClientMessage(ev, client); } } } void WindowManager::handleColormapEvent(XColormapEvent *ev) { Client *client = findClient(ev->window); if (client) { client = static_cast(((Frame*) client->getParent())->getActiveChild()); client->handleColormapChange(ev); } } void WindowManager::handlePropertyEvent(XPropertyEvent *ev) { if (ev->window == _screen->getRoot()) return; Client *client = findClientFromWindow(ev->window); if (client != NULL) { ((Frame*) client->getParent())->handlePropertyChange(ev, client); } } void WindowManager::handleExposeEvent(XExposeEvent *ev) { ActionEvent *ae = NULL; PWinObj *wo = PWinObj::findPWinObj(ev->window); if (wo != NULL) { ae = wo->handleExposeEvent(ev); } if (ae != NULL) { ActionPerformed ap(wo, *ae); ap.type = ev->type; ap.event.expose = ev; _action_handler->handleAction(ap); } } #ifdef HAVE_XRANDR //! @brief Handles XRandr event. void WindowManager::handleXRandrEvent(XRRScreenChangeNotifyEvent *ev) { // don't care about what it is, only update screen size _screen->updateGeometry(ev->width, ev->height); #ifdef HARBOUR _harbour->updateGeometry(); #endif // HARBOUR Viewport *vp; for (uint i = 0; i < _workspaces->size(); ++i) { if ((vp = _workspaces->getViewport(i)) != NULL) { vp->updateGeometry(); } } screenEdgeResize(); } #endif // HAVE_XRANDR // Event handling routines stop ============================================ //! @brief Searches for a PWinObj to focus, and then gives it input focus void WindowManager::findWOAndFocus(PWinObj *search) { PWinObj *focus = NULL; if ((PWinObj::windowObjectExists(search) == true) && (search->isMapped()) && (search->isFocusable()) && _workspaces->getActiveViewport()->isInside(search)) { focus = search; } // search window object didn't exist, go through the MRU list if (focus == NULL) { list::reverse_iterator f_it = _mru_list.rbegin(); for (; (focus == NULL) && (f_it != _mru_list.rend()); ++f_it) { if ((*f_it)->isMapped() && (*f_it)->isFocusable() && _workspaces->getActiveViewport()->isInside(*f_it)) { focus = *f_it; } } } if (focus != NULL) { focus->giveInputFocus(); } else if (PWinObj::getFocusedPWinObj() == NULL) { _root_wo->giveInputFocus(); setEwmhActiveWindow(None); } } //! @brief Finds the Client wich holds the window w, only matching the window. //! @param win Window to use as criteria when searching Client* WindowManager::findClientFromWindow(Window win) { if (win == _screen->getRoot()) return NULL; list::iterator it(_client_list.begin()); for(; it != _client_list.end(); ++it) { if (win == (*it)->getWindow()) return (*it); } return NULL; } //! @brief Frame* WindowManager::findFrameFromWindow(Window win) { if (win == _screen->getRoot()) return NULL; list::iterator it(_frame_list.begin()); for(; it != _frame_list.end(); ++it) { if (win == (*it)->getWindow()) { // operator == does more than that return (*it); } } return NULL; } //! @brief Finds the Client wich holds the Window w. //! @param win Window to use as criteria when searching. //! @return Pointer to the client if found, else NULL Client* WindowManager::findClient(Window win) { if ((win == None) || (win == _screen->getRoot())) return NULL; Frame *frame; if (_client_list.size()) { list::iterator it(_client_list.begin()); for (; it != _client_list.end(); ++it) { if (win == (*it)->getWindow()) { return (*it); } else { frame = dynamic_cast((*it)->getParent()); if ((frame != NULL) && (*frame == win)) { return (*it); } } } } return NULL; } //! @brief Insert all clients with the transient for set to win void WindowManager::findFamily(std::list &client_list, Window win) { // search for windows having transient for set to this window list::iterator it(_client_list.begin()); for (; it != _client_list.end(); ++it) { if ((*it)->getTransientWindow() == win) { client_list.push_back(*it); } } } //! @brief (Un)Maps all windows having transient_for set to win void WindowManager::findTransientsToMapOrUnmap(Window win, bool hide) { list client_list; findFamily(client_list, win); list::iterator it(client_list.begin()); for (; it != client_list.end(); ++it) { if (static_cast((*it)->getParent())->getActiveChild() == *it) { if (hide) { (*it)->getParent()->iconify(); } else { (*it)->getParent()->mapWindow(); } } } } //! @brief Raises the client and all window having transient relationship with it //! @param client Client part of the famliy //! @param raise If true, raise frames, else lowers them void WindowManager::familyRaiseLower(Client *client, bool raise) { Client *parent; Window win_search; if (client->getTransientWindow() == None) { parent = client; win_search = client->getWindow(); } else { parent = findClientFromWindow(client->getTransientWindow()); win_search = client->getTransientWindow(); } list client_list; findFamily(client_list, win_search); if (parent != NULL) { // make sure parent gets underneath the children if (raise == true) { client_list.push_front(parent); } else { client_list.push_back(parent); } } Frame *frame; list::iterator it(client_list.begin()); for (; it != client_list.end(); ++it) { frame = dynamic_cast((*it)->getParent()); if ((frame != NULL) && (frame->getActiveChild() == *it)) { if (raise == true) { frame->raise(); } else { frame->lower(); } } } } //! @brief void WindowManager::removeFromClientList(Client *client) { _client_list.remove(client); } //! @brief void WindowManager::removeFromFrameList(Frame *frame) { if (_tagged_frame == frame) { _tagged_frame = NULL; } _frame_list.remove(frame); _mru_list.remove(frame); _frameid_list.push_back(frame->getId()); } //! @brief Client* WindowManager::findClient(const ClassHint *class_hint) { if (! _client_list.size()) return NULL; list::iterator it(_client_list.begin()); for (; it != _client_list.end(); ++it) { if (*class_hint == *(*it)->getClassHint()) return *it; } return NULL; } //! @brief Tries to find a Frame to autogroup with Frame* WindowManager::findGroup(AutoProperty *property) { if (_allow_grouping == false) { return NULL; } Frame *frame = NULL; Viewport *vp = _workspaces->getActiveViewport(); #define MATCH_GROUP(F,P) \ ((P->group_global || ((F)->isMapped() && vp->isInside(F))) && \ ((P->group_size == 0) || (signed((F)->size()) < P->group_size)) && \ ((((F)->getClassHint()->group.size() > 0) \ ? ((F)->getClassHint()->group == P->group_name) : false) || \ AutoProperties::matchAutoClass(*(F)->getClassHint(), (Property*) P))) // try to match the focused window first if (property->group_focused_first && (PWinObj::getFocusedPWinObj() != NULL) && (PWinObj::getFocusedPWinObj()->getType() == PWinObj::WO_CLIENT)) { Frame *fo_frame = static_cast(PWinObj::getFocusedPWinObj()->getParent()); if (MATCH_GROUP(fo_frame, property)) { frame = fo_frame; } } // search the list of frames if (frame == NULL) { list::iterator it(_frame_list.begin()); for (; it != _frame_list.end(); ++it) { if (MATCH_GROUP(*it, property)) { frame = *it; break; } } } #undef MATCH_GROUP return frame; } //! @brief Sees if there is a tagged frame and if it's visible Frame* WindowManager::findTaggedFrame(bool &activate) { if (_tagged_frame && _tagged_frame->isMapped()) { activate = _tag_activate; return _tagged_frame; } return NULL; } //! @brief Frame* WindowManager::findFrameFromId(uint id) { list::iterator it(_frame_list.begin()); for (; it != _frame_list.end(); ++it) { if ((*it)->getId() == id) return (*it); } return NULL; } //! @brief uint WindowManager::findUniqueFrameId(void) { if (!_startup) // always return 0 while scanning windows return 0; uint id = 0; if (_frameid_list.size()) { id = _frameid_list.back(); _frameid_list.pop_back(); } else { id = (_frame_list.size() + 1); // this is called before the frame is pushed } return id; } //! @brief void WindowManager::setupFrameIds(void) { list::iterator it(_frame_list.begin()); for (uint i = 1; it != _frame_list.end(); ++i, ++it) (*it)->setId(i); } //! @brief void WindowManager::setTaggedFrame(Frame *frame, bool activate) { _tagged_frame = frame; _tag_activate = activate; } //! @brief Attaches all marked clients to frame void WindowManager::attachMarked(Frame *frame) { list::iterator it(_client_list.begin()); for (; it != _client_list.end(); ++it) { if ((*it)->isMarked()) { if ((*it)->getParent() != frame) { ((Frame*) (*it)->getParent())->removeChild(*it); (*it)->setWorkspace(frame->getWorkspace()); frame->addChild(*it); } (*it)->mark(); } } } //! @brief Attaches the Client/Frame into the Next/Prev Frame void WindowManager::attachInNextPrevFrame(Client *client, bool frame, bool next) { if (!client) return; Frame *new_frame; if (next) { new_frame = getNextFrame((Frame*) client->getParent(), true, SKIP_FOCUS_TOGGLE); } else { new_frame = getPrevFrame((Frame*) client->getParent(), true, SKIP_FOCUS_TOGGLE); } if (new_frame) { // we found a frame if (frame) { new_frame->addDecor((Frame*) client->getParent()); } else { client->getParent()->setFocused(false); ((Frame*) client->getParent())->removeChild(client); new_frame->addChild(client); new_frame->activateChild(client); new_frame->giveInputFocus(); } } } //! @brief Finds the next frame in the list //! //! @param frame Frame to search from //! @param mapped Match only agains mapped frames //! @param mask Defaults to 0 Frame* WindowManager::getNextFrame(Frame* frame, bool mapped, uint mask) { if (!frame || (_frame_list.size() < 2)) return NULL; Frame *next_frame = NULL; list::iterator f_it(find(_frame_list.begin(), _frame_list.end(), frame)); if (f_it != _frame_list.end()) { list::iterator n_it(f_it); if (++n_it == _frame_list.end()) n_it = _frame_list.begin(); while (!next_frame && (n_it != f_it)) { if (!(*n_it)->isSkip(mask) && (!mapped || (*n_it)->isMapped())) next_frame = (*n_it); if (++n_it == _frame_list.end()) n_it = _frame_list.begin(); } } return next_frame; } //! @brief Finds the previous frame in the list //! //! @param frame Frame to search from //! @param mapped Match only agains mapped frames //! @param mask Defaults to 0 Frame* WindowManager::getPrevFrame(Frame* frame, bool mapped, uint mask) { if (!frame || (_frame_list.size() < 2)) return NULL; Frame *next_frame = NULL; list::iterator f_it(find(_frame_list.begin(), _frame_list.end(), frame)); if (f_it != _frame_list.end()) { list::iterator n_it(f_it); if (n_it == _frame_list.begin()) n_it = --_frame_list.end(); else --n_it; while (!next_frame && (n_it != f_it)) { if (!(*n_it)->isSkip(mask) && (!mapped || (*n_it)->isMapped())) next_frame = (*n_it); if (n_it == _frame_list.begin()) n_it = --_frame_list.end(); else --n_it; } } return next_frame; } #ifdef MENUS //! @brief void WindowManager::hideAllMenus(void) { map::iterator it(_menus.begin()); for (; it != _menus.end(); ++it) it->second->unmapAll(); } #endif // MENUS // here follows methods for hints and atoms void WindowManager::initHints(void) { // Motif hints _atom_mwm_hints = XInternAtom(_screen->getDpy(), "_MOTIF_WM_HINTS", False); // Setup Extended Net WM hints _extended_hints_win = XCreateSimpleWindow(_screen->getDpy(), _screen->getRoot(), -200, -200, 5, 5, 0, 0, 0); XSetWindowAttributes pattr; pattr.override_redirect = True; XChangeWindowAttributes(_screen->getDpy(), _extended_hints_win, CWOverrideRedirect, &pattr); AtomUtil::setString(_extended_hints_win, _ewmh_atoms->getAtom(NET_WM_NAME), _wm_name); AtomUtil::setWindow(_extended_hints_win, _ewmh_atoms->getAtom(NET_SUPPORTING_WM_CHECK), _extended_hints_win); AtomUtil::setWindow(_screen->getRoot(), _ewmh_atoms->getAtom(NET_SUPPORTING_WM_CHECK), _extended_hints_win); setEwmhSupported(); AtomUtil::setLong(_screen->getRoot(), _ewmh_atoms->getAtom(NET_NUMBER_OF_DESKTOPS), _config->getWorkspaces()); _workspaces->getActiveViewport()->hintsUpdate(); AtomUtil::setLong(_screen->getRoot(), _ewmh_atoms->getAtom(NET_CURRENT_DESKTOP), 0); } void WindowManager::setEwmhSupported(void) { Atom *atoms = _ewmh_atoms->getAtomArray(); AtomUtil::setAtoms(_screen->getRoot(), _ewmh_atoms->getAtom(NET_SUPPORTED), atoms, _ewmh_atoms->size()); delete [] atoms; } void WindowManager::setEwmhActiveWindow(Window w) { AtomUtil::setWindow(_screen->getRoot(), _ewmh_atoms->getAtom(NET_ACTIVE_WINDOW), w); }