"Fossies" - the Fresh Open Source Software Archive 
Member "bbkeys-0.9.1/src/ScreenHandler.cpp" (22 Dec 2008, 30322 Bytes) of package /linux/privat/old/bbkeys-0.9.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "ScreenHandler.cpp" see the
Fossies "Dox" file reference documentation.
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // -- ScreenHandler.cpp --
3 // Copyright (c) 2001 - 2003 Jason 'vanRijn' Kasper <vR at movingparts dot net>
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 // DEALINGS IN THE SOFTWARE.
22
23 // E_O_H_VR
24
25 #include "../config.h"
26
27 extern "C" {
28 #ifdef HAVE_STDIO_H
29 # include <stdio.h>
30 #endif // HAVE_STDIO_H
31
32 #ifdef HAVE_UNISTD_H
33 # include <sys/types.h>
34 # include <unistd.h>
35 #endif // HAVE_UNISTD_H
36
37 #include <X11/keysym.h>
38 #include <stdlib.h>
39 }
40
41 #include "ScreenHandler.h"
42
43 using std::cout;
44
45 //--------------------------------------------------------
46 // Constructor/Destructor
47 //--------------------------------------------------------
48 ScreenHandler::ScreenHandler (KeyClient * k, unsigned int number)
49 : _managed(true), _screenNumber(number),
50 _screenInfo(k->display().screenInfo(number)),
51 _clients(k->clientsList()), _active(k->activeWindow())
52 {
53 _keyClient = k;
54 _netclient = k->getNetclient();
55 _config = k->getConfig();
56 _display = k->XDisplay();
57 _last_active = _clients.end();
58 _keyGrabber = k->getKeyGrabber();
59 _keybindings = k->getKeybindings();
60 _root = _screenInfo.rootWindow();
61
62 // get our lockmasks from bt::Application
63 k->getLockModifiers(_numlockMask, _scrolllockMask);
64
65 // find a window manager supporting NETWM, waiting for it to load if we must
66 int count = 20; // try 20 times
67 _managed = false;
68 while (! (_keyClient->shuttingDown() || _managed || count <= 0)) {
69 if (! (_managed = findSupportingWM()))
70 sleep(5);
71 --count;
72 }
73
74 if (!_managed) {
75 cout << BBTOOL << ": " << "ScreenHandler: Unable to find a "
76 << "compatible window manager for screen: [" << number << "].\n";
77 return;
78 }
79
80 bt::EWMH::AtomList atoms;
81 if (_netclient->readSupported(_root, atoms)) {
82 cout << BBTOOL << ": " << "ScreenHandler: Supported atoms: [" << atoms.size() << "].\n";
83 } else {
84 cout << BBTOOL << ": " << "ScreenHandler: No supported ewmh hints. Not able to be managed.\n";
85 _managed = false;
86 return;
87 }
88
89 XSelectInput(_display, _root,
90 PropertyChangeMask | KeyPressMask | KeyReleaseMask);
91
92 // add an event handler for our root window
93 k->insertEventHandler(_root, this);
94
95 // get configuration options
96 _honor_modifiers = _config->getBoolValue("honormodifiers", false);
97 _raise_while_cycling = _config->getBoolValue("raisewhilecycling", true);
98 _show_cycle_menu = _config->getBoolValue("showcyclemenu", true);
99 _menu_text_justify = _config->getStringValue("menutextjustify", "left");
100 _workspace_columns = _config->getNumberValue("workspacecolumns", 0);
101 _workspace_rows = _config->getNumberValue("workspacerows", 0);
102 _follow_window_on_send = _config->getBoolValue("followwindowonsend", false);
103 _include_iconified_windows_in_cycle = _config->getBoolValue("includeiconifiedwindowsincycle", true);
104 _debug = _config->getBoolValue("debug", false);
105
106 _cycling = false;
107
108 // our popup window list menu
109 _windowmenu = new WindowlistMenu(this);
110
111 }
112 ScreenHandler::~ScreenHandler ()
113 {
114 _keyClient->removeEventHandler( _root );
115
116 _keyGrabber->ungrabAll(_root);
117
118 if (_managed)
119 XSelectInput(_display, _root, None);
120 }
121
122 void ScreenHandler::initialize()
123 {
124 _keybindings->grabDefaults(this);
125
126 updateActiveDesktop();
127 updateNumDesktops();
128 updateDesktopNames();
129 updateClientList();
130 updateActiveWindow();
131
132 // load graphics resource from config file
133 std::string menuTextJustify =
134 _config->getStringValue("menuTextJustify", "right");
135 std::string menuTitleJustify =
136 _config->getStringValue("menuTitleJustify", "right");
137
138 bt::Resource res(_config->getStringValue("stylefile", DEFAULTSTYLE));
139 res.write("menu.frame.alignment", menuTextJustify.c_str());
140 res.write("menu.title.alignment", menuTitleJustify.c_str());
141
142 bt::MenuStyle::get(_keyClient->getMainApplication(),
143 _screenNumber)->load(res);
144
145
146 }
147
148 bool ScreenHandler::findSupportingWM() {
149
150 if (_debug)
151 cout << endl << BBTOOL << ": " << "ScreenHandler: in findSupportingWM."<< endl;
152
153 Window client, tmp;
154 bool res = false;
155
156 res = _netclient->readSupportingWMCheck(_root, &client);
157 if (!res) {
158 if (_debug)
159 cout << BBTOOL << ": " << "ScreenHandler: first readSupportingWMCheck failed." << endl;
160 return false;
161 }
162
163 if (_debug)
164 cout << BBTOOL << ": " << "ScreenHandler: first readSupportingWMCheck succeeded." << endl;
165
166 res = _netclient->readSupportingWMCheck(client, &tmp);
167 if (!res || client != tmp) {
168 if (_debug)
169 cout << BBTOOL << ": " << "ScreenHandler: second readSupportingWMCheck failed." << endl;
170 return false;
171 }
172
173 if (_debug)
174 cout << BBTOOL << ": " << "ScreenHandler: second readSupportingWMCheck worked." << endl;
175
176 // now try to get the name of the window manager, using utf8 first
177 // and falling back to ansi if that fails
178
179
180 // try ewmh
181 if (! _netclient->getValue(client, _netclient->wmName(),
182 Netclient::utf8, _wm_name)) {
183 if (_debug)
184 cout << BBTOOL << ": " << "ScreenHandler: first try at getting wmName failed." << endl;
185 // try old x stuff
186 _netclient->getValue(client, XA_WM_NAME, Netclient::ansi, _wm_name);
187 }
188
189 if (_wm_name.empty()) {
190 if (_debug)
191 cout << BBTOOL << ": " << "ScreenHandler: couldn't get wm's name. letting it slide this time...." << endl;
192 _wm_name = "beats the heck out of me";
193 }
194
195 cout << BBTOOL << ": " << "ScreenHandler: Found compatible "
196 << "window manager: [" << _wm_name << "] for screen: ["
197 << _screenNumber << "].\n";
198
199 return true;
200
201 }
202
203 bool ScreenHandler::grabKey(const KeyCode keyCode,
204 const int modifierMask) const {
205 return _keyGrabber->grab(keyCode, modifierMask, _root );
206 }
207
208 bool ScreenHandler::ungrabKey(const KeyCode keyCode,
209 const int modifierMask) const {
210 return _keyGrabber->ungrab(keyCode, modifierMask, _root );
211 }
212
213 void ScreenHandler::keyPressEvent (const XKeyEvent * const e)
214 {
215 unsigned int state = e->state;
216
217 // Mask out the lock modifiers unless our user doesn't want this
218 if (! _honor_modifiers) {
219 state= e->state & ~(LockMask|_scrolllockMask|_numlockMask);
220 }
221
222 // first, check to see if we're in the middle of a window cycling
223 // loop-de-loop and we're getting a cancel....
224 if (_cycling && e->keycode == XKeysymToKeycode(_display, XK_Escape)) {
225
226 // we've been told to cancel out of a cycleWindow loop, so we turn
227 // off cycling, ungrab the keyboard, then raise the last-active
228 // window for our user
229 _cycling = false;
230 XUngrabKeyboard(_display, CurrentTime);
231
232 const XWindow * la = lastActiveWindow();
233
234 if (la) la->focus(true);
235
236 return;
237 }
238
239 // if we've made it this far, handle the action....
240 Action *it = _keybindings->getAction(e, state, this);
241
242 if (!it)
243 return;
244
245 if (_debug)
246 cout <<BBTOOL << ": " << "action fired: [" << it->toString() <<"]" <<endl;
247
248
249 switch (it->type()) {
250
251 case Action::chain:
252 // if we're doing a chain, then keytree has done everything for us...
253 // just return
254 return;
255
256 case Action::nextScreen:
257 _keyClient->cycleScreen(_screenNumber, true);
258 return;
259
260 case Action::prevScreen:
261 _keyClient->cycleScreen(_screenNumber, false);
262 return;
263
264 case Action::nextWorkspace:
265 cycleWorkspace(true, it->number() != 0 ? it->number(): 1);
266 return;
267
268 case Action::prevWorkspace:
269 cycleWorkspace(false, it->number() != 0 ? it->number(): 1);
270 return;
271
272 case Action::nextWindow:
273 cycleWindow(state, true, it->number() != 0 ? it->number(): 1);
274 return;
275
276 case Action::prevWindow:
277 cycleWindow(state, false, it->number() != 0 ? it->number(): 1);
278 return;
279
280 case Action::nextWindowOnAllWorkspaces:
281 cycleWindow(state, true, it->number() != 0 ? it->number(): 1, false, true);
282 return;
283
284 case Action::prevWindowOnAllWorkspaces:
285 cycleWindow(state, false, it->number() != 0 ? it->number(): 1, false, true);
286 return;
287
288 case Action::nextWindowOnAllScreens:
289 cycleWindow(state, true, it->number() != 0 ? it->number(): 1, true);
290 return;
291
292 case Action::prevWindowOnAllScreens:
293 cycleWindow(state, false, it->number() != 0 ? it->number(): 1, true);
294 return;
295
296 case Action::nextWindowOfClass:
297 cycleWindow(state, true, it->number() != 0 ? it->number(): 1,
298 false, false, true, it->string());
299 return;
300
301 case Action::prevWindowOfClass:
302 cycleWindow(state, false, it->number() != 0 ? it->number(): 1,
303 false, false, true, it->string());
304 return;
305
306 case Action::nextWindowOfClassOnAllWorkspaces:
307 cycleWindow(state, true, it->number() != 0 ? it->number(): 1,
308 false, true, true, it->string());
309 return;
310
311 case Action::prevWindowOfClassOnAllWorkspaces:
312 cycleWindow(state, false, it->number() != 0 ? it->number(): 1,
313 false, true, true, it->string());
314 return;
315
316 case Action::changeWorkspace:
317 changeWorkspace(it->number());
318 return;
319
320 case Action::upWorkspace:
321 changeWorkspaceVert(-1);
322 return;
323
324 case Action::downWorkspace:
325 changeWorkspaceVert(1);
326 return;
327
328 case Action::leftWorkspace:
329 changeWorkspaceHorz(-1);
330 return;
331
332 case Action::rightWorkspace:
333 changeWorkspaceHorz(1);
334 return;
335
336 case Action::execute:
337 execCommand(it->string());
338 return;
339
340 case Action::showRootMenu:
341 _netclient->sendClientMessage(_root, _netclient->xaOpenboxShowRootMenu(),
342 None);
343 return;
344
345 case Action::showWorkspaceMenu:
346 _netclient->sendClientMessage(_root, _netclient->xaOpenboxShowWorkspaceMenu(),
347 None);
348 return;
349
350 case Action::toggleGrabs: {
351 if (_grabbed) {
352 _keybindings->ungrabDefaults(this);
353 _grabbed = false;
354 } else {
355 _keybindings->grabDefaults(this);
356 _grabbed = true;
357 }
358 return;
359 }
360
361 default:
362 break;
363 }
364
365 // these actions require an active window
366 if (_active != _clients.end()) {
367 XWindow *window = *_active;
368
369 switch (it->type()) {
370 case Action::iconify:
371 window->iconify();
372 return;
373
374 case Action::close:
375 window->close();
376 return;
377
378 case Action::raise:
379 window->raise();
380 return;
381
382 case Action::lower:
383 window->lower();
384 return;
385
386 case Action::sendToWorkspace:
387 window->sendTo(it->number());
388 if (_follow_window_on_send ) {
389 window->focus(true);
390 }
391 return;
392
393 case Action::sendToNextWorkspace:
394 if (_active_desktop == _num_desktops - 1) {
395 window->sendTo(0);
396 } else {
397 window->sendTo(_active_desktop + 1);
398 }
399 if (_follow_window_on_send ) {
400 window->focus(true);
401 }
402 return;
403
404 case Action::sendToPrevWorkspace:
405 if (_active_desktop == 0) {
406 window->sendTo(_num_desktops - 1);
407 } else {
408 window->sendTo(_active_desktop - 1);
409 }
410 if (_follow_window_on_send ) {
411 window->focus(true);
412 }
413 return;
414
415 case Action::toggleOmnipresent:
416 if (window->desktop() == 0xffffffff)
417 window->sendTo(_active_desktop);
418 else
419 window->sendTo(0xffffffff);
420 return;
421
422 case Action::moveWindowUp:
423 window->move(0, -(it->number() != 0 ? it->number(): 1));
424 return;
425
426 case Action::moveWindowDown:
427 window->move(0, it->number() != 0 ? it->number(): 1);
428 return;
429
430 case Action::moveWindowLeft:
431 window->move(-(it->number() != 0 ? it->number(): 1), 0);
432 return;
433
434 case Action::moveWindowRight:
435 window->move(it->number() != 0 ? it->number(): 1,0);
436 return;
437
438 case Action::resizeWindowWidth:
439 window->resizeRel(it->number(), 0);
440 return;
441
442 case Action::resizeWindowHeight:
443 window->resizeRel(0, it->number());
444 return;
445
446 case Action::toggleShade:
447 window->shade(! window->shaded());
448 return;
449
450 case Action::toggleMaximizeHorizontal:
451 window->toggleMaximize(XWindow::Max_Horz);
452 return;
453
454 case Action::toggleMaximizeVertical:
455 window->toggleMaximize(XWindow::Max_Vert);
456 return;
457
458 case Action::toggleMaximizeFull:
459 window->toggleMaximize(XWindow::Max_Full);
460 return;
461
462 case Action::toggleDecorations:
463 window->decorate(! window->decorated());
464 return;
465
466 default:
467 assert(false); // unhandled action type!
468 break;
469 }
470 }
471 }
472
473 void ScreenHandler::keyReleaseEvent (const XKeyEvent * const e)
474 {
475 // the only keyrelease event we care about (for now) is when we do window
476 // cycling and the modifier is released
477 if ( _cycling && nothingIsPressed()) {
478 // all modifiers have been released. ungrab the keyboard, move the
479 // focused window to the top of the Z-order and raise it
480 XUngrabKeyboard(_display, CurrentTime);
481
482 if (_active != _clients.end()) {
483 XWindow *w = *_active;
484 bool e = _last_active == _active;
485 _clients.remove(w);
486 _clients.push_front(w);
487 _active = _clients.begin();
488 if (!e) _last_active = _active;
489 w->raise();
490 }
491
492 _cycling = false;
493 }
494 }
495
496 void ScreenHandler::propertyNotifyEvent(const XPropertyEvent * const e)
497 {
498 if (e->atom == _netclient->numberOfDesktops()) {
499 updateNumDesktops();
500 } else if (e->atom == _netclient->desktopNames()) {
501 updateDesktopNames();
502 } else if (e->atom == _netclient->currentDesktop()) {
503 updateActiveDesktop();
504 } else if (e->atom == _netclient->activeWindow()) {
505 updateActiveWindow();
506 } else if (e->atom == _netclient->clientList()) {
507 updateClientList();
508 }
509 }
510
511 void ScreenHandler::updateNumDesktops()
512 {
513 assert(_managed);
514
515 if (! _netclient->readNumberOfDesktops(_root, & _num_desktops))
516 _num_desktops = 1; // assume that there is at least 1 desktop!
517
518 }
519
520 void ScreenHandler::updateDesktopNames()
521 {
522 assert(_managed);
523
524 if(! _netclient->readDesktopNames(_root, _desktop_names)) {
525 _desktop_names.clear();
526 return;
527 }
528
529 // bt::EWMH::UTF8StringList::const_iterator it = _desktop_names.begin(),
530 // end = _desktop_names.end();
531
532 // for (; it != end; ++it) {
533 // std::cout << BBTOOL << ": " << "name: ->" << *it << "<-\n";
534 // char default_name[80];
535 // sprintf(default_name, "Workspace %u", _id + 1);
536 // the_name = default_name;
537 // }
538
539 }
540
541 bt::ustring ScreenHandler::getDesktopName(unsigned int desktopNbr) const {
542
543 if (0xFFFFFFFF == desktopNbr)
544 return bt::toUnicode("");
545
546 if (desktopNbr > _desktop_names.size() )
547 return bt::toUnicode("error");
548
549 return _desktop_names[desktopNbr];
550
551 }
552
553 void ScreenHandler::updateActiveDesktop()
554 {
555 assert(_managed);
556
557 if (! _netclient->readCurrentDesktop(_root, & _active_desktop))
558 _active_desktop = 0; // there must be at least one desktop, and it must
559 // be the current one
560
561 }
562
563 void ScreenHandler::updateActiveWindow()
564 {
565 assert(_managed);
566
567 Window a = None;
568 _netclient->getValue(_root, _netclient->activeWindow(), XA_WINDOW, a);
569
570 if ( None == a ) {
571 return;
572 }
573
574 WindowList::iterator it, end = _clients.end();
575 for (it = _clients.begin(); it != end; ++it) {
576 if ( (*it)->window() == a) {
577 if ( (*it)->getScreenNumber() != _screenNumber )
578 return;
579 break;
580 }
581 }
582
583 _active = it;
584
585 if (_active != end) {
586 /* if we're not cycling and a window gets focus, add it to the top of the
587 * cycle stack.
588 */
589
590 if ( !_cycling) {
591 XWindow *win = *_active;
592 _clients.remove(win);
593 _clients.push_front(win);
594 _active = _clients.begin();
595
596 _last_active = _active;
597
598 if ( _debug )
599 cout <<BBTOOL << ": " << "active window now: [" << bt::toLocale((*_active)->title()) <<"]" <<endl;
600 }
601
602 }
603
604 }
605
606 void ScreenHandler::updateClientList()
607 {
608
609 assert(_managed);
610
611 WindowList::iterator insert_point = _active;
612 if (insert_point != _clients.end())
613 ++insert_point; // get to the item client the focused client
614
615 // get the client list from the root window
616 Netclient::WindowList rootclients;
617 unsigned long num = (unsigned) -1;
618
619 if ( ! _netclient->readClientList(_root, rootclients) ) {
620 cerr << BBTOOL << ": " << "couldn't get client list from WM.\n";
621 num = 0;
622 } else {
623 num = rootclients.size();
624 }
625
626 WindowList::iterator it;
627 const WindowList::iterator end = _clients.end();
628 unsigned long i;
629
630 for (i = 0; i < num; ++i) {
631 for (it = _clients.begin(); it != end; ++it)
632 if (**it == rootclients[i])
633 break;
634 if (it == end) { // didn't already exist
635 if (careAboutWindow(rootclients[i])) {
636 XWindow * wTmp = new XWindow( rootclients[i], _netclient, _screenInfo , *_keyClient );
637 _clients.insert(insert_point, wTmp);
638 }
639 }
640 }
641
642 // remove clients that no longer exist (that belong to this screen)
643 for (it = _clients.begin(); it != end;) {
644 WindowList::iterator it2 = it;
645 ++it;
646
647 // is on another screen?
648 if ((*it2)->getScreenNumber() != _screenNumber)
649 continue;
650
651 for (i = 0; i < num; ++i)
652 if (**it2 == rootclients[i])
653 break;
654 if (i == num) { // no longer exists
655 // watch for the active and last-active window
656 if (it2 == _active)
657 _active = _clients.end();
658 if (it2 == _last_active)
659 _last_active = _clients.end();
660 delete *it2;
661 _clients.erase(it2);
662 }
663 }
664
665 }
666
667
668 // do we care about this window as a client?
669 bool ScreenHandler::careAboutWindow(Window window) const
670 {
671 assert(_managed);
672
673 Atom type;
674 if (! _netclient->getValue(window, _netclient->wmWindowType(), XA_ATOM,
675 type)) {
676 return True;
677 }
678
679 if (type == _netclient->wmWindowTypeDock() ||
680 type == _netclient->wmWindowTypeMenu() ) {
681 return False;
682 } else {
683 return True;
684 }
685 }
686
687 XWindow * ScreenHandler::findWindow(Window window) const {
688 assert(_managed);
689
690 WindowList::const_iterator it, end = _clients.end();
691 for (it = _clients.begin(); it != end; ++it)
692 if (**it == window)
693 break;
694 if(it == end)
695 return 0;
696 return *it;
697 }
698
699 void ScreenHandler::execCommand(const string &cmd) const {
700 pid_t pid;
701 if ((pid = fork()) == 0) {
702 // disconnect the child from this session and the tty
703 if (setsid() == -1) {
704 cout << BBTOOL << ": " << "warning: could not start a new process group\n";
705 perror("setsid");
706 }
707
708 // make the command run on the correct screen
709 if (putenv(const_cast<char*>(_screenInfo.displayString().c_str()))) {
710 cout << BBTOOL << ": " << "warning: couldn't set environment variable 'DISPLAY'\n";
711 perror("putenv()");
712 }
713 execl("/bin/sh", "sh", "-c", cmd.c_str(), NULL);
714 exit(-1);
715 } else if (pid == -1) {
716 cout << BBTOOL << ": " << ": Could not fork a process for executing a command\n";
717 }
718 }
719
720 WindowList ScreenHandler::getCycleWindowList(unsigned int state, const bool forward,
721 const int increment, const bool allscreens,
722 const bool alldesktops, const bool sameclass,
723 const string &cn)
724 {
725 assert(_managed);
726 assert(increment > 0);
727
728 WindowList theList;
729
730 if (_clients.empty()) return theList;
731
732 string classname(cn);
733 if (sameclass && classname.empty() && _active != _clients.end())
734 classname = (*_active)->appClass();
735
736
737 WindowList::const_iterator it = _clients.begin();
738 const WindowList::const_iterator end = _clients.end();
739
740 for (; it != end; ++it) {
741 XWindow *t = *it;
742
743 // determine if this window is invalid for cycling to
744 if (t->iconic() && !_include_iconified_windows_in_cycle) continue;
745 if (! allscreens && t->getScreenNumber() != _screenNumber) continue;
746 if (! alldesktops && ! (t->desktop() == _active_desktop ||
747 t->desktop() == 0xffffffff)) continue;
748 if (sameclass && ! classname.empty() &&
749 t->appClass() != classname) continue;
750 if (! t->canFocus()) continue;
751 if (t->skipPager()) continue;
752
753 // found a focusable window
754 theList.push_back(t);
755 }
756
757 return theList;
758
759 }
760
761 void ScreenHandler::cycleWindow(unsigned int state, const bool forward,
762 const int increment, const bool allscreens,
763 const bool alldesktops, const bool sameclass,
764 const string &cn)
765 {
766 assert(_managed);
767 assert(increment > 0);
768
769 if (_clients.empty()) {
770 if (_debug)
771 std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: no clients list. can't do anything..." << std::endl;
772 return;
773 }
774
775 // if our user wants the window cycling menu to show (who wouldn't!!
776 // =:) ) and if it's not already showing...
777 if ( _show_cycle_menu && ! _windowmenu->isVisible() ) {
778 if (_debug)
779 std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: menu not visible. loading and showing..." << std::endl;
780
781 _cycling = true;
782 WindowList theList = getCycleWindowList(state, forward, increment,
783 allscreens, alldesktops,
784 sameclass, cn);
785 // can't show the window list if there's not even one window =:)
786 if (theList.size() >= 1)
787 _windowmenu->showCycleMenu(theList);
788
789 return;
790
791 }
792
793 if (_debug)
794 std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: doing non-menu-based cycling..." << std::endl;
795
796 string classname(cn);
797 if (sameclass && classname.empty() && _active != _clients.end())
798 classname = (*_active)->appClass();
799
800 WindowList::const_iterator target = _active,
801 begin = _clients.begin(),
802 end = _clients.end();
803
804 XWindow *t = 0;
805
806 for (int x = 0; x < increment; ++x) {
807 while (1) {
808 if (forward) {
809 if (target == end)
810 target = begin;
811 else
812 ++target;
813 } else {
814 if (target == begin)
815 target = end;
816 else
817 --target;
818 }
819
820 // must be no window to focus
821 if (target == _active) {
822 if (_debug)
823 std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: target == _active..." << std::endl;
824 return;
825 }
826
827 // start back at the beginning of the loop
828 if (target == end)
829 continue;
830
831 // determine if this window is invalid for cycling to
832 t = *target;
833 if (t->iconic() && !_include_iconified_windows_in_cycle) continue;
834 if (! allscreens && t->getScreenNumber() != _screenNumber) continue;
835 if (! alldesktops && ! (t->desktop() == _active_desktop ||
836 t->desktop() == 0xffffffff)) continue;
837 if (sameclass && ! classname.empty() &&
838 t->appClass() != classname) continue;
839 if (! t->canFocus()) continue;
840 if (t->skipPager()) continue;
841
842 // found a good window so break out of the while, and perhaps continue
843 // with the for loop
844 break;
845 }
846 }
847
848 if (_debug)
849 std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: dealing with window: [" << bt::toLocale(t->title()) << "]..." << std::endl;
850 // phew. we found the window, so focus it.
851 if ( state) {
852 if (!_cycling) {
853 if (_debug)
854 std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: not cycling. grabbing keyboard..." << std::endl;
855 // grab keyboard so we can intercept KeyReleases from it
856 XGrabKeyboard(_display, _root, True, GrabModeAsync,
857 GrabModeAsync, CurrentTime);
858 _cycling = true;
859 }
860 if (_debug)
861 std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: focusing window while cycling..." << std::endl;
862 focusWindow(t);
863
864 } else {
865 if (_debug)
866 std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: done cycling, focusing window now" << std::endl;
867 t->focus();
868 }
869 }
870
871 void ScreenHandler::focusWindow(const XWindow * win) {
872
873 // if the window our little user has selected is on a different
874 // workspace, go there first
875 if ( ! win->isSticky() && (_active_desktop != win->desktop() ) ) {
876 // this turns out to be yucky. if we're not on the same desktop as the
877 // window we're told to focus, just return and don't do anything...
878 // changeWorkspace(win->desktop() );
879 return;
880 }
881
882 // if we're cycling and user wants to raise windows while cycling,
883 // raise the window, else if we're cycling without raising windows,
884 // just set focus on the window, else focus and raise the window
885 if (_cycling) {
886 if (_raise_while_cycling) {
887 win->focus();
888 } else {
889 win->focus(false);
890 }
891 } else {
892 win->focus();
893 }
894
895 }
896
897 void ScreenHandler::cycleWorkspace(const bool forward, const int increment,
898 const bool loop) const {
899 assert(_managed);
900 assert(increment > 0);
901
902 unsigned int destination = _active_desktop;
903
904 for (int x = 0; x < increment; ++x) {
905 if (forward) {
906 if (destination < _num_desktops - 1)
907 ++destination;
908 else if (loop)
909 destination = 0;
910 } else {
911 if (destination > 0)
912 --destination;
913 else if (loop)
914 destination = _num_desktops - 1;
915 }
916 }
917
918 if (destination != _active_desktop)
919 changeWorkspace(destination);
920 }
921
922
923 void ScreenHandler::changeWorkspace(const int num) const {
924 assert(_managed);
925
926 _netclient->sendClientMessage(_root, _netclient->currentDesktop(), _root, num);
927 }
928
929 void ScreenHandler::changeWorkspaceVert(const int num) const {
930 assert(_managed);
931 int width = _workspace_columns;
932 int height = _workspace_rows;
933 int total = (signed)_num_desktops; // starts at 1
934 int n = (signed)_active_desktop; // starts at 0
935 int wnum = 0;
936 bool moveUp = (num < 0);
937
938 // to understand the mathemathics in here, consider the following arrangements:
939
940 // | 0 1 2 columns | 0 1 2
941 // ------------------- ---------
942 // 0 | 0 1 2 0| 0 3 6
943 // 1 | 3 4 5 1| 1 4 7
944 // 2 | 6 7 2| 2 5
945 // rows
946
947 // left: horizontal arrangement, right: vertical
948 // last workspace missing, total number of workspaces = 8
949 // n%width = current column
950 // n%height = current row
951
952
953 if ( width > 0 ) { // width is set -> assume horizontal arrangement
954 // (default if height is given as well)
955
956 if ( moveUp ) { // we go up...
957 if ( n < width ) { // we're in the first row and want to change to the last
958 if ( (total-1)%width < n%width ) // last row is incomplete, our column isn't there
959 wnum = total-1 - (total-1)%width + n%width - width; // go to last but one
960 // I guess, there's a more elegant expression for this...
961 else // our column exists in the last row
962 wnum = total-1 - (total-1)%width + n%width; // go to same column in last row
963 } else wnum = n-width; // else, just go up one row
964
965 } else { // we go down...
966
967 if ( n+width > total-1 ) // next row would be out of range -> we're in the last
968 wnum = n%width; // current column in first row
969 else
970 wnum = n+width; // go down one row
971
972 }
973 } else if ( height > 0 ) { // height is set -> vertical arrangement
974 if ( moveUp ) {
975 if ( n%height==0 ) { // if in first row
976 if ( n + height > total - 1 ) // we're in an incomplete column
977 wnum = total-1;
978 else
979 wnum = n+height-1;
980 }
981 else // current row>1
982 wnum = n-1;
983 } else { // we're on our way down
984 if ( n==total-1 || n%height==height-1 ) // incomplete column or last row
985 wnum = n - n%height ;
986 else
987 wnum = n+1 ;
988 }
989 } else {} // no arrangement given -> do nothing
990 changeWorkspace(wnum);
991 }
992
993 void ScreenHandler::changeWorkspaceHorz(const int num) const {
994 assert(_managed);
995 int width = _workspace_columns;
996 int height = _workspace_rows;
997 int total = (signed)_num_desktops;
998 int n = (signed)_active_desktop;
999 int wnum = 0;
1000 bool moveLeft = (num < 0);
1001
1002 if ( width > 0 ) { // width is set -> assume horizontal arrangement
1003 // (default if height is given as well)
1004
1005 if ( moveLeft ) {
1006 if ( n%width == 0 ) { // if in first col
1007 if ( n + width > total - 1 ) // we're in an incomplete row
1008 wnum = total-1;
1009 else
1010 wnum = n+width-1;
1011 } else wnum = n-1;
1012
1013 } else { // move right
1014 if ( n==total-1 || n%width==width-1 ) // incomplete row or last col
1015 wnum = n - n%width ;
1016 else
1017 wnum = n+1 ;
1018 }
1019
1020 } else if ( height > 0 ) { // height is set -> vertical arrangement
1021 if ( moveLeft ) {
1022 if ( n < height ) { // move first col -> last
1023 if ( (total-1)%height < n%height ) // last col is incomplete
1024 wnum = total-1 - (total-1)%height + n%height - height; // go to last but one
1025 else // our row exists
1026 wnum = total-1 - (total-1)%height + n%height; // go to same row in last col
1027 } else wnum = n-height; // else, just go left one col
1028
1029 } else { // go right
1030 if ( n+height > total-1 ) // we would be out of range
1031 wnum = n%height; // current row in first col
1032 else
1033 wnum = n+height; // go down one row
1034 }
1035 }
1036 changeWorkspace(wnum);
1037 }
1038
1039 bool ScreenHandler::nothingIsPressed(void) const
1040 {
1041 char keys[32];
1042 XQueryKeymap(_display, keys);
1043
1044 for (int i = 0; i < 32; ++i) {
1045 if (keys[i] != 0)
1046 return false;
1047 }
1048
1049 return true;
1050 }
1051
1052 const XWindow *ScreenHandler::lastActiveWindow() const {
1053 if (_last_active != _clients.end())
1054 return *_last_active;
1055
1056 // find a window if one exists
1057 WindowList::const_iterator it, end = _clients.end();
1058 for (it = _clients.begin(); it != end; ++it)
1059 if ((*it)->getScreenNumber() == _screenNumber && ! (*it)->iconic() &&
1060 (*it)->canFocus() &&
1061 ((*it)->desktop() == 0xffffffff ||
1062 (*it)->desktop() == _active_desktop))
1063 return *it;
1064
1065 // no windows on this screen
1066 return 0;
1067 }
1068
1069 void ScreenHandler::p()
1070 {
1071 cout << BBTOOL << ": " << "\nNOW LISTING CLIENTS!!!" << endl;
1072
1073 WindowList::const_iterator it = _clients.begin();
1074 const WindowList::const_iterator end = _clients.end();
1075
1076 for (; it != end; ++it)
1077 cout << BBTOOL << ": " << "desktop: ["
1078 << (*it)->desktop()
1079 << "], window: [" << bt::toLocale((*it)->title()) << "]" << endl;
1080
1081
1082 }
1083
1084