diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Slit.cc | 210 | ||||
-rw-r--r-- | src/Slit.hh | 19 |
2 files changed, 207 insertions, 22 deletions
diff --git a/src/Slit.cc b/src/Slit.cc index 48345c9..79e3d31 100644 --- a/src/Slit.cc +++ b/src/Slit.cc | |||
@@ -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: Slit.cc,v 1.13 2002/05/08 14:12:28 fluxgen Exp $ | 22 | // $Id: Slit.cc,v 1.14 2002/05/29 06:21:59 fluxgen Exp $ |
23 | 23 | ||
24 | //use GNU extensions | 24 | //use GNU extensions |
25 | #ifndef _GNU_SOURCE | 25 | #ifndef _GNU_SOURCE |
@@ -42,9 +42,60 @@ | |||
42 | #include "Toolbar.hh" | 42 | #include "Toolbar.hh" |
43 | 43 | ||
44 | #include <algorithm> | 44 | #include <algorithm> |
45 | #include <iostream> | ||
46 | #include <cassert> | ||
45 | 47 | ||
48 | #ifdef HAVE_SYS_STAT_H | ||
49 | # include <sys/types.h> | ||
50 | # include <sys/stat.h> | ||
51 | #endif // HAVE_SYS_STAT_H | ||
52 | |||
53 | |||
54 | // Utility method for extracting name from window | ||
55 | namespace { | ||
56 | void getWMName(BScreen *screen, Window window, std::string& name) { | ||
57 | assert(screen); | ||
58 | name = ""; | ||
59 | |||
60 | if (screen != 0 && window != None) { | ||
61 | Display *display = screen->getBaseDisplay()->getXDisplay(); | ||
62 | |||
63 | XTextProperty text_prop; | ||
64 | char **list; | ||
65 | int num; | ||
66 | I18n *i18n = I18n::instance(); | ||
67 | |||
68 | if (XGetWMName(display, window, &text_prop)) { | ||
69 | if (text_prop.value && text_prop.nitems > 0) { | ||
70 | if (text_prop.encoding != XA_STRING) { | ||
71 | |||
72 | text_prop.nitems = strlen((char *) text_prop.value); | ||
73 | |||
74 | if ((XmbTextPropertyToTextList(display, &text_prop, | ||
75 | &list, &num) == Success) && | ||
76 | (num > 0) && *list) { | ||
77 | name = static_cast<char *>(*list); | ||
78 | XFreeStringList(list); | ||
79 | } else | ||
80 | name = (char *)text_prop.value; | ||
81 | |||
82 | } else | ||
83 | name = (char *)text_prop.value; | ||
84 | } else | ||
85 | name = i18n->getMessage( | ||
86 | FBNLS::WindowSet, FBNLS::WindowUnnamed, | ||
87 | "Unnamed"); | ||
88 | } else { | ||
89 | name = i18n->getMessage( | ||
90 | FBNLS::WindowSet, FBNLS::WindowUnnamed, | ||
91 | "Unnamed"); | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | }; // End anonymous namespace | ||
46 | 96 | ||
47 | Slit::Slit(BScreen *scr):screen(scr), timer(this), slitmenu(*this) { | 97 | Slit::Slit(BScreen *scr):screen(scr), timer(this), slitmenu(*this) { |
98 | assert(scr); | ||
48 | fluxbox = Fluxbox::instance(); | 99 | fluxbox = Fluxbox::instance(); |
49 | 100 | ||
50 | on_top = screen->isSlitOnTop(); | 101 | on_top = screen->isSlitOnTop(); |
@@ -66,7 +117,7 @@ Slit::Slit(BScreen *scr):screen(scr), timer(this), slitmenu(*this) { | |||
66 | attrib.colormap = screen->getColormap(); | 117 | attrib.colormap = screen->getColormap(); |
67 | attrib.override_redirect = True; | 118 | attrib.override_redirect = True; |
68 | attrib.event_mask = SubstructureRedirectMask | ButtonPressMask | | 119 | attrib.event_mask = SubstructureRedirectMask | ButtonPressMask | |
69 | EnterWindowMask | LeaveWindowMask; | 120 | EnterWindowMask | LeaveWindowMask; |
70 | 121 | ||
71 | frame.x = frame.y = 0; | 122 | frame.x = frame.y = 0; |
72 | frame.width = frame.height = 1; | 123 | frame.width = frame.height = 1; |
@@ -78,6 +129,9 @@ Slit::Slit(BScreen *scr):screen(scr), timer(this), slitmenu(*this) { | |||
78 | create_mask, &attrib); | 129 | create_mask, &attrib); |
79 | fluxbox->saveSlitSearch(frame.window, this); | 130 | fluxbox->saveSlitSearch(frame.window, this); |
80 | 131 | ||
132 | // Get client list for sorting purposes | ||
133 | loadClientList(); | ||
134 | |||
81 | reconfigure(); | 135 | reconfigure(); |
82 | } | 136 | } |
83 | 137 | ||
@@ -102,8 +156,37 @@ void Slit::addClient(Window w) { | |||
102 | 156 | ||
103 | fluxbox->grab(); | 157 | fluxbox->grab(); |
104 | if (fluxbox->validateWindow(w)) { | 158 | if (fluxbox->validateWindow(w)) { |
105 | SlitClient *client = new SlitClient; | 159 | // Look for slot in client list by name |
106 | client->client_window = w; | 160 | SlitClient *client = 0; |
161 | std::string match_name; | ||
162 | ::getWMName(screen, w, match_name); | ||
163 | SlitClients::iterator it = clientList.begin(); | ||
164 | SlitClients::iterator it_end = clientList.end(); | ||
165 | bool found_match = false; | ||
166 | for (; it != it_end; ++it) { | ||
167 | // If the name matches... | ||
168 | if ((*it)->match_name == match_name) { | ||
169 | // Use the slot if no window is assigned | ||
170 | if ((*it)->window == None) { | ||
171 | client = (*it); | ||
172 | client->initialize(screen, w); | ||
173 | break; | ||
174 | } | ||
175 | // Otherwise keep looking for an unused match or a non-match | ||
176 | found_match = true; // Possibly redundant | ||
177 | |||
178 | } else if (found_match) { | ||
179 | // Insert before first non-match after a previously found match? | ||
180 | client = new SlitClient(screen, w); | ||
181 | clientList.insert(it, client); | ||
182 | break; | ||
183 | } | ||
184 | } | ||
185 | // Append to client list? | ||
186 | if (client == 0) { | ||
187 | client = new SlitClient(screen, w); | ||
188 | clientList.push_back(client); | ||
189 | } | ||
107 | 190 | ||
108 | XWMHints *wmhints = XGetWMHints(display, w); | 191 | XWMHints *wmhints = XGetWMHints(display, w); |
109 | 192 | ||
@@ -184,22 +267,26 @@ void Slit::addClient(Window w) { | |||
184 | SubstructureNotifyMask | EnterWindowMask); | 267 | SubstructureNotifyMask | EnterWindowMask); |
185 | XFlush(display); | 268 | XFlush(display); |
186 | 269 | ||
187 | clientList.push_back(client); | ||
188 | |||
189 | fluxbox->saveSlitSearch(client->client_window, this); | 270 | fluxbox->saveSlitSearch(client->client_window, this); |
190 | fluxbox->saveSlitSearch(client->icon_window, this); | 271 | fluxbox->saveSlitSearch(client->icon_window, this); |
191 | reconfigure(); | 272 | reconfigure(); |
273 | |||
274 | saveClientList(); | ||
192 | } | 275 | } |
193 | 276 | ||
194 | fluxbox->ungrab(); | 277 | fluxbox->ungrab(); |
195 | } | 278 | } |
196 | 279 | ||
197 | 280 | ||
198 | void Slit::removeClient(SlitClient *client, bool remap) { | 281 | void Slit::removeClient(SlitClient *client, bool remap, bool destroy) { |
199 | fluxbox->removeSlitSearch(client->client_window); | 282 | fluxbox->removeSlitSearch(client->client_window); |
200 | fluxbox->removeSlitSearch(client->icon_window); | 283 | fluxbox->removeSlitSearch(client->icon_window); |
201 | 284 | ||
202 | clientList.remove(client); | 285 | // Destructive removal? |
286 | if (destroy) | ||
287 | clientList.remove(client); | ||
288 | else // Clear the window info, but keep around to help future sorting? | ||
289 | client->initialize(); | ||
203 | 290 | ||
204 | screen->removeNetizen(client->window); | 291 | screen->removeNetizen(client->window); |
205 | 292 | ||
@@ -214,7 +301,9 @@ void Slit::removeClient(SlitClient *client, bool remap) { | |||
214 | XFlush(display); | 301 | XFlush(display); |
215 | } | 302 | } |
216 | 303 | ||
217 | delete client; | 304 | // Destructive removal? |
305 | if (destroy) | ||
306 | delete client; | ||
218 | } | 307 | } |
219 | 308 | ||
220 | 309 | ||
@@ -227,7 +316,7 @@ void Slit::removeClient(Window w, bool remap) { | |||
227 | SlitClients::iterator it_end = clientList.end(); | 316 | SlitClients::iterator it_end = clientList.end(); |
228 | for (; it != it_end; ++it) { | 317 | for (; it != it_end; ++it) { |
229 | if ((*it)->window == w) { | 318 | if ((*it)->window == w) { |
230 | removeClient((*it), remap); | 319 | removeClient((*it), remap, false); |
231 | reconf = true; | 320 | reconf = true; |
232 | 321 | ||
233 | break; | 322 | break; |
@@ -243,16 +332,25 @@ void Slit::reconfigure(void) { | |||
243 | frame.width = 0; | 332 | frame.width = 0; |
244 | frame.height = 0; | 333 | frame.height = 0; |
245 | 334 | ||
335 | // Need to count windows because not all client list entries | ||
336 | // actually correspond to mapped windows. | ||
337 | int num_windows = 0; | ||
338 | |||
246 | switch (screen->getSlitDirection()) { | 339 | switch (screen->getSlitDirection()) { |
247 | case VERTICAL: | 340 | case VERTICAL: |
248 | { | 341 | { |
249 | SlitClients::iterator it = clientList.begin(); | 342 | SlitClients::iterator it = clientList.begin(); |
250 | SlitClients::iterator it_end = clientList.end(); | 343 | SlitClients::iterator it_end = clientList.end(); |
251 | for (; it != it_end; ++it) { | 344 | for (; it != it_end; ++it) { |
252 | frame.height += (*it)->height + screen->getBevelWidth(); | 345 | //client created window? |
253 | 346 | if ((*it)->window != None) { | |
254 | if (frame.width < (*it)->width) | 347 | num_windows++; |
255 | frame.width = (*it)->width; | 348 | frame.height += (*it)->height + screen->getBevelWidth(); |
349 | |||
350 | //frame width < client window? | ||
351 | if (frame.width < (*it)->width) | ||
352 | frame.width = (*it)->width; | ||
353 | } | ||
256 | } | 354 | } |
257 | } | 355 | } |
258 | 356 | ||
@@ -273,10 +371,14 @@ void Slit::reconfigure(void) { | |||
273 | SlitClients::iterator it = clientList.begin(); | 371 | SlitClients::iterator it = clientList.begin(); |
274 | SlitClients::iterator it_end = clientList.end(); | 372 | SlitClients::iterator it_end = clientList.end(); |
275 | for (; it != it_end; ++it) { | 373 | for (; it != it_end; ++it) { |
276 | frame.width += (*it)->width + screen->getBevelWidth(); | 374 | //client created window? |
277 | 375 | if ((*it)->window != None) { | |
278 | if (frame.height < (*it)->height) | 376 | num_windows++; |
279 | frame.height = (*it)->height; | 377 | frame.width += (*it)->width + screen->getBevelWidth(); |
378 | //frame height < client height? | ||
379 | if (frame.height < (*it)->height) | ||
380 | frame.height = (*it)->height; | ||
381 | } | ||
280 | } | 382 | } |
281 | } | 383 | } |
282 | 384 | ||
@@ -299,7 +401,8 @@ void Slit::reconfigure(void) { | |||
299 | XSetWindowBorder(display, frame.window, | 401 | XSetWindowBorder(display, frame.window, |
300 | screen->getBorderColor()->getPixel()); | 402 | screen->getBorderColor()->getPixel()); |
301 | 403 | ||
302 | if (clientList.size()==0) | 404 | //did we actually use slit slots |
405 | if (num_windows == 0) | ||
303 | XUnmapWindow(display, frame.window); | 406 | XUnmapWindow(display, frame.window); |
304 | else | 407 | else |
305 | XMapWindow(display, frame.window); | 408 | XMapWindow(display, frame.window); |
@@ -316,7 +419,9 @@ void Slit::reconfigure(void) { | |||
316 | texture); | 419 | texture); |
317 | XSetWindowBackgroundPixmap(display, frame.window, frame.pixmap); | 420 | XSetWindowBackgroundPixmap(display, frame.window, frame.pixmap); |
318 | } | 421 | } |
319 | if (tmp) image_ctrl->removeImage(tmp); | 422 | |
423 | if (tmp) | ||
424 | image_ctrl->removeImage(tmp); | ||
320 | XClearWindow(display, frame.window); | 425 | XClearWindow(display, frame.window); |
321 | 426 | ||
322 | int x, y; | 427 | int x, y; |
@@ -330,6 +435,10 @@ void Slit::reconfigure(void) { | |||
330 | SlitClients::iterator it = clientList.begin(); | 435 | SlitClients::iterator it = clientList.begin(); |
331 | SlitClients::iterator it_end = clientList.end(); | 436 | SlitClients::iterator it_end = clientList.end(); |
332 | for (; it != it_end; ++it) { | 437 | for (; it != it_end; ++it) { |
438 | //client created window? | ||
439 | if ((*it)->window == None) | ||
440 | continue; | ||
441 | |||
333 | x = (frame.width - (*it)->width) / 2; | 442 | x = (frame.width - (*it)->width) / 2; |
334 | 443 | ||
335 | XMoveResizeWindow(display, (*it)->window, x, y, | 444 | XMoveResizeWindow(display, (*it)->window, x, y, |
@@ -371,6 +480,10 @@ void Slit::reconfigure(void) { | |||
371 | SlitClients::iterator it = clientList.begin(); | 480 | SlitClients::iterator it = clientList.begin(); |
372 | SlitClients::iterator it_end = clientList.end(); | 481 | SlitClients::iterator it_end = clientList.end(); |
373 | for (; it != it_end; ++it) { | 482 | for (; it != it_end; ++it) { |
483 | //client created window? | ||
484 | if ((*it)->window == None) | ||
485 | continue; | ||
486 | |||
374 | y = (frame.height - (*it)->height) / 2; | 487 | y = (frame.height - (*it)->height) / 2; |
375 | 488 | ||
376 | XMoveResizeWindow(display, (*it)->window, x, y, | 489 | XMoveResizeWindow(display, (*it)->window, x, y, |
@@ -556,8 +669,9 @@ void Slit::reposition(void) { | |||
556 | 669 | ||
557 | 670 | ||
558 | void Slit::shutdown(void) { | 671 | void Slit::shutdown(void) { |
672 | saveClientList(); | ||
559 | while (clientList.size() != 0) | 673 | while (clientList.size() != 0) |
560 | removeClient(clientList.front()); | 674 | removeClient(clientList.front(), true, true); |
561 | } | 675 | } |
562 | 676 | ||
563 | 677 | ||
@@ -663,6 +777,39 @@ void Slit::timeout(void) { | |||
663 | XMoveWindow(display, frame.window, frame.x, frame.y); | 777 | XMoveWindow(display, frame.window, frame.x, frame.y); |
664 | } | 778 | } |
665 | 779 | ||
780 | void Slit::loadClientList(void) { | ||
781 | const std::string &filename = fluxbox->getSlitlistFilename(); | ||
782 | struct stat buf; | ||
783 | if (!stat(filename.c_str(), &buf)) | ||
784 | { | ||
785 | std::ifstream file(fluxbox->getSlitlistFilename().c_str()); | ||
786 | std::string name; | ||
787 | while (! file.eof()) { | ||
788 | name = ""; | ||
789 | file >> name; | ||
790 | if (name.size() > 0) { | ||
791 | SlitClient *client = new SlitClient(name.c_str()); | ||
792 | clientList.push_back(client); | ||
793 | } | ||
794 | } | ||
795 | } | ||
796 | } | ||
797 | |||
798 | void Slit::saveClientList(void) { | ||
799 | const std::string &filename = fluxbox->getSlitlistFilename(); | ||
800 | std::ofstream file(filename.c_str()); | ||
801 | SlitClients::iterator it = clientList.begin(); | ||
802 | SlitClients::iterator it_end = clientList.end(); | ||
803 | std::string prevName; | ||
804 | std::string name; | ||
805 | for (; it != it_end; ++it) { | ||
806 | name = (*it)->match_name; | ||
807 | if (name != prevName) | ||
808 | file << name.c_str() << std::endl; | ||
809 | prevName = name; | ||
810 | } | ||
811 | } | ||
812 | |||
666 | 813 | ||
667 | Slitmenu::Slitmenu(Slit &sl) : Basemenu(sl.screen), | 814 | Slitmenu::Slitmenu(Slit &sl) : Basemenu(sl.screen), |
668 | slit(sl) { | 815 | slit(sl) { |
@@ -929,4 +1076,25 @@ void Slitmenu::Headmenu::itemSelected(int button, unsigned int index) { | |||
929 | 1076 | ||
930 | #endif // XINERAMA | 1077 | #endif // XINERAMA |
931 | 1078 | ||
1079 | Slit::SlitClient::SlitClient(const char *name) | ||
1080 | { | ||
1081 | initialize(); | ||
1082 | match_name = name; | ||
1083 | } | ||
1084 | |||
1085 | Slit::SlitClient::SlitClient(BScreen *screen, Window w) | ||
1086 | { | ||
1087 | initialize(screen, w); | ||
1088 | } | ||
1089 | |||
1090 | void Slit::SlitClient::initialize(BScreen *screen, Window w) { | ||
1091 | assert(screen); | ||
1092 | client_window = w; | ||
1093 | window = icon_window = None; | ||
1094 | x = y = 0; | ||
1095 | width = height = 0; | ||
1096 | if (match_name.size() == 0) | ||
1097 | getWMName(screen, client_window, match_name); | ||
1098 | } | ||
1099 | |||
932 | #endif // SLIT | 1100 | #endif // SLIT |
diff --git a/src/Slit.hh b/src/Slit.hh index 75111d0..61a7d33 100644 --- a/src/Slit.hh +++ b/src/Slit.hh | |||
@@ -35,6 +35,7 @@ class Slitmenu; | |||
35 | #include "Basemenu.hh" | 35 | #include "Basemenu.hh" |
36 | 36 | ||
37 | #include <list> | 37 | #include <list> |
38 | #include <string> | ||
38 | 39 | ||
39 | class Slitmenu : public Basemenu { | 40 | class Slitmenu : public Basemenu { |
40 | public: | 41 | public: |
@@ -130,6 +131,7 @@ public: | |||
130 | void reconfigure(void); | 131 | void reconfigure(void); |
131 | void reposition(void); | 132 | void reposition(void); |
132 | void shutdown(void); | 133 | void shutdown(void); |
134 | void saveClientList(void); | ||
133 | 135 | ||
134 | void buttonPressEvent(XButtonEvent *); | 136 | void buttonPressEvent(XButtonEvent *); |
135 | void enterNotifyEvent(XCrossingEvent *); | 137 | void enterNotifyEvent(XCrossingEvent *); |
@@ -145,13 +147,27 @@ public: | |||
145 | private: | 147 | private: |
146 | class SlitClient { | 148 | class SlitClient { |
147 | public: | 149 | public: |
150 | SlitClient(BScreen *, Window); // For adding an actual window | ||
151 | SlitClient(const char *); // For adding a placeholder | ||
152 | |||
153 | // Now we pre-initialize a list of slit clients with names for | ||
154 | // comparison with incoming client windows. This allows the slit | ||
155 | // to maintain a sorted order based on a saved window name list. | ||
156 | // Incoming windows not found in the list are appended. Matching | ||
157 | // duplicates are inserted after the last found instance of the | ||
158 | // matching name. | ||
159 | std::string match_name; | ||
160 | |||
148 | Window window, client_window, icon_window; | 161 | Window window, client_window, icon_window; |
149 | 162 | ||
150 | int x, y; | 163 | int x, y; |
151 | unsigned int width, height; | 164 | unsigned int width, height; |
165 | |||
166 | void initialize(BScreen * = NULL, Window = None); | ||
152 | }; | 167 | }; |
153 | 168 | ||
154 | void removeClient(SlitClient *, bool = true); | 169 | void removeClient(SlitClient *, bool, bool); |
170 | void loadClientList(void); | ||
155 | 171 | ||
156 | Bool on_top, hidden, do_auto_hide; | 172 | Bool on_top, hidden, do_auto_hide; |
157 | Display *display; | 173 | Display *display; |
@@ -164,6 +180,7 @@ private: | |||
164 | 180 | ||
165 | SlitClients clientList; | 181 | SlitClients clientList; |
166 | Slitmenu slitmenu; | 182 | Slitmenu slitmenu; |
183 | std::string clientListPath; | ||
167 | 184 | ||
168 | struct frame { | 185 | struct frame { |
169 | Pixmap pixmap; | 186 | Pixmap pixmap; |