// // FrameListMenu.cc for pekwm // Copyright (C) 2002-2004 Claes Nasten // // This program is licensed under the GNU GPL. // See the LICENSE file for more information. // #include "../config.h" #ifdef MENUS #include "PWinObj.hh" #include "PDecor.hh" #include "PMenu.hh" #include "WORefMenu.hh" #include "FrameListMenu.hh" #include "Config.hh" #include "Client.hh" #include "Frame.hh" #include "Workspaces.hh" #include "Viewport.hh" #include "WindowManager.hh" #include #include #ifdef DEBUG #include using std::cerr; using std::endl; #endif // DEBUG using std::string; using std::list; using std::vector; //! @brief FrameListMenu constructor. FrameListMenu::FrameListMenu(PScreen *scr, Theme *theme, const std::list &frame_list, MenuType type) : WORefMenu(scr, theme), _frame_list(frame_list) { _menu_type = type; switch(_menu_type) { case GOTOMENU_TYPE: _title_base = "GoTo"; break; case ICONMENU_TYPE: _title_base = "IconMenu"; break; case ATTACH_CLIENT_TYPE: _title_base = "Attach Client"; break; case ATTACH_FRAME_TYPE: _title_base = "Attach Frame"; break; case ATTACH_CLIENT_IN_FRAME_TYPE: _title_base = "Attach Client In Frame"; break; case ATTACH_FRAME_IN_FRAME_TYPE: _title_base = "Attach Frame In Frame"; break; case GOTOCLIENTMENU_TYPE: _title_base = "GoTo Client"; break; default: // do nothing break; } } //! @brief FrameListMenu destructor FrameListMenu::~FrameListMenu(void) { } // START - PWinObj interface. //! @brief Rebuilds the menu and if it has any items after it shows it. void FrameListMenu::mapWindow(void) { updateFrameListMenu(); if (size() > 0) { WORefMenu::mapWindow(); } } // END - PWinObj interface. //! @brief void FrameListMenu::handleItemExec(PMenu::Item *item) { if (item == NULL) { return; } if (PWinObj::windowObjectExists(_wo_ref) == false) { _wo_ref = NULL; } if (PWinObj::windowObjectExists(item->getWORef()) == false) { item->setWORef(NULL); } switch (_menu_type) { case GOTOMENU_TYPE: case GOTOCLIENTMENU_TYPE: handleGotomenu(dynamic_cast(item->getWORef())); break; case ICONMENU_TYPE: handleIconmenu(dynamic_cast(item->getWORef())); break; case ATTACH_CLIENT_TYPE: case ATTACH_FRAME_TYPE: handleAttach(dynamic_cast(_wo_ref), dynamic_cast(item->getWORef()), (_menu_type == ATTACH_FRAME_TYPE)); break; case ATTACH_CLIENT_IN_FRAME_TYPE: case ATTACH_FRAME_IN_FRAME_TYPE: handleAttach(dynamic_cast(item->getWORef()), dynamic_cast(_wo_ref), (_menu_type == ATTACH_FRAME_IN_FRAME_TYPE)); break; default: // do nothing break; } } //! @brief Rebuilds the menu. void FrameListMenu::updateFrameListMenu(void) { removeAll(); char buf[16]; string name; // need to add an action, otherwise it looks as if we don't have anything // to exec and thus it doesn't get handled. Action action; ActionEvent ae; ae.action_list.push_back(action); // Decide wheter to show clients and iconified. bool show_clients = false, show_iconified_only = false; if (_menu_type == ATTACH_CLIENT_TYPE || _menu_type == GOTOCLIENTMENU_TYPE) { show_clients = true; } else if (_menu_type == ICONMENU_TYPE) { show_iconified_only = true; } list::const_iterator it; // if we have 1 workspace, we won't put an workspace indicator buf[0] = '\0'; for (uint i = 0; i < Workspaces::instance()->size(); ++i) { if (Workspaces::instance()->size() > 1) { snprintf(buf, sizeof(buf), "<%d> ", i + 1); } for (it = _frame_list.begin(); it != _frame_list.end(); ++it) { if (((*it)->getWorkspace() == i) && // sort by workspace // don't include ourselves if we're not doing a gotoclient menu ((_menu_type != GOTOCLIENTMENU_TYPE) ? ((*it)->getActiveChild() != _wo_ref) : true) && (show_iconified_only ? (*it)->isIconified() : !(*it)->isSkip(SKIP_MENUS))) { name = buf; if (show_clients) { buildFrameNames(*it, name); } else { buildName(*it, name); name.append("] "); name.append(static_cast((*it)->getActiveChild())->getTitle()->getVisible()); insert(name, ae, (*it)->getActiveChild()); } } } } // remove the last separator, not needed if ((show_clients == true) && (size() > 0)) { remove(_item_list.back()); } buildMenu(); } //! @brief Builds the name for the frame. void FrameListMenu::buildName(Frame* frame, std::string &name) { // only show viewport information if having more than one if ((Config::instance()->getViewportCols() > 1) || (Config::instance()->getViewportRows() > 1)) { char buf[64]; snprintf(buf, 64, "(%ix%i) ", Workspaces::instance()->getActiveViewport()->getCol(frame) + 1, Workspaces::instance()->getActiveViewport()->getRow(frame) + 1); name.append(buf); } name.append("["); if (frame->isSticky()) name.append("*"); if (frame->isIconified()) name.append("."); if (frame->isShaded()) name.append("^"); if (frame->getActiveChild()->getLayer() > LAYER_NORMAL) name.append("+"); else if (frame->getActiveChild()->getLayer() < LAYER_NORMAL) name.append("-"); } //! @brief Builds names for all the clients in a frame. void FrameListMenu::buildFrameNames(Frame *frame, std::string &pre_name) { string name, status_name; // need to add an action, otherwise it looks as if we don't have anything // to exec and thus it doesn't get handled. Action action; ActionEvent ae; ae.action_list.push_back(action); buildName(frame, status_name); // add states to the name list::iterator it(frame->begin()); for (; it != frame->end(); ++it) { name = pre_name; name.append(status_name); if (frame->getActiveChild() == *it) { name.append("A"); } name.append("] "); name.append(static_cast(*it)->getTitle()->getVisible()); insert(name, ae, *it); } // add separator PMenu::Item *item = new PMenu::Item(""); item->setType(PMenu::Item::MENU_ITEM_SEPARATOR); insert(item); } //! @brief Handles gotomeu presses void FrameListMenu::handleGotomenu(Client *client) { if (client == NULL) { return; } Frame *frame = static_cast(client->getParent()); // make sure it's on correct workspace if ((frame->isSticky() == false) && (frame->getWorkspace() != Workspaces::instance()->getActive())) { Workspaces::instance()->setWorkspace(frame->getWorkspace(), false); } // make sure it isn't hidden if (frame->isMapped() == false) { frame->mapWindow(); } // make sure the viewport is correct if (Workspaces::instance()->getActiveViewport()->isInside(frame) == false) { Workspaces::instance()->getActiveViewport()->moveToWO(frame); } frame->activateChild(client); frame->raise(); frame->giveInputFocus(); } //! @brief Handles iconmenu presses void FrameListMenu::handleIconmenu(Client *client) { if (client == NULL) { return; } Frame *frame = static_cast(client->getParent()); // make sure it's on the current workspace if (frame->getWorkspace() != Workspaces::instance()->getActive()) { frame->setWorkspace(Workspaces::instance()->getActive()); } frame->raise(); frame->mapWindow(); } //! @brief Handles attach*menu presses void FrameListMenu::handleAttach(Client *client_to, Client *client_from, bool frame) { if ((client_to == NULL) || (client_from == NULL)) { return; } Frame *frame_to = static_cast(client_to->getParent()); Frame *frame_from = static_cast(client_from->getParent()); // insert frame if (frame == true) { frame_to->addDecor(frame_from); // insert client } else if (frame_to != frame_from) { frame_from->removeChild(client_from); client_from->setWorkspace(frame_to->getWorkspace()); frame_to->addChild(client_from); frame_to->activateChild(client_from); frame_to->giveInputFocus(); } } #endif // MENUS