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