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