diff options
Diffstat (limited to 'src/Workspace.cc')
-rw-r--r-- | src/Workspace.cc | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/src/Workspace.cc b/src/Workspace.cc new file mode 100644 index 0000000..48b0d67 --- /dev/null +++ b/src/Workspace.cc | |||
@@ -0,0 +1,512 @@ | |||
1 | // Workspace.cc for Blackbox - an X11 Window manager | ||
2 | // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) | ||
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 | // stupid macros needed to access some functions in version 2 of the GNU C | ||
23 | // library | ||
24 | #ifndef _GNU_SOURCE | ||
25 | #define _GNU_SOURCE | ||
26 | #endif // _GNU_SOURCE | ||
27 | |||
28 | #ifdef HAVE_CONFIG_H | ||
29 | # include "../config.h" | ||
30 | #endif // HAVE_CONFIG_H | ||
31 | |||
32 | #include <X11/Xlib.h> | ||
33 | #include <X11/Xatom.h> | ||
34 | |||
35 | #include "i18n.hh" | ||
36 | #include "fluxbox.hh" | ||
37 | #include "Clientmenu.hh" | ||
38 | #include "Screen.hh" | ||
39 | #include "Toolbar.hh" | ||
40 | #include "Window.hh" | ||
41 | #include "Workspace.hh" | ||
42 | #include "Windowmenu.hh" | ||
43 | |||
44 | #ifdef HAVE_STDIO_H | ||
45 | # include <stdio.h> | ||
46 | #endif // HAVE_STDIO_H | ||
47 | |||
48 | #ifdef STDC_HEADERS | ||
49 | # include <string.h> | ||
50 | #endif // STDC_HEADERS | ||
51 | |||
52 | #define MIN(x,y) ((x < y) ? x : y) | ||
53 | #define MAX(x,y) ((x > y) ? x : y) | ||
54 | |||
55 | |||
56 | Workspace::Workspace(BScreen *scrn, int i) { | ||
57 | screen = scrn; | ||
58 | |||
59 | cascade_x = cascade_y = 32; | ||
60 | |||
61 | id = i; | ||
62 | |||
63 | stackingList = new LinkedList<FluxboxWindow>; | ||
64 | windowList = new LinkedList<FluxboxWindow>; | ||
65 | clientmenu = new Clientmenu(this); | ||
66 | |||
67 | lastfocus = (FluxboxWindow *) 0; | ||
68 | |||
69 | char *tmp; | ||
70 | name = (char *) 0; | ||
71 | screen->getNameOfWorkspace(id, &tmp); | ||
72 | setName(tmp); | ||
73 | |||
74 | if (tmp) | ||
75 | delete [] tmp; | ||
76 | } | ||
77 | |||
78 | |||
79 | Workspace::~Workspace(void) { | ||
80 | delete stackingList; | ||
81 | delete windowList; | ||
82 | delete clientmenu; | ||
83 | |||
84 | if (name) | ||
85 | delete [] name; | ||
86 | } | ||
87 | |||
88 | |||
89 | const int Workspace::addWindow(FluxboxWindow *w, Bool place) { | ||
90 | if (! w) return -1; | ||
91 | |||
92 | if (place) placeWindow(w); | ||
93 | |||
94 | w->setWorkspace(id); | ||
95 | w->setWindowNumber(windowList->count()); | ||
96 | |||
97 | stackingList->insert(w, 0); | ||
98 | windowList->insert(w); | ||
99 | |||
100 | clientmenu->insert((const char **) w->getTitle()); | ||
101 | clientmenu->update(); | ||
102 | |||
103 | screen->updateNetizenWindowAdd(w->getClientWindow(), id); | ||
104 | |||
105 | raiseWindow(w); | ||
106 | |||
107 | return w->getWindowNumber(); | ||
108 | } | ||
109 | |||
110 | |||
111 | const int Workspace::removeWindow(FluxboxWindow *w) { | ||
112 | if (! w) return -1; | ||
113 | |||
114 | stackingList->remove(w); | ||
115 | |||
116 | if (w->isFocused()) { | ||
117 | if (screen->isSloppyFocus()) | ||
118 | Fluxbox::instance()->setFocusedWindow((FluxboxWindow *) 0); | ||
119 | else if (w->isTransient() && w->getTransientFor() && | ||
120 | w->getTransientFor()->isVisible()) | ||
121 | w->getTransientFor()->setInputFocus(); | ||
122 | else { | ||
123 | |||
124 | FluxboxWindow *top = stackingList->first(); | ||
125 | |||
126 | if (! top || ! top->setInputFocus()) { | ||
127 | Fluxbox::instance()->setFocusedWindow((FluxboxWindow *) 0); | ||
128 | XSetInputFocus(Fluxbox::instance()->getXDisplay(), | ||
129 | screen->getToolbar()->getWindowID(), | ||
130 | RevertToParent, CurrentTime); | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | if (lastfocus == w) | ||
136 | lastfocus = (FluxboxWindow *) 0; | ||
137 | |||
138 | windowList->remove(w->getWindowNumber()); | ||
139 | clientmenu->remove(w->getWindowNumber()); | ||
140 | clientmenu->update(); | ||
141 | |||
142 | screen->updateNetizenWindowDel(w->getClientWindow()); | ||
143 | |||
144 | LinkedListIterator<FluxboxWindow> it(windowList); | ||
145 | for (int i = 0; it.current(); it++, i++) | ||
146 | it.current()->setWindowNumber(i); | ||
147 | |||
148 | return windowList->count(); | ||
149 | } | ||
150 | |||
151 | |||
152 | void Workspace::showAll(void) { | ||
153 | LinkedListIterator<FluxboxWindow> it(stackingList); | ||
154 | for (; it.current(); it++) | ||
155 | it.current()->deiconify(False, False); | ||
156 | } | ||
157 | |||
158 | |||
159 | void Workspace::hideAll(void) { | ||
160 | LinkedList<FluxboxWindow> lst; | ||
161 | |||
162 | LinkedListIterator<FluxboxWindow> it(stackingList); | ||
163 | for (; it.current(); it++) | ||
164 | lst.insert(it.current(), 0); | ||
165 | |||
166 | LinkedListIterator<FluxboxWindow> it2(&lst); | ||
167 | for (; it2.current(); it2++) | ||
168 | if (! it2.current()->isStuck()) | ||
169 | it2.current()->withdraw(); | ||
170 | } | ||
171 | |||
172 | |||
173 | void Workspace::removeAll(void) { | ||
174 | LinkedListIterator<FluxboxWindow> it(windowList); | ||
175 | for (; it.current(); it++) | ||
176 | it.current()->iconify(); | ||
177 | } | ||
178 | |||
179 | |||
180 | void Workspace::raiseWindow(FluxboxWindow *w) { | ||
181 | FluxboxWindow *win = (FluxboxWindow *) 0, *bottom = w; | ||
182 | |||
183 | while (bottom->isTransient() && bottom->getTransientFor()) | ||
184 | bottom = bottom->getTransientFor(); | ||
185 | |||
186 | int i = 1; | ||
187 | win = bottom; | ||
188 | while (win->hasTransient() && win->getTransient()) { | ||
189 | win = win->getTransient(); | ||
190 | |||
191 | i++; | ||
192 | } | ||
193 | |||
194 | Window *nstack = new Window[i], *curr = nstack; | ||
195 | Workspace *wkspc; | ||
196 | |||
197 | win = bottom; | ||
198 | while (True) { | ||
199 | *(curr++) = win->getFrameWindow(); | ||
200 | screen->updateNetizenWindowRaise(win->getClientWindow()); | ||
201 | |||
202 | if (! win->isIconic()) { | ||
203 | wkspc = screen->getWorkspace(win->getWorkspaceNumber()); | ||
204 | wkspc->stackingList->remove(win); | ||
205 | wkspc->stackingList->insert(win, 0); | ||
206 | } | ||
207 | |||
208 | if (! win->hasTransient() || ! win->getTransient()) | ||
209 | break; | ||
210 | |||
211 | win = win->getTransient(); | ||
212 | } | ||
213 | |||
214 | screen->raiseWindows(nstack, i); | ||
215 | |||
216 | delete [] nstack; | ||
217 | } | ||
218 | |||
219 | |||
220 | void Workspace::lowerWindow(FluxboxWindow *w) { | ||
221 | FluxboxWindow *win = (FluxboxWindow *) 0, *bottom = w; | ||
222 | |||
223 | while (bottom->isTransient() && bottom->getTransientFor()) | ||
224 | bottom = bottom->getTransientFor(); | ||
225 | |||
226 | int i = 1; | ||
227 | win = bottom; | ||
228 | while (win->hasTransient() && win->getTransient()) { | ||
229 | win = win->getTransient(); | ||
230 | |||
231 | i++; | ||
232 | } | ||
233 | |||
234 | Window *nstack = new Window[i], *curr = nstack; | ||
235 | Workspace *wkspc; | ||
236 | |||
237 | while (True) { | ||
238 | *(curr++) = win->getFrameWindow(); | ||
239 | screen->updateNetizenWindowLower(win->getClientWindow()); | ||
240 | |||
241 | if (! win->isIconic()) { | ||
242 | wkspc = screen->getWorkspace(win->getWorkspaceNumber()); | ||
243 | wkspc->stackingList->remove(win); | ||
244 | wkspc->stackingList->insert(win); | ||
245 | } | ||
246 | |||
247 | if (! win->getTransientFor()) | ||
248 | break; | ||
249 | |||
250 | win = win->getTransientFor(); | ||
251 | } | ||
252 | |||
253 | Fluxbox::instance()->grab(); | ||
254 | |||
255 | XLowerWindow(screen->getBaseDisplay()->getXDisplay(), *nstack); | ||
256 | XRestackWindows(screen->getBaseDisplay()->getXDisplay(), nstack, i); | ||
257 | |||
258 | Fluxbox::instance()->ungrab(); | ||
259 | |||
260 | delete [] nstack; | ||
261 | } | ||
262 | |||
263 | |||
264 | void Workspace::reconfigure(void) { | ||
265 | clientmenu->reconfigure(); | ||
266 | |||
267 | LinkedListIterator<FluxboxWindow> it(windowList); | ||
268 | for (; it.current(); it++) | ||
269 | if (it.current()->validateClient()) | ||
270 | it.current()->reconfigure(); | ||
271 | } | ||
272 | |||
273 | |||
274 | FluxboxWindow *Workspace::getWindow(int index) { | ||
275 | if ((index >= 0) && (index < windowList->count())) | ||
276 | return windowList->find(index); | ||
277 | else | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | |||
282 | const int Workspace::getCount(void) { | ||
283 | return windowList->count(); | ||
284 | } | ||
285 | |||
286 | |||
287 | void Workspace::update(void) { | ||
288 | clientmenu->update(); | ||
289 | screen->getToolbar()->redrawWindowLabel(True); | ||
290 | } | ||
291 | |||
292 | |||
293 | Bool Workspace::isCurrent(void) { | ||
294 | return (id == screen->getCurrentWorkspaceID()); | ||
295 | } | ||
296 | |||
297 | |||
298 | Bool Workspace::isLastWindow(FluxboxWindow *w) { | ||
299 | return (w == windowList->last()); | ||
300 | } | ||
301 | |||
302 | void Workspace::setCurrent(void) { | ||
303 | screen->changeWorkspaceID(id); | ||
304 | } | ||
305 | |||
306 | |||
307 | void Workspace::setName(char *new_name) { | ||
308 | if (name) | ||
309 | delete [] name; | ||
310 | |||
311 | if (new_name) { | ||
312 | name = bstrdup(new_name); | ||
313 | } else { | ||
314 | name = new char[128]; | ||
315 | sprintf(name, I18n::instance()-> | ||
316 | getMessage( | ||
317 | #ifdef NLS | ||
318 | WorkspaceSet, WorkspaceDefaultNameFormat, | ||
319 | #else // !NLS | ||
320 | 0, 0, | ||
321 | #endif // NLS | ||
322 | "Workspace %d"), id + 1); | ||
323 | } | ||
324 | |||
325 | screen->updateWorkspaceNamesAtom(); | ||
326 | |||
327 | clientmenu->setLabel(name); | ||
328 | clientmenu->update(); | ||
329 | } | ||
330 | |||
331 | |||
332 | void Workspace::shutdown(void) { | ||
333 | while (windowList->count()) { | ||
334 | windowList->first()->restore(); | ||
335 | delete windowList->first(); | ||
336 | } | ||
337 | } | ||
338 | |||
339 | |||
340 | void Workspace::placeWindow(FluxboxWindow *win) { | ||
341 | Bool placed = False; | ||
342 | LinkedListIterator<FluxboxWindow> it(windowList); | ||
343 | int win_w = win->getWidth() + (screen->getBorderWidth2x() * 2), | ||
344 | win_h = win->getHeight() + (screen->getBorderWidth2x() * 2), | ||
345 | #ifdef SLIT | ||
346 | slit_x = screen->getSlit()->getX() - screen->getBorderWidth(), | ||
347 | slit_y = screen->getSlit()->getY() - screen->getBorderWidth(), | ||
348 | slit_w = screen->getSlit()->getWidth() + | ||
349 | (screen->getBorderWidth2x() * 2), | ||
350 | slit_h = screen->getSlit()->getHeight() + | ||
351 | (screen->getBorderWidth2x() * 2), | ||
352 | #endif // SLIT | ||
353 | toolbar_x = screen->getToolbar()->getX() - screen->getBorderWidth(), | ||
354 | toolbar_y = screen->getToolbar()->getY() - screen->getBorderWidth(), | ||
355 | toolbar_w = screen->getToolbar()->getWidth() + | ||
356 | (screen->getBorderWidth2x() * 2), | ||
357 | toolbar_h = screen->getToolbar()->getHeight() + | ||
358 | (screen->getBorderWidth2x() * 2), | ||
359 | place_x = 0, place_y = 0, change_x = 1, change_y = 1; | ||
360 | |||
361 | if (screen->getColPlacementDirection() == BScreen::BottomTop) | ||
362 | change_y = -1; | ||
363 | if (screen->getRowPlacementDirection() == BScreen::RightLeft) | ||
364 | change_x = -1; | ||
365 | |||
366 | register int test_x, test_y, curr_w, curr_h; | ||
367 | |||
368 | switch (screen->getPlacementPolicy()) { | ||
369 | case BScreen::RowSmartPlacement: { | ||
370 | test_y = screen->getBorderWidth() + screen->getEdgeSnapThreshold(); | ||
371 | if (screen->getColPlacementDirection() == BScreen::BottomTop) | ||
372 | test_y = screen->getHeight() - win_h - test_y; | ||
373 | |||
374 | while (((screen->getColPlacementDirection() == BScreen::BottomTop) ? | ||
375 | test_y > 0 : test_y + win_h < (signed) screen->getHeight()) && | ||
376 | ! placed) { | ||
377 | test_x = screen->getBorderWidth() + screen->getEdgeSnapThreshold(); | ||
378 | if (screen->getRowPlacementDirection() == BScreen::RightLeft) | ||
379 | test_x = screen->getWidth() - win_w - test_x; | ||
380 | |||
381 | while (((screen->getRowPlacementDirection() == BScreen::RightLeft) ? | ||
382 | test_x > 0 : test_x + win_w < (signed) screen->getWidth()) && | ||
383 | ! placed) { | ||
384 | placed = True; | ||
385 | |||
386 | it.reset(); | ||
387 | for (; it.current() && placed; it++) { | ||
388 | curr_w = it.current()->getWidth() + screen->getBorderWidth2x() + | ||
389 | screen->getBorderWidth2x(); | ||
390 | curr_h = | ||
391 | ((it.current()->isShaded()) ? it.current()->getTitleHeight() : | ||
392 | it.current()->getHeight()) + | ||
393 | screen->getBorderWidth2x() + screen->getBorderWidth2x(); | ||
394 | |||
395 | if (it.current()->getXFrame() < test_x + win_w && | ||
396 | it.current()->getXFrame() + curr_w > test_x && | ||
397 | it.current()->getYFrame() < test_y + win_h && | ||
398 | it.current()->getYFrame() + curr_h > test_y) | ||
399 | placed = False; | ||
400 | } | ||
401 | |||
402 | if ((toolbar_x < test_x + win_w && | ||
403 | toolbar_x + toolbar_w > test_x && | ||
404 | toolbar_y < test_y + win_h && | ||
405 | toolbar_y + toolbar_h > test_y) | ||
406 | #ifdef SLIT | ||
407 | || | ||
408 | (slit_x < test_x + win_w && | ||
409 | slit_x + slit_w > test_x && | ||
410 | slit_y < test_y + win_h && | ||
411 | slit_y + slit_h > test_y) | ||
412 | #endif // SLIT | ||
413 | ) | ||
414 | placed = False; | ||
415 | |||
416 | if (placed) { | ||
417 | place_x = test_x; | ||
418 | place_y = test_y; | ||
419 | |||
420 | break; | ||
421 | } | ||
422 | |||
423 | test_x += change_x; | ||
424 | } | ||
425 | |||
426 | test_y += change_y; | ||
427 | } | ||
428 | |||
429 | break; } | ||
430 | |||
431 | case BScreen::ColSmartPlacement: { | ||
432 | test_x = screen->getBorderWidth() + screen->getEdgeSnapThreshold(); | ||
433 | if (screen->getRowPlacementDirection() == BScreen::RightLeft) | ||
434 | test_x = screen->getWidth() - win_w - test_x; | ||
435 | |||
436 | while (((screen->getRowPlacementDirection() == BScreen::RightLeft) ? | ||
437 | test_x > 0 : test_x + win_w < (signed) screen->getWidth()) && | ||
438 | ! placed) { | ||
439 | test_y = screen->getBorderWidth() + screen->getEdgeSnapThreshold(); | ||
440 | if (screen->getColPlacementDirection() == BScreen::BottomTop) | ||
441 | test_y = screen->getHeight() - win_h - test_y; | ||
442 | |||
443 | while (((screen->getColPlacementDirection() == BScreen::BottomTop) ? | ||
444 | test_y > 0 : test_y + win_h < (signed) screen->getHeight()) && | ||
445 | ! placed) { | ||
446 | placed = True; | ||
447 | |||
448 | it.reset(); | ||
449 | for (; it.current() && placed; it++) { | ||
450 | curr_w = it.current()->getWidth() + screen->getBorderWidth2x() + | ||
451 | screen->getBorderWidth2x(); | ||
452 | curr_h = | ||
453 | ((it.current()->isShaded()) ? it.current()->getTitleHeight() : | ||
454 | it.current()->getHeight()) + | ||
455 | screen->getBorderWidth2x() + screen->getBorderWidth2x(); | ||
456 | |||
457 | if (it.current()->getXFrame() < test_x + win_w && | ||
458 | it.current()->getXFrame() + curr_w > test_x && | ||
459 | it.current()->getYFrame() < test_y + win_h && | ||
460 | it.current()->getYFrame() + curr_h > test_y) | ||
461 | placed = False; | ||
462 | } | ||
463 | |||
464 | if ((toolbar_x < test_x + win_w && | ||
465 | toolbar_x + toolbar_w > test_x && | ||
466 | toolbar_y < test_y + win_h && | ||
467 | toolbar_y + toolbar_h > test_y) | ||
468 | #ifdef SLIT | ||
469 | || | ||
470 | (slit_x < test_x + win_w && | ||
471 | slit_x + slit_w > test_x && | ||
472 | slit_y < test_y + win_h && | ||
473 | slit_y + slit_h > test_y) | ||
474 | #endif // SLIT | ||
475 | ) | ||
476 | placed = False; | ||
477 | |||
478 | if (placed) { | ||
479 | place_x = test_x; | ||
480 | place_y = test_y; | ||
481 | |||
482 | break; | ||
483 | } | ||
484 | |||
485 | test_y += change_y; | ||
486 | } | ||
487 | |||
488 | test_x += change_x; | ||
489 | } | ||
490 | |||
491 | break; } | ||
492 | } | ||
493 | |||
494 | if (! placed) { | ||
495 | if (((unsigned) cascade_x > (screen->getWidth() / 2)) || | ||
496 | ((unsigned) cascade_y > (screen->getHeight() / 2))) | ||
497 | cascade_x = cascade_y = 32; | ||
498 | |||
499 | place_x = cascade_x; | ||
500 | place_y = cascade_y; | ||
501 | |||
502 | cascade_x += win->getTitleHeight(); | ||
503 | cascade_y += win->getTitleHeight(); | ||
504 | } | ||
505 | |||
506 | if (place_x + win_w > (signed) screen->getWidth()) | ||
507 | place_x = (((signed) screen->getWidth()) - win_w) / 2; | ||
508 | if (place_y + win_h > (signed) screen->getHeight()) | ||
509 | place_y = (((signed) screen->getHeight()) - win_h) / 2; | ||
510 | |||
511 | win->configure(place_x, place_y, win->getWidth(), win->getHeight()); | ||
512 | } | ||