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