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