]> Dogcows Code - chaz/openbox/blob - src/screen.cc
add an OBRootWindow class that watches events/properties on root windows
[chaz/openbox] / 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 "frame.hh"
25 #include "otk/display.hh"
26
27 static bool running;
28 static int anotherWMRunning(Display *display, XErrorEvent *) {
29 printf(_("Another window manager already running on display %s.\n"),
30 DisplayString(display));
31 running = true;
32 return -1;
33 }
34
35
36 namespace ob {
37
38
39 OBScreen::OBScreen(int screen, const otk::Configuration &config)
40 : _number(screen),
41 _root(screen)
42 {
43 assert(screen >= 0); assert(screen < ScreenCount(otk::OBDisplay::display));
44 _info = otk::OBDisplay::screenInfo(screen);
45
46 ::running = false;
47 XErrorHandler old = XSetErrorHandler(::anotherWMRunning);
48 XSelectInput(otk::OBDisplay::display, _info->getRootWindow(),
49 OBScreen::event_mask);
50 XSync(otk::OBDisplay::display, false);
51 XSetErrorHandler(old);
52
53 _managed = !::running;
54 if (! _managed) return; // was unable to manage the screen
55
56 printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
57 _number, XVisualIDFromVisual(_info->getVisual()), _info->getDepth());
58
59 Openbox::instance->property()->set(_info->getRootWindow(),
60 otk::OBProperty::openbox_pid,
61 otk::OBProperty::Atom_Cardinal,
62 (unsigned long) getpid());
63
64 // set the mouse cursor for the root window (the default cursor)
65 XDefineCursor(otk::OBDisplay::display, _info->getRootWindow(),
66 Openbox::instance->cursors().session);
67
68 // initialize the shit that is used for all drawing on the screen
69 _image_control = new otk::BImageControl(Openbox::instance->timerManager(),
70 _info, true);
71 _image_control->installRootColormap();
72 _root_cmap_installed = True;
73
74 // initialize the screen's style
75 _style.setImageControl(_image_control);
76 _style.load(config);
77
78
79 // Set the netwm atoms for geomtery and viewport
80 unsigned long geometry[] = { _info->getWidth(),
81 _info->getHeight() };
82 Openbox::instance->property()->set(_info->getRootWindow(),
83 otk::OBProperty::net_desktop_geometry,
84 otk::OBProperty::Atom_Cardinal,
85 geometry, 2);
86 unsigned long viewport[] = { 0, 0 };
87 Openbox::instance->property()->set(_info->getRootWindow(),
88 otk::OBProperty::net_desktop_viewport,
89 otk::OBProperty::Atom_Cardinal,
90 viewport, 2);
91
92 // these may be further updated if any pre-existing windows are found in
93 // the manageExising() function
94 setClientList(); // initialize the client lists, which will be empty
95 calcArea(); // initialize the available working area
96 }
97
98
99 OBScreen::~OBScreen()
100 {
101 if (! _managed) return;
102
103 // unmanage all windows
104 while (!_clients.empty())
105 unmanageWindow(_clients.front());
106
107 delete _image_control;
108 }
109
110
111 void OBScreen::manageExisting()
112 {
113 unsigned int i, j, nchild;
114 Window r, p, *children;
115 XQueryTree(otk::OBDisplay::display, _info->getRootWindow(), &r, &p,
116 &children, &nchild);
117
118 // preen the window list of all icon windows... for better dockapp support
119 for (i = 0; i < nchild; i++) {
120 if (children[i] == None) continue;
121
122 XWMHints *wmhints = XGetWMHints(otk::OBDisplay::display,
123 children[i]);
124
125 if (wmhints) {
126 if ((wmhints->flags & IconWindowHint) &&
127 (wmhints->icon_window != children[i])) {
128 for (j = 0; j < nchild; j++) {
129 if (children[j] == wmhints->icon_window) {
130 children[j] = None;
131 break;
132 }
133 }
134 }
135
136 XFree(wmhints);
137 }
138 }
139
140 // manage shown windows
141 for (i = 0; i < nchild; ++i) {
142 if (children[i] == None)
143 continue;
144
145 XWindowAttributes attrib;
146 if (XGetWindowAttributes(otk::OBDisplay::display, children[i], &attrib)) {
147 if (attrib.override_redirect) continue;
148
149 if (attrib.map_state != IsUnmapped) {
150 manageWindow(children[i]);
151 }
152 }
153 }
154
155 XFree(children);
156 }
157
158
159 //! Adds a window's strut to the screen's list of reserved spaces
160 void OBScreen::addStrut(otk::Strut *strut)
161 {
162 _struts.push_back(strut);
163 }
164
165
166 //! Removes a window's strut from the screen's list of reserved spaces
167 void OBScreen::removeStrut(otk::Strut *strut)
168 {
169 _struts.remove(strut);
170 }
171
172
173 void OBScreen::calcArea()
174 {
175 otk::Rect old_area = _area;
176
177 /*
178 #ifdef XINERAMA
179 // reset to the full areas
180 if (isXineramaActive())
181 xineramaUsableArea = getXineramaAreas();
182 #endif // XINERAMA
183 */
184
185 /* these values represent offsets from the screen edge
186 * we look for the biggest offset on each edge and then apply them
187 * all at once
188 * do not be confused by the similarity to the names of Rect's members
189 */
190 unsigned int current_left = 0, current_right = 0, current_top = 0,
191 current_bottom = 0;
192
193 StrutList::const_iterator it = _struts.begin(), end = _struts.end();
194
195 for(; it != end; ++it) {
196 otk::Strut *strut = *it;
197 if (strut->left > current_left)
198 current_left = strut->left;
199 if (strut->top > current_top)
200 current_top = strut->top;
201 if (strut->right > current_right)
202 current_right = strut->right;
203 if (strut->bottom > current_bottom)
204 current_bottom = strut->bottom;
205 }
206
207 _area.setRect(current_left, current_top,
208 _info->getWidth() - (current_left + current_right),
209 _info->getHeight() - (current_top + current_bottom));
210
211 /*
212 #ifdef XINERAMA
213 if (isXineramaActive()) {
214 // keep each of the ximerama-defined areas inside the strut
215 RectList::iterator xit, xend = xineramaUsableArea.end();
216 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
217 if (xit->x() < usableArea.x()) {
218 xit->setX(usableArea.x());
219 xit->setWidth(xit->width() - usableArea.x());
220 }
221 if (xit->y() < usableArea.y()) {
222 xit->setY(usableArea.y());
223 xit->setHeight(xit->height() - usableArea.y());
224 }
225 if (xit->x() + xit->width() > usableArea.width())
226 xit->setWidth(usableArea.width() - xit->x());
227 if (xit->y() + xit->height() > usableArea.height())
228 xit->setHeight(usableArea.height() - xit->y());
229 }
230 }
231 #endif // XINERAMA
232 */
233
234 if (old_area != _area)
235 // XXX: re-maximize windows
236
237 setWorkArea();
238 }
239
240
241 void OBScreen::setClientList()
242 {
243 Window *windows;
244
245 // create an array of the window ids
246 if (_clients.size() > 0) {
247 Window *win_it;
248
249 windows = new Window[_clients.size()];
250 win_it = windows;
251 ClientList::const_iterator it = _clients.begin();
252 const ClientList::const_iterator end = _clients.end();
253 for (; it != end; ++it, ++win_it)
254 *win_it = (*it)->window();
255 } else
256 windows = (Window*) 0;
257
258 Openbox::instance->property()->set(_info->getRootWindow(),
259 otk::OBProperty::net_client_list,
260 otk::OBProperty::Atom_Window,
261 windows, _clients.size());
262
263 if (_clients.size())
264 delete [] windows;
265
266 setStackingList();
267 }
268
269
270 void OBScreen::setStackingList()
271 {
272 // The below comment is wrong now hopefully :> but ill keep it here for
273 // reference anyways
274 /*
275 Get the stacking order from all of the workspaces.
276 We start with the current workspace so that the sticky windows will be
277 in the right order on the current workspace.
278 */
279 /*
280 Openbox::instance->property()->set(_info->getRootWindow(),
281 otk::OBProperty::net_client_list_stacking,
282 otk::OBProperty::Atom_Window,
283 _stacking, _stacking.size());
284 */
285 }
286
287
288 void OBScreen::setWorkArea() {
289 unsigned long area[] = { _area.x(), _area.y(),
290 _area.width(), _area.height() };
291 Openbox::instance->property()->set(_info->getRootWindow(),
292 otk::OBProperty::net_workarea,
293 otk::OBProperty::Atom_Cardinal,
294 area, 4);
295 /*
296 if (workspacesList.size() > 0) {
297 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
298 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
299 // XXX: this could be different for each workspace
300 const otk::Rect &area = availableArea();
301 dims[(i * 4) + 0] = area.x();
302 dims[(i * 4) + 1] = area.y();
303 dims[(i * 4) + 2] = area.width();
304 dims[(i * 4) + 3] = area.height();
305 }
306 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
307 otk::OBProperty::Atom_Cardinal,
308 dims, 4 * workspacesList.size());
309 delete [] dims;
310 } else
311 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
312 otk::OBProperty::Atom_Cardinal, 0, 0);
313 */
314 }
315
316
317 void OBScreen::loadStyle(const otk::Configuration &config)
318 {
319 _style.load(config);
320
321 // XXX: make stuff redraw!
322 }
323
324
325 void OBScreen::manageWindow(Window window)
326 {
327 OBClient *client = 0;
328 XWMHints *wmhint;
329 XSetWindowAttributes attrib_set;
330
331 // is the window a docking app
332 if ((wmhint = XGetWMHints(otk::OBDisplay::display, window))) {
333 if ((wmhint->flags & StateHint) &&
334 wmhint->initial_state == WithdrawnState) {
335 //slit->addClient(w); // XXX: make dock apps work!
336 XFree(wmhint);
337 return;
338 }
339 XFree(wmhint);
340 }
341
342 otk::OBDisplay::grab();
343
344 // choose the events we want to receive on the CLIENT window
345 attrib_set.event_mask = OBClient::event_mask;
346 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
347 ButtonMotionMask;
348 XChangeWindowAttributes(otk::OBDisplay::display, window,
349 CWEventMask|CWDontPropagate, &attrib_set);
350
351 // create the OBClient class, which gets all of the hints on the window
352 Openbox::instance->addClient(window, client = new OBClient(_number, window));
353
354 // we dont want a border on the client
355 XSetWindowBorderWidth(otk::OBDisplay::display, window, 0);
356
357 // specify that if we exit, the window should not be destroyed and should be
358 // reparented back to root automatically
359 XChangeSaveSet(otk::OBDisplay::display, window, SetModeInsert);
360
361 if (!client->positionRequested()) {
362 // XXX: position the window intelligenty
363 }
364
365 // create the decoration frame for the client window
366 client->frame = new OBFrame(client, &_style);
367
368 // XXX: if on the current desktop..
369 client->frame->show();
370
371 // XXX: handle any requested states such as shaded/maximized
372
373 otk::OBDisplay::ungrab();
374
375 // add to the screen's list
376 _clients.push_back(client);
377 // update the root properties
378 setClientList();
379 }
380
381
382 void OBScreen::unmanageWindow(OBClient *client)
383 {
384 OBFrame *frame = client->frame;
385
386 // XXX: pass around focus if this window was focused
387
388 // remove the window from our save set
389 XChangeSaveSet(otk::OBDisplay::display, client->window(), SetModeDelete);
390
391 // we dont want events no more
392 XSelectInput(otk::OBDisplay::display, client->window(), NoEventMask);
393
394 frame->hide();
395
396 // we dont want a border on the client
397 XSetWindowBorderWidth(otk::OBDisplay::display, client->window(),
398 client->borderWidth());
399
400 delete client->frame;
401 client->frame = 0;
402
403 // remove from the screen's list
404 _clients.remove(client);
405 delete client;
406
407 // update the root properties
408 setClientList();
409 }
410
411 }
This page took 0.056075 seconds and 5 git commands to generate.