allow arbitrary window patterns in iconbar

This commit is contained in:
markt 2007-11-12 21:59:43 +00:00
parent 807a1b5575
commit 5d7043320d
28 changed files with 724 additions and 463 deletions

View file

@ -1,5 +1,11 @@
(Format: Year/Month/Day)
Changes for 1.0.1:
*07/11/12:
* Allow arbitrary window patterns for the iconbar mode (Mark)
- Note: for now, if you match against the current head of a window, it will
not be updated as expected in the toolbar
ClientPattern.cc/hh FocusControl.cc/hh IconbarTool.cc/hh FbTk/Subject.cc
fluxbox.cc, added FocusableList.cc/hh
*07/11/08:
* Fix crash when cycling focus and window closes, bug #1787345 (Mark)
FocusControl.cc

View file

@ -31,4 +31,4 @@ session.colorsPerChannel: 4
session.doubleClickInterval: 250
session.cacheMax: 200
session.imageDither: True
session.configVersion: 4
session.configVersion: 5

View file

@ -779,15 +779,10 @@ session.screen0.toolbar.onhead: <integer>
head where they would like to see the slit and toolbar, starting from 1.
Setting this to 0 will ignore xinerama information. Default: 0
session.screen0.iconbar.mode: <mode>
This value is set in the Iconbar Mode menu. The available options are::
- All Windows
- Icons
- NoIcons
- None
- Workspace
- WorkspaceIcons
- WorkspaceNoIcons
session.screen0.iconbar.mode: <pattern>
This determines which windows will be displayed in the iconbar. Any window
pattern available to the Next/PrevWindow keybindings is acceptable.
Default: {static groups} (workspace)
session.screen0.iconbar.usePixmap: <boolean>
This is also set in the Iconbar Mode menu. When set to True, this will

View file

