]> Dogcows Code - chaz/openbox/blob - src/screen.cc
manages windows that exist before running.
[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
97
98 OBScreen::~OBScreen()
99 {
100 if (! _managed) return;
101
102 // unmanage all windows
103 while (!_clients.empty())
104 unmanageWindow(_clients.front());
105
106 delete _image_control;
107 }
108
109
110 void OBScreen::manageExisting()
111 {
112 unsigned int i, j, nchild;
113 Window r, p, *children;
114 XQueryTree(otk::OBDisplay::display, _info->getRootWindow(), &r, &p,
115 &children, &nchild);
116
117 // preen the window list of all icon windows... for better dockapp support
118 for (i = 0; i < nchild; i++) {
119 if (children[i] == None) continue;
120
121 XWMHints *wmhints = XGetWMHints(otk::OBDisplay::display,
122 children[i]);
123
124 if (wmhints) {
125 if ((wmhints->flags & IconWindowHint) &&
126 (wmhints->icon_window != children[i])) {
127 for (j = 0; j < nchild; j++) {
128 if (children[j] == wmhints->icon_window) {
129 children[j] = None;
130 break;
131 }
132 }
133 }
134
135 XFree(wmhints);
136 }
137 }
138
139 // manage shown windows
140 for (i = 0; i < nchild; ++i) {
141 if (children[i] == None)
142 continue;
143
144 XWindowAttributes attrib;
145 if (XGetWindowAttributes(otk::OBDisplay::display, children[i], &attrib)) {
146 if (attrib.override_redirect) continue;
147
148 if (attrib.map_state != IsUnmapped) {
149 manageWindow(children[i]);
150 }
151 }
152 }
153
154 XFree(children);
155 }
156
157
158 //! Adds a window's strut to the screen's list of reserved spaces
159 void OBScreen::addStrut(otk::Strut *strut)
160 {
161 _struts.push_back(strut);
162 }
163
164
165 //! Removes a window's strut from the screen's list of reserved spaces
166 void OBScreen::removeStrut(otk::Strut *strut)
167 {
168 _struts.remove(strut);
169 }
170
171
172 void OBScreen::calcArea()
173 {
174 otk::Rect old_area = _area;
175
176 /*
177 #ifdef XINERAMA
178 // reset to the full areas
179 if (isXineramaActive())
180 xineramaUsableArea = getXineramaAreas();
181 #endif // XINERAMA
182 */
183
184 /* these values represent offsets from the screen edge
185 * we look for the biggest offset on each edge and then apply them
186 * all at once
187 * do not be confused by the similarity to the names of Rect's members
188 */
189 unsigned int current_left = 0, current_right = 0, current_top = 0,
190 current_bottom = 0;
191
192 StrutList::const_iterator it = _struts.begin(), end = _struts.end();
193
194 for(; it != end; ++it) {
195 otk::Strut *strut = *it;
196 if (strut->left > current_left)
197 current_left = strut->left;
198 if (strut->top > current_top)
199 current_top = strut->top;
200 if (strut->right > current_right)
201 current_right = strut->right;
202 if (strut->bottom > current_bottom)
203 current_bottom = strut->bottom;
204 }
205
206 _area.setRect(current_left, current_top,
207 _info->getWidth() - (current_left + current_right),
208 _info->getHeight() - (current_top + current_bottom));
209
210 /*
211 #ifdef XINERAMA
212 if (isXineramaActive()) {
213 // keep each of the ximerama-defined areas inside the strut
214 RectList::iterator xit, xend = xineramaUsableArea.end();
215 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
216 if (xit->x() < usableArea.x()) {
217 xit->setX(usableArea.x());
218 xit->setWidth(xit->width() - usableArea.x());
219 }
220 if (xit->y() < usableArea.y()) {
221 xit->setY(usableArea.y());
222 xit->setHeight(xit->height() - usableArea.y());
223 }
224 if (xit->x() + xit->width() > usableArea.width())
225 xit->setWidth(usableArea.width() - xit->x());
226 if (xit->y() + xit->height() > usableArea.height())
227 xit->setHeight(usableArea.height() - xit->y());
228 }
229 }
230 #endif // XINERAMA
231 */
232
233 if (old_area != _area)
234 // XXX: re-maximize windows
235
236 setWorkArea();
237 }
238
239
240 void OBScreen::setClientList()
241 {
242 Window *windows;
243
244 // create an array of the window ids
245 if (_clients.size() > 0) {
246 Window *win_it;
247
248 windows = new Window[_clients.size()];
249 win_it = windows;
250 ClientList::const_iterator it = _clients.begin();
251 const ClientList::const_iterator end = _clients.end();
252 for (; it != end; ++it, ++win_it)
253 *win_it = (*it)->window();
254 } else
255 windows = (Window*) 0;
256
257 Openbox::instance->property()->set(_info->getRootWindow(),
258 otk::OBProperty::net_client_list,
259 otk::OBProperty::Atom_Window,
260 windows, _clients.size());
261
262 if (_clients.size())
263 delete [] windows;
264
265 setStackingList();
266 }
267
268
269 void OBScreen::setStackingList()
270 {
271 // The below comment is wrong now hopefully :> but ill keep it here for
272 // reference anyways
273 /*
274 Get the stacking order from all of the workspaces.
275 We start with the current workspace so that the sticky windows will be
276 in the right order on the current workspace.
277 */
278 /*
279 Openbox::instance->property()->set(_info->getRootWindow(),
280 otk::OBProperty::net_client_list_stacking,
281 otk::OBProperty::Atom_Window,
282 _stacking, _stacking.size());
283 */
284 }
285
286
287 void OBScreen::setWorkArea() {
288 unsigned long area[] = { _area.x(), _area.y(),
289 _area.width(), _area.height() };
290 Openbox::instance->property()->set(_info->getRootWindow(),
291 otk::OBProperty::net_workarea,
292 otk::OBProperty::Atom_Cardinal,
293 area, 4);
294 /*
295 if (workspacesList.size() > 0) {
296 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
297 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
298 // XXX: this could be different for each workspace
299 const otk::Rect &area = availableArea();
300 dims[(i * 4) + 0] = area.x();
301 dims[(i * 4) + 1] = area.y();
302 dims[(i * 4) + 2] = area.width();
303 dims[(i * 4) + 3] = area.height();
304 }
305 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
306 otk::OBProperty::Atom_Cardinal,
307 dims, 4 * workspacesList.size());
308 delete [] dims;
309 } else
310 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
311 otk::OBProperty::Atom_Cardinal, 0, 0);
312 */
313 }
314
315
316 void OBScreen::loadStyle(const otk::Configuration &config)
317 {
318 _style.load(config);
319
320 // XXX: make stuff redraw!
321 }
322
323
324 void OBScreen::manageWindow(Window window)
325 {
326 OBClient *client = 0;
327 XWMHints *wmhint;
328 XSetWindowAttributes attrib_set;
329
330 // is the window a docking app
331 if ((wmhint = XGetWMHints(otk::OBDisplay::display, window))) {
332 if ((wmhint->flags & StateHint) &&
333 wmhint->initial_state == WithdrawnState) {
334 //slit->addClient(w); // XXX: make dock apps work!
335 XFree(wmhint);
336 return;
337 }
338 XFree(wmhint);
339 }
340
341 otk::OBDisplay::grab();
342
343 // choose the events we want to receive on the CLIENT window
344 attrib_set.event_mask = OBClient::event_mask;
345 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
346 ButtonMotionMask;
347 XChangeWindowAttributes(otk::OBDisplay::display, window,
348 CWEventMask|CWDontPropagate, &attrib_set);
349
350 // create the OBClient class, which gets all of the hints on the window
351 Openbox::instance->addClient(window, client = new OBClient(_number, window));
352
353 // we dont want a border on the client
354 XSetWindowBorderWidth(otk::OBDisplay::display, window, 0);
355
356 // specify that if we exit, the window should not be destroyed and should be
357 // reparented back to root automatically
358 XChangeSaveSet(otk::OBDisplay::display, window, SetModeInsert);
359
360 if (!client->positionRequested()) {
361 // XXX: position the window intelligenty
362 }
363
364 // create the decoration frame for the client window
365 client->frame = new OBFrame(client, &_style);
366
367 // XXX: if on the current desktop..
368 XMapWindow(otk::OBDisplay::display, client->frame->window());
369
370 // XXX: handle any requested states such as shaded/maximized
371
372 otk::OBDisplay::ungrab();
373
374 // add all the client's windows as event handlers for the client
375 Openbox::instance->addClient(window, client);
376 Openbox::instance->addClient(client->frame->window(), client);
377 Openbox::instance->addClient(client->frame->titlebar(), client);
378 Openbox::instance->addClient(client->frame->buttonIconify(), client);
379 Openbox::instance->addClient(client->frame->buttonMax(), client);
380 Openbox::instance->addClient(client->frame->buttonStick(), client);
381 Openbox::instance->addClient(client->frame->buttonClose(), client);
382 Openbox::instance->addClient(client->frame->label(), client);
383 Openbox::instance->addClient(client->frame->handle(), client);
384 Openbox::instance->addClient(client->frame->gripLeft(), client);
385 Openbox::instance->addClient(client->frame->gripRight(), client);
386
387 // add to the screen's list
388 _clients.push_back(client);
389 // update the root properties
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 // remove from the screen's list
430 _clients.remove(client);
431 delete client;
432
433 // update the root properties
434 setClientList();
435 }
436
437 }
This page took 0.057438 seconds and 5 git commands to generate.