aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormarkt <markt>2007-11-12 21:59:43 (GMT)
committermarkt <markt>2007-11-12 21:59:43 (GMT)
commit5d7043320da1378e7dd3b10f7e425f3b47455b28 (patch)
tree305db18a58ab6768b78ab230074da576d09e372d /src
parent807a1b557552e43dbdc169c1e7a3065a3f12aac7 (diff)
downloadfluxbox-5d7043320da1378e7dd3b10f7e425f3b47455b28.zip
fluxbox-5d7043320da1378e7dd3b10f7e425f3b47455b28.tar.bz2
allow arbitrary window patterns in iconbar
Diffstat (limited to 'src')
-rw-r--r--src/ClientPattern.cc36
-rw-r--r--src/ClientPattern.hh6
-rw-r--r--src/ColSmartPlacement.cc2
-rw-r--r--src/Ewmh.cc3
-rw-r--r--src/FbCommandFactory.cc39
-rw-r--r--src/FbCommands.cc18
-rw-r--r--src/FbCommands.hh3
-rw-r--r--src/FbTk/Subject.cc24
-rw-r--r--src/FocusControl.cc127
-rw-r--r--src/FocusControl.hh31
-rw-r--r--src/Focusable.hh2
-rw-r--r--src/FocusableList.cc293
-rw-r--r--src/FocusableList.hh121
-rw-r--r--src/IconbarTool.cc315
-rw-r--r--src/IconbarTool.hh38
-rw-r--r--src/Makefile.am2
-rw-r--r--src/MinOverlapPlacement.cc2
-rw-r--r--src/RowSmartPlacement.cc2
-rw-r--r--src/Screen.cc16
-rw-r--r--src/Screen.hh3
-rw-r--r--src/Window.cc6
-rw-r--r--src/WorkspaceCmd.cc16
-rw-r--r--src/fluxbox.cc28
-rw-r--r--src/fluxbox.hh6
24 files changed, 687 insertions, 452 deletions
diff --git a/src/ClientPattern.cc b/src/ClientPattern.cc
index 9ee1848..d094e63 100644
--- a/src/ClientPattern.cc
+++ b/src/ClientPattern.cc
@@ -274,9 +274,19 @@ bool ClientPattern::match(const Focusable &win) const {
274 for (; it != it_end; ++it) { 274 for (; it != it_end; ++it) {
275 if ((*it)->orig == "[current]") { 275 if ((*it)->orig == "[current]") {
276 WinClient *focused = FocusControl::focusedWindow(); 276 WinClient *focused = FocusControl::focusedWindow();
277 if (!focused || !((*it)->negate ^ 277 if ((*it)->prop == WORKSPACE) {
278 (getProperty((*it)->prop, win) == 278 char tmpstr[128];
279 getProperty((*it)->prop, *focused)))) 279 sprintf(tmpstr, "%d", win.screen().currentWorkspaceID());
280 if (!(*it)->negate ^ (getProperty((*it)->prop, win) == tmpstr))
281 return false;
282 } else if ((*it)->prop == WORKSPACENAME) {
283 const Workspace *w = win.screen().currentWorkspace();
284 if (!w || (!(*it)->negate ^
285 (getProperty((*it)->prop, win) == w->name())))
286 return false;
287 } else if (!focused || (!(*it)->negate ^
288 (getProperty((*it)->prop, win) ==
289 getProperty((*it)->prop, *focused))))
280 return false; 290 return false;
281 } else if ((*it)->prop == HEAD && 291 } else if ((*it)->prop == HEAD &&
282 (*it)->orig == "[mouse]") { 292 (*it)->orig == "[mouse]") {
@@ -293,6 +303,26 @@ bool ClientPattern::match(const Focusable &win) const {
293 return true; 303 return true;
294} 304}
295 305
306bool ClientPattern::dependsOnFocusedWindow() const {
307 Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end();
308 for (; it != it_end; ++it) {
309 if ((*it)->prop != WORKSPACE && (*it)->prop != WORKSPACENAME &&
310 (*it)->orig == "[current]")
311 return true;
312 }
313 return false;
314}
315
316bool ClientPattern::dependsOnCurrentWorkspace() const {
317 Terms::const_iterator it = m_terms.begin(), it_end = m_terms.end();
318 for (; it != it_end; ++it) {
319 if (((*it)->prop == WORKSPACE || (*it)->prop == WORKSPACENAME) &&
320 (*it)->orig == "[current]")
321 return true;
322 }
323 return false;
324}
325
296// add an expression to match against 326// add an expression to match against
297// The first argument is a regular expression, the second is the member 327// The first argument is a regular expression, the second is the member
298// function that we wish to match against. 328// function that we wish to match against.
diff --git a/src/ClientPattern.hh b/src/ClientPattern.hh
index a6d1ede..b76aef8 100644
--- a/src/ClientPattern.hh
+++ b/src/ClientPattern.hh
@@ -62,6 +62,12 @@ public:
62 /// Does this client match this pattern? 62 /// Does this client match this pattern?
63 bool match(const Focusable &win) const; 63 bool match(const Focusable &win) const;
64 64
65 /// Does this pattern depend on the focused window?
66 bool dependsOnFocusedWindow() const;
67
68 /// Does this pattern depend on the current workspace?
69 bool dependsOnCurrentWorkspace() const;
70
65 /** 71 /**
66 * Add an expression to match against 72 * Add an expression to match against
67 * @param str is a regular expression 73 * @param str is a regular expression
diff --git a/src/ColSmartPlacement.cc b/src/ColSmartPlacement.cc
index bdffa41..0fbae68 100644
--- a/src/ColSmartPlacement.cc
+++ b/src/ColSmartPlacement.cc
@@ -33,7 +33,7 @@ bool ColSmartPlacement::placeWindow(const FluxboxWindow &win, int head,
33 33
34 std::list<FluxboxWindow *> windowlist; 34 std::list<FluxboxWindow *> windowlist;
35 const std::list<Focusable *> focusables = 35 const std::list<Focusable *> focusables =
36 win.screen().focusControl().focusedOrderWinList(); 36 win.screen().focusControl().focusedOrderWinList().clientList();
37 std::list<Focusable *>::const_iterator foc_it = focusables.begin(), 37 std::list<Focusable *>::const_iterator foc_it = focusables.begin(),
38 foc_it_end = focusables.end(); 38 foc_it_end = focusables.end();
39 unsigned int workspace = win.workspaceNumber(); 39 unsigned int workspace = win.workspaceNumber();
diff --git a/src/Ewmh.cc b/src/Ewmh.cc
index 3e01e36..ee98944 100644
--- a/src/Ewmh.cc
+++ b/src/Ewmh.cc
@@ -345,7 +345,8 @@ void Ewmh::updateClientList(BScreen &screen) {
345 if (screen.isShuttingdown()) 345 if (screen.isShuttingdown())
346 return; 346 return;
347 347
348 list<Focusable *> creation_order_list = screen.focusControl().creationOrderList(); 348 list<Focusable *> creation_order_list =
349 screen.focusControl().creationOrderList().clientList();
349 350
350 size_t num = creation_order_list.size(); 351 size_t num = creation_order_list.size();
351 Window *wl = FB_new_nothrow Window[num]; 352 Window *wl = FB_new_nothrow Window[num];
diff --git a/src/FbCommandFactory.cc b/src/FbCommandFactory.cc
index d347878..72de740 100644
--- a/src/FbCommandFactory.cc
+++ b/src/FbCommandFactory.cc
@@ -24,6 +24,7 @@
24 24
25#include "FbCommandFactory.hh" 25#include "FbCommandFactory.hh"
26 26
27#include "FocusableList.hh"
27#include "CurrentWindowCmd.hh" 28#include "CurrentWindowCmd.hh"
28#include "FbCommands.hh" 29#include "FbCommands.hh"
29#include "Window.hh" 30#include "Window.hh"
@@ -59,26 +60,6 @@ static int getint(const char *str, int defaultvalue) {
59 return defaultvalue; 60 return defaultvalue;
60} 61}
61 62
62void parseNextWindowArgs(const string &in, int &opts, string &pat) {
63 string options;
64 int err = FbTk::StringUtil::getStringBetween(options, in.c_str(), '{', '}');
65
66 // the rest of the string is a ClientPattern
67 pat = in.c_str() + err;
68
69 // now parse the options
70 vector<string> args;
71 FbTk::StringUtil::stringtok(args, options);
72 vector<string>::iterator it = args.begin(), it_end = args.end();
73 opts = 0;
74 for (; it != it_end; ++it) {
75 if (strcasecmp((*it).c_str(), "static") == 0)
76 opts |= FocusControl::CYCLELINEAR;
77 else if (strcasecmp((*it).c_str(), "groups") == 0)
78 opts |= FocusControl::CYCLEGROUPS;
79 }
80}
81
82}; // end anonymous namespace 63}; // end anonymous namespace
83 64
84FbCommandFactory::FbCommandFactory() { 65FbCommandFactory::FbCommandFactory() {
@@ -522,29 +503,29 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command,
522 } else if (command == "attach") { 503 } else if (command == "attach") {
523 int opts; // not used 504 int opts; // not used
524 string pat; 505 string pat;
525 parseNextWindowArgs(arguments, opts, pat); 506 FocusableList::parseArgs(arguments, opts, pat);
526 return new AttachCmd(pat); 507 return new AttachCmd(pat);
527 } else if (command == "nextwindow") { 508 } else if (command == "nextwindow") {
528 int opts; 509 int opts;
529 string pat; 510 string pat;
530 parseNextWindowArgs(arguments, opts, pat); 511 FocusableList::parseArgs(arguments, opts, pat);
531 return new NextWindowCmd(opts, pat); 512 return new NextWindowCmd(opts, pat);
532 } else if (command == "nextgroup") { 513 } else if (command == "nextgroup") {
533 int opts; 514 int opts;
534 string pat; 515 string pat;
535 parseNextWindowArgs(arguments, opts, pat); 516 FocusableList::parseArgs(arguments, opts, pat);
536 opts |= FocusControl::CYCLEGROUPS; 517 opts |= FocusableList::LIST_GROUPS;
537 return new NextWindowCmd(opts, pat); 518 return new NextWindowCmd(opts, pat);
538 } else if (command == "prevwindow") { 519 } else if (command == "prevwindow") {
539 int opts; 520 int opts;
540 string pat; 521 string pat;
541 parseNextWindowArgs(arguments, opts, pat); 522 FocusableList::parseArgs(arguments, opts, pat);
542 return new PrevWindowCmd(opts, pat); 523 return new PrevWindowCmd(opts, pat);
543 } else if (command == "prevgroup") { 524 } else if (command == "prevgroup") {
544 int opts; 525 int opts;
545 string pat; 526 string pat;
546 parseNextWindowArgs(arguments, opts, pat); 527 FocusableList::parseArgs(arguments, opts, pat);
547 opts |= FocusControl::CYCLEGROUPS; 528 opts |= FocusableList::LIST_GROUPS;
548 return new PrevWindowCmd(opts, pat); 529 return new PrevWindowCmd(opts, pat);
549 } else if (command == "gotowindow") { 530 } else if (command == "gotowindow") {
550 int num, opts; 531 int num, opts;
@@ -554,12 +535,12 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command,
554 string::size_type pos = arguments.find_first_of("({"); 535 string::size_type pos = arguments.find_first_of("({");
555 if (pos != string::npos && pos != arguments.size()) 536 if (pos != string::npos && pos != arguments.size())
556 args = arguments.c_str() + pos; 537 args = arguments.c_str() + pos;
557 parseNextWindowArgs(args, opts, pat); 538 FocusableList::parseArgs(args, opts, pat);
558 return new GoToWindowCmd(num, opts, pat); 539 return new GoToWindowCmd(num, opts, pat);
559 } else if (command == "clientmenu") { 540 } else if (command == "clientmenu") {
560 int opts; 541 int opts;
561 string pat; 542 string pat;
562 parseNextWindowArgs(arguments, opts, pat); 543 FocusableList::parseArgs(arguments, opts, pat);
563 return new ShowClientMenuCmd(opts, pat); 544 return new ShowClientMenuCmd(opts, pat);
564 } else if (command == "focusup") 545 } else if (command == "focusup")
565 return new DirFocusCmd(FocusControl::FOCUSUP); 546 return new DirFocusCmd(FocusControl::FOCUSUP);
diff --git a/src/FbCommands.cc b/src/FbCommands.cc
index 698f2db..28c0a30 100644
--- a/src/FbCommands.cc
+++ b/src/FbCommands.cc
@@ -277,20 +277,12 @@ void ShowClientMenuCmd::execute() {
277 return; 277 return;
278 278
279 // TODO: ClientMenu only accepts lists of FluxboxWindows for now 279 // TODO: ClientMenu only accepts lists of FluxboxWindows for now
280 const FocusControl::Focusables *win_list = 0; 280 // when that's fixed, use a FocusableList for m_list
281// if (m_option & FocusControl::CYCLEGROUPS) { 281 const FocusableList *list =
282 win_list = (m_option & FocusControl::CYCLELINEAR) ? 282 FocusableList::getListFromOptions(*screen, m_option);
283 &screen->focusControl().creationOrderWinList() :
284 &screen->focusControl().focusedOrderWinList();
285/* } else {
286 win_list = (m_option & FocusControl::CYCLELINEAR) ?
287 &screen->focusControl().creationOrderList() :
288 &screen->focusControl().focusedOrderList();
289 } */
290
291 m_list.clear(); 283 m_list.clear();
292 FocusControl::Focusables::const_iterator it = win_list->begin(), 284 FocusControl::Focusables::const_iterator it = list->clientList().begin(),
293 it_end = win_list->end(); 285 it_end = list->clientList().end();
294 for (; it != it_end; ++it) { 286 for (; it != it_end; ++it) {
295 if (typeid(**it) == typeid(FluxboxWindow) && m_pat.match(**it)) 287 if (typeid(**it) == typeid(FluxboxWindow) && m_pat.match(**it))
296 m_list.push_back(static_cast<FluxboxWindow *>(*it)); 288 m_list.push_back(static_cast<FluxboxWindow *>(*it));
diff --git a/src/FbCommands.hh b/src/FbCommands.hh
index c563899..c130050 100644
--- a/src/FbCommands.hh
+++ b/src/FbCommands.hh
@@ -31,6 +31,7 @@
31#include "FbTk/RefCount.hh" 31#include "FbTk/RefCount.hh"
32#include "ClientMenu.hh" 32#include "ClientMenu.hh"
33#include "ClientPattern.hh" 33#include "ClientPattern.hh"
34#include "FocusableList.hh"
34 35
35#include <list> 36#include <list>
36#include <string> 37#include <string>
@@ -118,7 +119,7 @@ public:
118class ShowClientMenuCmd: public FbTk::Command { 119class ShowClientMenuCmd: public FbTk::Command {
119public: 120public:
120 ShowClientMenuCmd(int option, std::string &pat): 121 ShowClientMenuCmd(int option, std::string &pat):
121 m_option(option), m_pat(pat.c_str()) { } 122 m_option(option|FocusableList::LIST_GROUPS), m_pat(pat.c_str()) { }
122 void execute(); 123 void execute();
123private: 124private:
124 const int m_option; 125 const int m_option;
diff --git a/src/FbTk/Subject.cc b/src/FbTk/Subject.cc
index 08a211c..7ff80cf 100644
--- a/src/FbTk/Subject.cc
+++ b/src/FbTk/Subject.cc
@@ -58,16 +58,22 @@ void Subject::detach(Observer *obj) {
58} 58}
59 59
60void Subject::notify() { 60void Subject::notify() {
61 m_notify_mode = true; 61 ObserverList::iterator it = m_observerlist.begin(),
62 std::for_each(m_observerlist.begin(), m_observerlist.end(), 62 it_end = m_observerlist.end();
63 std::bind2nd(std::mem_fun(&Observer::update), this)); 63 for (; it != it_end; ++it) {
64 m_notify_mode = false; 64 m_notify_mode = true;
65 (*it)->update(this);
66 ObserverList::iterator d_it = m_dead_observers.begin(),
67 d_it_end = m_dead_observers.end();
68 m_notify_mode = false;
65 69
66 // remove dead observers 70 // there might be dead observers later in the list, so we must remove
67 if (!m_dead_observers.empty()) { 71 // them now
68 std::for_each(m_dead_observers.begin(), 72 for (; d_it != d_it_end; ++d_it) {
69 m_dead_observers.end(), 73 if (*d_it == *it)
70 std::bind1st(std::mem_fun(&Subject::detach), this)); 74 --it; // don't invalidate our iterator
75 detach(*d_it);
76 }
71 m_dead_observers.clear(); 77 m_dead_observers.clear();
72 } 78 }
73} 79}
diff --git a/src/FocusControl.cc b/src/FocusControl.cc
index 7bc1db4..ae5b5e3 100644
--- a/src/FocusControl.cc
+++ b/src/FocusControl.cc
@@ -78,15 +78,17 @@ FocusControl::FocusControl(BScreen &screen):
78 m_focus_new(screen.resourceManager(), true, 78 m_focus_new(screen.resourceManager(), true,
79 screen.name()+".focusNewWindows", 79 screen.name()+".focusNewWindows",
80 screen.altName()+".FocusNewWindows"), 80 screen.altName()+".FocusNewWindows"),
81 m_focused_list(screen), m_creation_order_list(screen),
82 m_focused_win_list(screen), m_creation_order_win_list(screen),
81 m_cycling_list(0), 83 m_cycling_list(0),
82 m_was_iconic(false), 84 m_was_iconic(false),
83 m_cycling_last(0) { 85 m_cycling_last(0) {
84 86
85 m_cycling_window = m_focused_win_list.end(); 87 m_cycling_window = m_focused_list.clientList().end();
86 88
87} 89}
88 90
89void FocusControl::cycleFocus(const Focusables &window_list, 91void FocusControl::cycleFocus(const FocusableList &window_list,
90 const ClientPattern *pat, bool cycle_reverse) { 92 const ClientPattern *pat, bool cycle_reverse) {
91 93
92 if (!m_cycling_list) { 94 if (!m_cycling_list) {
@@ -98,8 +100,8 @@ void FocusControl::cycleFocus(const Focusables &window_list,
98 } else if (m_cycling_list != &window_list) 100 } else if (m_cycling_list != &window_list)
99 m_cycling_list = &window_list; 101 m_cycling_list = &window_list;
100 102
101 Focusables::const_iterator it_begin = window_list.begin(); 103 Focusables::const_iterator it_begin = window_list.clientList().begin();
102 Focusables::const_iterator it_end = window_list.end(); 104 Focusables::const_iterator it_end = window_list.clientList().end();
103 105
104 // too many things can go wrong with remembering this 106 // too many things can go wrong with remembering this
105 m_cycling_window = find(it_begin, it_end, s_focused_window); 107 m_cycling_window = find(it_begin, it_end, s_focused_window);
@@ -165,10 +167,10 @@ void FocusControl::cycleFocus(const Focusables &window_list,
165 167
166} 168}
167 169
168void FocusControl::goToWindowNumber(const Focusables &winlist, int num, 170void FocusControl::goToWindowNumber(const FocusableList &winlist, int num,
169 const ClientPattern *pat) { 171 const ClientPattern *pat) {
170 Focusables::const_iterator it = winlist.begin(); 172 Focusables::const_iterator it = winlist.clientList().begin();
171 Focusables::const_iterator it_end = winlist.end(); 173 Focusables::const_iterator it_end = winlist.clientList().end();
172 for (; it != it_end && num; ++it) { 174 for (; it != it_end && num; ++it) {
173 if (!doSkipWindow(**it, pat) && (*it)->acceptsFocus()) { 175 if (!doSkipWindow(**it, pat) && (*it)->acceptsFocus()) {
174 num > 0 ? --num : ++num; 176 num > 0 ? --num : ++num;
@@ -182,61 +184,43 @@ void FocusControl::goToWindowNumber(const Focusables &winlist, int num,
182} 184}
183 185
184void FocusControl::addFocusBack(WinClient &client) { 186void FocusControl::addFocusBack(WinClient &client) {
185 m_focused_list.push_back(&client); 187 m_focused_list.pushBack(client);
186 m_creation_order_list.push_back(&client); 188 m_creation_order_list.pushBack(client);
187} 189}
188 190
189void FocusControl::addFocusFront(WinClient &client) { 191void FocusControl::addFocusFront(WinClient &client) {
190 m_focused_list.push_front(&client); 192 m_focused_list.pushFront(client);
191 m_creation_order_list.push_back(&client); 193 m_creation_order_list.pushBack(client);
192} 194}
193 195
194void FocusControl::addFocusWinBack(Focusable &win) { 196void FocusControl::addFocusWinBack(Focusable &win) {
195 m_focused_win_list.push_back(&win); 197 m_focused_win_list.pushBack(win);
196 m_creation_order_win_list.push_back(&win); 198 m_creation_order_win_list.pushBack(win);
197} 199}
198 200
199void FocusControl::addFocusWinFront(Focusable &win) { 201void FocusControl::addFocusWinFront(Focusable &win) {
200 m_focused_win_list.push_front(&win); 202 m_focused_win_list.pushFront(win);
201 m_creation_order_win_list.push_back(&win); 203 m_creation_order_win_list.pushBack(win);
202} 204}
203 205
204// move all clients in given window to back of focused list 206// move all clients in given window to back of focused list
205void FocusControl::setFocusBack(FluxboxWindow *fbwin) { 207void FocusControl::setFocusBack(FluxboxWindow &fbwin) {
206 // do nothing if there are no windows open 208 // do nothing if there are no windows open
207 // don't change focus order while cycling 209 // don't change focus order while cycling
208 if (m_focused_list.empty() || s_reverting) 210 if (m_focused_list.empty() || s_reverting)
209 return; 211 return;
210 212
211 // if the window isn't already in this list, we could accidentally add it 213 m_focused_win_list.moveToBack(fbwin);
212 Focusables::iterator win_begin = m_focused_win_list.begin(),
213 win_end = m_focused_win_list.end();
214 Focusables::iterator win_it = find(win_begin, win_end, fbwin);
215 if (win_it == win_end)
216 return;
217
218 m_focused_win_list.erase(win_it);
219 m_focused_win_list.push_back(fbwin);
220 214
221 Focusables::iterator it = m_focused_list.begin(); 215 // we need to move its clients to the back while preserving their order
222 // use back to avoid an infinite loop 216 Focusables list = m_focused_list.clientList();
223 Focusables::iterator it_back = --m_focused_list.end(); 217 Focusables::iterator it = list.begin(), it_end = list.end();
224 218 for (; it != it_end; ++it) {
225 while (it != it_back) { 219 if ((*it)->fbwindow() == &fbwin)
226 if ((*it)->fbwindow() == fbwin) { 220 m_focused_list.moveToBack(**it);
227 m_focused_list.push_back(*it);
228 it = m_focused_list.erase(it);
229 } else
230 ++it;
231 }
232 // move the last one, if necessary, in order to preserve focus order
233 if ((*it)->fbwindow() == fbwin) {
234 m_focused_list.push_back(*it);
235 m_focused_list.erase(it);
236 } 221 }
237
238} 222}
239 223
240void FocusControl::stopCyclingFocus() { 224void FocusControl::stopCyclingFocus() {
241 // nothing to do 225 // nothing to do
242 if (m_cycling_list == 0) 226 if (m_cycling_list == 0)
@@ -262,10 +246,10 @@ void FocusControl::stopCyclingFocus() {
262Focusable *FocusControl::lastFocusedWindow(int workspace) { 246Focusable *FocusControl::lastFocusedWindow(int workspace) {
263 if (m_focused_list.empty() || m_screen.isShuttingdown()) return 0; 247 if (m_focused_list.empty() || m_screen.isShuttingdown()) return 0;
264 if (workspace < 0 || workspace >= (int) m_screen.numberOfWorkspaces()) 248 if (workspace < 0 || workspace >= (int) m_screen.numberOfWorkspaces())
265 return m_focused_list.front(); 249 return m_focused_list.clientList().front();
266 250
267 Focusables::iterator it = m_focused_list.begin(); 251 Focusables::iterator it = m_focused_list.clientList().begin();
268 Focusables::iterator it_end = m_focused_list.end(); 252 Focusables::iterator it_end = m_focused_list.clientList().end();
269 for (; it != it_end; ++it) { 253 for (; it != it_end; ++it) {
270 if ((*it)->fbwindow() && 254 if ((*it)->fbwindow() &&
271 ((((int)(*it)->fbwindow()->workspaceNumber()) == workspace || 255 ((((int)(*it)->fbwindow()->workspaceNumber()) == workspace ||
@@ -285,8 +269,8 @@ WinClient *FocusControl::lastFocusedWindow(FluxboxWindow &group, WinClient *igno
285 if (m_focused_list.empty() || m_screen.isShuttingdown()) 269 if (m_focused_list.empty() || m_screen.isShuttingdown())
286 return 0; 270 return 0;
287 271
288 Focusables::iterator it = m_focused_list.begin(); 272 Focusables::iterator it = m_focused_list.clientList().begin();
289 Focusables::iterator it_end = m_focused_list.end(); 273 Focusables::iterator it_end = m_focused_list.clientList().end();
290 for (; it != it_end; ++it) { 274 for (; it != it_end; ++it) {
291 if (((*it)->fbwindow() == &group) && 275 if (((*it)->fbwindow() == &group) &&
292 (*it) != ignore_client) 276 (*it) != ignore_client)
@@ -300,27 +284,9 @@ void FocusControl::setScreenFocusedWindow(WinClient &win_client) {
300 // raise newly focused window to the top of the focused list 284 // raise newly focused window to the top of the focused list
301 // don't change the order if we're cycling or shutting down 285 // don't change the order if we're cycling or shutting down
302 if (!isCycling() && !m_screen.isShuttingdown() && !s_reverting) { 286 if (!isCycling() && !m_screen.isShuttingdown() && !s_reverting) {
303 287 m_focused_list.moveToFront(win_client);
304 // make sure client is in our list, or else we could end up adding it 288 if (win_client.fbwindow())
305 Focusables::iterator it_begin = m_focused_list.begin(), 289 m_focused_win_list.moveToFront(*win_client.fbwindow());
306 it_end = m_focused_list.end();
307 Focusables::iterator it = find(it_begin, it_end, &win_client);
308 if (it == it_end)
309 return;
310
311 m_focused_list.erase(it);
312 m_focused_list.push_front(&win_client);
313
314 // also check the fbwindow
315 it_begin = m_focused_win_list.begin();
316 it_end = m_focused_win_list.end();
317 it = find(it_begin, it_end, win_client.fbwindow());
318
319 if (it != it_end) {
320 m_focused_win_list.erase(it);
321 m_focused_win_list.push_front(win_client.fbwindow());
322 }
323
324 } 290 }
325} 291}
326 292
@@ -435,15 +401,15 @@ void FocusControl::removeClient(WinClient &client) {
435 if (client.screen().isShuttingdown()) 401 if (client.screen().isShuttingdown())
436 return; 402 return;
437 403
438 if (m_cycling_list && m_cycling_window != m_cycling_list->end() && 404 if (isCycling() && m_cycling_window != m_cycling_list->clientList().end() &&
439 *m_cycling_window == &client) { 405 *m_cycling_window == &client) {
440 m_cycling_window = m_cycling_list->end(); 406 m_cycling_window = m_cycling_list->clientList().end();
441 stopCyclingFocus(); 407 stopCyclingFocus();
442 } else if (m_cycling_last == &client) 408 } else if (m_cycling_last == &client)
443 m_cycling_last = 0; 409 m_cycling_last = 0;
444 410
445 m_focused_list.remove(&client); 411 m_focused_list.remove(client);
446 m_creation_order_list.remove(&client); 412 m_creation_order_list.remove(client);
447 client.screen().clientListSig().notify(); 413 client.screen().clientListSig().notify();
448} 414}
449 415
@@ -451,21 +417,21 @@ void FocusControl::removeWindow(Focusable &win) {
451 if (win.screen().isShuttingdown()) 417 if (win.screen().isShuttingdown())
452 return; 418 return;
453 419
454 if (m_cycling_list && m_cycling_window != m_cycling_list->end() && 420 if (isCycling() && m_cycling_window != m_cycling_list->clientList().end() &&
455 *m_cycling_window == &win) { 421 *m_cycling_window == &win) {
456 m_cycling_window = m_cycling_list->end(); 422 m_cycling_window = m_cycling_list->clientList().end();
457 stopCyclingFocus(); 423 stopCyclingFocus();
458 } 424 }
459 425
460 m_focused_win_list.remove(&win); 426 m_focused_win_list.remove(win);
461 m_creation_order_win_list.remove(&win); 427 m_creation_order_win_list.remove(win);
462 win.screen().clientListSig().notify(); 428 win.screen().clientListSig().notify();
463} 429}
464 430
465void FocusControl::shutdown() { 431void FocusControl::shutdown() {
466 // restore windows backwards so they get put back correctly on restart 432 // restore windows backwards so they get put back correctly on restart
467 Focusables::reverse_iterator it = m_focused_list.rbegin(); 433 Focusables::reverse_iterator it = m_focused_list.clientList().rbegin();
468 for (; it != m_focused_list.rend(); ++it) { 434 for (; it != m_focused_list.clientList().rend(); ++it) {
469 WinClient *client = dynamic_cast<WinClient *>(*it); 435 WinClient *client = dynamic_cast<WinClient *>(*it);
470 if (client && client->fbwindow()) 436 if (client && client->fbwindow())
471 client->fbwindow()->restore(client, true); 437 client->fbwindow()->restore(client, true);
@@ -582,7 +548,10 @@ void FocusControl::setFocusedWindow(WinClient *client) {
582 } 548 }
583 549
584 // update AtomHandlers and/or other stuff... 550 // update AtomHandlers and/or other stuff...
585 Fluxbox::instance()->updateFocusedWindow(screen, old_screen); 551 if (screen)
552 screen->focusedWindowSig().notify();
553 if (old_screen && screen != old_screen)
554 old_screen->focusedWindowSig().notify();
586} 555}
587 556
588////////////////////// FocusControl RESOURCES 557////////////////////// FocusControl RESOURCES
diff --git a/src/FocusControl.hh b/src/FocusControl.hh
index 4e2ceab..84f0269 100644
--- a/src/FocusControl.hh
+++ b/src/FocusControl.hh
@@ -27,6 +27,7 @@
27#include <list> 27#include <list>
28 28
29#include "FbTk/Resource.hh" 29#include "FbTk/Resource.hh"
30#include "FocusableList.hh"
30 31
31class ClientPattern; 32class ClientPattern;
32class WinClient; 33class WinClient;
@@ -60,12 +61,6 @@ public:
60 FOCUSRIGHT ///< window is right 61 FOCUSRIGHT ///< window is right
61 }; 62 };
62 63
63 /// prevFocus/nextFocus option bits
64 enum {
65 CYCLEGROUPS = 0x01, //< cycle through groups
66 CYCLELINEAR = 0x08, ///< linear cycle
67 };
68
69 explicit FocusControl(BScreen &screen); 64 explicit FocusControl(BScreen &screen);
70 /// cycle previous focuable 65 /// cycle previous focuable
71 void prevFocus() { cycleFocus(m_focused_list, 0, true); } 66 void prevFocus() { cycleFocus(m_focused_list, 0, true); }
@@ -77,10 +72,10 @@ public:
77 * @param pat pattern for matching focusables 72 * @param pat pattern for matching focusables
78 * @param reverse reverse the cycle order 73 * @param reverse reverse the cycle order
79 */ 74 */
80 void cycleFocus(const Focusables &winlist, const ClientPattern *pat = 0, 75 void cycleFocus(const FocusableList &winlist, const ClientPattern *pat = 0,
81 bool reverse = false); 76 bool reverse = false);
82 77
83 void goToWindowNumber(const Focusables &winlist, int num, 78 void goToWindowNumber(const FocusableList &winlist, int num,
84 const ClientPattern *pat = 0); 79 const ClientPattern *pat = 0);
85 /// sets the focused window on a screen 80 /// sets the focused window on a screen
86 void setScreenFocusedWindow(WinClient &win_client); 81 void setScreenFocusedWindow(WinClient &win_client);
@@ -108,7 +103,7 @@ public:
108 void addFocusFront(WinClient &client); 103 void addFocusFront(WinClient &client);
109 void addFocusWinBack(Focusable &win); 104 void addFocusWinBack(Focusable &win);
110 void addFocusWinFront(Focusable &win); 105 void addFocusWinFront(Focusable &win);
111 void setFocusBack(FluxboxWindow *fbwin); 106 void setFocusBack(FluxboxWindow &fbwin);
112 /// @return main focus model 107 /// @return main focus model
113 FocusModel focusModel() const { return *m_focus_model; } 108 FocusModel focusModel() const { return *m_focus_model; }
114 /// @return tab focus model 109 /// @return tab focus model
@@ -122,11 +117,11 @@ public:
122 WinClient *lastFocusedWindow(FluxboxWindow &group, WinClient *ignore_client = 0); 117 WinClient *lastFocusedWindow(FluxboxWindow &group, WinClient *ignore_client = 0);
123 118
124 /// @return focus list in creation order 119 /// @return focus list in creation order
125 const Focusables &creationOrderList() const { return m_creation_order_list; } 120 const FocusableList &creationOrderList() const { return m_creation_order_list; }
126 /// @return the focus list in focused order 121 /// @return the focus list in focused order
127 const Focusables &focusedOrderList() const { return m_focused_list; } 122 const FocusableList &focusedOrderList() const { return m_focused_list; }
128 const Focusables &creationOrderWinList() const { return m_creation_order_win_list; } 123 const FocusableList &creationOrderWinList() const { return m_creation_order_win_list; }
129 const Focusables &focusedOrderWinList() const { return m_focused_win_list; } 124 const FocusableList &focusedOrderWinList() const { return m_focused_win_list; }
130 125
131 /// remove client from focus list 126 /// remove client from focus list
132 void removeClient(WinClient &client); 127 void removeClient(WinClient &client);
@@ -153,13 +148,13 @@ private:
153 148
154 // This list keeps the order of window focusing for this screen 149 // This list keeps the order of window focusing for this screen
155 // Screen global so it works for sticky windows too. 150 // Screen global so it works for sticky windows too.
156 Focusables m_focused_list; 151 FocusableList m_focused_list;
157 Focusables m_creation_order_list; 152 FocusableList m_creation_order_list;
158 Focusables m_focused_win_list; 153 FocusableList m_focused_win_list;
159 Focusables m_creation_order_win_list; 154 FocusableList m_creation_order_win_list;
160 155
161 Focusables::const_iterator m_cycling_window; 156 Focusables::const_iterator m_cycling_window;
162 const Focusables *m_cycling_list; 157 const FocusableList *m_cycling_list;
163 Focusable *m_was_iconic; 158 Focusable *m_was_iconic;
164 WinClient *m_cycling_last; 159 WinClient *m_cycling_last;
165 160
diff --git a/src/Focusable.hh b/src/Focusable.hh
index 3903e25..5a2f40c 100644
--- a/src/Focusable.hh
+++ b/src/Focusable.hh
@@ -19,7 +19,7 @@
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE. 20// DEALINGS IN THE SOFTWARE.
21 21
22// $Id$ 22// $Id: $
23 23
24#ifndef FOCUSABLE_HH 24#ifndef FOCUSABLE_HH
25#define FOCUSABLE_HH 25#define FOCUSABLE_HH
diff --git a/src/FocusableList.cc b/src/FocusableList.cc
new file mode 100644
index 0000000..8a5c8f7
--- /dev/null
+++ b/src/FocusableList.cc
@@ -0,0 +1,293 @@
1// FocusableList.cc
2// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22// $Id: $
23
24#include "FocusableList.hh"
25
26#include "Focusable.hh"
27#include "FocusControl.hh"
28#include "Screen.hh"
29#include "WinClient.hh"
30#include "Window.hh"
31
32#include "FbTk/StringUtil.hh"
33
34#include <vector>
35
36using std::string;
37using std::vector;
38
39void FocusableList::parseArgs(const string &in, int &opts, string &pat) {
40 string options;
41 int err = FbTk::StringUtil::getStringBetween(options, in.c_str(), '{', '}');
42
43 // the rest of the string is a ClientPattern
44 pat = in.c_str() + err;
45
46 // now parse the options
47 vector<string> args;
48 FbTk::StringUtil::stringtok(args, options);
49 vector<string>::iterator it = args.begin(), it_end = args.end();
50 opts = 0;
51 for (; it != it_end; ++it) {
52 if (strcasecmp((*it).c_str(), "static") == 0)
53 opts |= STATIC_ORDER;
54 else if (strcasecmp((*it).c_str(), "groups") == 0)
55 opts |= LIST_GROUPS;
56 }
57}
58
59const FocusableList *FocusableList::getListFromOptions(BScreen &scr, int opts) {
60 if (opts & LIST_GROUPS)
61 return (opts & STATIC_ORDER) ?
62 &scr.focusControl().creationOrderWinList() :
63 &scr.focusControl().focusedOrderWinList();
64 return (opts & STATIC_ORDER) ?
65 &scr.focusControl().creationOrderList() :
66 &scr.focusControl().focusedOrderList();
67}
68
69FocusableList::FocusableList(BScreen &scr, const string pat):
70 m_pat(0), m_parent(0), m_screen(scr) {
71
72 int options = 0;
73 string pattern;
74 parseArgs(pat, options, pattern);
75 m_parent = getListFromOptions(scr, options);
76 m_pat.reset(new ClientPattern(pattern.c_str()));
77
78 init();
79}
80
81FocusableList::FocusableList(BScreen &scr, const FocusableList &parent,
82 const string pat):
83 m_pat(new ClientPattern(pat.c_str())), m_parent(&parent), m_screen(scr) {
84
85 init();
86}
87
88void FocusableList::init() {
89 addMatching();
90 m_parent->attachChild(*this);
91
92 // TODO: can't handle (head=[mouse]) yet
93 if (m_pat->dependsOnCurrentWorkspace())
94 m_screen.currentWorkspaceSig().attach(this);
95 if (m_pat->dependsOnFocusedWindow())
96 m_screen.focusedWindowSig().attach(this);
97}
98
99void FocusableList::update(FbTk::Subject *subj) {
100 if (subj == 0 || m_screen.isShuttingdown())
101 return;
102
103 if (typeid(*subj) == typeid(Focusable::FocusSubject)) {
104 Focusable::FocusSubject *fsubj =
105 static_cast<Focusable::FocusSubject *>(subj);
106 if (fsubj == &fsubj->win().dieSig())
107 remove(fsubj->win());
108 else if (fsubj == &fsubj->win().titleSig())
109 checkUpdate(fsubj->win());
110 }
111 if (typeid(*subj) == typeid(FluxboxWindow::WinSubject)) {
112 FluxboxWindow::WinSubject *fsubj =
113 static_cast<FluxboxWindow::WinSubject *>(subj);
114 // we only bind these for matching patterns, so skip finding out signal
115 FluxboxWindow &fbwin = fsubj->win();
116 if (m_parent->contains(fbwin))
117 checkUpdate(fbwin);
118 std::list<WinClient *> list = fbwin.clientList();
119 std::list<WinClient *>::iterator it = list.begin(), it_end = list.end();
120 for (; it != it_end; ++it) {
121 if (m_parent->contains(**it))
122 checkUpdate(**it);
123 }
124 }
125 if (typeid(*subj) == typeid(FocusableListSubject)) {
126 FocusableListSubject *fsubj =
127 static_cast<FocusableListSubject *>(subj);
128 if (subj == &m_parent->addSig()) {
129 if (m_pat->match(*fsubj->win())) {
130 insertFromParent(*fsubj->win());
131 m_addsig.notify(fsubj->win());
132 } else // we still want to watch it, in case it changes to match
133 attachSignals(*fsubj->win());
134 } else if (subj == &m_parent->removeSig())
135 remove(*fsubj->win());
136 else if (subj == &m_parent->resetSig())
137 reset();
138 else if (subj == &m_parent->orderSig()) {
139 Focusable *win = fsubj->win();
140 if (!win || !contains(*win))
141 return;
142 if (insertFromParent(*win))
143 m_ordersig.notify(win);
144 }
145 } else if (subj == &m_screen.currentWorkspaceSig() ||
146 subj == &m_screen.focusedWindowSig())
147 reset();
148}
149
150void FocusableList::checkUpdate(Focusable &win) {
151 if (contains(win)) {
152 if (!m_pat->match(win)) {
153 m_list.remove(&win);
154 m_removesig.notify(&win);
155 }
156 } else if (m_pat->match(win)) {
157 insertFromParent(win);
158 m_addsig.notify(&win);
159 }
160}
161
162// returns whether or not the window was moved
163bool FocusableList::insertFromParent(Focusable &win) {
164 const Focusables list = m_parent->clientList();
165 Focusables::const_iterator p_it = list.begin(), p_it_end = list.end();
166 Focusables::iterator our_it = m_list.begin(), our_it_end = m_list.end();
167 // walk through our list looking for corresponding entries in
168 // parent's list, until we find the window that moved
169 for (; our_it != our_it_end && p_it != p_it_end; p_it++) {
170 if (*p_it == &win) {
171 if (*our_it == &win) // win didn't move in our list
172 return false;
173 m_list.remove(&win);
174 m_list.insert(our_it, &win);
175 return true;
176 }
177 if (*p_it == *our_it)
178 ++our_it;
179 }
180 m_list.remove(&win);
181 m_list.push_back(&win);
182 return true;
183}
184
185void FocusableList::addMatching() {
186 if (!m_parent)
187 return;
188
189 const Focusables list = m_parent->clientList();
190 Focusables::const_iterator it = list.begin(), it_end = list.end();
191 for (; it != it_end; ++it) {
192 if (m_pat->match(**it))
193 pushBack(**it);
194 else // we still want to watch it, in case it changes to match
195 attachSignals(**it);
196 }
197}
198
199void FocusableList::pushFront(Focusable &win) {
200 m_list.push_front(&win);
201 attachSignals(win);
202 m_addsig.notify(&win);
203}
204
205void FocusableList::pushBack(Focusable &win) {
206 m_list.push_back(&win);
207 attachSignals(win);
208 m_addsig.notify(&win);
209}
210
211void FocusableList::moveToFront(Focusable &win) {
212 // if the window isn't already in this list, we could accidentally add it
213 if (!contains(win))
214 return;
215
216 m_list.remove(&win);
217 m_list.push_front(&win);
218 m_ordersig.notify(&win);
219}
220
221void FocusableList::moveToBack(Focusable &win) {
222 // if the window isn't already in this list, we could accidentally add it
223 if (!contains(win))
224 return;
225
226 m_list.remove(&win);
227 m_list.push_back(&win);
228 m_ordersig.notify(&win);
229}
230
231void FocusableList::remove(Focusable &win) {
232 // if the window isn't already in this list, we could send a bad signal
233 bool contained = contains(win);
234
235 detachSignals(win);
236 if (!contained)
237 return;
238 m_list.remove(&win);
239 m_removesig.notify(&win);
240}
241
242void FocusableList::attachSignals(Focusable &win) {
243 win.dieSig().attach(this);
244 if (m_parent) {
245 // attach various signals for matching
246 win.titleSig().attach(this);
247 FluxboxWindow *fbwin = win.fbwindow();
248 if (!fbwin)
249 return;
250 fbwin->workspaceSig().attach(this);
251 fbwin->stateSig().attach(this);
252 fbwin->layerSig().attach(this);
253 // TODO: can't watch (head=...) yet
254 }
255}
256
257void FocusableList::detachSignals(Focusable &win) {
258 win.dieSig().detach(this);
259 if (m_parent) {
260 // detach various signals for matching
261 win.titleSig().detach(this);
262 FluxboxWindow *fbwin = win.fbwindow();
263 if (!fbwin)
264 return;
265 fbwin->workspaceSig().detach(this);
266 fbwin->stateSig().detach(this);
267 fbwin->layerSig().detach(this);
268 // TODO: can't watch (head=...) yet
269 }
270}
271
272void FocusableList::reset() {
273 while (!m_list.empty()) {
274 detachSignals(*m_list.back());
275 m_list.pop_back();
276 }
277 if (m_parent)
278 addMatching();
279 m_resetsig.notify(0);
280}
281
282bool FocusableList::contains(const Focusable &win) const {
283 Focusables::const_iterator it = m_list.begin(), it_end = m_list.end();
284 it = find(it, it_end, &win);
285 return (it != it_end);
286}
287
288void FocusableList::attachChild(FocusableList &child) const {
289 m_addsig.attach(&child);
290 m_removesig.attach(&child);
291 m_resetsig.attach(&child);
292 m_ordersig.attach(&child);
293}
diff --git a/src/FocusableList.hh b/src/FocusableList.hh
new file mode 100644
index 0000000..7cca298
--- /dev/null
+++ b/src/FocusableList.hh
@@ -0,0 +1,121 @@
1// FocusableList.hh
2// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22// $Id: $
23
24#ifndef FOCUSABLELIST_HH
25#define FOCUSABLELIST_HH
26
27#include "FbTk/NotCopyable.hh"
28#include "FbTk/Observer.hh"
29#include "FbTk/Subject.hh"
30
31#include "ClientPattern.hh"
32
33#include <list>
34#include <string>
35
36class BScreen;
37class Focusable;
38
39class FocusableList: public FbTk::Observer, private FbTk::NotCopyable {
40public:
41 typedef std::list<Focusable *> Focusables;
42
43 /// list option bits
44 enum {
45 LIST_GROUPS = 0x01, //< list groups instead of clients
46 STATIC_ORDER = 0x02, ///< use creation order instead of focused order
47 };
48
49 FocusableList(BScreen &scr): m_pat(0), m_parent(0), m_screen(scr) { }
50 FocusableList(BScreen &scr, const std::string pat);
51 FocusableList(BScreen &scr, const FocusableList &parent,
52 const std::string pat);
53
54 static void parseArgs(const std::string &in, int &opts, std::string &out);
55 static const FocusableList *getListFromOptions(BScreen &scr, int opts);
56
57 void update(FbTk::Subject *subj);
58
59 /// functions for modifying the list contents
60 void pushFront(Focusable &win);
61 void pushBack(Focusable &win);
62 void moveToFront(Focusable &win);
63 void moveToBack(Focusable &win);
64 void remove(Focusable &win);
65
66 /// accessor for list
67 Focusables &clientList() { return m_list; }
68 const Focusables &clientList() const { return m_list; }
69
70 /// does the list contain any windows?
71 bool empty() const { return m_list.empty(); }
72 /// does the list contain the given window?
73 bool contains(const Focusable &win) const;
74
75 /**
76 @name signals
77 @{
78 */
79 FbTk::Subject &orderSig() { return m_ordersig; }
80 const FbTk::Subject &orderSig() const { return m_ordersig; }
81 FbTk::Subject &addSig() { return m_addsig; }
82 const FbTk::Subject &addSig() const { return m_addsig; }
83 FbTk::Subject &removeSig() { return m_removesig; }
84 const FbTk::Subject &removeSig() const { return m_removesig; }
85 FbTk::Subject &resetSig() { return m_resetsig; }
86 const FbTk::Subject &resetSig() const { return m_resetsig; }
87 /** @} */ // end group signals
88
89 /**
90 * Signaling object to attatch observers to.
91 */
92 class FocusableListSubject: public FbTk::Subject {
93 public:
94 explicit FocusableListSubject(): m_win(0) { }
95 void notify(Focusable *win) { m_win = win; FbTk::Subject::notify(); }
96 /// @return context for this signal
97 Focusable *win() { return m_win; }
98
99 private:
100 Focusable *m_win;
101 };
102
103private:
104 void init();
105 void addMatching();
106 void checkUpdate(Focusable &win);
107 bool insertFromParent(Focusable &win);
108 void attachSignals(Focusable &win);
109 void detachSignals(Focusable &win);
110 void reset();
111 void attachChild(FocusableList &child) const;
112
113 std::auto_ptr<ClientPattern> m_pat;
114 const FocusableList *m_parent;
115 BScreen &m_screen;
116 std::list<Focusable *> m_list;
117
118 mutable FocusableListSubject m_ordersig, m_addsig, m_removesig, m_resetsig;
119};
120
121#endif // FOCUSABLELIST_HH
diff --git a/src/IconbarTool.cc b/src/IconbarTool.cc
index bbd867b..1a4e87c 100644
--- a/src/IconbarTool.cc
+++ b/src/IconbarTool.cc
@@ -38,6 +38,7 @@
38#include "FocusControl.hh" 38#include "FocusControl.hh"
39#include "FbCommands.hh" 39#include "FbCommands.hh"
40#include "Layer.hh" 40#include "Layer.hh"
41#include "STLUtil.hh"
41 42
42#include "FbTk/I18n.hh" 43#include "FbTk/I18n.hh"
43#include "FbTk/Menu.hh" 44#include "FbTk/Menu.hh"
@@ -68,26 +69,6 @@ using std::endl;
68namespace FbTk { 69namespace FbTk {
69 70
70template<> 71template<>
71void FbTk::Resource<IconbarTool::Mode>::setFromString(const char *strval) {
72 if (strcasecmp(strval, "None") == 0)
73 m_value = IconbarTool::NONE;
74 else if (strcasecmp(strval, "Icons") == 0)
75 m_value = IconbarTool::ICONS;
76 else if (strcasecmp(strval, "NoIcons") == 0)
77 m_value = IconbarTool::NOICONS;
78 else if (strcasecmp(strval, "WorkspaceIcons") == 0)
79 m_value = IconbarTool::WORKSPACEICONS;
80 else if (strcasecmp(strval, "WorkspaceNoIcons") == 0)
81 m_value = IconbarTool::WORKSPACENOICONS;
82 else if (strcasecmp(strval, "Workspace") == 0)
83 m_value = IconbarTool::WORKSPACE;
84 else if (strcasecmp(strval, "AllWindows") == 0)
85 m_value = IconbarTool::ALLWINDOWS;
86 else
87 setDefaultValue();
88}
89
90template<>
91void FbTk::Resource<Container::Alignment>::setDefaultValue() { 72void FbTk::Resource<Container::Alignment>::setDefaultValue() {
92 m_value = Container::RELATIVE; 73 m_value = Container::RELATIVE;
93} 74}
@@ -117,35 +98,6 @@ void FbTk::Resource<Container::Alignment>::setFromString(const char *str) {
117 setDefaultValue(); 98 setDefaultValue();
118} 99}
119 100
120template<>
121string FbTk::Resource<IconbarTool::Mode>::getString() const {
122
123 switch (m_value) {
124 case IconbarTool::NONE:
125 return string("None");
126 break;
127 case IconbarTool::ICONS:
128 return string("Icons");
129 break;
130 case IconbarTool::NOICONS:
131 return string("NoIcons");
132 break;
133 case IconbarTool::WORKSPACEICONS:
134 return string("WorkspaceIcons");
135 break;
136 case IconbarTool::WORKSPACENOICONS:
137 return string("WorkspaceNoIcons");
138 break;
139 case IconbarTool::WORKSPACE:
140 return string("Workspace");
141 break;
142 case IconbarTool::ALLWINDOWS:
143 return string("AllWindows");
144 break;
145 }
146 // default string
147 return string("Icons");
148}
149} // end namespace FbTk 101} // end namespace FbTk
150 102
151namespace { 103namespace {
@@ -153,7 +105,7 @@ namespace {
153class ToolbarModeMenuItem : public FbTk::MenuItem { 105class ToolbarModeMenuItem : public FbTk::MenuItem {
154public: 106public:
155 ToolbarModeMenuItem(const FbTk::FbString &label, IconbarTool &handler, 107 ToolbarModeMenuItem(const FbTk::FbString &label, IconbarTool &handler,
156 IconbarTool::Mode mode, 108 string mode,
157 FbTk::RefCount<FbTk::Command> &cmd): 109 FbTk::RefCount<FbTk::Command> &cmd):
158 FbTk::MenuItem(label, cmd), m_handler(handler), m_mode(mode) { 110 FbTk::MenuItem(label, cmd), m_handler(handler), m_mode(mode) {
159 } 111 }
@@ -165,7 +117,7 @@ public:
165 117
166private: 118private:
167 IconbarTool &m_handler; 119 IconbarTool &m_handler;
168 IconbarTool::Mode m_mode; 120 string m_mode;
169}; 121};
170 122
171class ToolbarAlignMenuItem: public FbTk::MenuItem { 123class ToolbarAlignMenuItem: public FbTk::MenuItem {
@@ -198,42 +150,42 @@ void setupModeMenu(FbTk::Menu &menu, IconbarTool &handler) {
198 menu.insert(new ToolbarModeMenuItem(_FB_XTEXT(Toolbar, IconbarModeNone, 150 menu.insert(new ToolbarModeMenuItem(_FB_XTEXT(Toolbar, IconbarModeNone,
199 "None", "No icons are shown in the iconbar"), 151 "None", "No icons are shown in the iconbar"),
200 handler, 152 handler,
201 IconbarTool::NONE, saverc_cmd)); 153 "none", saverc_cmd));
202 154
203 menu.insert(new ToolbarModeMenuItem( 155 menu.insert(new ToolbarModeMenuItem(
204 _FB_XTEXT(Toolbar, IconbarModeIcons, 156 _FB_XTEXT(Toolbar, IconbarModeIcons,
205 "Icons", "Iconified windows from all workspaces are shown"), 157 "Icons", "Iconified windows from all workspaces are shown"),
206 handler, 158 handler,
207 IconbarTool::ICONS, saverc_cmd)); 159 "{static groups} (minimized=yes)", saverc_cmd));
208 160
209 menu.insert(new ToolbarModeMenuItem( 161 menu.insert(new ToolbarModeMenuItem(
210 _FB_XTEXT(Toolbar, IconbarModeNoIcons, 162 _FB_XTEXT(Toolbar, IconbarModeNoIcons,
211 "NoIcons", "No iconified windows from all workspaces are shown"), 163 "NoIcons", "No iconified windows from all workspaces are shown"),
212 handler, 164 handler,
213 IconbarTool::NOICONS, saverc_cmd)); 165 "{static groups} (minimized=no)", saverc_cmd));
214 166
215 menu.insert(new ToolbarModeMenuItem( 167 menu.insert(new ToolbarModeMenuItem(
216 _FB_XTEXT(Toolbar, IconbarModeWorkspaceIcons, 168 _FB_XTEXT(Toolbar, IconbarModeWorkspaceIcons,
217 "WorkspaceIcons", "Iconified windows from this workspace are shown"), 169 "WorkspaceIcons", "Iconified windows from this workspace are shown"),
218 handler, 170 handler,
219 IconbarTool::WORKSPACEICONS, saverc_cmd)); 171 "{static groups} (minimized=yes) (workspace)", saverc_cmd));
220 172
221 menu.insert(new ToolbarModeMenuItem( 173 menu.insert(new ToolbarModeMenuItem(
222 _FB_XTEXT(Toolbar, IconbarModeWorkspaceNoIcons, 174 _FB_XTEXT(Toolbar, IconbarModeWorkspaceNoIcons,
223 "WorkspaceNoIcons", "No iconified windows from this workspace are shown"), 175 "WorkspaceNoIcons", "No iconified windows from this workspace are shown"),
224 handler, 176 handler,
225 IconbarTool::WORKSPACENOICONS, saverc_cmd)); 177 "{static groups} (minimized=no) (workspace)", saverc_cmd));
226 178
227 menu.insert(new ToolbarModeMenuItem( 179 menu.insert(new ToolbarModeMenuItem(
228 _FB_XTEXT(Toolbar, IconbarModeWorkspace, 180 _FB_XTEXT(Toolbar, IconbarModeWorkspace,
229 "Workspace", "Normal and iconified windows from this workspace are shown"), 181 "Workspace", "Normal and iconified windows from this workspace are shown"),
230 handler, 182 handler,
231 IconbarTool::WORKSPACE, saverc_cmd)); 183 "{static groups} (workspace)", saverc_cmd));
232 184
233 menu.insert(new ToolbarModeMenuItem( 185 menu.insert(new ToolbarModeMenuItem(
234 _FB_XTEXT(Toolbar, IconbarModeAllWindows, "All Windows", "All windows are shown"), 186 _FB_XTEXT(Toolbar, IconbarModeAllWindows, "All Windows", "All windows are shown"),
235 handler, 187 handler,
236 IconbarTool::ALLWINDOWS, saverc_cmd)); 188 "{static groups}", saverc_cmd));
237 189
238 menu.insert(new FbTk::MenuSeparator()); 190 menu.insert(new FbTk::MenuSeparator());
239 191
@@ -257,26 +209,6 @@ void setupModeMenu(FbTk::Menu &menu, IconbarTool &handler) {
257 menu.updateMenu(); 209 menu.updateMenu();
258} 210}
259 211
260inline bool checkAddWindow(IconbarTool::Mode mode, const FluxboxWindow &win) {
261 if (win.isIconHidden() || mode == IconbarTool::NONE)
262 return false;
263
264 if ((mode == IconbarTool::ICONS || mode == IconbarTool::WORKSPACEICONS) &&
265 !win.isIconic())
266 return false;
267
268 if ((mode == IconbarTool::NOICONS || mode == IconbarTool::WORKSPACENOICONS)
269 && win.isIconic())
270 return false;
271
272 if ((mode == IconbarTool::WORKSPACE || mode == IconbarTool::WORKSPACEICONS
273 || mode == IconbarTool::WORKSPACENOICONS) &&
274 win.workspaceNumber() != win.screen().currentWorkspaceID())
275 return false;
276
277 return true;
278}
279
280typedef FbTk::RefCount<FbTk::Command> RefCmd; 212typedef FbTk::RefCount<FbTk::Command> RefCmd;
281 213
282class ShowMenu: public FbTk::Command { 214class ShowMenu: public FbTk::Command {
@@ -322,14 +254,16 @@ private:
322 254
323}; // end anonymous namespace 255}; // end anonymous namespace
324 256
325IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScreen &screen, 257IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme,
326 FbTk::Menu &menu): 258 BScreen &screen, FbTk::Menu &menu):
327 ToolbarItem(ToolbarItem::RELATIVE), 259 ToolbarItem(ToolbarItem::RELATIVE),
328 m_screen(screen), 260 m_screen(screen),
329 m_icon_container(parent), 261 m_icon_container(parent),
330 m_theme(theme), 262 m_theme(theme),
331 m_empty_pm( screen.imageControl() ), 263 m_empty_pm( screen.imageControl() ),
332 m_rc_mode(screen.resourceManager(), WORKSPACE, 264 m_winlist(new FocusableList(screen)),
265 m_mode("none"),
266 m_rc_mode(screen.resourceManager(), "{static groups} (workspace)",
333 screen.name() + ".iconbar.mode", screen.altName() + ".Iconbar.Mode"), 267 screen.name() + ".iconbar.mode", screen.altName() + ".Iconbar.Mode"),
334 m_rc_alignment(screen.resourceManager(), Container::LEFT, 268 m_rc_alignment(screen.resourceManager(), Container::LEFT,
335 screen.name() + ".iconbar.alignment", screen.altName() + ".Iconbar.Alignment"), 269 screen.name() + ".iconbar.alignment", screen.altName() + ".Iconbar.Alignment"),
@@ -365,10 +299,7 @@ IconbarTool::IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, BScr
365 299
366 // setup signals 300 // setup signals
367 theme.reconfigSig().attach(this); 301 theme.reconfigSig().attach(this);
368 screen.clientListSig().attach(this); 302 setMode(*m_rc_mode);
369 screen.iconListSig().attach(this);
370 screen.currentWorkspaceSig().attach(this);
371
372} 303}
373 304
374IconbarTool::~IconbarTool() { 305IconbarTool::~IconbarTool() {
@@ -405,20 +336,33 @@ void IconbarTool::setAlignment(Container::Alignment align) {
405 m_menu.reconfigure(); 336 m_menu.reconfigure();
406} 337}
407 338
408void IconbarTool::setMode(Mode mode) { 339void IconbarTool::setMode(string mode) {
409 if (mode == *m_rc_mode) 340 if (mode == m_mode)
410 return; 341 return;
411 342
412 *m_rc_mode = mode; 343 *m_rc_mode = m_mode = mode;
413 344
414 // lock graphics update 345 // lock graphics update
415 m_icon_container.setUpdateLock(true); 346 m_icon_container.setUpdateLock(true);
416 347
417 deleteIcons(); 348 if (m_winlist.get()) {
418 349 m_winlist->addSig().detach(this);
419 // update mode 350 m_winlist->removeSig().detach(this);
420 if (mode != NONE) 351 m_winlist->orderSig().detach(this);
421 updateList(); 352 m_winlist->resetSig().detach(this);
353 }
354 if (mode == "none")
355 m_winlist.reset(new FocusableList(m_screen));
356 else
357 m_winlist.reset(new FocusableList(m_screen,
358 mode + " (iconhidden=no)"));
359 if (m_winlist.get()) {
360 m_winlist->addSig().attach(this);
361 m_winlist->removeSig().attach(this);
362 m_winlist->orderSig().attach(this);
363 m_winlist->resetSig().attach(this);
364 }
365 reset();
422 366
423 // unlock graphics update 367 // unlock graphics update
424 m_icon_container.setUpdateLock(false); 368 m_icon_container.setUpdateLock(false);
@@ -445,10 +389,7 @@ unsigned int IconbarTool::borderWidth() const {
445void IconbarTool::update(FbTk::Subject *subj) { 389void IconbarTool::update(FbTk::Subject *subj) {
446 // ignore updates if we're shutting down 390 // ignore updates if we're shutting down
447 if (m_screen.isShuttingdown()) { 391 if (m_screen.isShuttingdown()) {
448 m_screen.clientListSig().detach(this); 392 if (!m_icons.empty())
449 m_screen.iconListSig().detach(this);
450 m_screen.currentWorkspaceSig().detach(this);
451 if (!m_icon_list.empty())
452 deleteIcons(); 393 deleteIcons();
453 return; 394 return;
454 } 395 }
@@ -462,68 +403,26 @@ void IconbarTool::update(FbTk::Subject *subj) {
462 403
463 m_icon_container.setMaxSizePerClient(*m_rc_client_width); 404 m_icon_container.setMaxSizePerClient(*m_rc_client_width);
464 405
465 406 if (subj == &m_theme.reconfigSig()) {
466 if (mode() == NONE) { 407 setMode(*m_rc_mode);
467 if (subj != 0 && typeid(*subj) == typeid(IconbarTheme))
468 renderTheme();
469 return; 408 return;
470 } 409 }
471 410
472 // handle window signal
473 if (subj != 0 && typeid(*subj) == typeid(FluxboxWindow::WinSubject)) {
474 // we handle everything except die signal here
475 FluxboxWindow::WinSubject *winsubj = static_cast<FluxboxWindow::WinSubject *>(subj);
476 if (subj == &(winsubj->win().workspaceSig())) {
477 // we can ignore this signal if we're in ALLWINDOWS mode
478 if (mode() == ALLWINDOWS || mode() == ICONS || mode() == NOICONS)
479 return;
480
481 // workspace changed for this window, and if it's not on current workspace we remove it
482 if (m_screen.currentWorkspaceID() != winsubj->win().workspaceNumber()) {
483 removeWindow(winsubj->win());
484 renderTheme();
485 }
486 return;
487 } else if (subj == &(winsubj->win().stateSig())) {
488 if (!checkAddWindow(mode(), winsubj->win())) {
489 removeWindow(winsubj->win());
490 renderTheme();
491 }
492 return;
493
494 } else {
495 // signal not handled
496 return;
497 }
498 } else if (subj != 0 && typeid(*subj) == typeid(Focusable::FocusSubject)) {
499 Focusable::FocusSubject *winsubj = static_cast<Focusable::FocusSubject *>(subj);
500 if (subj == &(winsubj->win().dieSig())) { // die sig
501 removeWindow(winsubj->win());
502 renderTheme();
503 return; // we don't need to update the entire list
504 }
505 }
506
507 bool remove_all = false; // if we should readd all windows
508
509 if (subj != 0 && typeid(*subj) == typeid(BScreen::ScreenSubject) &&
510 mode() != ALLWINDOWS && mode() != ICONS && mode() != NOICONS) {
511 BScreen::ScreenSubject *screen_subj = static_cast<BScreen::ScreenSubject *>(subj);
512 // current workspace sig
513 if (&m_screen.currentWorkspaceSig() == screen_subj ) {
514 remove_all = true; // remove and readd all windows
515 }
516
517 }
518
519 // lock graphic update 411 // lock graphic update
520 m_icon_container.setUpdateLock(true); 412 m_icon_container.setUpdateLock(true);
521 413
522 if (remove_all) 414 if (typeid(*subj) == typeid(FocusableList::FocusableListSubject)) {
523 deleteIcons(); 415 FocusableList::FocusableListSubject *fsubj =
524 416 static_cast<FocusableList::FocusableListSubject *>(subj);
525 // ok, we got some signal that we need to update our iconbar container 417 if (subj == &m_winlist->addSig())
526 updateList(); 418 insertWindow(*fsubj->win());
419 else if (subj == &m_winlist->removeSig())
420 removeWindow(*fsubj->win());
421 else if (subj == &m_winlist->resetSig())
422 reset();
423 else if (subj == &m_winlist->orderSig())
424 insertWindow(*fsubj->win());
425 }
527 426
528 // unlock container and update graphics 427 // unlock container and update graphics
529 m_icon_container.setUpdateLock(false); 428 m_icon_container.setUpdateLock(false);
@@ -540,25 +439,42 @@ void IconbarTool::update(FbTk::Subject *subj) {
540 renderTheme(); 439 renderTheme();
541} 440}
542 441
543IconButton *IconbarTool::findButton(Focusable &win) { 442void IconbarTool::insertWindow(Focusable &win, int pos) {
443 IconButton *button = 0;
444
445 IconMap::iterator icon_it = m_icons.find(&win);
446 if (icon_it != m_icons.end())
447 button = icon_it->second;
544 448
545 IconList::iterator icon_it = m_icon_list.begin(); 449 if (button)
546 IconList::iterator icon_it_end = m_icon_list.end(); 450 m_icon_container.removeItem(button);
547 for (; icon_it != icon_it_end; ++icon_it) { 451 else
548 if (&(*icon_it)->win() == &win) 452 button = makeButton(win);
549 return *icon_it; 453 if (!button) return;
454
455 if (pos == -2) {
456 pos = 0;
457 list<Focusable *>::iterator it = m_winlist->clientList().begin(),
458 it_end = m_winlist->clientList().end();
459 for (; it != it_end && *it != &win; ++it)
460 pos++;
550 } 461 }
551 462
552 return 0; 463 m_icon_container.insertItem(button, pos);
464}
465
466void IconbarTool::reset() {
467 deleteIcons();
468 updateList();
553} 469}
554 470
555void IconbarTool::updateSizing() { 471void IconbarTool::updateSizing() {
556 m_icon_container.setBorderWidth(m_theme.border().width()); 472 m_icon_container.setBorderWidth(m_theme.border().width());
557 473
558 IconList::iterator icon_it = m_icon_list.begin(); 474 IconMap::iterator icon_it = m_icons.begin();
559 const IconList::iterator icon_it_end = m_icon_list.end(); 475 const IconMap::iterator icon_it_end = m_icons.end();
560 for (; icon_it != icon_it_end; ++icon_it) 476 for (; icon_it != icon_it_end; ++icon_it)
561 (*icon_it)->reconfigTheme(); 477 icon_it->second->reconfigTheme();
562 478
563} 479}
564 480
@@ -588,10 +504,10 @@ void IconbarTool::renderTheme() {
588 m_icon_container.setAlpha(m_alpha); 504 m_icon_container.setAlpha(m_alpha);
589 505
590 // update buttons 506 // update buttons
591 IconList::iterator icon_it = m_icon_list.begin(); 507 IconMap::iterator icon_it = m_icons.begin();
592 const IconList::iterator icon_it_end = m_icon_list.end(); 508 const IconMap::iterator icon_it_end = m_icons.end();
593 for (; icon_it != icon_it_end; ++icon_it) 509 for (; icon_it != icon_it_end; ++icon_it)
594 renderButton(*(*icon_it)); 510 renderButton(*icon_it->second);
595 511
596} 512}
597 513
@@ -606,49 +522,30 @@ void IconbarTool::renderButton(IconButton &button, bool clear) {
606 522
607void IconbarTool::deleteIcons() { 523void IconbarTool::deleteIcons() {
608 m_icon_container.removeAll(); 524 m_icon_container.removeAll();
609 while (!m_icon_list.empty()) { 525 STLUtil::destroyAndClearSecond(m_icons);
610 delete m_icon_list.back();
611 m_icon_list.pop_back();
612 }
613} 526}
614 527
615void IconbarTool::removeWindow(Focusable &win) { 528void IconbarTool::removeWindow(Focusable &win) {
616 // got window die signal, lets find and remove the window 529 // got window die signal, lets find and remove the window
617 IconList::iterator it = m_icon_list.begin(); 530 IconMap::iterator it = m_icons.find(&win);
618 IconList::iterator it_end = m_icon_list.end(); 531 if (it == m_icons.end())
619 for (; it != it_end; ++it) {
620 if (&(*it)->win() == &win)
621 break;
622 }
623 // did we find it?
624 if (it == m_icon_list.end()) {
625 return; 532 return;
626 }
627#ifdef DEBUG 533#ifdef DEBUG
628 cerr<<"IconbarTool::"<<__FUNCTION__<<"( 0x"<<&win<<" title = "<<win.title()<<") found!"<<endl; 534 cerr<<"IconbarTool::"<<__FUNCTION__<<"( 0x"<<&win<<" title = "<<win.title()<<") found!"<<endl;
629#endif // DEBUG 535#endif // DEBUG
630 // detach from all signals
631 win.dieSig().detach(this);
632 if (win.fbwindow()) {
633 win.fbwindow()->workspaceSig().detach(this);
634 win.fbwindow()->stateSig().detach(this);
635 }
636 536
637 // remove from list and render theme again 537 // remove from list and render theme again
638 IconButton *button = *it; 538 IconButton *button = it->second;
639 539 m_icons.erase(it);
640 m_icon_container.removeItem(m_icon_container.find(*it)); 540 m_icon_container.removeItem(button);
641 m_icon_list.erase(it);
642
643 delete button; 541 delete button;
644
645} 542}
646 543
647void IconbarTool::addWindow(Focusable &win) { 544IconButton *IconbarTool::makeButton(Focusable &win) {
648 // we just want windows that have clients 545 // we just want windows that have clients
649 FluxboxWindow *fbwin = win.fbwindow(); 546 FluxboxWindow *fbwin = win.fbwindow();
650 if (!fbwin || fbwin->clientList().empty() || fbwin->isIconHidden()) 547 if (!fbwin || fbwin->clientList().empty())
651 return; 548 return 0;
652#ifdef DEBUG 549#ifdef DEBUG
653 cerr<<"IconbarTool::addWindow(0x"<<&win<<" title = "<<win.title()<<")"<<endl; 550 cerr<<"IconbarTool::addWindow(0x"<<&win<<" title = "<<win.title()<<")"<<endl;
654#endif // DEBUG 551#endif // DEBUG
@@ -660,39 +557,21 @@ void IconbarTool::addWindow(Focusable &win) {
660 button->setOnClick(menu_cmd, 3); 557 button->setOnClick(menu_cmd, 3);
661 558
662 renderButton(*button, false); // update the attributes, but don't clear it 559 renderButton(*button, false); // update the attributes, but don't clear it
663 m_icon_container.insertItem(button); 560 m_icons[&win] = button;
664 m_icon_list.push_back(button); 561 return button;
665
666 // dont forget to detach signal in removeWindow
667 win.dieSig().attach(this);
668 fbwin->workspaceSig().attach(this);
669 fbwin->stateSig().attach(this);
670} 562}
671 563
672void IconbarTool::updateList() { 564void IconbarTool::updateList() {
673 list<Focusable *> ordered_list = 565 list<Focusable *>::iterator it = m_winlist->clientList().begin();
674 m_screen.focusControl().creationOrderWinList(); 566 list<Focusable *>::iterator it_end = m_winlist->clientList().end();
675 list<Focusable *>::iterator it = ordered_list.begin();
676 list<Focusable *>::iterator it_end = ordered_list.end();
677 for (; it != it_end; ++it) { 567 for (; it != it_end; ++it) {
678 if ((*it)->fbwindow() && checkAddWindow(mode(), *(*it)->fbwindow()) && 568 if ((*it)->fbwindow())
679 !checkDuplicate(**it)) 569 insertWindow(**it, -1);
680 addWindow(**it);
681 } 570 }
682 571
683 renderTheme(); 572 renderTheme();
684} 573}
685 574
686bool IconbarTool::checkDuplicate(Focusable &win) {
687 IconList::iterator it = m_icon_list.begin();
688 IconList::iterator it_end = m_icon_list.end();
689 for (; it != it_end; ++it) {
690 if (&win == &(*it)->win())
691 return true;
692 }
693 return false;
694}
695
696void IconbarTool::setOrientation(FbTk::Orientation orient) { 575void IconbarTool::setOrientation(FbTk::Orientation orient) {
697 m_icon_container.setOrientation(orient); 576 m_icon_container.setOrientation(orient);
698 ToolbarItem::setOrientation(orient); 577 ToolbarItem::setOrientation(orient);
diff --git a/src/IconbarTool.hh b/src/IconbarTool.hh
index 323c714..e1bebe3 100644
--- a/src/IconbarTool.hh
+++ b/src/IconbarTool.hh
@@ -28,6 +28,7 @@
28#include "ToolbarItem.hh" 28#include "ToolbarItem.hh"
29#include "Container.hh" 29#include "Container.hh"
30#include "FbMenu.hh" 30#include "FbMenu.hh"
31#include "FocusableList.hh"
31 32
32#include "FbTk/CachedPixmap.hh" 33#include "FbTk/CachedPixmap.hh"
33#include "FbTk/Observer.hh" 34#include "FbTk/Observer.hh"
@@ -36,7 +37,7 @@
36 37
37#include <X11/Xlib.h> 38#include <X11/Xlib.h>
38 39
39#include <list> 40#include <map>
40 41
41class IconbarTheme; 42class IconbarTheme;
42class BScreen; 43class BScreen;
@@ -45,17 +46,7 @@ class Focusable;
45 46
46class IconbarTool: public ToolbarItem, public FbTk::Observer { 47class IconbarTool: public ToolbarItem, public FbTk::Observer {
47public: 48public:
48 typedef std::list<IconButton *> IconList; 49 typedef std::map<Focusable *, IconButton *> IconMap;
49 /// iconbar mode
50 enum Mode {
51 NONE, ///< no icons
52 ICONS, ///< all icons from all workspaces
53 NOICONS, ///< all noniconified windows from all workspaces
54 WORKSPACEICONS, ///< icons on current workspace
55 WORKSPACENOICONS, ///< non iconified workspaces on current workspaces
56 WORKSPACE, ///< all windows and all icons on current workspace
57 ALLWINDOWS ///< all windows and all icons from all workspaces
58 };
59 50
60 IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme, 51 IconbarTool(const FbTk::FbWindow &parent, IconbarTheme &theme,
61 BScreen &screen, FbTk::Menu &menu); 52 BScreen &screen, FbTk::Menu &menu);
@@ -70,14 +61,14 @@ public:
70 void show(); 61 void show();
71 void hide(); 62 void hide();
72 void setAlignment(Container::Alignment a); 63 void setAlignment(Container::Alignment a);
73 void setMode(Mode mode); 64 void setMode(std::string mode);
74 void parentMoved() { m_icon_container.parentMoved(); } 65 void parentMoved() { m_icon_container.parentMoved(); }
75 66
76 unsigned int width() const; 67 unsigned int width() const;
77 unsigned int height() const; 68 unsigned int height() const;
78 unsigned int borderWidth() const; 69 unsigned int borderWidth() const;
79 70
80 Mode mode() const { return *m_rc_mode; } 71 std::string mode() const { return *m_rc_mode; }
81 72
82 void setOrientation(FbTk::Orientation orient); 73 void setOrientation(FbTk::Orientation orient);
83 Container::Alignment alignment() const { return m_icon_container.alignment(); } 74 Container::Alignment alignment() const { return m_icon_container.alignment(); }
@@ -85,9 +76,6 @@ public:
85 const BScreen &screen() const { return m_screen; } 76 const BScreen &screen() const { return m_screen; }
86private: 77private:
87 78
88 /// @return button associated with window
89 IconButton *findButton(Focusable &win);
90
91 void updateSizing(); 79 void updateSizing();
92 80
93 /// render single button, and probably apply changes (clear) 81 /// render single button, and probably apply changes (clear)
@@ -99,14 +87,16 @@ private:
99 void renderTheme(unsigned char alpha); 87 void renderTheme(unsigned char alpha);
100 /// destroy all icons 88 /// destroy all icons
101 void deleteIcons(); 89 void deleteIcons();
90 /// add or move a single window
91 void insertWindow(Focusable &win, int pos = -2);
102 /// remove a single window 92 /// remove a single window
103 void removeWindow(Focusable &win); 93 void removeWindow(Focusable &win);
104 /// add a single window 94 /// make a button for the window
105 void addWindow(Focusable &win); 95 IconButton *makeButton(Focusable &win);
96 /// remove all windows and add again
97 void reset();
106 /// add icons to the list 98 /// add icons to the list
107 void updateList(); 99 void updateList();
108 /// check if window is already in the list
109 bool checkDuplicate(Focusable &win);
110 100
111 BScreen &m_screen; 101 BScreen &m_screen;
112 Container m_icon_container; 102 Container m_icon_container;
@@ -114,8 +104,10 @@ private:
114 FbTk::CachedPixmap m_empty_pm; ///< pixmap for empty container 104 FbTk::CachedPixmap m_empty_pm; ///< pixmap for empty container
115 105
116 106
117 IconList m_icon_list; 107 std::auto_ptr<FocusableList> m_winlist;
118 FbTk::Resource<Mode> m_rc_mode; 108 IconMap m_icons;
109 std::string m_mode;
110 FbTk::Resource<std::string> m_rc_mode;
119 FbTk::Resource<Container::Alignment> m_rc_alignment; ///< alignment of buttons 111 FbTk::Resource<Container::Alignment> m_rc_alignment; ///< alignment of buttons
120 FbTk::Resource<int> m_rc_client_width; ///< size of client button in LEFT/RIGHT mode 112 FbTk::Resource<int> m_rc_client_width; ///< size of client button in LEFT/RIGHT mode
121 FbTk::Resource<unsigned int> m_rc_client_padding; ///< padding of the text 113 FbTk::Resource<unsigned int> m_rc_client_padding; ///< padding of the text
diff --git a/src/Makefile.am b/src/Makefile.am
index 9245097..3ecc610 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -151,7 +151,7 @@ fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.cc \
151 IconButton.hh IconButton.cc \ 151 IconButton.hh IconButton.cc \
152 IconbarTheme.hh IconbarTheme.cc \ 152 IconbarTheme.hh IconbarTheme.cc \
153 STLUtil.hh \ 153 STLUtil.hh \
154 Focusable.hh \ 154 Focusable.hh FocusableList.hh FocusableList.cc \
155 ${newwmspec_SOURCE} ${gnome_SOURCE} \ 155 ${newwmspec_SOURCE} ${gnome_SOURCE} \
156 ${REMEMBER_SOURCE} ${TOOLBAR_SOURCE} 156 ${REMEMBER_SOURCE} ${TOOLBAR_SOURCE}
157 157
diff --git a/src/MinOverlapPlacement.cc b/src/MinOverlapPlacement.cc
index ce7ff3c..874aea8 100644
--- a/src/MinOverlapPlacement.cc
+++ b/src/MinOverlapPlacement.cc
@@ -40,7 +40,7 @@ bool MinOverlapPlacement::placeWindow(const FluxboxWindow &win, int head,
40 40
41 std::list<FluxboxWindow *> windowlist; 41 std::list<FluxboxWindow *> windowlist;
42 const std::list<Focusable *> focusables = 42 const std::list<Focusable *> focusables =
43 win.screen().focusControl().focusedOrderWinList(); 43 win.screen().focusControl().focusedOrderWinList().clientList();
44 std::list<Focusable *>::const_iterator foc_it = focusables.begin(), 44 std::list<Focusable *>::const_iterator foc_it = focusables.begin(),
45 foc_it_end = focusables.end(); 45 foc_it_end = focusables.end();
46 unsigned int workspace = win.workspaceNumber(); 46 unsigned int workspace = win.workspaceNumber();
diff --git a/src/RowSmartPlacement.cc b/src/RowSmartPlacement.cc
index 6457d59..5d1786c 100644
--- a/src/RowSmartPlacement.cc
+++ b/src/RowSmartPlacement.cc
@@ -33,7 +33,7 @@ bool RowSmartPlacement::placeWindow(const FluxboxWindow &win, int head,
33 33
34 std::list<FluxboxWindow *> windowlist; 34 std::list<FluxboxWindow *> windowlist;
35 const std::list<Focusable *> focusables = 35 const std::list<Focusable *> focusables =
36 win.screen().focusControl().focusedOrderWinList(); 36 win.screen().focusControl().focusedOrderWinList().clientList();
37 std::list<Focusable *>::const_iterator foc_it = focusables.begin(), 37 std::list<Focusable *>::const_iterator foc_it = focusables.begin(),
38 foc_it_end = focusables.end(); 38 foc_it_end = focusables.end();
39 unsigned int workspace = win.workspaceNumber(); 39 unsigned int workspace = win.workspaceNumber();
diff --git a/src/Screen.cc b/src/Screen.cc
index e618216..a53792b 100644
--- a/src/Screen.cc
+++ b/src/Screen.cc
@@ -346,6 +346,7 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
346 m_workspacenames_sig(*this), // workspace names signal 346 m_workspacenames_sig(*this), // workspace names signal
347 m_workspace_area_sig(*this), // workspace area signal 347 m_workspace_area_sig(*this), // workspace area signal
348 m_currentworkspace_sig(*this), // current workspace signal 348 m_currentworkspace_sig(*this), // current workspace signal
349 m_focusedwindow_sig(*this), // focused window signal
349 m_reconfigure_sig(*this), // reconfigure signal 350 m_reconfigure_sig(*this), // reconfigure signal
350 m_resize_sig(*this), 351 m_resize_sig(*this),
351 m_bg_change_sig(*this), 352 m_bg_change_sig(*this),
@@ -871,19 +872,10 @@ void BScreen::cycleFocus(int options, const ClientPattern *pat, bool reverse) {
871 } 872 }
872 873
873 if (mods == 0) // can't stacked cycle unless there is a mod to grab 874 if (mods == 0) // can't stacked cycle unless there is a mod to grab
874 options |= FocusControl::CYCLELINEAR; 875 options |= FocusableList::STATIC_ORDER;
875
876 const FocusControl::Focusables *win_list = 0;
877 if (options & FocusControl::CYCLEGROUPS) {
878 win_list = (options & FocusControl::CYCLELINEAR) ?
879 &focusControl().creationOrderWinList() :
880 &focusControl().focusedOrderWinList();
881 } else {
882 win_list = (options & FocusControl::CYCLELINEAR) ?
883 &focusControl().creationOrderList() :
884 &focusControl().focusedOrderList();
885 }
886 876
877 const FocusableList *win_list =
878 FocusableList::getListFromOptions(*this, options);
887 focusControl().cycleFocus(*win_list, pat, reverse); 879 focusControl().cycleFocus(*win_list, pat, reverse);
888 880
889} 881}
diff --git a/src/Screen.hh b/src/Screen.hh
index f5641e2..953411c 100644
--- a/src/Screen.hh
+++ b/src/Screen.hh
@@ -222,6 +222,8 @@ public:
222 FbTk::Subject &workspaceAreaSig() { return m_workspace_area_sig; } 222 FbTk::Subject &workspaceAreaSig() { return m_workspace_area_sig; }
223 /// current workspace signal 223 /// current workspace signal
224 FbTk::Subject &currentWorkspaceSig() { return m_currentworkspace_sig; } 224 FbTk::Subject &currentWorkspaceSig() { return m_currentworkspace_sig; }
225 /// focused window signal
226 FbTk::Subject &focusedWindowSig() { return m_focusedwindow_sig; }
225 /// reconfigure signal 227 /// reconfigure signal
226 FbTk::Subject &reconfigureSig() { return m_reconfigure_sig; } 228 FbTk::Subject &reconfigureSig() { return m_reconfigure_sig; }
227 FbTk::Subject &resizeSig() { return m_resize_sig; } 229 FbTk::Subject &resizeSig() { return m_resize_sig; }
@@ -488,6 +490,7 @@ private:
488 m_workspacenames_sig, ///< workspace names signal 490 m_workspacenames_sig, ///< workspace names signal
489 m_workspace_area_sig, ///< workspace area changed signal 491 m_workspace_area_sig, ///< workspace area changed signal
490 m_currentworkspace_sig, ///< current workspace signal 492 m_currentworkspace_sig, ///< current workspace signal
493 m_focusedwindow_sig, ///< focused window signal
491 m_reconfigure_sig, ///< reconfigure signal 494 m_reconfigure_sig, ///< reconfigure signal
492 m_resize_sig, ///< resize signal 495 m_resize_sig, ///< resize signal
493 m_bg_change_sig; ///< background change signal 496 m_bg_change_sig; ///< background change signal
diff --git a/src/Window.cc b/src/Window.cc
index 898111d..903756a 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -1405,7 +1405,7 @@ void FluxboxWindow::iconify() {
1405 1405
1406 hide(true); 1406 hide(true);
1407 1407
1408 screen().focusControl().setFocusBack(this); 1408 screen().focusControl().setFocusBack(*this);
1409 1409
1410 ClientList::iterator client_it = m_clientlist.begin(); 1410 ClientList::iterator client_it = m_clientlist.begin();
1411 const ClientList::iterator client_it_end = m_clientlist.end(); 1411 const ClientList::iterator client_it_end = m_clientlist.end();
@@ -2038,10 +2038,6 @@ void FluxboxWindow::setState(unsigned long new_state, bool setting_up) {
2038 (*it)->show(); 2038 (*it)->show();
2039 (*it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask | KeyPressMask); 2039 (*it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask | KeyPressMask);
2040 } 2040 }
2041
2042 saveBlackboxAttribs();
2043 //notify state changed
2044 m_statesig.notify();
2045} 2041}
2046 2042
2047bool FluxboxWindow::getState() { 2043bool FluxboxWindow::getState() {
diff --git a/src/WorkspaceCmd.cc b/src/WorkspaceCmd.cc
index a525078..79ceb40 100644
--- a/src/WorkspaceCmd.cc
+++ b/src/WorkspaceCmd.cc
@@ -49,7 +49,7 @@ void WindowListCmd::execute() {
49 49
50 BScreen *screen = Fluxbox::instance()->keyScreen(); 50 BScreen *screen = Fluxbox::instance()->keyScreen();
51 if (screen != 0) { 51 if (screen != 0) {
52 FocusControl::Focusables win_list(screen->focusControl().creationOrderWinList()); 52 FocusControl::Focusables win_list(screen->focusControl().creationOrderWinList().clientList());
53 53
54 FocusControl::Focusables::iterator it = win_list.begin(), 54 FocusControl::Focusables::iterator it = win_list.begin(),
55 it_end = win_list.end(); 55 it_end = win_list.end();
@@ -63,7 +63,7 @@ void WindowListCmd::execute() {
63void AttachCmd::execute() { 63void AttachCmd::execute() {
64 BScreen *screen = Fluxbox::instance()->keyScreen(); 64 BScreen *screen = Fluxbox::instance()->keyScreen();
65 if (screen != 0) { 65 if (screen != 0) {
66 FocusControl::Focusables win_list(screen->focusControl().focusedOrderWinList()); 66 FocusControl::Focusables win_list(screen->focusControl().focusedOrderWinList().clientList());
67 67
68 FocusControl::Focusables::iterator it = win_list.begin(), 68 FocusControl::Focusables::iterator it = win_list.begin(),
69 it_end = win_list.end(); 69 it_end = win_list.end();
@@ -95,16 +95,8 @@ void PrevWindowCmd::execute() {
95void GoToWindowCmd::execute() { 95void GoToWindowCmd::execute() {
96 BScreen *screen = Fluxbox::instance()->keyScreen(); 96 BScreen *screen = Fluxbox::instance()->keyScreen();
97 if (screen != 0) { 97 if (screen != 0) {
98 const FocusControl::Focusables *win_list = 0; 98 const FocusableList *win_list =
99 if (m_option & FocusControl::CYCLEGROUPS) { 99 FocusableList::getListFromOptions(*screen, m_option);
100 win_list = (m_option & FocusControl::CYCLELINEAR) ?
101 &screen->focusControl().creationOrderWinList() :
102 &screen->focusControl().focusedOrderWinList();
103 } else {
104 win_list = (m_option & FocusControl::CYCLELINEAR) ?
105 &screen->focusControl().creationOrderList() :
106 &screen->focusControl().focusedOrderList();
107 }
108 screen->focusControl().goToWindowNumber(*win_list, m_num, &m_pat); 100 screen->focusControl().goToWindowNumber(*win_list, m_num, &m_pat);
109 } 101 }
110} 102}
diff --git a/src/fluxbox.cc b/src/fluxbox.cc
index ddb09e2..3c30c14 100644
--- a/src/fluxbox.cc
+++ b/src/fluxbox.cc
@@ -514,6 +514,7 @@ void Fluxbox::initScreen(BScreen *screen) {
514 514
515 // attach screen signals to this 515 // attach screen signals to this
516 screen->currentWorkspaceSig().attach(this); 516 screen->currentWorkspaceSig().attach(this);
517 screen->focusedWindowSig().attach(this);
517 screen->workspaceCountSig().attach(this); 518 screen->workspaceCountSig().attach(this);
518 screen->workspaceNamesSig().attach(this); 519 screen->workspaceNamesSig().attach(this);
519 screen->workspaceAreaSig().attach(this); 520 screen->workspaceAreaSig().attach(this);
@@ -642,7 +643,7 @@ void Fluxbox::setupConfigFiles() {
642 if (create_init) 643 if (create_init)
643 FbTk::FileUtil::copyFile(DEFAULT_INITFILE, init_file.c_str()); 644 FbTk::FileUtil::copyFile(DEFAULT_INITFILE, init_file.c_str());
644 645
645#define CONFIG_VERSION 4 646#define CONFIG_VERSION 5
646 FbTk::Resource<int> config_version(m_resourcemanager, 0, 647 FbTk::Resource<int> config_version(m_resourcemanager, 0,
647 "session.configVersion", "Session.ConfigVersion"); 648 "session.configVersion", "Session.ConfigVersion");
648 if (*config_version < CONFIG_VERSION) { 649 if (*config_version < CONFIG_VERSION) {
@@ -1191,6 +1192,14 @@ void Fluxbox::update(FbTk::Subject *changedsub) {
1191 if ((*it).first->update()) 1192 if ((*it).first->update())
1192 (*it).first->updateCurrentWorkspace(screen); 1193 (*it).first->updateCurrentWorkspace(screen);
1193 } 1194 }
1195 } else if ((&(screen.focusedWindowSig())) == changedsub) {
1196 for (AtomHandlerContainerIt it= m_atomhandler.begin();
1197 it != m_atomhandler.end(); it++) {
1198 (*it).first->updateFocusedWindow(screen,
1199 (FocusControl::focusedWindow() ?
1200 FocusControl::focusedWindow()->window() :
1201 0));
1202 }
1194 } else if ((&(screen.workspaceAreaSig())) == changedsub) { 1203 } else if ((&(screen.workspaceAreaSig())) == changedsub) {
1195 for (AtomHandlerContainerIt it= m_atomhandler.begin(); 1204 for (AtomHandlerContainerIt it= m_atomhandler.begin();
1196 it != m_atomhandler.end(); ++it) { 1205 it != m_atomhandler.end(); ++it) {
@@ -1682,23 +1691,6 @@ bool Fluxbox::validateClient(const WinClient *client) const {
1682 return it != m_window_search.end(); 1691 return it != m_window_search.end();
1683} 1692}
1684 1693
1685void Fluxbox::updateFocusedWindow(BScreen *screen, BScreen *old_screen) {
1686 if (screen != 0) {
1687 for (AtomHandlerContainerIt it= m_atomhandler.begin();
1688 it != m_atomhandler.end(); it++) {
1689 (*it).first->updateFocusedWindow(*screen, (FocusControl::focusedWindow() ?
1690 FocusControl::focusedWindow()->window() :
1691 0));
1692 }
1693 }
1694
1695 if (old_screen && old_screen != screen) {
1696 for (AtomHandlerContainerIt it= m_atomhandler.begin();
1697 it != m_atomhandler.end(); it++)
1698 (*it).first->updateFocusedWindow(*old_screen, 0);
1699 }
1700}
1701
1702void Fluxbox::updateFrameExtents(FluxboxWindow &win) { 1694void Fluxbox::updateFrameExtents(FluxboxWindow &win) {
1703 AtomHandlerContainerIt it = m_atomhandler.begin(); 1695 AtomHandlerContainerIt it = m_atomhandler.begin();
1704 AtomHandlerContainerIt it_end = m_atomhandler.end(); 1696 AtomHandlerContainerIt it_end = m_atomhandler.end();
diff --git a/src/fluxbox.hh b/src/fluxbox.hh
index 82ff76d..d5a48c6 100644
--- a/src/fluxbox.hh
+++ b/src/fluxbox.hh
@@ -162,12 +162,6 @@ public:
162 /// handle any system signal sent to the application 162 /// handle any system signal sent to the application
163 void handleSignal(int signum); 163 void handleSignal(int signum);
164 void update(FbTk::Subject *changed); 164 void update(FbTk::Subject *changed);
165 /**
166 * Sends update signal to atomhandlers,
167 * @param screen the new screen
168 * @param old_screen the old screen if any, can be the same as new screen
169 */
170 void updateFocusedWindow(BScreen *screen, BScreen *old_screen);
171 /// todo, remove this. just temporary 165 /// todo, remove this. just temporary
172 void updateFrameExtents(FluxboxWindow &win); 166 void updateFrameExtents(FluxboxWindow &win);
173 167