@ -274,9 +274,19 @@ bool ClientPattern::match(const Focusable &win) const {
for (; it != it_end; ++it) {
if ((*it)->orig == "[current]") {
WinClient *focused = FocusControl::focusedWindow();
if (!focused || !((*it)->negate ^
(getProperty((*it)->prop, win) ==
getProperty((*it)->prop, *focused))))
if ((*it)->prop == WORKSPACE) {
char tmpstr[128];
sprintf(tmpstr, "%d", win.screen().currentWorkspaceID());
if (!(*it)->negate ^ (getProperty((*it)->prop, win) == tmpstr))
return false;
} else if ((*it)->prop == WORKSPACENAME) {
const Workspace *w = win.screen().currentWorkspace();
if (!w || (!(*it)->negate ^
(getProperty((*it)->prop, win) == w->name())))
return false;
} else if (!focused || (!(*it)->negate ^
(getProperty((*it)->prop, win) ==
getProperty((*it)->prop, *focused))))
return false;
} else if ((*it)->prop == HEAD &&
(*it)->orig == "[mouse]") {
@ -293,6 +303,26 @@ bool ClientPattern::match(const Focusable &win) const {
return true;
}
bool ClientPattern::dependsOnFocusedWindow() const {
Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end();
for (; it != it_end; ++it) {
if ((*it)->prop != WORKSPACE && (*it)->prop != WORKSPACENAME &&
(*it)->orig == "[current]")
return true;
}
return false;
}
bool ClientPattern::dependsOnCurrentWorkspace() const {
Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end();
for (; it != it_end; ++it) {
if (((*it)->prop == WORKSPACE || (*it)->prop == WORKSPACENAME) &&
(*it)->orig == "[current]")
return true;
}
return false;
}
// add an expression to match against
// The first argument is a regular expression, the second is the member
// function that we wish to match against.

View file

@ -62,6 +62,12 @@ public:
/// Does this client match this pattern?
bool match(const Focusable &win) const;
/// Does this pattern depend on the focused window?
bool dependsOnFocusedWindow() const;
/// Does this pattern depend on the current workspace?
bool dependsOnCurrentWorkspace() const;
/**
* Add an expression to match against
* @param str is a regular expression

View file

@ -33,7 +33,7 @@ bool ColSmartPlacement::placeWindow(const FluxboxWindow &win, int head,
std::list<FluxboxWindow *> windowlist;
const std::list<Focusable *> focusables =
win.screen().focusControl().focusedOrderWinList();
win.screen().focusControl().focusedOrderWinList().clientList();
std::list<Focusable *>::const_iterator foc_it = focusables.begin(),
foc_it_end = focusables.end();
unsigned int workspace = win.workspaceNumber();

View file

@ -345,7 +345,8 @@ void Ewmh::updateClientList(BScreen &screen) {
if (screen.isShuttingdown())
return;
list<Focusable *> creation_order_list = screen.focusControl().creationOrderList();
list<Focusable *> creation_order_list =
screen.focusControl().creationOrderList().clientList();
size_t num = creation_order_list.size();
Window *wl = FB_new_nothrow Window[num];

View file

@ -24,6 +24,7 @@
#include "FbCommandFactory.hh"
#include "FocusableList.hh"
#include "CurrentWindowCmd.hh"
#include "FbCommands.hh"
#include "Window.hh"
@ -59,26 +60,6 @@ static int getint(const char *str, int defaultvalue) {
return defaultvalue;
}
void parseNextWindowArgs(const string &in, int &opts, string &pat) {
string options;
int err = FbTk::StringUtil::getStringBetween(options, in.c_str(), '{', '}');
// the rest of the string is a ClientPattern
pat = in.c_str() + err;
// now parse the options
vector<string> args;
FbTk::StringUtil::stringtok(args, options);
vector<string>::iterator it = args.begin(), it_end = args.end();
opts = 0;
for (; it != it_end; ++it) {
if (strcasecmp((*it).c_str(), "static") == 0)
opts |= FocusControl::CYCLELINEAR;
else if (strcasecmp((*it).c_str(), "groups") == 0)
opts |= FocusControl::CYCLEGROUPS;
}
}
}; // end anonymous namespace
FbCommandFactory::FbCommandFactory() {
@ -522,29 +503,29 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command,
} else if (command == "attach") {
int opts; // not used
string pat;
parseNextWindowArgs(arguments, opts, pat);
FocusableList::parseArgs(arguments, opts, pat);
return new AttachCmd(pat);
} else if (command == "nextwindow") {
int opts;
string pat;
parseNextWindowArgs(arguments, opts, pat);
FocusableList::parseArgs(arguments, opts, pat);
return new NextWindowCmd(opts, pat);
} else if (command == "nextgroup") {
int opts;
string pat;
parseNextWindowArgs(arguments, opts, pat);
opts |= FocusControl::CYCLEGROUPS;
FocusableList::parseArgs(arguments, opts, pat);
opts |= FocusableList::LIST_GROUPS;
return new NextWindowCmd(opts, pat);
} else if (command == "prevwindow") {
int opts;
string pat;
parseNextWindowArgs(arguments, opts, pat);
FocusableList::parseArgs(arguments, opts, pat);
return new PrevWindowCmd(opts, pat);
} else if (command == "prevgroup") {
int opts;
string pat;
parseNextWindowArgs(arguments, opts, pat);
opts |= FocusControl::CYCLEGROUPS;
FocusableList::parseArgs(arguments, opts, pat);
opts |= FocusableList::LIST_GROUPS;
return new PrevWindowCmd(opts, pat);
} else if (command == "gotowindow") {
int num, opts;
@ -554,12 +535,12 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command,
string::size_type pos = arguments.find_first_of("({");
if (pos != string::npos && pos != arguments.size())
args = arguments.c_str() + pos;
parseNextWindowArgs(args, opts, pat);
FocusableList::parseArgs(args, opts, pat);
return new GoToWindowCmd(num, opts, pat);
} else if (command == "clientmenu") {
int opts;
string pat;
parseNextWindowArgs(arguments, opts, pat);
FocusableList::parseArgs(arguments, opts, pat);
return new ShowClientMenuCmd(opts, pat);
} else if (command == "focusup")
return new DirFocusCmd(FocusControl::FOCUSUP);

View file

@ -277,20 +277,12 @@ void ShowClientMenuCmd::execute() {
return;
// TODO: ClientMenu only accepts lists of FluxboxWindows for now
const FocusControl::Focusables *win_list = 0;
// if (m_option & FocusControl::CYCLEGROUPS) {
win_list = (m_option & FocusControl::CYCLELINEAR) ?
&screen->focusControl().creationOrderWinList() :
&screen->focusControl().focusedOrderWinList();
/* } else {
win_list = (m_option & FocusControl::CYCLELINEAR) ?
&screen->focusControl().creationOrderList() :
&screen->focusControl().focusedOrderList();
} */
// when that's fixed, use a FocusableList for m_list
const FocusableList *list =
FocusableList::getListFromOptions(*screen, m_option);
m_list.clear();
FocusControl::Focusables::const_iterator it = win_list->begin(),
it_end = win_list->end();
FocusControl::Focusables::const_iterator it = list->clientList().begin(),
it_end = list->clientList().end();
for (; it != it_end; ++it) {
if (typeid(**it) == typeid(FluxboxWindow) && m_pat.match(**it))
m_list.push_back(static_cast<FluxboxWindow *>(*it));

View file

@ -31,6 +31,7 @@
#include "FbTk/RefCount.hh"
#include "ClientMenu.hh"
#include "ClientPattern.hh"
#include "FocusableList.hh"
#include <list>
#include <string>
@ -118,7 +119,7 @@ public:
class ShowClientMenuCmd: public FbTk::Command {
public:
ShowClientMenuCmd(int option, std::string &pat):
m_option(option), m_pat(pat.c_str()) { }
m_option(option|FocusableList::LIST_GROUPS), m_pat(pat.c_str()) { }
void execute();
private:
const int m_option;

View file

@ -58,16 +58,22 @@ void Subject::detach(Observer *obj) {
}
void Subject::notify() {
m_notify_mode = true;
std::for_each(m_observerlist.begin(), m_observerlist.end(),
std::bind2nd(std::mem_fun(&Observer::update), this));
m_notify_mode = false;
ObserverList::iterator it = m_observerlist.begin(),
it_end = m_observerlist.end();
for (; it != it_end; ++it) {
m_notify_mode = true;
(*it)->update(this);
ObserverList::iterator d_it = m_dead_observers.begin(),
d_it_end = m_dead_observers.end();
m_notify_mode = false;
// remove dead observers
if (!m_dead_observers.empty()) {
std::for_each(m_dead_observers.begin(),
m_dead_observers.end(),
std::bind1st(std::mem_fun(&Subject::detach), this));
// there might be dead observers later in the list, so we must remove
// them now
for (; d_it != d_it_end; ++d_it) {
if (*d_it == *it)
--it; // don't invalidate our iterator
detach(*d_it);
}
m_dead_observers.clear();
}
}

View file

@ -78,15 +78,17 @@ FocusControl::FocusControl(BScreen &screen):
m_focus_new(screen.resourceManager(), true,
screen.name()+".focusNewWindows",
screen.altName()+".FocusNewWindows"),
m_focused_list(screen), m_creation_order_list(screen),
m_focused_win_list(screen), m_creation_order_win_list(screen),
m_cycling_list(0),
m_was_iconic(false),
m_cycling_last(0) {
m_cycling_window = m_focused_win_list.end();
m_cycling_window = m_focused_list.clientList().end();
}
void FocusControl::cycleFocus(const Focusables &window_list,
void FocusControl::cycleFocus(const FocusableList &window_list,
const ClientPattern *pat, bool cycle_reverse) {
if (!m_cycling_list) {
@ -98,8 +100,8 @@ void FocusControl::cycleFocus(const Focusables &window_list,
} else if (m_cycling_list != &window_list)
m_cycling_list = &window_list;
Focusables::const_iterator it_begin = window_list.begin();
Focusables::const_iterator it_end = window_list.end();
Focusables::const_iterator it_begin = window_list.clientList().begin();
Focusables::const_iterator it_end = window_list.clientList().end();
// too many things can go wrong with remembering this
m_cycling_window = find(it_begin, it_end, s_focused_window);
@ -165,10 +167,10 @@ void FocusControl::cycleFocus(const Focusables &window_list,
}
void FocusControl::goToWindowNumber(const Focusables &winlist, int num,
void FocusControl::goToWindowNumber(const FocusableList &winlist, int num,
const ClientPattern *pat) {
Focusables::const_iterator it = winlist.begin();
Focusables::const_iterator it_end = winlist.end();
Focusables::const_iterator it = winlist.clientList().begin();
Focusables::const_iterator it_end = winlist.clientList().end();
for (; it != it_end && num; ++it) {
if (!doSkipWindow(**it, pat) && (*it)->acceptsFocus()) {
num > 0 ? --num : ++num;
@ -182,61 +184,43 @@ void FocusControl::goToWindowNumber(const Focusables &winlist, int num,
}
void FocusControl::addFocusBack(WinClient &client) {
m_focused_list.push_back(&client);
m_creation_order_list.push_back(&client);
m_focused_list.pushBack(client);
m_creation_order_list.pushBack(client);
}
void FocusControl::addFocusFront(WinClient &client) {
m_focused_list.push_front(&client);
m_creation_order_list.push_back(&client);
m_focused_list.pushFront(client);
m_creation_order_list.pushBack(client);
}
void FocusControl::addFocusWinBack(Focusable &win) {
m_focused_win_list.push_back(&win);
m_creation_order_win_list.push_back(&win);
m_focused_win_list.pushBack(win);
m_creation_order_win_list.pushBack(win);
}
void FocusControl::addFocusWinFront(Focusable &win) {
m_focused_win_list.push_front(&win);
m_creation_order_win_list.push_back(&win);
m_focused_win_list.pushFront(win);
m_creation_order_win_list.pushBack(win);
}
// move all clients in given window to back of focused list
void FocusControl::setFocusBack(FluxboxWindow *fbwin) {
void FocusControl::setFocusBack(FluxboxWindow &fbwin) {
// do nothing if there are no windows open
// don't change focus order while cycling
if (m_focused_list.empty() || s_reverting)
return;
// if the window isn't already in this list, we could accidentally add it
Focusables::iterator win_begin = m_focused_win_list.begin(),
win_end = m_focused_win_list.end();
Focusables::iterator win_it = find(win_begin, win_end, fbwin);
if (win_it == win_end)
return;
m_focused_win_list.moveToBack(fbwin);
m_focused_win_list.erase(win_it);
m_focused_win_list.push_back(fbwin);
Focusables::iterator it = m_focused_list.begin();
// use back to avoid an infinite loop
Focusables::iterator it_back = --m_focused_list.end();
while (it != it_back) {
if ((*it)->fbwindow() == fbwin) {
m_focused_list.push_back(*it);
it = m_focused_list.erase(it);
} else
++it;
// we need to move its clients to the back while preserving their order
Focusables list = m_focused_list.clientList();
Focusables::iterator it = list.begin(), it_end = list.end();
for (; it != it_end; ++it) {
if ((*it)->fbwindow() == &fbwin)
m_focused_list.moveToBack(**it);
}
// move the last one, if necessary, in order to preserve focus order
if ((*it)->fbwindow() == fbwin) {
m_focused_list.push_back(*it);
m_focused_list.erase(it);
}
}
void FocusControl::stopCyclingFocus() {
// nothing to do
if (m_cycling_list == 0)
@ -262,10 +246,10 @@ void FocusControl::stopCyclingFocus() {
Focusable *FocusControl::lastFocusedWindow(int workspace) {
if (m_focused_list.empty() || m_screen.isShuttingdown()) return 0;
if (workspace < 0 || workspace >= (int) m_screen.numberOfWorkspaces())
return m_focused_list.front();
return m_focused_list.clientList().front();
Focusables::iterator it = m_focused_list.begin();
Focusables::iterator it_end = m_focused_list.end();
Focusables::iterator it = m_focused_list.clientList().begin();
Focusables::iterator it_end = m_focused_list.clientList().end();
for (; it != it_end; ++it) {
if ((*it)->fbwindow() &&
((((int)(*it)->fbwindow()->workspaceNumber()) == workspace ||
@ -285,8 +269,8 @@ WinClient *FocusControl::lastFocusedWindow(FluxboxWindow &group, WinClient *igno
if (m_focused_list.empty() || m_screen.isShuttingdown())
return 0;
Focusables::iterator it = m_focused_list.begin();
Focusables::iterator it_end = m_focused_list.end();
Focusables::iterator it = m_focused_list.clientList().begin();
Focusables::iterator it_end = m_focused_list.clientList().end();
for (; it != it_end; ++it) {
if (((*it)->fbwindow() == &group) &&
(*it) != ignore_client)
@ -300,27 +284,9 @@ void FocusControl::setScreenFocusedWindow(WinClient &win_client) {
// raise newly focused window to the top of the focused list
// don't change the order if we're cycling or shutting down
if (!isCycling() && !m_screen.isShuttingdown() && !s_reverting) {
// make sure client is in our list, or else we could end up adding it
Focusables::iterator it_begin = m_focused_list.begin(),
it_end = m_focused_list.end();
Focusables::iterator it = find(it_begin, it_end, &win_client);
if (it == it_end)
return;
m_focused_list.erase(it);
m_focused_list.push_front(&win_client);
// also check the fbwindow
it_begin = m_focused_win_list.begin();
it_end = m_focused_win_list.end();
it = find(it_begin, it_end, win_client.fbwindow());
if (it != it_end) {
m_focused_win_list.erase(it);
m_focused_win_list.push_front(win_client.fbwindow());
}
m_focused_list.moveToFront(win_client);
if (win_client.fbwindow())
m_focused_win_list.moveToFront(*win_client.fbwindow());
}
}
@ -435,15 +401,15 @@ void FocusControl::removeClient(WinClient &client) {
if (client.screen().isShuttingdown())
return;
if (m_cycling_list && m_cycling_window != m_cycling_list->end() &&
if (isCycling() && m_cycling_window != m_cycling_list->clientList().end() &&
*m_cycling_window == &client) {
m_cycling_window = m_cycling_list->end();
m_cycling_window = m_cycling_list->clientList().end();
stopCyclingFocus();
} else if (m_cycling_last == &client)
m_cycling_last = 0;
m_focused_list.remove(&client);
m_creation_order_list.remove(&client);
m_focused_list.remove(client);
m_creation_order_list.remove(client);
client.screen().clientListSig().notify();
}
@ -451,21 +417,21 @@ void FocusControl::removeWindow(Focusable &win) {
if (win.screen().isShuttingdown())
return;
if (m_cycling_list && m_cycling_window != m_cycling_list->end() &&
if (isCycling() && m_cycling_window != m_cycling_list->clientList().end() &&
*m_cycling_window == &win) {
m_cycling_window = m_cycling_list->end();
m_cycling_window = m_cycling_list->clientList().end();
stopCyclingFocus();
}
m_focused_win_list.remove(&win);
m_creation_order_win_list.remove(&win);
m_focused_win_list.remove(win);
m_creation_order_win_list.remove(win);
win.screen().clientListSig().notify();
}
void FocusControl::shutdown() {
// restore windows backwards so they get put back correctly on restart
Focusables::reverse_iterator it = m_focused_list.rbegin();
for (; it != m_focused_list.rend(); ++it) {
Focusables::reverse_iterator it = m_focused_list.clientList().rbegin();
for (; it != m_focused_list.clientList().rend(); ++it) {
WinClient *client = dynamic_cast<WinClient *>(*it);
if (client && client->fbwindow())
client->fbwindow()->restore(client, true);
@ -582,7 +548,10 @@ void FocusControl::setFocusedWindow(WinClient *client) {
}
// update AtomHandlers and/or other stuff...
Fluxbox::instance()->updateFocusedWindow(screen, old_screen);
if (screen)
screen->focusedWindowSig().notify();
if (old_screen && screen != old_screen)
old_screen->focusedWindowSig().notify();
}
////////////////////// FocusControl RESOURCES

View file

@ -27,6 +27,7 @@
#include <list>
#include "FbTk/Resource.hh"
#include "FocusableList.hh"
class ClientPattern;
class WinClient;
@ -60,12 +61,6 @@ public:
FOCUSRIGHT ///< window is right
};
/// prevFocus/nextFocus option bits
enum {
CYCLEGROUPS = 0x01, //< cycle through groups
CYCLELINEAR = 0x08, ///< linear cycle
};
explicit FocusControl(BScreen &screen);
/// cycle previous focuable
void prevFocus() { cycleFocus(m_focused_list, 0, true); }
@ -77,10 +72,10 @@ public:
* @param pat pattern for matching focusables
* @param reverse reverse the cycle order
*/
void cycleFocus(const Focusables &winlist, const ClientPattern *pat = 0,
void cycleFocus(const FocusableList &winlist, const ClientPattern *pat = 0,
bool reverse = false);
void goToWindowNumber(const Focusables &winlist, int num,
void goToWindowNumber(const FocusableList &winlist, int num,
const ClientPattern *pat = 0);
/// sets the focused window on a screen
void setScreenFocusedWindow(WinClient &win_client);
@ -108,7 +103,7 @@ public:
void addFocusFront(WinClient &client);
void addFocusWinBack(Focusable &win);
void addFocusWinFront(Focusable &win);
void setFocusBack(FluxboxWindow *fbwin);
void setFocusBack(FluxboxWindow &fbwin);
/// @return main focus model
FocusModel focusModel() const { return *m_focus_model; }
/// @return tab focus model
@ -122,11 +117,11 @@ public:
WinClient *lastFocusedWindow(FluxboxWindow &group, WinClient *ignore_client = 0);
/// @return focus list in creation order
const Focusables &creationOrderList() const { return m_creation_order_list; }
const FocusableList &creationOrderList() const { return m_creation_order_list; }
/// @return the focus list in focused order
const Focusables &focusedOrderList() const { return m_focused_list; }
const Focusables &creationOrderWinList() const { return m_creation_order_win_list; }
const Focusables &focusedOrderWinList() const { return m_focused_win_list; }
const FocusableList &focusedOrderList() const { return m_focused_list; }
const FocusableList &creationOrderWinList() const { return m_creation_order_win_list; }
const FocusableList &focusedOrderWinList() const { return m_focused_win_list; }
/// remove client from focus list
void removeClient(WinClient &client);
@ -153,13 +148,13 @@ private:
// This list keeps the order of window focusing for this screen
// Screen global so it works for sticky windows too.
Focusables m_focused_list;
Focusables m_creation_order_list;
Focusables m_focused_win_list;
Focusables m_creation_order_win_list;
FocusableList m_focused_list;
FocusableList m_creation_order_list;
FocusableList m_focused_win_list;
FocusableList m_creation_order_win_list;
Focusables::const_iterator m_cycling_window;
const Focusables *m_cycling_list;
const FocusableList *m_cycling_list;
Focusable *m_was_iconic;
WinClient *m_cycling_last;

View file

@ -19,7 +19,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id$
// $Id: $
#ifndef FOCUSABLE_HH
#define FOCUSABLE_HH

293
src/FocusableList.cc Normal file
View file

@ -0,0 +1,293 @@
// FocusableList.cc
// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: $
#include "FocusableList.hh"
#include "Focusable.hh"
#include "FocusControl.hh"
#include "Screen.hh"
#include "WinClient.hh"
#include "Window.hh"
#include "FbTk/StringUtil.hh"
#include <vector>
using std::string;
using std::vector;
void FocusableList::parseArgs(const string &in, int &opts, string &pat) {
string options;
int err = FbTk::StringUtil::getStringBetween(options, in.c_str(), '{', '}');
// the rest of the string is a ClientPattern
pat = in.c_str() + err;
// now parse the options
vector<string> args;
FbTk::StringUtil::stringtok(args, options);
vector<string>::iterator it = args.begin(), it_end = args.end();
opts = 0;
for (; it != it_end; ++it) {
if (strcasecmp((*it).c_str(), "static") == 0)
opts |= STATIC_ORDER;
else if (strcasecmp((*it).c_str(), "groups") == 0)
opts |= LIST_GROUPS;
}
}
const FocusableList *FocusableList::getListFromOptions(BScreen &scr, int opts) {
if (opts & LIST_GROUPS)
return (opts & STATIC_ORDER) ?
&scr.focusControl().creationOrderWinList() :
&scr.focusControl().focusedOrderWinList();
return (opts & STATIC_ORDER) ?
&scr.focusControl().creationOrderList() :
&scr.focusControl().focusedOrderList();
}
FocusableList::FocusableList(BScreen &scr, const string pat):
m_pat(0), m_parent(0), m_screen(scr) {
int options = 0;
string pattern;
parseArgs(pat, options, pattern);
m_parent = getListFromOptions(scr, options);
m_pat.reset(new ClientPattern(pattern.c_str()));
init();
}
FocusableList::FocusableList(BScreen &scr, const FocusableList &parent,
const string pat):
m_pat(new ClientPattern(pat.c_str())), m_parent(&parent), m_screen(scr) {
init();
}
void FocusableList::init() {
addMatching();
m_parent->attachChild(*this);
// TODO: can't handle (head=[mouse]) yet
if (m_pat->dependsOnCurrentWorkspace())
m_screen.currentWorkspaceSig().attach(this);
if (m_pat->dependsOnFocusedWindow())
m_screen.focusedWindowSig().attach(this);
}
void FocusableList::update(FbTk::Subject *subj) {
if (subj == 0 || m_screen.isShuttingdown())
return;
if (typeid(*subj) == typeid(Focusable::FocusSubject)) {
Focusable::FocusSubject *fsubj =
static_cast<Focusable::FocusSubject *>(subj);
if (fsubj == &fsubj->win().dieSig())
remove(fsubj->win());
else if (fsubj == &fsubj->win().titleSig())
checkUpdate(fsubj->win());
}
if (typeid(*subj) == typeid(FluxboxWindow::WinSubject)) {
FluxboxWindow::WinSubject *fsubj =
static_cast<FluxboxWindow::WinSubject *>(subj);
// we only bind these for matching patterns, so skip finding out signal
FluxboxWindow &fbwin = fsubj->win();
if (m_parent->contains(fbwin))
checkUpdate(fbwin);
std::list<WinClient *> list = fbwin.clientList();
std::list<WinClient *>::iterator it = list.begin(), it_end = list.end();
for (; it != it_end; ++it) {
if (m_parent->contains(**it))
checkUpdate(**it);
}
}
if (typeid(*subj) == typeid(FocusableListSubject)) {
FocusableListSubject *fsubj =
static_cast<FocusableListSubject *>(subj);
if (subj == &m_parent->addSig()) {
if (m_pat->match(*fsubj->win())) {
insertFromParent(*fsubj->win());
m_addsig.notify(fsubj->win());
} else // we still want to watch it, in case it changes to match
attachSignals(*fsubj->win());
} else if (subj == &m_parent->removeSig())
remove(*fsubj->win());
else if (subj == &m_parent->resetSig())
reset();
else if (subj == &m_parent->orderSig()) {
Focusable *win = fsubj->win();
if (!win || !contains(*win))
return;
if (insertFromParent(*win))
m_ordersig.notify(win);
}
} else if (subj == &m_screen.currentWorkspaceSig() ||
subj == &m_screen.focusedWindowSig())
reset();
}
void FocusableList::checkUpdate(Focusable &win) {
if (contains(win)) {
if (!m_pat->match(win)) {
m_list.remove(&win);
m_removesig.notify(&win);
}
} else if (m_pat->match(win)) {
insertFromParent(win);
m_addsig.notify(&win);
}
}
// returns whether or not the window was moved
bool FocusableList::insertFromParent(Focusable &win) {
const Focusables list = m_parent->clientList();
Focusables::const_iterator p_it = list.begin(), p_it_end = list.end();
Focusables::iterator our_it = m_list.begin(), our_it_end = m_list.end();
// walk through our list looking for corresponding entries in
// parent's list, until we find the window that moved
for (; our_it != our_it_end && p_it != p_it_end; p_it++) {
if (*p_it == &win) {
if (*our_it == &win) // win didn't move in our list
return false;
m_list.remove(&win);
m_list.insert(our_it, &win);
return true;
}
if (*p_it == *our_it)
++our_it;
}
m_list.remove(&win);
m_list.push_back(&win);
return true;
}
void FocusableList::addMatching() {
if (!m_parent)
return;
const Focusables list = m_parent->clientList();
Focusables::const_iterator it = list.begin(), it_end = list.end();
for (; it != it_end; ++it) {
if (m_pat->match(**it))
pushBack(**it);
else // we still want to watch it, in case it changes to match
attachSignals(**it);
}
}
void FocusableList::pushFront(Focusable &win) {
m_list.push_front(&win);
attachSignals(win);
m_addsig.notify(&win);
}
void FocusableList::pushBack(Focusable &win) {
m_list.push_back(&win);
attachSignals(win);
m_addsig.notify(&win);
}
void FocusableList::moveToFront(Focusable &win) {
// if the window isn't already in this list, we could accidentally add it
if (!contains(win))
return;
m_list.remove(&win);
m_list.push_front(&win);
m_ordersig.notify(&win);
}
void FocusableList::moveToBack(Focusable &win) {
// if the window isn't already in this list, we could accidentally add it
if (!contains(win))
return;
m_list.remove(&win);
m_list.push_back(&win);
m_ordersig.notify(&win);
}
void FocusableList::remove(Focusable &win) {
// if the window isn't already in this list, we could send a bad signal
bool contained = contains(win);
detachSignals(win);
if (!contained)
return;
m_list.remove(&win);
m_removesig.notify(&win);
}
void FocusableList::attachSignals(Focusable &win) {
win.dieSig().attach(this);
if (m_parent) {
// attach various signals for matching
win.titleSig().attach(this);
FluxboxWindow *fbwin = win.fbwindow();
if (!fbwin)
return;
fbwin->workspaceSig().attach(this);
fbwin->stateSig().attach(this);
fbwin->layerSig().attach(this);
// TODO: can't watch (head=...) yet
}
}
void FocusableList::detachSignals(Focusable &win) {
win.dieSig().detach(this);
if (m_parent) {
// detach various signals for matching
win.titleSig().detach(this);
FluxboxWindow *fbwin = win.fbwindow();
if (!fbwin)
return;
fbwin->workspaceSig().detach(this);
fbwin->stateSig().detach(this);
fbwin->layerSig().detach(this);
// TODO: can't watch (head=...) yet
}
}
void FocusableList::reset() {
while (!m_list.empty()) {
detachSignals(*m_list.back());
m_list.pop_back();
}
if (m_parent)
addMatching();
m_resetsig.notify(0);
}
bool FocusableList::contains(const Focusable &win) const {
Focusables::const_iterator it = m_list.begin(), it_end = m_list.end();
it = find(it, it_end, &win);
return (it != it_end);
}
void FocusableList::attachChild(FocusableList &child) const {
m_addsig.attach(&child);
m_removesig.attach(&child);
m_resetsig.attach(&child);
m_ordersig.attach(&child);
}

121
src/FocusableList.hh Normal file
View file

@ -0,0 +1,121 @@
// FocusableList.hh
// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// $Id: $
#ifndef FOCUSABLELIST_HH
#define FOCUSABLELIST_HH
#include "FbTk/NotCopyable.hh"
#include "FbTk/Observer.hh"
#include "FbTk/Subject.hh"
#include "ClientPattern.hh"
#include <list>
#include <string>
class BScreen;
class Focusable;
class FocusableList: public FbTk::Observer, private FbTk::NotCopyable {
public:
typedef std::list<Focusable *> Focusables;
/// list option bits
enum {
LIST_GROUPS = 0x01, //< list groups instead of clients
STATIC_ORDER = 0x02, ///< use creation order instead of focused order
};
FocusableList(BScreen &scr): m_pat(0), m_parent(0), m_screen(scr) { }
FocusableList(BScreen &scr, const std::string pat);
FocusableList(BScreen &scr, const FocusableList &parent,
const std::string pat);
static void parseArgs(const std::string &in, int &opts, std::string &out);
static const FocusableList *getListFromOptions(BScreen &scr, int opts);
void update(FbTk::Subject *subj);
/// functions for modifying the list contents
void pushFront(Focusable &win);
void pushBack(Focusable &win);
void moveToFront(Focusable &win);
void moveToBack(Focusable &win);
void remove(Focusable &win);
/// accessor for list
Focusables &clientList() { return m_list; }
const Focusables &clientList() const { return m_list; }
/// does the list contain any windows?
bool empty() const { return m_list.empty(); }
/// does the list contain the given window?
bool contains(const Focusable &win) const;
/**
@name signals
@{
*/
FbTk::Subject &orderSig() { return m_ordersig; }
const FbTk::Subject &orderSig() const { return m_ordersig; }
FbTk::Subject &addSig() { return m_addsig; }
const FbTk::Subject &addSig() const { return m_addsig; }
FbTk::Subject &removeSig() { return m_removesig; }
const FbTk::Subject &removeSig() const { return m_removesig; }
FbTk::Subject &resetSig() { return m_resetsig; }
const FbTk::Subject &resetSig() const { return m_resetsig; }
/** @} */ // end group signals
/**
* Signaling object to attatch observers to.
*/
class FocusableListSubject: public FbTk::Subject {
public:
explicit FocusableListSubject(): m_win(0) { }
void notify(Focusable *win) { m_win = win; FbTk::Subject::notify(); }
/// @return context for this signal
Focusable *win() { return m_win; }
private:
Focusable *m_win;
};
private:
void init();
void addMatching();
void checkUpdate(Focusable &win);
bool insertFromParent(Focusable &win);
void attachSignals(Focusable &win);
void detachSignals(Focusable &win);
void reset();
void attachChild(FocusableList &child) const;
std::auto_ptr<ClientPattern> m_pat;
const FocusableList *m_parent;
BScreen &m_screen;
std::list<Focusable *> m_list;
mutable FocusableListSubject m_ordersig, m_addsig, m_removesig, m_resetsig;
};
#endif // FOCUSABLELIST_HH

View file

@ -38,6 +38,7 @@
#include "FocusControl.hh"
#include "FbCommands.hh"
#include "Layer.hh"
#include "STLUtil.hh"
#include "FbTk/I18n.hh"
#include "FbTk/Menu.hh"
@ -67,26 +68,6 @@ using std::endl;
namespace FbTk {
template<>
void FbTk::Resource<IconbarTool::Mode>::setFromString(const char *strval) {
if (strcasecmp(strval, "None") == 0)
m_value = IconbarTool::NONE;
else if (strcasecmp(strval, "Icons") == 0)
m_value = IconbarTool::ICONS;
else if (strcasecmp(strval, "NoIcons") == 0)
m_value = IconbarTool::NOICONS;
else if (strcasecmp(strval, "WorkspaceIcons") == 0)
m_value = IconbarTool::WORKSPACEICONS;
else if (strcasecmp(strval, "WorkspaceNoIcons") == 0)
m_value = IconbarTool::WORKSPACENOICONS;
else if (strcasecmp(strval, "Workspace") == 0)
m_value = IconbarTool::WORKSPACE;
else if (strcasecmp(strval, "AllWindows") == 0)
m_value = IconbarTool::ALLWINDOWS;
else
setDefaultValue();
}
template<>
void FbTk::Resource<Container::Alignment>::setDefaultValue() {
m_value = Container::RELATIVE;
@ -117,35 +98,6 @@ void FbTk::Resource<Container::Alignment>::setFromString(const char *str) {
setDefaultValue();
}
template<>
string FbTk::Resource<IconbarTool::Mode>::getString() const {
switch (m_value) {
case IconbarTool::NONE:
return string("None");
break;
case IconbarTool::ICONS:
return string("Icons");
break;
case IconbarTool::NOICONS:
return string("NoIcons");
break;
case IconbarTool::WORKSPACEICONS:
return string("WorkspaceIcons");
break;
case IconbarTool::WORKSPACENOICONS:
return string("WorkspaceNoIcons");
break;
case IconbarTool::WORKSPACE:
return string("Workspace");
break;
case IconbarTool::ALLWINDOWS:
return string("AllWindows");
break;
}
// default string
return string("Icons");
}
} // end namespace FbTk
namespace {
@ -153,7 +105,7 @@ namespace {
class ToolbarModeMenuItem : public FbTk::MenuItem {
public:
ToolbarModeMenuItem(const FbTk::FbString &label, IconbarTool &handler,
IconbarTool::Mode mode,
string mode,
FbTk::RefCount<FbTk::Command> &cmd):
FbTk::MenuItem(label, cmd), m_handler(handler), m_mode(mode) {
}
@ -165,7 +117,7 @@ public:
private:
IconbarTool &m_handler;
IconbarTool::Mode m_mode;
string m_mode;
};
class ToolbarAlignMenuItem: public FbTk::MenuItem {
@ -198,42 +150,42 @@ void setupModeMenu(FbTk::Menu &menu, IconbarTool &handler) {
menu.insert(new ToolbarModeMenuItem(_FB_XTEXT(Toolbar, IconbarModeNone,
"None", "No icons are shown in the iconbar"),
handler,
IconbarTool::NONE, saverc_cmd));
"none", saverc_cmd));
menu.insert(new ToolbarModeMenuItem(
_FB_XTEXT(Toolbar, IconbarModeIcons,
"Icons", "Iconified windows from all workspaces are shown"),
handler,
IconbarTool::ICONS, saverc_cmd));
"{static groups} (minimized=yes)", saverc_cmd));
menu.insert(new ToolbarModeMenuItem(
_FB_XTEXT(Toolbar, IconbarModeNoIcons,
"NoIcons", "No iconified windows from all workspaces are shown"),
handler,
IconbarTool::NOICONS, saverc_cmd));
"{static groups} (minimized=no)", saverc_cmd));
menu.insert(new ToolbarModeMenuItem(
_FB_XTEXT(Toolbar, IconbarModeWorkspaceIcons,
"WorkspaceIcons", "Iconified windows from this workspace are shown"),
handler,
IconbarTool::WORKSPACEICONS, saverc_cmd));
"{static groups} (minimized=yes) (workspace)", saverc_cmd));
menu.insert(new ToolbarModeMenuItem(
_FB_XTEXT(Toolbar, IconbarModeWorkspaceNoIcons,
"WorkspaceNoIcons", "No iconified windows from this workspace are shown"),
handler,
IconbarTool::WORKSPACENOICONS, saverc_cmd));
"{static groups} (minimized=no) (workspace)", saverc_cmd));
menu.insert(new ToolbarModeMenuItem(
_FB_XTEXT(Toolbar, IconbarModeWorkspace,
"Workspace", "Normal and iconified windows from this workspace are shown"),
handler,
IconbarTool::WORKSPACE, saverc_cmd));
"{static groups} (workspace)", saverc_cmd));
menu.insert(new ToolbarModeMenuItem(
_FB_XTEXT(Toolbar, IconbarModeAllWindows, "All Windows", "All windows are shown"),
handler,
IconbarTool::ALLWINDOWS, saverc_cmd));
"{static groups}", saverc_cmd));
menu.insert(new FbTk::MenuSeparator());
@ -257,26 +209,6 @@ void setupModeMenu(FbTk::Menu &menu, IconbarTool &handler) {
menu.updateMenu();
}
inline bool checkAddWindow(IconbarTool::Mode mode, const FluxboxWindow &win) {
if (win.isIconHidden() || mode == IconbarTool::NONE)
return false;
if ((mode == IconbarTool::ICONS || mode == IconbarTool::WORKSPACEICONS) &&
!win.isIconic())
return false;
if ((mode == IconbarTool::NOICONS || mode == IconbarTool::WORKSPACENOICONS)
&& win.isIconic())
return false;
if ((mode == IconbarTool::WORKSPACE || mode == IconbarTool::WORKSPACEICONS
|| mode == IconbarTool::WORKSPACENOICONS) &&
win.workspaceNumber() != win.screen().currentWorkspaceID())
return false;
return true;
}
typedef FbTk::RefCount<FbTk::Command> RefCmd;
class ShowMenu: public FbTk::Command {
@ -322,14 +254,16 @@ private:
}; // end anonymous namespace
IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScreen &screen,
FbTk::Menu &menu):
IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme,
BScreen &screen, FbTk::Menu &menu):
ToolbarItem(ToolbarItem::RELATIVE),
m_screen(screen),
m_icon_container(parent),
m_theme(theme),
m_empty_pm( screen.imageControl() ),
m_rc_mode(screen.resourceManager(), WORKSPACE,
m_winlist(new FocusableList(screen)),
m_mode("none"),
m_rc_mode(screen.resourceManager(), "{static groups} (workspace)",
screen.name() + ".iconbar.mode", screen.altName() + ".Iconbar.Mode"),
m_rc_alignment(screen.resourceManager(), Container::LEFT,
screen.name() + ".iconbar.alignment", screen.altName() + ".Iconbar.Alignment"),
@ -365,10 +299,7 @@ IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScr
// setup signals
theme.reconfigSig().attach(this);
screen.clientListSig().attach(this);
screen.iconListSig().attach(this);
screen.currentWorkspaceSig().attach(this);
setMode(*m_rc_mode);
}
IconbarTool::~IconbarTool() {
@ -405,20 +336,33 @@ void IconbarTool::setAlignment(Container::Alignment align) {
m_menu.reconfigure();
}
void IconbarTool::setMode(Mode mode) {
if (mode == *m_rc_mode)
void IconbarTool::setMode(string mode) {
if (mode == m_mode)
return;
*m_rc_mode = mode;
*m_rc_mode = m_mode = mode;
// lock graphics update
m_icon_container.setUpdateLock(true);
deleteIcons();
// update mode
if (mode != NONE)
updateList();
if (m_winlist.get()) {
m_winlist->addSig().detach(this);
m_winlist->removeSig().detach(this);
m_winlist->orderSig().detach(this);
m_winlist->resetSig().detach(this);
}
if (mode == "none")
m_winlist.reset(new FocusableList(m_screen));
else
m_winlist.reset(new FocusableList(m_screen,
mode + " (iconhidden=no)"));
if (m_winlist.get()) {
m_winlist->addSig().attach(this);
m_winlist->removeSig().attach(this);
m_winlist->orderSig().attach(this);
m_winlist->resetSig().attach(this);
}
reset();
// unlock graphics update
m_icon_container.setUpdateLock(false);
@ -445,10 +389,7 @@ unsigned int IconbarTool::borderWidth() const {
void IconbarTool::update(FbTk::Subject *subj) {
// ignore updates if we're shutting down
if (m_screen.isShuttingdown()) {
m_screen.clientListSig().detach(this);
m_screen.iconListSig().detach(this);
m_screen.currentWorkspaceSig().detach(this);
if (!m_icon_list.empty())
if (!m_icons.empty())
deleteIcons();
return;
}
@ -462,68 +403,26 @@ void IconbarTool::update(FbTk::Subject *subj) {
m_icon_container.setMaxSizePerClient(*m_rc_client_width);
if (mode() == NONE) {
if (subj != 0 && typeid(*subj) == typeid(IconbarTheme))
renderTheme();
if (subj == &m_theme.reconfigSig()) {
setMode(*m_rc_mode);
return;
}
// handle window signal
if (subj != 0 && typeid(*subj) == typeid(FluxboxWindow::WinSubject)) {
// we handle everything except die signal here
FluxboxWindow::WinSubject *winsubj = static_cast<FluxboxWindow::WinSubject *>(subj);
if (subj == &(winsubj->win().workspaceSig())) {
// we can ignore this signal if we're in ALLWINDOWS mode
if (mode() == ALLWINDOWS || mode() == ICONS || mode() == NOICONS)
return;
// workspace changed for this window, and if it's not on current workspace we remove it
if (m_screen.currentWorkspaceID() != winsubj->win().workspaceNumber()) {
removeWindow(winsubj->win());
renderTheme();
}
return;
} else if (subj == &(winsubj->win().stateSig())) {
if (!checkAddWindow(mode(), winsubj->win())) {
removeWindow(winsubj->win());
renderTheme();
}
return;
} else {
// signal not handled
return;
}
} else if (subj != 0 && typeid(*subj) == typeid(Focusable::FocusSubject)) {
Focusable::FocusSubject *winsubj = static_cast<Focusable::FocusSubject *>(subj);
if (subj == &(winsubj->win().dieSig())) { // die sig
removeWindow(winsubj->win());
renderTheme();
return; // we don't need to update the entire list
}
}
bool remove_all = false; // if we should readd all windows
if (subj != 0 && typeid(*subj) == typeid(BScreen::ScreenSubject) &&
mode() != ALLWINDOWS && mode() != ICONS && mode() != NOICONS) {
BScreen::ScreenSubject *screen_subj = static_cast<BScreen::ScreenSubject *>(subj);
// current workspace sig
if (&m_screen.currentWorkspaceSig() == screen_subj ) {
remove_all = true; // remove and readd all windows
}
}
// lock graphic update
m_icon_container.setUpdateLock(true);
if (remove_all)
deleteIcons();
// ok, we got some signal that we need to update our iconbar container
updateList();
if (typeid(*subj) == typeid(FocusableList::FocusableListSubject)) {
FocusableList::FocusableListSubject *fsubj =
static_cast<FocusableList::FocusableListSubject *>(subj);
if (subj == &m_winlist->addSig())
insertWindow(*fsubj->win());
else if (subj == &m_winlist->removeSig())
removeWindow(*fsubj->win());
else if (subj == &m_winlist->resetSig())
reset();
else if (subj == &m_winlist->orderSig())
insertWindow(*fsubj->win());
}
// unlock container and update graphics
m_icon_container.setUpdateLock(false);
@ -540,25 +439,42 @@ void IconbarTool::update(FbTk::Subject *subj) {
renderTheme();
}
IconButton *IconbarTool::findButton(Focusable &win) {
void IconbarTool::insertWindow(Focusable &win, int pos) {
IconButton *button = 0;
IconList::iterator icon_it = m_icon_list.begin();
IconList::iterator icon_it_end = m_icon_list.end();
for (; icon_it != icon_it_end; ++icon_it) {
if (&(*icon_it)->win() == &win)
return *icon_it;
IconMap::iterator icon_it = m_icons.find(&win);
if (icon_it != m_icons.end())
button = icon_it->second;
if (button)
m_icon_container.removeItem(button);
else
button = makeButton(win);
if (!button) return;
if (pos == -2) {
pos = 0;
list<Focusable *>::iterator it = m_winlist->clientList().begin(),
it_end = m_winlist->clientList().end();
for (; it != it_end && *it != &win; ++it)
pos++;
}
return 0;
m_icon_container.insertItem(button, pos);
}
void IconbarTool::reset() {
deleteIcons();
updateList();
}
void IconbarTool::updateSizing() {
m_icon_container.setBorderWidth(m_theme.border().width());
IconList::iterator icon_it = m_icon_list.begin();
const IconList::iterator icon_it_end = m_icon_list.end();
IconMap::iterator icon_it = m_icons.begin();
const IconMap::iterator icon_it_end = m_icons.end();
for (; icon_it != icon_it_end; ++icon_it)
(*icon_it)->reconfigTheme();
icon_it->second->reconfigTheme();
}
@ -588,10 +504,10 @@ void IconbarTool::renderTheme() {
m_icon_container.setAlpha(m_alpha);
// update buttons
IconList::iterator icon_it = m_icon_list.begin();
const IconList::iterator icon_it_end = m_icon_list.end();
IconMap::iterator icon_it = m_icons.begin();
const IconMap::iterator icon_it_end = m_icons.end();
for (; icon_it != icon_it_end; ++icon_it)
renderButton(*(*icon_it));
renderButton(*icon_it->second);
}
@ -606,49 +522,30 @@ void IconbarTool::renderButton(IconButton &button, bool clear) {
void IconbarTool::deleteIcons() {
m_icon_container.removeAll();
while (!m_icon_list.empty()) {
delete m_icon_list.back();
m_icon_list.pop_back();
}
STLUtil::destroyAndClearSecond(m_icons);
}
void IconbarTool::removeWindow(Focusable &win) {
// got window die signal, lets find and remove the window
IconList::iterator it = m_icon_list.begin();
IconList::iterator it_end = m_icon_list.end();
for (; it != it_end; ++it) {
if (&(*it)->win() == &win)
break;
}
// did we find it?
if (it == m_icon_list.end()) {
IconMap::iterator it = m_icons.find(&win);
if (it == m_icons.end())
return;
}
#ifdef DEBUG
cerr<<"IconbarTool::"<<__FUNCTION__<<"( 0x"<<&win<<" title = "<<win.title()<<") found!"<<endl;
#endif // DEBUG
// detach from all signals
win.dieSig().detach(this);
if (win.fbwindow()) {
win.fbwindow()->workspaceSig().detach(this);
win.fbwindow()->stateSig().detach(this);
}
// remove from list and render theme again
IconButton *button = *it;
m_icon_container.removeItem(m_icon_container.find(*it));
m_icon_list.erase(it);
IconButton *button = it->second;
m_icons.erase(it);
m_icon_container.removeItem(button);
delete button;
}
void IconbarTool::addWindow(Focusable &win) {
IconButton *IconbarTool::makeButton(Focusable &win) {
// we just want windows that have clients
FluxboxWindow *fbwin = win.fbwindow();
if (!fbwin || fbwin->clientList().empty() || fbwin->isIconHidden())
return;
if (!fbwin || fbwin->clientList().empty())
return 0;
#ifdef DEBUG
cerr<<"IconbarTool::addWindow(0x"<<&win<<" title = "<<win.title()<<")"<<endl;
#endif // DEBUG
@ -660,39 +557,21 @@ void IconbarTool::addWindow(Focusable &win) {
button->setOnClick(menu_cmd, 3);
renderButton(*button, false); // update the attributes, but don't clear it
m_icon_container.insertItem(button);
m_icon_list.push_back(button);
// dont forget to detach signal in removeWindow
win.dieSig().attach(this);
fbwin->workspaceSig().attach(this);
fbwin->stateSig().attach(this);
m_icons[&win] = button;
return button;
}
void IconbarTool::updateList() {
list<Focusable *> ordered_list =
m_screen.focusControl().creationOrderWinList();
list<Focusable *>::iterator it = ordered_list.begin();
list<Focusable *>::iterator it_end = ordered_list.end();
list<Focusable *>::iterator it = m_winlist->clientList().begin();
list<Focusable *>::iterator it_end = m_winlist->clientList().end();
for (; it != it_end; ++it) {
if ((*it)->fbwindow() && checkAddWindow(mode(), *(*it)->fbwindow()) &&
!checkDuplicate(**it))
addWindow(**it);
if ((*it)->fbwindow())
insertWindow(**it, -1);
}
renderTheme();
}
bool IconbarTool::checkDuplicate(Focusable &win) {
IconList::iterator it = m_icon_list.begin();
IconList::iterator it_end = m_icon_list.end();
for (; it != it_end; ++it) {
if (&win == &(*it)->win())
return true;
}
return false;
}
void IconbarTool::setOrientation(FbTk::Orientation orient) {
m_icon_container.setOrientation(orient);
ToolbarItem::setOrientation(orient);

View file

@ -28,6 +28,7 @@
#include "ToolbarItem.hh"
#include "Container.hh"
#include "FbMenu.hh"
#include "FocusableList.hh"
#include "FbTk/CachedPixmap.hh"
#include "FbTk/Observer.hh"
@ -36,7 +37,7 @@
#include <X11/Xlib.h>
#include <list>
#include <map>
class IconbarTheme;
class BScreen;
@ -45,17 +46,7 @@ class Focusable;
class IconbarTool: public ToolbarItem, public FbTk::Observer {
public:
typedef std::list<IconButton *> IconList;
/// iconbar mode
enum Mode {
NONE, ///< no icons
ICONS, ///< all icons from all workspaces
NOICONS, ///< all noniconified windows from all workspaces
WORKSPACEICONS, ///< icons on current workspace
WORKSPACENOICONS, ///< non iconified workspaces on current workspaces
WORKSPACE, ///< all windows and all icons on current workspace
ALLWINDOWS ///< all windows and all icons from all workspaces
};
typedef std::map<Focusable *, IconButton *> IconMap;
IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme,
BScreen &screen, FbTk::Menu &menu);
@ -70,14 +61,14 @@ public:
void show();
void hide();
void setAlignment(Container::Alignment a);
void setMode(Mode mode);
void setMode(std::string mode);
void parentMoved() { m_icon_container.parentMoved(); }
unsigned int width() const;
unsigned int height() const;
unsigned int borderWidth() const;
Mode mode() const { return *m_rc_mode; }
std::string mode() const { return *m_rc_mode; }
void setOrientation(FbTk::Orientation orient);
Container::Alignment alignment() const { return m_icon_container.alignment(); }
@ -85,9 +76,6 @@ public:
const BScreen &screen() const { return m_screen; }
private:
/// @return button associated with window
IconButton *findButton(Focusable &win);
void updateSizing();
/// render single button, and probably apply changes (clear)
@ -99,14 +87,16 @@ private:
void renderTheme(unsigned char alpha);
/// destroy all icons
void deleteIcons();
/// add or move a single window
void insertWindow(Focusable &win, int pos = -2);
/// remove a single window
void removeWindow(Focusable &win);
/// add a single window
void addWindow(Focusable &win);
/// make a button for the window
IconButton *makeButton(Focusable &win);
/// remove all windows and add again
void reset();
/// add icons to the list
void updateList();
/// check if window is already in the list
bool checkDuplicate(Focusable &win);
BScreen &m_screen;
Container m_icon_container;
@ -114,8 +104,10 @@ private:
FbTk::CachedPixmap m_empty_pm; ///< pixmap for empty container
IconList m_icon_list;
FbTk::Resource<Mode> m_rc_mode;
std::auto_ptr<FocusableList> m_winlist;
IconMap m_icons;
std::string m_mode;
FbTk::Resource<std::string> m_rc_mode;
FbTk::Resource<Container::Alignment> m_rc_alignment; ///< alignment of buttons
FbTk::Resource<int> m_rc_client_width; ///< size of client button in LEFT/RIGHT mode
FbTk::Resource<unsigned int> m_rc_client_padding; ///< padding of the text

View file

@ -151,7 +151,7 @@ fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.cc \
IconButton.hh IconButton.cc \
IconbarTheme.hh IconbarTheme.cc \
STLUtil.hh \
Focusable.hh \
Focusable.hh FocusableList.hh FocusableList.cc \
${newwmspec_SOURCE} ${gnome_SOURCE} \
${REMEMBER_SOURCE} ${TOOLBAR_SOURCE}

View file

@ -40,7 +40,7 @@ bool MinOverlapPlacement::placeWindow(const FluxboxWindow &win, int head,
std::list<FluxboxWindow *> windowlist;
const std::list<Focusable *> focusables =
win.screen().focusControl().focusedOrderWinList();
win.screen().focusControl().focusedOrderWinList().clientList();
std::list<Focusable *>::const_iterator foc_it = focusables.begin(),
foc_it_end = focusables.end();
unsigned int workspace = win.workspaceNumber();

View file

@ -33,7 +33,7 @@ bool RowSmartPlacement::placeWindow(const FluxboxWindow &win, int head,
std::list<FluxboxWindow *> windowlist;
const std::list<Focusable *> focusables =
win.screen().focusControl().focusedOrderWinList();
win.screen().focusControl().focusedOrderWinList().clientList();
std::list<Focusable *>::const_iterator foc_it = focusables.begin(),
foc_it_end = focusables.end();
unsigned int workspace = win.workspaceNumber();

View file

@ -346,6 +346,7 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
m_workspacenames_sig(*this), // workspace names signal
m_workspace_area_sig(*this), // workspace area signal
m_currentworkspace_sig(*this), // current workspace signal
m_focusedwindow_sig(*this), // focused window signal
m_reconfigure_sig(*this), // reconfigure signal
m_resize_sig(*this),
m_bg_change_sig(*this),
@ -871,19 +872,10 @@ void BScreen::cycleFocus(int options, const ClientPattern *pat, bool reverse) {
}
if (mods == 0) // can't stacked cycle unless there is a mod to grab
options |= FocusControl::CYCLELINEAR;
const FocusControl::Focusables *win_list = 0;
if (options & FocusControl::CYCLEGROUPS) {
win_list = (options & FocusControl::CYCLELINEAR) ?
&focusControl().creationOrderWinList() :
&focusControl().focusedOrderWinList();
} else {
win_list = (options & FocusControl::CYCLELINEAR) ?
&focusControl().creationOrderList() :
&focusControl().focusedOrderList();
}
options |= FocusableList::STATIC_ORDER;
const FocusableList *win_list =
FocusableList::getListFromOptions(*this, options);
focusControl().cycleFocus(*win_list, pat, reverse);
}

View file

@ -222,6 +222,8 @@ public:
FbTk::Subject &workspaceAreaSig() { return m_workspace_area_sig; }
/// current workspace signal
FbTk::Subject &currentWorkspaceSig() { return m_currentworkspace_sig; }
/// focused window signal
FbTk::Subject &focusedWindowSig() { return m_focusedwindow_sig; }
/// reconfigure signal
FbTk::Subject &reconfigureSig() { return m_reconfigure_sig; }
FbTk::Subject &resizeSig() { return m_resize_sig; }
@ -488,6 +490,7 @@ private:
m_workspacenames_sig, ///< workspace names signal
m_workspace_area_sig, ///< workspace area changed signal
m_currentworkspace_sig, ///< current workspace signal
m_focusedwindow_sig, ///< focused window signal
m_reconfigure_sig, ///< reconfigure signal
m_resize_sig, ///< resize signal
m_bg_change_sig; ///< background change signal

View file

@ -1405,7 +1405,7 @@ void FluxboxWindow::iconify() {
hide(true);
screen().focusControl().setFocusBack(this);
screen().focusControl().setFocusBack(*this);
ClientList::iterator client_it = m_clientlist.begin();
const ClientList::iterator client_it_end = m_clientlist.end();
@ -2038,10 +2038,6 @@ void FluxboxWindow::setState(unsigned long new_state, bool setting_up) {
(*it)->show();
(*it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask | KeyPressMask);
}
saveBlackboxAttribs();
//notify state changed
m_statesig.notify();
}
bool FluxboxWindow::getState() {

View file

@ -49,7 +49,7 @@ void WindowListCmd::execute() {
BScreen *screen = Fluxbox::instance()->keyScreen();
if (screen != 0) {
FocusControl::Focusables win_list(screen->focusControl().creationOrderWinList());
FocusControl::Focusables win_list(screen->focusControl().creationOrderWinList().clientList());
FocusControl::Focusables::iterator it = win_list.begin(),
it_end = win_list.end();
@ -63,7 +63,7 @@ void WindowListCmd::execute() {
void AttachCmd::execute() {
BScreen *screen = Fluxbox::instance()->keyScreen();
if (screen != 0) {
FocusControl::Focusables win_list(screen->focusControl().focusedOrderWinList());
FocusControl::Focusables win_list(screen->focusControl().focusedOrderWinList().clientList());
FocusControl::Focusables::iterator it = win_list.begin(),
it_end = win_list.end();
@ -95,16 +95,8 @@ void PrevWindowCmd::execute() {
void GoToWindowCmd::execute() {
BScreen *screen = Fluxbox::instance()->keyScreen();
if (screen != 0) {
const FocusControl::Focusables *win_list = 0;
if (m_option & FocusControl::CYCLEGROUPS) {
win_list = (m_option & FocusControl::CYCLELINEAR) ?
&screen->focusControl().creationOrderWinList() :
&screen->focusControl().focusedOrderWinList();
} else {
win_list = (m_option & FocusControl::CYCLELINEAR) ?
&screen->focusControl().creationOrderList() :
&screen->focusControl().focusedOrderList();
}
const FocusableList *win_list =
FocusableList::getListFromOptions(*screen, m_option);
screen->focusControl().goToWindowNumber(*win_list, m_num, &m_pat);
}
}

View file

@ -514,6 +514,7 @@ void Fluxbox::initScreen(BScreen *screen) {
// attach screen signals to this
screen->currentWorkspaceSig().attach(this);
screen->focusedWindowSig().attach(this);
screen->workspaceCountSig().attach(this);
screen->workspaceNamesSig().attach(this);
screen->workspaceAreaSig().attach(this);
@ -642,7 +643,7 @@ void Fluxbox::setupConfigFiles() {
if (create_init)
FbTk::FileUtil::copyFile(DEFAULT_INITFILE, init_file.c_str());
#define CONFIG_VERSION 4
#define CONFIG_VERSION 5
FbTk::Resource<int> config_version(m_resourcemanager, 0,
"session.configVersion", "Session.ConfigVersion");
if (*config_version < CONFIG_VERSION) {
@ -1191,6 +1192,14 @@ void Fluxbox::update(FbTk::Subject *changedsub) {
if ((*it).first->update())
(*it).first->updateCurrentWorkspace(screen);
}
} else if ((&(screen.focusedWindowSig())) == changedsub) {
for (AtomHandlerContainerIt it= m_atomhandler.begin();
it != m_atomhandler.end(); it++) {
(*it).first->updateFocusedWindow(screen,
(FocusControl::focusedWindow() ?
FocusControl::focusedWindow()->window() :
0));
}
} else if ((&(screen.workspaceAreaSig())) == changedsub) {
for (AtomHandlerContainerIt it= m_atomhandler.begin();
it != m_atomhandler.end(); ++it) {
@ -1682,23 +1691,6 @@ bool Fluxbox::validateClient(const WinClient *client) const {
return it != m_window_search.end();
}
void Fluxbox::updateFocusedWindow(BScreen *screen, BScreen *old_screen) {
if (screen != 0) {
for (AtomHandlerContainerIt it= m_atomhandler.begin();
it != m_atomhandler.end(); it++) {
(*it).first->updateFocusedWindow(*screen, (FocusControl::focusedWindow() ?
FocusControl::focusedWindow()->window() :
0));
}
}
if (old_screen && old_screen != screen) {
for (AtomHandlerContainerIt it= m_atomhandler.begin();
it != m_atomhandler.end(); it++)
(*it).first->updateFocusedWindow(*old_screen, 0);
}
}
void Fluxbox::updateFrameExtents(FluxboxWindow &win) {
AtomHandlerContainerIt it = m_atomhandler.begin();
AtomHandlerContainerIt it_end = m_atomhandler.end();

View file

@ -162,12 +162,6 @@ public:
/// handle any system signal sent to the application
void handleSignal(int signum);
void update(FbTk::Subject *changed);
/**
* Sends update signal to atomhandlers,
* @param screen the new screen
* @param old_screen the old screen if any, can be the same as new screen
*/
void updateFocusedWindow(BScreen *screen, BScreen *old_screen);
/// todo, remove this. just temporary
void updateFrameExtents(FluxboxWindow &win);

View file

@ -64,7 +64,7 @@ string read_file(string filename);
void write_file(string filename, string &contents);
void save_all_files();
int run_updates(int old_version, FbTk::ResourceManager rm) {
int run_updates(int old_version, FbTk::ResourceManager &rm) {
int new_version = old_version;
FbTk::Resource<string> rc_keyfile(rm, "~/.fluxbox/keys",
@ -214,6 +214,31 @@ int run_updates(int old_version, FbTk::ResourceManager rm) {
new_version = 4;
}
if (old_version < 5) { // window patterns for iconbar
// this needs to survive after going out of scope
// it won't get freed, but that's ok
FbTk::Resource<string> *rc_mode =
new FbTk::Resource<string>(rm, "Workspace",
"session.screen0.iconbar.mode",
"Session.Screen0.Iconbar.Mode");
if (strcasecmp((**rc_mode).c_str(), "None") == 0)
*rc_mode = "none";
else if (strcasecmp((**rc_mode).c_str(), "Icons") == 0)
*rc_mode = "{static groups} (minimized=yes)";
else if (strcasecmp((**rc_mode).c_str(), "NoIcons") == 0)
*rc_mode = "{static groups} (minimized=no)";
else if (strcasecmp((**rc_mode).c_str(), "WorkspaceIcons") == 0)
*rc_mode = "{static groups} (minimized=yes) (workspace)";
else if (strcasecmp((**rc_mode).c_str(), "WorkspaceNoIcons") == 0)
*rc_mode = "{static groups} (minimized=no) (workspace)";
else if (strcasecmp((**rc_mode).c_str(), "AllWindows") == 0)
*rc_mode = "{static groups}";
else
*rc_mode = "{static groups} (workspace)";
new_version = 5;
}
return new_version;
}