include stdio
[mikachu/openbox.git] / src / screen.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif
6
7 extern "C" {
8 #ifdef    HAVE_STDIO_H
9 #  include <stdio.h>
10 #endif // HAVE_STDIO_H
11
12 #include "gettext.h"
13 #define _(str) gettext(str)
14 }
15
16 #include "screen.hh"
17 #include "client.hh"
18 #include "openbox.hh"
19 #include "otk/display.hh"
20
21 static bool running;
22 static int anotherWMRunning(Display *display, XErrorEvent *) {
23   printf(_("Another window manager already running on display %s.\n"),
24          DisplayString(display));
25   running = true;
26   return -1;
27 }
28
29
30 namespace ob {
31
32
33 OBScreen::OBScreen(int screen)
34   : _number(screen)
35 {
36   assert(screen >= 0); assert(screen < ScreenCount(otk::OBDisplay::display));
37   _info = otk::OBDisplay::screenInfo(screen);
38
39   ::running = false;
40   XErrorHandler old = XSetErrorHandler(::anotherWMRunning);
41   XSelectInput(otk::OBDisplay::display, _info->getRootWindow(),
42                OBScreen::event_mask);
43   XSync(otk::OBDisplay::display, false);
44   XSetErrorHandler(old);
45
46   _managed = !::running;
47   if (! _managed) return; // was unable to manage the screen
48
49   printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
50          _number, XVisualIDFromVisual(_info->getVisual()), _info->getDepth());
51
52 #ifdef    HAVE_GETPID
53   Openbox::instance->property()->set(_info->getRootWindow(),
54                                      otk::OBProperty::openbox_pid,
55                                      otk::OBProperty::Atom_Cardinal,
56                                      (unsigned long) getpid());
57 #endif // HAVE_GETPID
58
59   // set the mouse cursor for the root window (the default cursor)
60   XDefineCursor(otk::OBDisplay::display, _info->getRootWindow(),
61                 Openbox::instance->cursors().session);
62   
63   _image_control = new otk::BImageControl(Openbox::instance->timerManager(),
64                                           _info, true);
65   _image_control->installRootColormap();
66   _root_cmap_installed = True;
67
68   
69   // Set the netwm atoms for geomtery and viewport
70   unsigned long geometry[] = { _size.x(),
71                                _size.y() };
72   Openbox::instance->property()->set(_info->getRootWindow(),
73                                      otk::OBProperty::net_desktop_geometry,
74                                      otk::OBProperty::Atom_Cardinal,
75                                      geometry, 2);
76   unsigned long viewport[] = { 0, 0 };
77   Openbox::instance->property()->set(_info->getRootWindow(),
78                                      otk::OBProperty::net_desktop_viewport,
79                                      otk::OBProperty::Atom_Cardinal,
80                                      viewport, 2);
81
82   // these may be further updated if any pre-existing windows are found in
83   // the manageExising() function
84   setClientList();     // initialize the client lists, which will be empty
85   calcArea();          // initialize the available working area
86
87   manageExisting();
88
89   // XXX: "change to" the first workspace to initialize stuff
90 }
91
92
93 OBScreen::~OBScreen()
94 {
95   if (! _managed) return;
96
97   delete _image_control;
98 }
99
100
101 void OBScreen::manageExisting()
102 {
103   unsigned int i, j, nchild;
104   Window r, p, *children;
105   XQueryTree(otk::OBDisplay::display, _info->getRootWindow(), &r, &p,
106              &children, &nchild);
107
108   // preen the window list of all icon windows... for better dockapp support
109   for (i = 0; i < nchild; i++) {
110     if (children[i] == None) continue;
111
112     XWMHints *wmhints = XGetWMHints(otk::OBDisplay::display,
113                                     children[i]);
114
115     if (wmhints) {
116       if ((wmhints->flags & IconWindowHint) &&
117           (wmhints->icon_window != children[i])) {
118         for (j = 0; j < nchild; j++) {
119           if (children[j] == wmhints->icon_window) {
120             children[j] = None;
121             break;
122           }
123         }
124       }
125
126       XFree(wmhints);
127     }
128   }
129
130   // manage shown windows
131   for (i = 0; i < nchild; ++i) {
132     if (children[i] == None)
133       continue;
134
135     XWindowAttributes attrib;
136     if (XGetWindowAttributes(otk::OBDisplay::display, children[i], &attrib)) {
137       if (attrib.override_redirect) continue;
138
139       if (attrib.map_state != IsUnmapped) {
140         // XXX: manageWindow(children[i]);
141       }
142     }
143   }
144
145   XFree(children);
146 }
147
148
149 //! Adds a window's strut to the screen's list of reserved spaces
150 void OBScreen::addStrut(otk::Strut *strut)
151 {
152   _struts.push_back(strut);
153 }
154
155
156 //! Removes a window's strut from the screen's list of reserved spaces
157 void OBScreen::removeStrut(otk::Strut *strut)
158 {
159   _struts.remove(strut);
160 }
161
162
163 void OBScreen::calcArea()
164 {
165   otk::Rect old_area = _area;
166
167 /*
168 #ifdef    XINERAMA
169   // reset to the full areas
170   if (isXineramaActive())
171     xineramaUsableArea = getXineramaAreas();
172 #endif // XINERAMA
173 */
174   
175   /* these values represent offsets from the screen edge
176    * we look for the biggest offset on each edge and then apply them
177    * all at once
178    * do not be confused by the similarity to the names of Rect's members
179    */
180   unsigned int current_left = 0, current_right = 0, current_top = 0,
181     current_bottom = 0;
182
183   StrutList::const_iterator it = _struts.begin(), end = _struts.end();
184
185   for(; it != end; ++it) {
186     otk::Strut *strut = *it;
187     if (strut->left > current_left)
188       current_left = strut->left;
189     if (strut->top > current_top)
190       current_top = strut->top;
191     if (strut->right > current_right)
192       current_right = strut->right;
193     if (strut->bottom > current_bottom)
194       current_bottom = strut->bottom;
195   }
196
197   _area.setRect(current_left, current_top,
198                 _info->getWidth() - (current_left + current_right),
199                 _info->getHeight() - (current_top + current_bottom));
200
201 /*
202 #ifdef    XINERAMA
203   if (isXineramaActive()) {
204     // keep each of the ximerama-defined areas inside the strut
205     RectList::iterator xit, xend = xineramaUsableArea.end();
206     for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
207       if (xit->x() < usableArea.x()) {
208         xit->setX(usableArea.x());
209         xit->setWidth(xit->width() - usableArea.x());
210       }
211       if (xit->y() < usableArea.y()) {
212         xit->setY(usableArea.y());
213         xit->setHeight(xit->height() - usableArea.y());
214       }
215       if (xit->x() + xit->width() > usableArea.width())
216         xit->setWidth(usableArea.width() - xit->x());
217       if (xit->y() + xit->height() > usableArea.height())
218         xit->setHeight(usableArea.height() - xit->y());
219     }
220   }
221 #endif // XINERAMA
222 */
223   
224   if (old_area != _area)
225     // XXX: re-maximize windows
226
227   setWorkArea();
228 }
229
230
231 void OBScreen::setClientList()
232 {
233   Window *windows;
234
235   // create an array of the window ids
236   if (_clients.size() > 0) {
237     Window *win_it;
238     
239     windows = new Window[_clients.size()];
240     win_it = windows;
241     ClientList::const_iterator it = _clients.begin();
242     const ClientList::const_iterator end = _clients.end();
243     for (; it != end; ++it, ++win_it)
244       *win_it = (*it)->window();
245   } else
246     windows = (Window*) 0;
247
248   Openbox::instance->property()->set(_info->getRootWindow(),
249                                      otk::OBProperty::net_client_list,
250                                      otk::OBProperty::Atom_Window,
251                                      windows, _clients.size());
252
253   if (_clients.size())
254     delete [] windows;
255
256   setStackingList();
257 }
258
259
260 void OBScreen::setStackingList()
261 {
262   // The below comment is wrong now hopefully :> but ill keep it here for
263   // reference anyways
264   /*
265     Get the stacking order from all of the workspaces.
266     We start with the current workspace so that the sticky windows will be
267     in the right order on the current workspace.
268   */
269   /*
270   Openbox::instance->property()->set(_info->getRootWindow(),
271                                      otk::OBProperty::net_client_list_stacking,
272                                      otk::OBProperty::Atom_Window,
273                                      _stacking, _stacking.size());
274   */
275 }
276
277
278 void OBScreen::setWorkArea() {
279   unsigned long area[] = { _area.x(), _area.y(),
280                            _area.width(), _area.height() };
281   Openbox::instance->property()->set(_info->getRootWindow(),
282                                      otk::OBProperty::net_workarea,
283                                      otk::OBProperty::Atom_Cardinal,
284                                      area, 4);
285   /*
286   if (workspacesList.size() > 0) {
287     unsigned long *dims = new unsigned long[4 * workspacesList.size()];
288     for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
289       // XXX: this could be different for each workspace
290       const otk::Rect &area = availableArea();
291       dims[(i * 4) + 0] = area.x();
292       dims[(i * 4) + 1] = area.y();
293       dims[(i * 4) + 2] = area.width();
294       dims[(i * 4) + 3] = area.height();
295     }
296     xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
297                otk::OBProperty::Atom_Cardinal,
298                dims, 4 * workspacesList.size());
299     delete [] dims;
300   } else
301     xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
302                otk::OBProperty::Atom_Cardinal, 0, 0);
303   */
304 }
305
306
307 }