summaryrefslogtreecommitdiff
path: root/src/Workspace.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/Workspace.cc')
-rw-r--r--src/Workspace.cc512
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
56Workspace::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
79Workspace::~Workspace(void) {
80 delete stackingList;
81 delete windowList;
82 delete clientmenu;
83
84 if (name)
85 delete [] name;
86}
87
88
89const 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
111const 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
152void Workspace::showAll(void) {
153 LinkedListIterator<FluxboxWindow> it(stackingList);
154 for (; it.current(); it++)
155 it.current()->deiconify(False, False);
156}
157
158
159void 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
173void Workspace::removeAll(void) {
174 LinkedListIterator<FluxboxWindow> it(windowList);
175 for (; it.current(); it++)
176 it.current()->iconify();
177}
178
179
180void 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
220void 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
264void 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
274FluxboxWindow *Workspace::getWindow(int index) {
275 if ((index >= 0) && (index < windowList->count()))
276 return windowList->find(index);
277 else
278 return 0;
279}
280
281
282const int Workspace::getCount(void) {
283 return windowList->count();
284}
285
286
287void Workspace::update(void) {
288 clientmenu->update();
289 screen->getToolbar()->redrawWindowLabel(True);
290}
291
292
293Bool Workspace::isCurrent(void) {
294 return (id == screen->getCurrentWorkspaceID());
295}
296
297
298Bool Workspace::isLastWindow(FluxboxWindow *w) {
299 return (w == windowList->last());
300}
301
302void Workspace::setCurrent(void) {
303 screen->changeWorkspaceID(id);
304}
305
306
307void 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
332void Workspace::shutdown(void) {
333 while (windowList->count()) {
334 windowList->first()->restore();
335 delete windowList->first();
336 }
337}
338
339
340void 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}