1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Display.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2005 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000, 2002 - 2005
5 //         Bradley T Hughes <bhughes at trolltech.com>
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a
8 // copy of this software and associated documentation files (the "Software"),
9 // to deal in the Software without restriction, including without limitation
10 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 // and/or sell copies of the Software, and to permit persons to whom the
12 // Software is furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 // DEALINGS IN THE SOFTWARE.
24 
25 #include "Display.hh"
26 
27 #include <algorithm>
28 #include <cstdlib>
29 
30 #include <X11/Xutil.h>
31 
32 #include <assert.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 
36 namespace bt {
37 
38   void createBitmapLoader(const Display &display);
39   void destroyBitmapLoader(void);
40 
41   void createColorCache(const Display &display);
42   void destroyColorCache(void);
43 
44 
45   void createFontCache(const Display &display);
46   void destroyFontCache(void);
47 
48 
49   void createPenCache(const Display &display);
50   void destroyPenCache(void);
51 
52 
53   void createPixmapCache(const Display &display);
54   void destroyPixmapCache(void);
55 
56 
57   void destroyColorTables(void);
58 
59 
60 #ifdef    MITSHM
61   void startupShm(const Display &display);
62 #endif // MITSHM
63 
64 } // namespace bt
65 
66 
Display(const char * dpy_name,bool multi_head)67 bt::Display::Display(const char *dpy_name, bool multi_head) {
68   if (!(xdisplay = XOpenDisplay(dpy_name))) {
69     fprintf(stderr, "bt::Display: failed to open display '%s'\n",
70             dpy_name ? dpy_name : "");
71     std::exit(2);
72   }
73 
74 #ifdef DEBUG
75   XSynchronize(xdisplay, True);
76 #endif // DEBUG
77 
78   if (fcntl(XConnectionNumber(xdisplay), F_SETFD, 1) == -1) {
79     fprintf(stderr, "bt::Display: failed to mark connection close-on-exec\n");
80     std::exit(2);
81   }
82 
83   if (!multi_head || ScreenCount(xdisplay) == 1) {
84     screen_info_count = 1;
85     screen_info_list = new bt::ScreenInfo*[screen_info_count];
86     screen_info_list[0] = new bt::ScreenInfo(*this, DefaultScreen(xdisplay));
87   } else {
88     screen_info_count = ScreenCount(xdisplay);
89     screen_info_list = new bt::ScreenInfo*[screen_info_count];
90     for (unsigned int i = 0; i < screen_info_count; ++i)
91       screen_info_list[i] = new bt::ScreenInfo(*this, i);
92   }
93   createBitmapLoader(*this);
94   createColorCache(*this);
95   createFontCache(*this);
96   createPenCache(*this);
97   createPixmapCache(*this);
98 
99 #ifdef    MITSHM
100   startupShm(*this);
101 #endif // MITSHM
102 }
103 
104 
~Display()105 bt::Display::~Display() {
106   destroyColorTables();
107   destroyPixmapCache();
108   destroyPenCache();
109   destroyFontCache();
110   destroyColorCache();
111   destroyBitmapLoader();
112 
113   std::for_each(screen_info_list, screen_info_list + screen_info_count,
114                 bt::PointerAssassin());
115   delete [] screen_info_list;
116 
117   XCloseDisplay(xdisplay);
118 }
119 
120 
screenInfo(unsigned int i) const121 const bt::ScreenInfo &bt::Display::screenInfo(unsigned int i) const {
122   if (screen_info_count == 1)
123     return *(screen_info_list[0]);
124 
125   assert(i < screen_info_count);
126   return *screen_info_list[i];
127 }
128 
129 
ScreenInfo(bt::Display & d,unsigned int num)130 bt::ScreenInfo::ScreenInfo(bt::Display& d, unsigned int num)
131   : _display(d), _screennumber(num)
132 {
133   _rootwindow = RootWindow(_display.XDisplay(), _screennumber);
134 
135   _rect.setSize(WidthOfScreen(ScreenOfDisplay(_display.XDisplay(),
136                                               _screennumber)),
137                 HeightOfScreen(ScreenOfDisplay(_display.XDisplay(),
138                                                _screennumber)));
139 
140   /*
141     If the default depth is at least 8 we will use that,
142     otherwise we try to find the largest TrueColor visual.
143     Preference is given to 24 bit over larger depths if 24 bit is an option.
144   */
145 
146   _depth = DefaultDepth(_display.XDisplay(), _screennumber);
147   _visual = DefaultVisual(_display.XDisplay(), _screennumber);
148   _colormap = DefaultColormap(_display.XDisplay(), _screennumber);
149 
150   if (_depth < 8) {
151     // search for a TrueColor Visual... if we can't find one...
152     // we will use the default visual for the screen
153     XVisualInfo vinfo_template, *vinfo_return;
154     int vinfo_nitems;
155     int best = -1;
156 
157     vinfo_template.screen = _screennumber;
158     vinfo_template.c_class = TrueColor;
159 
160     vinfo_return = XGetVisualInfo(_display.XDisplay(),
161                                   VisualScreenMask | VisualClassMask,
162                                   &vinfo_template, &vinfo_nitems);
163     if (vinfo_return) {
164       int max_depth = 1;
165       for (int i = 0; i < vinfo_nitems; ++i) {
166         if (vinfo_return[i].depth < max_depth ||
167             // prefer 24 bit over 32
168             (max_depth == 24 && vinfo_return[i].depth > 24))
169           continue;
170         max_depth = vinfo_return[i].depth;
171         best = i;
172       }
173       if (max_depth < _depth) best = -1;
174     }
175 
176     if (best != -1) {
177       _depth = vinfo_return[best].depth;
178       _visual = vinfo_return[best].visual;
179       _colormap = XCreateColormap(_display.XDisplay(), _rootwindow,
180                                   _visual, AllocNone);
181     }
182 
183     XFree(vinfo_return);
184   }
185 
186   // get the default display string and strip the screen number
187   std::string default_string = DisplayString(_display.XDisplay());
188   const std::string::size_type pos = default_string.rfind(".");
189   if (pos != std::string::npos)
190     default_string.resize(pos);
191 
192   _displaystring = std::string("DISPLAY=") + default_string + '.' +
193                    bt::itostring(_screennumber);
194 }
195