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
);
126 XSync(otk::OBDisplay::display
, False
);
128 XDestroyWindow(otk::OBDisplay::display
, _focuswindow
);
130 // unmanage all windows
131 while (!clients
.empty())
132 unmanageWindow(clients
.front());
134 delete _image_control
;
138 void OBScreen::manageExisting()
140 unsigned int i
, j
, nchild
;
141 Window r
, p
, *children
;
142 XQueryTree(otk::OBDisplay::display
, _info
->rootWindow(), &r
, &p
,
145 // preen the window list of all icon windows... for better dockapp support
146 for (i
= 0; i
< nchild
; i
++) {
147 if (children
[i
] == None
) continue;
149 XWMHints
*wmhints
= XGetWMHints(otk::OBDisplay::display
,
153 if ((wmhints
->flags
& IconWindowHint
) &&
154 (wmhints
->icon_window
!= children
[i
])) {
155 for (j
= 0; j
< nchild
; j
++) {
156 if (children
[j
] == wmhints
->icon_window
) {
167 // manage shown windows
168 for (i
= 0; i
< nchild
; ++i
) {
169 if (children
[i
] == None
)
172 XWindowAttributes attrib
;
173 if (XGetWindowAttributes(otk::OBDisplay::display
, children
[i
], &attrib
)) {
174 if (attrib
.override_redirect
) continue;
176 if (attrib
.map_state
!= IsUnmapped
) {
177 manageWindow(children
[i
]);
186 //! Adds a window's strut to the screen's list of reserved spaces
187 void OBScreen::addStrut(otk::Strut
*strut
)
189 _struts
.push_back(strut
);
193 //! Removes a window's strut from the screen's list of reserved spaces
194 void OBScreen::removeStrut(otk::Strut
*strut
)
196 _struts
.remove(strut
);
200 void OBScreen::calcArea()
202 otk::Rect old_area
= _area
;
206 // reset to the full areas
207 if (isXineramaActive())
208 xineramaUsableArea = getXineramaAreas();
212 /* these values represent offsets from the screen edge
213 * we look for the biggest offset on each edge and then apply them
215 * do not be confused by the similarity to the names of Rect's members
217 unsigned int current_left
= 0, current_right
= 0, current_top
= 0,
220 StrutList::const_iterator it
= _struts
.begin(), end
= _struts
.end();
222 for(; it
!= end
; ++it
) {
223 otk::Strut
*strut
= *it
;
224 if (strut
->left
> current_left
)
225 current_left
= strut
->left
;
226 if (strut
->top
> current_top
)
227 current_top
= strut
->top
;
228 if (strut
->right
> current_right
)
229 current_right
= strut
->right
;
230 if (strut
->bottom
> current_bottom
)
231 current_bottom
= strut
->bottom
;
234 _area
.setRect(current_left
, current_top
,
235 _info
->width() - (current_left
+ current_right
),
236 _info
->height() - (current_top
+ current_bottom
));
240 if (isXineramaActive()) {
241 // keep each of the ximerama-defined areas inside the strut
242 RectList::iterator xit, xend = xineramaUsableArea.end();
243 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
244 if (xit->x() < usableArea.x()) {
245 xit->setX(usableArea.x());
246 xit->setWidth(xit->width() - usableArea.x());
248 if (xit->y() < usableArea.y()) {
249 xit->setY(usableArea.y());
250 xit->setHeight(xit->height() - usableArea.y());
252 if (xit->x() + xit->width() > usableArea.width())
253 xit->setWidth(usableArea.width() - xit->x());
254 if (xit->y() + xit->height() > usableArea.height())
255 xit->setHeight(usableArea.height() - xit->y());
261 if (old_area
!= _area
)
262 // XXX: re-maximize windows
268 void OBScreen::setClientList()
272 // create an array of the window ids
273 if (clients
.size() > 0) {
276 windows
= new Window
[clients
.size()];
278 ClientList::const_iterator it
= clients
.begin();
279 const ClientList::const_iterator end
= clients
.end();
280 for (; it
!= end
; ++it
, ++win_it
)
281 *win_it
= (*it
)->window();
283 windows
= (Window
*) 0;
285 Openbox::instance
->property()->set(_info
->rootWindow(),
286 otk::OBProperty::net_client_list
,
287 otk::OBProperty::Atom_Window
,
288 windows
, clients
.size());
297 void OBScreen::setStackingList()
299 // The below comment is wrong now hopefully :> but ill keep it here for
302 Get the stacking order from all of the workspaces.
303 We start with the current workspace so that the sticky windows will be
304 in the right order on the current workspace.
307 Openbox::instance->property()->set(_info->getRootWindow(),
308 otk::OBProperty::net_client_list_stacking,
309 otk::OBProperty::Atom_Window,
310 _stacking, _stacking.size());
315 void OBScreen::setWorkArea() {
316 unsigned long area
[] = { _area
.x(), _area
.y(),
317 _area
.width(), _area
.height() };
318 Openbox::instance
->property()->set(_info
->rootWindow(),
319 otk::OBProperty::net_workarea
,
320 otk::OBProperty::Atom_Cardinal
,
323 if (workspacesList.size() > 0) {
324 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
325 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
326 // XXX: this could be different for each workspace
327 const otk::Rect &area = availableArea();
328 dims[(i * 4) + 0] = area.x();
329 dims[(i * 4) + 1] = area.y();
330 dims[(i * 4) + 2] = area.width();
331 dims[(i * 4) + 3] = area.height();
333 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
334 otk::OBProperty::Atom_Cardinal,
335 dims, 4 * workspacesList.size());
338 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
339 otk::OBProperty::Atom_Cardinal, 0, 0);
344 void OBScreen::manageWindow(Window window
)
346 OBClient
*client
= 0;
348 XSetWindowAttributes attrib_set
;
350 // is the window a docking app
351 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
352 if ((wmhint
->flags
& StateHint
) &&
353 wmhint
->initial_state
== WithdrawnState
) {
354 //slit->addClient(w); // XXX: make dock apps work!
361 otk::OBDisplay::grab();
363 // choose the events we want to receive on the CLIENT window
364 attrib_set
.event_mask
= OBClient::event_mask
;
365 attrib_set
.do_not_propagate_mask
= OBClient::no_propagate_mask
;
366 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
367 CWEventMask
|CWDontPropagate
, &attrib_set
);
369 // create the OBClient class, which gets all of the hints on the window
370 client
= new OBClient(_number
, window
);
371 // register for events
372 Openbox::instance
->registerHandler(window
, client
);
373 // add to the wm's map
374 Openbox::instance
->addClient(window
, client
);
376 // we dont want a border on the client
377 client
->toggleClientBorder(false);
379 // specify that if we exit, the window should not be destroyed and should be
380 // reparented back to root automatically
381 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
383 if (!client
->positionRequested()) {
384 // XXX: position the window intelligenty
387 // create the decoration frame for the client window
388 client
->frame
= new OBFrame(client
, &_style
);
390 // add to the wm's map
391 Openbox::instance
->addClient(client
->frame
->window(), client
);
392 Openbox::instance
->addClient(client
->frame
->plate(), client
);
393 Openbox::instance
->addClient(client
->frame
->titlebar(), client
);
394 Openbox::instance
->addClient(client
->frame
->label(), client
);
395 Openbox::instance
->addClient(client
->frame
->button_max(), client
);
396 Openbox::instance
->addClient(client
->frame
->button_iconify(), client
);
397 Openbox::instance
->addClient(client
->frame
->button_stick(), client
);
398 Openbox::instance
->addClient(client
->frame
->button_close(), client
);
399 Openbox::instance
->addClient(client
->frame
->handle(), client
);
400 Openbox::instance
->addClient(client
->frame
->grip_left(), client
);
401 Openbox::instance
->addClient(client
->frame
->grip_right(), client
);
403 // XXX: if on the current desktop..
404 client
->frame
->show();
406 // XXX: handle any requested states such as shaded/maximized
408 otk::OBDisplay::ungrab();
410 // add to the screen's list
411 clients
.push_back(client
);
412 // this puts into the stacking order, then raises it
413 _stacking
.push_back(client
);
414 restack(true, client
);
415 // update the root properties
418 Openbox::instance
->bindings()->grabButtons(true, client
);
422 void OBScreen::unmanageWindow(OBClient
*client
)
424 OBFrame
*frame
= client
->frame
;
426 Openbox::instance
->bindings()->grabButtons(false, client
);
428 // XXX: pass around focus if this window was focused
430 // remove from the wm's map
431 Openbox::instance
->removeClient(client
->window());
432 Openbox::instance
->removeClient(frame
->window());
433 Openbox::instance
->removeClient(frame
->plate());
434 Openbox::instance
->removeClient(frame
->titlebar());
435 Openbox::instance
->removeClient(frame
->label());
436 Openbox::instance
->removeClient(frame
->button_max());
437 Openbox::instance
->removeClient(frame
->button_iconify());
438 Openbox::instance
->removeClient(frame
->button_stick());
439 Openbox::instance
->removeClient(frame
->button_close());
440 Openbox::instance
->removeClient(frame
->handle());
441 Openbox::instance
->removeClient(frame
->grip_left());
442 Openbox::instance
->removeClient(frame
->grip_right());
443 // unregister for handling events
444 Openbox::instance
->clearHandler(client
->window());
446 // remove the window from our save set
447 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
449 // we dont want events no more
450 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
454 // give the client its border back
455 client
->toggleClientBorder(true);
457 delete client
->frame
;
460 // remove from the screen's lists
461 _stacking
.remove(client
);
462 clients
.remove(client
);
465 // update the root properties
469 void OBScreen::restack(bool raise
, OBClient
*client
)
471 const int layer
= client
->layer();
472 std::vector
<Window
> wins
;
474 _stacking
.remove(client
);
476 // the stacking list is from highest to lowest
478 ClientList::iterator it
= _stacking
.begin(), end
= _stacking
.end();
479 // insert the windows above this window
480 for (; it
!= end
; ++it
) {
481 if ((*it
)->layer() < layer
|| (raise
&& (*it
)->layer() == layer
))
483 wins
.push_back((*it
)->frame
->window());
486 wins
.push_back(client
->frame
->window());
487 _stacking
.insert(it
, client
);
488 // insert the remaining below this window
489 for (; it
!= end
; ++it
)
490 wins
.push_back((*it
)->frame
->window());
492 XRestackWindows(otk::OBDisplay::display
, &wins
[0], wins
.size());