1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
10 #endif // HAVE_STDIO_H
13 # include <sys/types.h>
15 #endif // HAVE_UNISTD_H
18 #define _(str) gettext(str)
25 #include "bindings.hh"
27 #include "otk/display.hh"
32 static int anotherWMRunning(Display
*display
, XErrorEvent
*) {
33 printf(_("Another window manager already running on display %s.\n"),
34 DisplayString(display
));
43 OBScreen::OBScreen(int screen
)
47 assert(screen
>= 0); assert(screen
< ScreenCount(otk::OBDisplay::display
));
48 _info
= otk::OBDisplay::screenInfo(screen
);
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
);
57 _managed
= !::running
;
58 if (! _managed
) return; // was unable to manage the screen
60 printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
61 _number
, XVisualIDFromVisual(_info
->visual()), _info
->depth());
63 Openbox::instance
->property()->set(_info
->rootWindow(),
64 otk::OBProperty::openbox_pid
,
65 otk::OBProperty::Atom_Cardinal
,
66 (unsigned long) getpid());
68 // set the mouse cursor for the root window (the default cursor)
69 XDefineCursor(otk::OBDisplay::display
, _info
->rootWindow(),
70 Openbox::instance
->cursors().session
);
72 // initialize the shit that is used for all drawing on the screen
73 _image_control
= new otk::BImageControl(Openbox::instance
->timerManager(),
75 _image_control
->installRootColormap();
76 _root_cmap_installed
= True
;
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
);
93 // Set the netwm atoms for geomtery and viewport
94 unsigned long geometry
[] = { _info
->width(),
96 Openbox::instance
->property()->set(_info
->rootWindow(),
97 otk::OBProperty::net_desktop_geometry
,
98 otk::OBProperty::Atom_Cardinal
,
100 unsigned long viewport
[] = { 0, 0 };
101 Openbox::instance
->property()->set(_info
->rootWindow(),
102 otk::OBProperty::net_desktop_viewport
,
103 otk::OBProperty::Atom_Cardinal
,
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
);
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
121 OBScreen::~OBScreen()
123 if (! _managed
) return;
125 XSelectInput(otk::OBDisplay::display
, _info
->rootWindow(), NoEventMask
);
127 // unmanage all windows
128 while (!clients
.empty())
129 unmanageWindow(clients
.front());
131 XDestroyWindow(otk::OBDisplay::display
, _focuswindow
);
133 delete _image_control
;
137 void OBScreen::manageExisting()
139 unsigned int i
, j
, nchild
;
140 Window r
, p
, *children
;
141 XQueryTree(otk::OBDisplay::display
, _info
->rootWindow(), &r
, &p
,
144 // preen the window list of all icon windows... for better dockapp support
145 for (i
= 0; i
< nchild
; i
++) {
146 if (children
[i
] == None
) continue;
148 XWMHints
*wmhints
= XGetWMHints(otk::OBDisplay::display
,
152 if ((wmhints
->flags
& IconWindowHint
) &&
153 (wmhints
->icon_window
!= children
[i
])) {
154 for (j
= 0; j
< nchild
; j
++) {
155 if (children
[j
] == wmhints
->icon_window
) {
166 // manage shown windows
167 for (i
= 0; i
< nchild
; ++i
) {
168 if (children
[i
] == None
)
171 XWindowAttributes attrib
;
172 if (XGetWindowAttributes(otk::OBDisplay::display
, children
[i
], &attrib
)) {
173 if (attrib
.override_redirect
) continue;
175 if (attrib
.map_state
!= IsUnmapped
) {
176 manageWindow(children
[i
]);
185 //! Adds a window's strut to the screen's list of reserved spaces
186 void OBScreen::addStrut(otk::Strut
*strut
)
188 _struts
.push_back(strut
);
192 //! Removes a window's strut from the screen's list of reserved spaces
193 void OBScreen::removeStrut(otk::Strut
*strut
)
195 _struts
.remove(strut
);
199 void OBScreen::calcArea()
201 otk::Rect old_area
= _area
;
205 // reset to the full areas
206 if (isXineramaActive())
207 xineramaUsableArea = getXineramaAreas();
211 /* these values represent offsets from the screen edge
212 * we look for the biggest offset on each edge and then apply them
214 * do not be confused by the similarity to the names of Rect's members
216 unsigned int current_left
= 0, current_right
= 0, current_top
= 0,
219 StrutList::const_iterator it
= _struts
.begin(), end
= _struts
.end();
221 for(; it
!= end
; ++it
) {
222 otk::Strut
*strut
= *it
;
223 if (strut
->left
> current_left
)
224 current_left
= strut
->left
;
225 if (strut
->top
> current_top
)
226 current_top
= strut
->top
;
227 if (strut
->right
> current_right
)
228 current_right
= strut
->right
;
229 if (strut
->bottom
> current_bottom
)
230 current_bottom
= strut
->bottom
;
233 _area
.setRect(current_left
, current_top
,
234 _info
->width() - (current_left
+ current_right
),
235 _info
->height() - (current_top
+ current_bottom
));
239 if (isXineramaActive()) {
240 // keep each of the ximerama-defined areas inside the strut
241 RectList::iterator xit, xend = xineramaUsableArea.end();
242 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
243 if (xit->x() < usableArea.x()) {
244 xit->setX(usableArea.x());
245 xit->setWidth(xit->width() - usableArea.x());
247 if (xit->y() < usableArea.y()) {
248 xit->setY(usableArea.y());
249 xit->setHeight(xit->height() - usableArea.y());
251 if (xit->x() + xit->width() > usableArea.width())
252 xit->setWidth(usableArea.width() - xit->x());
253 if (xit->y() + xit->height() > usableArea.height())
254 xit->setHeight(usableArea.height() - xit->y());
260 if (old_area
!= _area
)
261 // XXX: re-maximize windows
267 void OBScreen::setClientList()
271 // create an array of the window ids
272 if (clients
.size() > 0) {
275 windows
= new Window
[clients
.size()];
277 ClientList::const_iterator it
= clients
.begin();
278 const ClientList::const_iterator end
= clients
.end();
279 for (; it
!= end
; ++it
, ++win_it
)
280 *win_it
= (*it
)->window();
282 windows
= (Window
*) 0;
284 Openbox::instance
->property()->set(_info
->rootWindow(),
285 otk::OBProperty::net_client_list
,
286 otk::OBProperty::Atom_Window
,
287 windows
, clients
.size());
296 void OBScreen::setStackingList()
298 // The below comment is wrong now hopefully :> but ill keep it here for
301 Get the stacking order from all of the workspaces.
302 We start with the current workspace so that the sticky windows will be
303 in the right order on the current workspace.
306 Openbox::instance->property()->set(_info->getRootWindow(),
307 otk::OBProperty::net_client_list_stacking,
308 otk::OBProperty::Atom_Window,
309 _stacking, _stacking.size());
314 void OBScreen::setWorkArea() {
315 unsigned long area
[] = { _area
.x(), _area
.y(),
316 _area
.width(), _area
.height() };
317 Openbox::instance
->property()->set(_info
->rootWindow(),
318 otk::OBProperty::net_workarea
,
319 otk::OBProperty::Atom_Cardinal
,
322 if (workspacesList.size() > 0) {
323 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
324 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
325 // XXX: this could be different for each workspace
326 const otk::Rect &area = availableArea();
327 dims[(i * 4) + 0] = area.x();
328 dims[(i * 4) + 1] = area.y();
329 dims[(i * 4) + 2] = area.width();
330 dims[(i * 4) + 3] = area.height();
332 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
333 otk::OBProperty::Atom_Cardinal,
334 dims, 4 * workspacesList.size());
337 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
338 otk::OBProperty::Atom_Cardinal, 0, 0);
343 void OBScreen::manageWindow(Window window
)
345 OBClient
*client
= 0;
347 XSetWindowAttributes attrib_set
;
349 // is the window a docking app
350 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
351 if ((wmhint
->flags
& StateHint
) &&
352 wmhint
->initial_state
== WithdrawnState
) {
353 //slit->addClient(w); // XXX: make dock apps work!
360 otk::OBDisplay::grab();
362 // choose the events we want to receive on the CLIENT window
363 attrib_set
.event_mask
= OBClient::event_mask
;
364 attrib_set
.do_not_propagate_mask
= OBClient::no_propagate_mask
;
365 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
366 CWEventMask
|CWDontPropagate
, &attrib_set
);
368 // create the OBClient class, which gets all of the hints on the window
369 client
= new OBClient(_number
, window
);
370 // register for events
371 Openbox::instance
->registerHandler(window
, client
);
372 // add to the wm's map
373 Openbox::instance
->addClient(window
, client
);
375 // we dont want a border on the client
376 client
->toggleClientBorder(false);
378 // specify that if we exit, the window should not be destroyed and should be
379 // reparented back to root automatically
380 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
382 if (!client
->positionRequested()) {
383 // XXX: position the window intelligenty
386 // create the decoration frame for the client window
387 client
->frame
= new OBFrame(client
, &_style
);
389 // add to the wm's map
390 Openbox::instance
->addClient(client
->frame
->window(), client
);
391 Openbox::instance
->addClient(client
->frame
->plate(), client
);
392 Openbox::instance
->addClient(client
->frame
->titlebar(), client
);
393 Openbox::instance
->addClient(client
->frame
->label(), client
);
394 Openbox::instance
->addClient(client
->frame
->button_max(), client
);
395 Openbox::instance
->addClient(client
->frame
->button_iconify(), client
);
396 Openbox::instance
->addClient(client
->frame
->button_stick(), client
);
397 Openbox::instance
->addClient(client
->frame
->button_close(), client
);
398 Openbox::instance
->addClient(client
->frame
->handle(), client
);
399 Openbox::instance
->addClient(client
->frame
->grip_left(), client
);
400 Openbox::instance
->addClient(client
->frame
->grip_right(), client
);
402 // XXX: if on the current desktop..
403 client
->frame
->show();
405 // XXX: handle any requested states such as shaded/maximized
407 otk::OBDisplay::ungrab();
409 // add to the screen's list
410 clients
.push_back(client
);
411 // this puts into the stacking order, then raises it
412 _stacking
.push_back(client
);
413 restack(true, client
);
414 // update the root properties
417 Openbox::instance
->bindings()->grabButtons(true, client
);
421 void OBScreen::unmanageWindow(OBClient
*client
)
423 OBFrame
*frame
= client
->frame
;
425 Openbox::instance
->bindings()->grabButtons(false, client
);
427 // remove from the stacking order
428 _stacking
.remove(client
);
430 // pass around focus if this window was focused XXX do this better!
431 if (Openbox::instance
->focusedClient() == client
) {
432 OBClient
*newfocus
= 0;
433 if (!_stacking
.empty())
434 newfocus
= _stacking
.front();
435 if (! (newfocus
&& newfocus
->focus()))
439 // remove from the wm's map
440 Openbox::instance
->removeClient(client
->window());
441 Openbox::instance
->removeClient(frame
->window());
442 Openbox::instance
->removeClient(frame
->plate());
443 Openbox::instance
->removeClient(frame
->titlebar());
444 Openbox::instance
->removeClient(frame
->label());
445 Openbox::instance
->removeClient(frame
->button_max());
446 Openbox::instance
->removeClient(frame
->button_iconify());
447 Openbox::instance
->removeClient(frame
->button_stick());
448 Openbox::instance
->removeClient(frame
->button_close());
449 Openbox::instance
->removeClient(frame
->handle());
450 Openbox::instance
->removeClient(frame
->grip_left());
451 Openbox::instance
->removeClient(frame
->grip_right());
452 // unregister for handling events
453 Openbox::instance
->clearHandler(client
->window());
455 // remove the window from our save set
456 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
458 // we dont want events no more
459 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
463 // give the client its border back
464 client
->toggleClientBorder(true);
466 delete client
->frame
;
469 // remove from the screen's list
470 clients
.remove(client
);
473 // update the root properties
477 void OBScreen::restack(bool raise
, OBClient
*client
)
479 const int layer
= client
->layer();
480 std::vector
<Window
> wins
;
482 _stacking
.remove(client
);
484 // the stacking list is from highest to lowest
486 ClientList::iterator it
= _stacking
.begin(), end
= _stacking
.end();
487 // insert the windows above this window
488 for (; it
!= end
; ++it
) {
489 if ((*it
)->layer() < layer
|| (raise
&& (*it
)->layer() == layer
))
491 wins
.push_back((*it
)->frame
->window());
494 wins
.push_back(client
->frame
->window());
495 _stacking
.insert(it
, client
);
496 // insert the remaining below this window
497 for (; it
!= end
; ++it
)
498 wins
.push_back((*it
)->frame
->window());
500 XRestackWindows(otk::OBDisplay::display
, &wins
[0], wins
.size());