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