]> Dogcows Code - chaz/openbox/blob - src/screen.cc
ba058c8fe4029324da52dbe43726a82c18573986
[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 client = new OBClient(_number, window);
353 // register for events
354 Openbox::instance->registerHandler(window, client);
355 // add to the wm's map
356 Openbox::instance->addClient(window, client);
357
358 // we dont want a border on the client
359 client->toggleClientBorder(false);
360
361 // specify that if we exit, the window should not be destroyed and should be
362 // reparented back to root automatically
363 XChangeSaveSet(otk::OBDisplay::display, window, SetModeInsert);
364
365 if (!client->positionRequested()) {
366 // XXX: position the window intelligenty
367 }
368
369 // create the decoration frame for the client window
370 client->frame = new OBFrame(client, &_style);
371
372 // add to the wm's map
373 Openbox::instance->addClient(client->frame->getWindow(), client);
374 Openbox::instance->addClient(client->frame->plate(), client);
375 Openbox::instance->addClient(client->frame->titlebar(), client);
376 Openbox::instance->addClient(client->frame->label(), client);
377 Openbox::instance->addClient(client->frame->button_max(), client);
378 Openbox::instance->addClient(client->frame->button_iconify(), client);
379 Openbox::instance->addClient(client->frame->button_stick(), client);
380 Openbox::instance->addClient(client->frame->button_close(), client);
381 Openbox::instance->addClient(client->frame->handle(), client);
382 Openbox::instance->addClient(client->frame->grip_left(), client);
383 Openbox::instance->addClient(client->frame->grip_right(), client);
384
385 // XXX: if on the current desktop..
386 client->frame->show();
387
388 // XXX: handle any requested states such as shaded/maximized
389
390 otk::OBDisplay::ungrab();
391
392 // add to the screen's list
393 _clients.push_back(client);
394 // update the root properties
395 setClientList();
396 }
397
398
399 void OBScreen::unmanageWindow(OBClient *client)
400 {
401 OBFrame *frame = client->frame;
402
403 // XXX: pass around focus if this window was focused
404
405 // remove from the wm's map
406 Openbox::instance->removeClient(client->window());
407 Openbox::instance->removeClient(frame->getWindow());
408 Openbox::instance->removeClient(frame->plate());
409 Openbox::instance->removeClient(frame->titlebar());
410 Openbox::instance->removeClient(frame->label());
411 Openbox::instance->removeClient(frame->button_max());
412 Openbox::instance->removeClient(frame->button_iconify());
413 Openbox::instance->removeClient(frame->button_stick());
414 Openbox::instance->removeClient(frame->button_close());
415 Openbox::instance->removeClient(frame->handle());
416 Openbox::instance->removeClient(frame->grip_left());
417 Openbox::instance->removeClient(frame->grip_right());
418 // unregister for handling events
419 Openbox::instance->clearHandler(client->window());
420
421 // remove the window from our save set
422 XChangeSaveSet(otk::OBDisplay::display, client->window(), SetModeDelete);
423
424 // we dont want events no more
425 XSelectInput(otk::OBDisplay::display, client->window(), NoEventMask);
426
427 frame->hide();
428
429 // give the client its border back
430 client->toggleClientBorder(true);
431
432 delete client->frame;
433 client->frame = 0;
434
435 // remove from the screen's list
436 _clients.remove(client);
437 delete client;
438
439 // update the root properties
440 setClientList();
441 }
442
443 }
This page took 0.055413 seconds and 4 git commands to generate.