aboutsummaryrefslogtreecommitdiff
path: root/src/FocusableList.cc
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/FocusableList.cc
parent807a1b557552e43dbdc169c1e7a3065a3f12aac7 (diff)
downloadfluxbox-5d7043320da1378e7dd3b10f7e425f3b47455b28.zip
fluxbox-5d7043320da1378e7dd3b10f7e425f3b47455b28.tar.bz2
allow arbitrary window patterns in iconbar
Diffstat (limited to 'src/FocusableList.cc')
-rw-r--r--src/FocusableList.cc293
1 files changed, 293 insertions, 0 deletions
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}