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