1 // pager.cxx.h for bbpager - an pager tool for Blackbox.
2 //
3 // Copyright (c) 1998-2004 by John Kennis, jkennis@chello.nl
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //
19 // (See the included file COPYING / GPL-2.0)
20 //
21
22 #include "pager.h"
23
24 extern "C" {
25 #include <X11/cursorfont.h>
26 }
27
28 #include <iostream>
29
30 using std::cout;
31 using std::endl;
32
PagerWindow(ToolWindow * toolwindow,Window _window)33 PagerWindow::PagerWindow(ToolWindow *toolwindow, Window _window):
34 bt::EventHandler(), bbtool(toolwindow), ewmh(toolwindow->ewmh())
35 {
36 pwin = 0;
37 win = _window;
38 ewmh->readWMDesktop(_window, desktop_nr);
39 display = bbtool->XDisplay();
40 screen = bbtool->getCurrentScreen();
41 marked = true;
42 focused = false;
43 hidden = false;
44 iconic = false;
45 sticky = false;
46 skip = false;
47 shaded = false;
48 pwin = NULL;
49 number_of_desktops = 0;
50 XSelectInput(display, win, PropertyChangeMask|StructureNotifyMask);
51 bbtool->insertEventHandler(win, this);
52
53 //get state of window
54 bt::EWMH::AtomList states;
55 bt::EWMH::AtomList::const_iterator it;
56
57 ewmh->readWMState(win, states);
58 for (it = states.begin(); it != states.end(); it++)
59 {
60 if ((*it) == ewmh->wmStateShaded())
61 {
62 shaded = true; // window resized by configureNotify ?
63 }
64 // handled by wmDesktop !
65 // else if ((*it) == ewmh->wmStateSticky()) {
66 // }
67 else if ((*it) == ewmh->wmStateSkipPager())
68 {
69 skip = true;
70 }
71 else if ((*it) == ewmh->wmStateHidden())
72 {
73 hidden = true;
74 }
75 }
76 if (bbtool->wminterface->isIconicState(win))
77 {
78 iconic = true;
79 }
80 buildWindow(false);
81 }
82
~PagerWindow(void)83 PagerWindow::~PagerWindow(void)
84 {
85 unsigned int i;
86 bbtool->removeEventHandler(win);
87 for (i = 0; i < number_of_desktops; i++)
88 {
89 bbtool->removeEventHandler(pwin[i]) ;
90 XDestroyWindow(display, pwin[i]);
91 }
92 delete [] pwin;
93 if (pixmap) bt::PixmapCache::release(pixmap);
94 if (pixmap_focused && bbtool->getResource()->getFocusStyle() == texture)
95 {
96 bt::PixmapCache::release(pixmap_focused);
97 }
98 }
99
window(int nr)100 Window PagerWindow::window(int nr)
101 {
102 if (static_cast<unsigned int>(nr) >= number_of_desktops)
103 {
104 return 0;
105 }
106 return pwin[nr];
107 }
108
window(void)109 Window PagerWindow::window(void)
110 {
111 Window win;
112 if (!sticky) {
113 win = pwin[0];
114 } else {
115 int nr = bbtool->getCurrentDesktopNr();
116 win = pwin[nr];
117 }
118 return win;
119 }
120
raise(void)121 void PagerWindow::raise(void)
122 {
123 unsigned int i;
124 for (i = 0; i < number_of_desktops; i++)
125 {
126 XRaiseWindow(display, pwin[i]);
127 }
128 }
129
lower(void)130 void PagerWindow::lower(void)
131 {
132 unsigned int i;
133 for (i = 0; i < number_of_desktops; i++)
134 {
135 XLowerWindow(display, pwin[i]);
136 }
137 }
138
139
calcGeometry()140 void PagerWindow::calcGeometry()
141 {
142 // Find the geometry of the original window that we're
143 // representing in the pager.
144 initWindowGeometry();
145
146 // Find the scaling factors necessary to scale the
147 // original window down to our pager window.
148 double xdiv =
149 static_cast<double>(bbtool->getResource()->desktopSize.width) /
150 bbtool->getCurrentScreenInfo()->width();
151 double ydiv =
152 static_cast<double>(bbtool->getResource()->desktopSize.height) /
153 bbtool->getCurrentScreenInfo()->height();
154
155 // Find the position of the pager window by scaling the
156 // original window position.
157 pager_x = (int)(window_x * xdiv);
158 pager_y = (int)(window_y * ydiv);
159
160 // Set the unadjusted size of the pager window
161 // by scaling the original window size.
162 pager_unfocus_width = (unsigned int)(window_width * xdiv);
163 pager_unfocus_height = (unsigned int)(window_height * ydiv);
164 pager_focus_width = (unsigned int)(window_width * xdiv);
165 pager_focus_height = (unsigned int)(window_height * ydiv);
166
167 // Because of the following:
168 //
169 // 1) we support different border widths for focused and unfocused windows
170 // 2) an X window's width property does not include its border width
171 // 3) we don't want our pager window's total width or height to change as
172 // its focus changes
173 //
174 // We must adjust the width and height property of the pager window by subtracting
175 // out the appropriate border width.
176 //
177 pager_unfocus_width -= 2 * bbtool->getResource()->pagerwin.inactiveWidth;
178 pager_unfocus_height -= 2 * bbtool->getResource()->pagerwin.inactiveWidth;
179 pager_focus_width -= 2 * bbtool->getResource()->pagerwin.activeWidth;
180 pager_focus_height -= 2 * bbtool->getResource()->pagerwin.activeWidth;
181
182 // Reduce the pager window's height if it's shaded.
183 if (shaded)
184 {
185 pager_unfocus_height = static_cast<unsigned int>(pager_unfocus_height *
186 ydiv);
187 pager_focus_height = static_cast<unsigned int>(pager_focus_height *
188 ydiv);
189 }
190
191 // Our adjustments may have created negative or zero width and height properties,
192 // so replace these with saner values.
193 if (pager_unfocus_width <= 0)
194 {
195 pager_unfocus_width = 1;
196 }
197 if (pager_unfocus_height <= 0)
198 {
199 pager_unfocus_height = 1;
200 }
201 if (pager_focus_width <= 0)
202 {
203 pager_focus_width = 1;
204 }
205 if (pager_focus_height <= 0)
206 {
207 pager_focus_height = 1;
208 }
209 }
210
buildWindow(bool reconfigure)211 void PagerWindow::buildWindow(bool reconfigure)
212 {
213 // if (skip) return; // don't build window if state skipPagerWindow is set.
214 calcGeometry();
215
216 if (desktop_nr == static_cast<unsigned int>(-1)) // on all desktops
217 {
218 sticky = true;
219 }
220 pixmap = bt::PixmapCache::find(screen,
221 bbtool->getResource()->pagerwin.texture,
222 pager_unfocus_width,
223 pager_unfocus_height);
224 if (bbtool->getResource()->getFocusStyle()==texture)
225 {
226 pixmap_focused = bt::PixmapCache::find(screen,
227 bbtool->getResource()->pagerwin.focusedTexture,
228 pager_focus_width,
229 pager_focus_height);
230 }
231 unsigned int i;
232 if (!sticky)
233 {
234 if (number_of_desktops != 1)
235 {
236 // Don't destroy windows on desktops > actual desktops,
237 // these windows are/will be detroyed by destroying desktop window.
238 for (i = 0;
239 i < number_of_desktops &&
240 i < static_cast<unsigned int>(bbtool->getNumberOfDesktops());
241 i++)
242 {
243 XDestroyWindow(display, pwin[i]);
244 }
245 number_of_desktops = 1;
246 delete [] pwin;
247 pwin = new Window[number_of_desktops];
248 reconfigure = false; // rebuild windows
249 }
250 buildPagerWindow(reconfigure, desktop_nr);
251 }
252 else
253 {
254 if (number_of_desktops !=
255 static_cast<unsigned int>(bbtool->getNumberOfDesktops()))
256 {
257 // Don't destroy windows on desktops > actual desktops,
258 // these windows are/will be detroyed by destroying desktop window.
259 for (i = 0;
260 i < number_of_desktops &&
261 i < static_cast<unsigned int>(bbtool->getNumberOfDesktops());
262 i++)
263 {
264 XDestroyWindow(display, pwin[i]);
265 }
266 number_of_desktops = bbtool->getNumberOfDesktops();
267 delete [] pwin;
268 pwin = new Window[number_of_desktops];
269 reconfigure = false;
270 }
271 for (i = 0; i < number_of_desktops; i++)
272 {
273 buildPagerWindow(reconfigure, i);
274 }
275 }
276
277 redraw();
278 }
279
showWindow()280 void PagerWindow::showWindow()
281 {
282 unsigned int i;
283 for (i = 0; i < number_of_desktops; i++)
284 {
285 XMapWindow(display, pwin[i]);
286 }
287 }
288
hideWindow()289 void PagerWindow::hideWindow()
290 {
291 unsigned int i;
292 for (i = 0; i < number_of_desktops; i++)
293 {
294 XUnmapWindow(display, pwin[i]);
295 }
296 }
297
destroyWindow()298 void PagerWindow::destroyWindow()
299 {
300 unsigned int i;
301 for (i = 0; i < number_of_desktops; i++)
302 {
303 XDestroyWindow(display, pwin[i]);
304 }
305 }
306
buildPagerWindow(bool reconfigure,unsigned int nr)307 void PagerWindow::buildPagerWindow(bool reconfigure, unsigned int nr)
308 {
309 unsigned long create_mask = CWBackPixmap | CWEventMask ;
310 XSetWindowAttributes attrib;
311
312 attrib.background_pixmap = ParentRelative;
313 attrib.event_mask = ExposureMask;
314
315 m_pDesktop = bbtool->findDesktopWindow(nr);
316 if (!sticky) nr = 0;
317 if (m_pDesktop == NULL) //not on existing window
318 {
319 return;
320 }
321
322 unsigned int pager_width =
323 ( focused ? pager_focus_width : pager_unfocus_width );
324 unsigned int pager_height =
325 ( focused ? pager_focus_height : pager_unfocus_height );
326
327 if (!reconfigure)
328 {
329 pwin[nr] = XCreateWindow(display, m_pDesktop->window(),
330 pager_x, pager_y, pager_width, pager_height,
331 0, bbtool->getCurrentScreenInfo()->depth(),
332 InputOutput, bbtool->getCurrentScreenInfo()->visual(),
333 create_mask, &attrib);
334 bbtool->insertEventHandler(pwin[nr], this);
335 }
336 else
337 {
338 XMoveResizeWindow(display,
339 pwin[nr],
340 pager_x,
341 pager_y,
342 pager_width,
343 pager_height);
344 }
345
346
347 // redraw();
348
349 if (!hidden /*&& !iconic*/ && !skip)
350 {
351 XMapWindow(display, pwin[nr]);
352 }
353
354 XClearWindow(display, pwin[nr]);
355 }
356
propertyNotifyEvent(const XPropertyEvent * const event)357 void PagerWindow::propertyNotifyEvent(const XPropertyEvent * const event)
358 {
359 if (event->atom == ewmh->wmDesktop())
360 {
361 //unsigned int desktop_nr;
362 ewmh->readWMDesktop(event->window, desktop_nr);
363 if (desktop_nr == static_cast<unsigned int>(-1))
364 {
365 if (!sticky)
366 {
367 sticky = true;
368 buildWindow(false); // rebuild windows,
369 // to appear on all desktops
370 }
371 //else ignore, cannot move to desktop we are already on.
372 }
373 else
374 {
375 if (sticky)
376 {
377 sticky = false;
378 buildWindow(false); // rebuild windows,
379 // to appear on only one desktop
380 }
381 else
382 {
383 bbtool->moveWinToDesktop(this, desktop_nr);
384 }
385 }
386 }
387 else if (event->atom == ewmh->wmState())
388 {
389 bt::EWMH::AtomList states;
390 bt::EWMH::AtomList::const_iterator it;
391 bool skip_state = false;
392 bool shaded_state = false;
393 bool hidden_state = false;
394 ewmh->readWMState(event->window, states);
395 for (it = states.begin(); it != states.end(); it++)
396 {
397 if ((*it) == ewmh->wmStateShaded())
398 {
399 shaded_state = true;
400 }
401 // handled by wmDesktop !
402 // if ((*it) == ewmh->wmStateSticky()) {
403 // }
404 if ((*it) == ewmh->wmStateSkipPager())
405 {
406 skip_state = true;
407 }
408 if ((*it) == ewmh->wmStateHidden())
409 {
410 hidden_state = true;
411 }
412 }
413 if (shaded_state)
414 {
415 if (!shaded)
416 {
417 shaded = true;
418 buildWindow(true);
419 }
420 }
421 else
422 {
423 if (shaded)
424 {
425 shaded = false;
426 buildWindow(true);
427 }
428 }
429 if (skip_state)
430 {
431 if (!skip)
432 {
433 skip = true;
434 hideWindow();
435 }
436 }
437 else
438 {
439 if (skip)
440 {
441 skip = false;
442 showWindow();
443 }
444 }
445 if (hidden_state)
446 {
447 if (!hidden)
448 {
449 hidden = true;
450 hideWindow();
451 }
452 }
453 else
454 {
455 if (hidden)
456 {
457 hidden = false;
458 showWindow();
459 }
460 }
461 // check out state.
462 }
463 else
464 {
465 if (event->atom == bbtool->wmStateAtom())
466 {
467 if (bbtool->wminterface->isIconicState(event->window))
468 {
469 if (!iconic)
470 {
471 iconic = true;
472 // hideWindow();
473 }
474 }
475 else
476 {
477 if (iconic)
478 {
479 iconic = false;
480 // showWindow();
481 }
482 }
483 }
484 }
485 }
486
configureNotifyEvent(const XConfigureEvent * const event)487 void PagerWindow::configureNotifyEvent(const XConfigureEvent * const event)
488 {
489 if (pwin)
490 {
491 redraw();
492 }
493 }
494
reconfigure(void)495 void PagerWindow::reconfigure(void)
496 {
497 buildWindow(true);
498 }
499
initWindowGeometry(void)500 int PagerWindow::initWindowGeometry(void)
501 {
502 unsigned int border_width, depth;
503 Window root_return, child_return;
504 int status;
505
506 status = XGetGeometry(display, win, &root_return, &window_x,
507 &window_y, &window_width, &window_height,
508 &border_width, &depth);
509 if (status)
510 {
511 XTranslateCoordinates(display, win, root_return, window_x,
512 window_y, &window_x, &window_y, &child_return);
513 return 1;
514 }
515 return 0;
516 }
517
setFocus(void)518 void PagerWindow::setFocus(void)
519 {
520 focused = true;
521 redraw();
522 }
523
clearFocus(void)524 void PagerWindow::clearFocus(void)
525 {
526 focused = false;
527 redraw();
528 }
529
getTexture(void)530 bt::Texture PagerWindow::getTexture(void)
531 {
532 return bbtool->getResource()->pagerwin.texture;
533 }
534
getFocusedTexture(void)535 bt::Texture PagerWindow::getFocusedTexture(void)
536 {
537 return bbtool->getResource()->pagerwin.focusedTexture;
538 }
539
redraw(void)540 void PagerWindow::redraw(void)
541 {
542 calcGeometry();
543
544 bt::Rect u(0, 0, width(), height());
545
546 pixmap = bt::PixmapCache::find(screen,
547 bbtool->getResource()->pagerwin.texture,
548 pager_unfocus_width,
549 pager_unfocus_height);
550 if (bbtool->getResource()->getFocusStyle()==texture)
551 {
552 pixmap_focused = bt::PixmapCache::find(screen,
553 bbtool->getResource()->pagerwin.focusedTexture,
554 pager_focus_width,
555 pager_focus_height);
556 }
557
558
559 unsigned int i;
560 for (i = 0; i < number_of_desktops; i++) // number_of_desktops=1
561 // for non-sticky windows
562 {
563 if (sticky)
564 {
565 m_pDesktop = bbtool->findDesktopWindow(i);
566 }
567 else
568 {
569 m_pDesktop = bbtool->findDesktopWindow(desktop_nr);
570 }
571
572 unsigned int pager_width = ( focused ? pager_focus_width :
573 pager_unfocus_width );
574 unsigned int pager_height = ( focused ? pager_focus_height :
575 pager_unfocus_height );
576
577 XMoveResizeWindow(display,
578 pwin[i],
579 pager_x,
580 pager_y,
581 pager_width,
582 pager_height);
583
584
585 if (focused)
586 {
587 XSetWindowBorderWidth(display,
588 pwin[i],
589 bbtool->getResource()->pagerwin.activeWidth);
590 XSetWindowBorder(display,
591 pwin[i],
592 bbtool->getResource()->pagerwin.activeColor.pixel(screen));
593 }
594 else
595 {
596 XSetWindowBorderWidth(display,
597 pwin[i],
598 bbtool->getResource()->pagerwin.inactiveWidth);
599 XSetWindowBorder(display,
600 pwin[i],
601 bbtool->getResource()->pagerwin.inactiveColor.pixel(screen));
602 }
603
604 if (bbtool->getResource()->getFocusStyle() == texture && focused)
605 {
606 if (pixmap_focused == ParentRelative)
607 {
608 if (m_pDesktop->pixmap() == ParentRelative)
609 {
610 bt::Rect t(-(pager_x + m_pDesktop->desktopX()),
611 -(pager_y + m_pDesktop->desktopY()),
612 bbtool->frameWindow()->width(),
613 bbtool->frameWindow()->height());
614 bt::drawTexture(screen,
615 bbtool->getResource()->frame.texture,
616 pwin[i],
617 t,
618 u,
619 bbtool->frameWindow()->pixmap());
620 }
621 else
622 {
623 bt::Rect t(-pager_x,
624 -pager_y,
625 m_pDesktop->desktopWidth(),
626 m_pDesktop->desktopHeight());
627 bt::drawTexture(screen,
628 bbtool->getResource()->getDesktopFocusStyle() ==
629 texture && m_pDesktop->focused() ?
630 bbtool->getResource()->desktopwin.focusedTexture :
631 bbtool->getResource()->desktopwin.texture,
632 pwin[i],
633 t,
634 u,
635 m_pDesktop->pixmap());
636 }
637 }
638 else
639 {
640
641 bt::drawTexture(screen,
642 getFocusedTexture(),
643 pwin[i],
644 u,
645 u,
646 pixmap_focused);
647 }
648 }
649 else
650 {
651 if (pixmap == ParentRelative)
652 {
653 if (m_pDesktop->pixmap() == ParentRelative)
654 {
655 bt::Rect t(-(pager_x + m_pDesktop->desktopX()),
656 -(pager_y + m_pDesktop->desktopY()),
657 bbtool->frameWindow()->width(),
658 bbtool->frameWindow()->height());
659 bt::drawTexture(screen,
660 bbtool->getResource()->frame.texture,
661 pwin[i],
662 t,
663 u,
664 bbtool->frameWindow()->pixmap());
665 }
666 else
667 {
668 bt::Rect t(-pager_x,
669 -pager_y,
670 m_pDesktop->desktopWidth(),
671 m_pDesktop->desktopHeight());
672 bt::drawTexture(screen,
673 bbtool->getResource()->getDesktopFocusStyle() ==
674 texture && m_pDesktop->focused() ?
675 bbtool->getResource()->desktopwin.focusedTexture :
676 bbtool->getResource()->desktopwin.texture,
677 pwin[i],
678 t,
679 u,
680 m_pDesktop->pixmap());
681 }
682 }
683 else
684 {
685 bt::drawTexture(screen,
686 getTexture(),
687 pwin[i],
688 u,
689 u,
690 pixmap);
691 }
692 }
693
694 }
695 }
696
exposeEvent(const XExposeEvent * const event)697 void PagerWindow::exposeEvent(const XExposeEvent * const event)
698 {
699 redraw();
700 }
701
702