ede/pekwm/FrameListMenu.cc

297 lines
7.7 KiB
C++
Raw Normal View History

//
// FrameListMenu.cc for pekwm
// Copyright © 2002-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <algorithm>
#include <cstdio>
#include <cwchar>
#include <iostream>
#include "Compat.hh"
#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 "WindowManager.hh"
using std::cerr;
using std::endl;
using std::list;
using std::string;
using std::vector;
using std::wstring;
using std::swprintf;
//! @brief FrameListMenu constructor.
//! @param scr Pointer to PScreen.
//! @param theme Pointer to Theme
//! @param type Type of menu.
//! @param title Title of menu.
//! @param name Name of menu
//! @param decor_name Decor name, defaults to MENU
FrameListMenu::FrameListMenu(PScreen *scr, Theme *theme,
MenuType type,
const std::wstring &title, const std::string &name,
const std::string &decor_name)
: WORefMenu(scr, theme, title, name, decor_name)
{
_menu_type = type;
}
//! @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.
/**
* Execute item execution.
*/
void
FrameListMenu::handleItemExec(PMenu::Item *item)
{
if (! item) {
return;
}
Client *item_client = dynamic_cast<Client*>(item->getWORef());
Client *wo_ref_client = dynamic_cast<Client*>(getWORef());
switch (_menu_type) {
case GOTOMENU_TYPE:
case GOTOCLIENTMENU_TYPE:
handleGotomenu(item_client);
break;
case ICONMENU_TYPE:
handleIconmenu(item_client);
break;
case ATTACH_CLIENT_TYPE:
case ATTACH_FRAME_TYPE:
handleAttach(wo_ref_client, item_client,
(_menu_type == ATTACH_FRAME_TYPE));
break;
case ATTACH_CLIENT_IN_FRAME_TYPE:
case ATTACH_FRAME_IN_FRAME_TYPE:
handleAttach(item_client, wo_ref_client,
(_menu_type == ATTACH_FRAME_IN_FRAME_TYPE));
break;
default:
// do nothing
break;
}
}
//! @brief Rebuilds the menu.
void
FrameListMenu::updateFrameListMenu(void)
{
removeAll();
wchar_t buf[16];
wstring 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<Frame*>::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) {
swprintf(buf, 16, L"<%d> ", i + 1);
}
for (it = Frame::frame_begin(); it != Frame::frame_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() != getWORef())
: true) &&
(show_iconified_only
? (*it)->isIconified()
: !(*it)->isSkip(SKIP_MENUS))) {
name = buf;
if (show_clients) {
buildFrameNames(*it, name);
} else {
buildName(*it, name);
name.append(L"] ");
name.append(static_cast<Client*>((*it)->getActiveChild())->getTitle()->getVisible());
insert(name, ae, (*it)->getActiveChild(),
static_cast<Client*>((*it)->getActiveChild())->getIcon());
}
}
}
}
// remove the last separator, not needed
if (show_clients && (size() > 0)) {
remove(_item_list.back());
}
buildMenu();
}
//! @brief Builds the name for the frame.
void
FrameListMenu::buildName(Frame* frame, std::wstring &name)
{
name.append(L"[");
if (frame->isSticky()) {
name.append(L"*");
}
if (frame->isIconified()) {
name.append(L".");
}
if (frame->isShaded()) {
name.append(L"^");
}
if (frame->getActiveChild()->getLayer() > LAYER_NORMAL) {
name.append(L"+");
} else if (frame->getActiveChild()->getLayer() < LAYER_NORMAL) {
name.append(L"-");
}
}
//! @brief Builds names for all the clients in a frame.
void
FrameListMenu::buildFrameNames(Frame *frame, std::wstring &pre_name)
{
wstring 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<PWinObj*>::iterator it(frame->begin());
for (; it != frame->end(); ++it) {
name = pre_name;
name.append(status_name);
if (frame->getActiveChild() == *it) {
name.append(L"A");
}
name.append(L"] ");
name.append(static_cast<Client*>(*it)->getTitle()->getVisible());
insert(name, ae, *it, static_cast<Client*>(*it)->getIcon());
}
// add separator
PMenu::Item *item = new PMenu::Item(L"");
item->setType(PMenu::Item::MENU_ITEM_SEPARATOR);
insert(item);
}
//! @brief Handles gotomeu presses
void
FrameListMenu::handleGotomenu(Client *client)
{
if (! client) {
return;
}
Frame *frame = static_cast<Frame*>(client->getParent());
// make sure it's on correct workspace
if (! frame->isSticky() &&
(frame->getWorkspace() != Workspaces::instance()->getActive())) {
Workspaces::instance()->setWorkspace(frame->getWorkspace(), false);
}
// make sure it isn't hidden
if (! frame->isMapped()) {
frame->mapWindow();
}
frame->activateChild(client);
frame->raise();
frame->giveInputFocus();
}
//! @brief Handles iconmenu presses
void
FrameListMenu::handleIconmenu(Client *client)
{
if (! client) {
return;
}
Frame *frame = static_cast<Frame*>(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 || ! client_from) {
return;
}
Frame *frame_to = static_cast<Frame*>(client_to->getParent());
Frame *frame_from = static_cast<Frame*>(client_from->getParent());
// insert frame
if (frame) {
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();
}
}