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