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