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