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 "otk/display.hh"
28 static int anotherWMRunning(Display
*display
, XErrorEvent
*) {
29 printf(_("Another window manager already running on display %s.\n"),
30 DisplayString(display
));
39 OBScreen::OBScreen(int screen
, const otk::Configuration
&config
)
43 assert(screen
>= 0); assert(screen
< ScreenCount(otk::OBDisplay::display
));
44 _info
= otk::OBDisplay::screenInfo(screen
);
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
);
53 _managed
= !::running
;
54 if (! _managed
) return; // was unable to manage the screen
56 printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
57 _number
, XVisualIDFromVisual(_info
->visual()), _info
->depth());
59 Openbox::instance
->property()->set(_info
->rootWindow(),
60 otk::OBProperty::openbox_pid
,
61 otk::OBProperty::Atom_Cardinal
,
62 (unsigned long) getpid());
64 // set the mouse cursor for the root window (the default cursor)
65 XDefineCursor(otk::OBDisplay::display
, _info
->rootWindow(),
66 Openbox::instance
->cursors().session
);
68 // initialize the shit that is used for all drawing on the screen
69 _image_control
= new otk::BImageControl(Openbox::instance
->timerManager(),
71 _image_control
->installRootColormap();
72 _root_cmap_installed
= True
;
74 // initialize the screen's style
75 _style
.setImageControl(_image_control
);
79 // Set the netwm atoms for geomtery and viewport
80 unsigned long geometry
[] = { _info
->width(),
82 Openbox::instance
->property()->set(_info
->rootWindow(),
83 otk::OBProperty::net_desktop_geometry
,
84 otk::OBProperty::Atom_Cardinal
,
86 unsigned long viewport
[] = { 0, 0 };
87 Openbox::instance
->property()->set(_info
->rootWindow(),
88 otk::OBProperty::net_desktop_viewport
,
89 otk::OBProperty::Atom_Cardinal
,
92 // these may be further updated if any pre-existing windows are found in
93 // the manageExising() function
94 setClientList(); // initialize the client lists, which will be empty
95 calcArea(); // initialize the available working area
101 if (! _managed
) return;
103 // unmanage all windows
104 while (!clients
.empty())
105 unmanageWindow(clients
.front());
107 delete _image_control
;
111 void OBScreen::manageExisting()
113 unsigned int i
, j
, nchild
;
114 Window r
, p
, *children
;
115 XQueryTree(otk::OBDisplay::display
, _info
->rootWindow(), &r
, &p
,
118 // preen the window list of all icon windows... for better dockapp support
119 for (i
= 0; i
< nchild
; i
++) {
120 if (children
[i
] == None
) continue;
122 XWMHints
*wmhints
= XGetWMHints(otk::OBDisplay::display
,
126 if ((wmhints
->flags
& IconWindowHint
) &&
127 (wmhints
->icon_window
!= children
[i
])) {
128 for (j
= 0; j
< nchild
; j
++) {
129 if (children
[j
] == wmhints
->icon_window
) {
140 // manage shown windows
141 for (i
= 0; i
< nchild
; ++i
) {
142 if (children
[i
] == None
)
145 XWindowAttributes attrib
;
146 if (XGetWindowAttributes(otk::OBDisplay::display
, children
[i
], &attrib
)) {
147 if (attrib
.override_redirect
) continue;
149 if (attrib
.map_state
!= IsUnmapped
) {
150 manageWindow(children
[i
]);
159 //! Adds a window's strut to the screen's list of reserved spaces
160 void OBScreen::addStrut(otk::Strut
*strut
)
162 _struts
.push_back(strut
);
166 //! Removes a window's strut from the screen's list of reserved spaces
167 void OBScreen::removeStrut(otk::Strut
*strut
)
169 _struts
.remove(strut
);
173 void OBScreen::calcArea()
175 otk::Rect old_area
= _area
;
179 // reset to the full areas
180 if (isXineramaActive())
181 xineramaUsableArea = getXineramaAreas();
185 /* these values represent offsets from the screen edge
186 * we look for the biggest offset on each edge and then apply them
188 * do not be confused by the similarity to the names of Rect's members
190 unsigned int current_left
= 0, current_right
= 0, current_top
= 0,
193 StrutList::const_iterator it
= _struts
.begin(), end
= _struts
.end();
195 for(; it
!= end
; ++it
) {
196 otk::Strut
*strut
= *it
;
197 if (strut
->left
> current_left
)
198 current_left
= strut
->left
;
199 if (strut
->top
> current_top
)
200 current_top
= strut
->top
;
201 if (strut
->right
> current_right
)
202 current_right
= strut
->right
;
203 if (strut
->bottom
> current_bottom
)
204 current_bottom
= strut
->bottom
;
207 _area
.setRect(current_left
, current_top
,
208 _info
->width() - (current_left
+ current_right
),
209 _info
->height() - (current_top
+ current_bottom
));
213 if (isXineramaActive()) {
214 // keep each of the ximerama-defined areas inside the strut
215 RectList::iterator xit, xend = xineramaUsableArea.end();
216 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
217 if (xit->x() < usableArea.x()) {
218 xit->setX(usableArea.x());
219 xit->setWidth(xit->width() - usableArea.x());
221 if (xit->y() < usableArea.y()) {
222 xit->setY(usableArea.y());
223 xit->setHeight(xit->height() - usableArea.y());
225 if (xit->x() + xit->width() > usableArea.width())
226 xit->setWidth(usableArea.width() - xit->x());
227 if (xit->y() + xit->height() > usableArea.height())
228 xit->setHeight(usableArea.height() - xit->y());
234 if (old_area
!= _area
)
235 // XXX: re-maximize windows
241 void OBScreen::setClientList()
245 // create an array of the window ids
246 if (clients
.size() > 0) {
249 windows
= new Window
[clients
.size()];
251 ClientList::const_iterator it
= clients
.begin();
252 const ClientList::const_iterator end
= clients
.end();
253 for (; it
!= end
; ++it
, ++win_it
)
254 *win_it
= (*it
)->window();
256 windows
= (Window
*) 0;
258 Openbox::instance
->property()->set(_info
->rootWindow(),
259 otk::OBProperty::net_client_list
,
260 otk::OBProperty::Atom_Window
,
261 windows
, clients
.size());
270 void OBScreen::setStackingList()
272 // The below comment is wrong now hopefully :> but ill keep it here for
275 Get the stacking order from all of the workspaces.
276 We start with the current workspace so that the sticky windows will be
277 in the right order on the current workspace.
280 Openbox::instance->property()->set(_info->getRootWindow(),
281 otk::OBProperty::net_client_list_stacking,
282 otk::OBProperty::Atom_Window,
283 _stacking, _stacking.size());
288 void OBScreen::setWorkArea() {
289 unsigned long area
[] = { _area
.x(), _area
.y(),
290 _area
.width(), _area
.height() };
291 Openbox::instance
->property()->set(_info
->rootWindow(),
292 otk::OBProperty::net_workarea
,
293 otk::OBProperty::Atom_Cardinal
,
296 if (workspacesList.size() > 0) {
297 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
298 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
299 // XXX: this could be different for each workspace
300 const otk::Rect &area = availableArea();
301 dims[(i * 4) + 0] = area.x();
302 dims[(i * 4) + 1] = area.y();
303 dims[(i * 4) + 2] = area.width();
304 dims[(i * 4) + 3] = area.height();
306 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
307 otk::OBProperty::Atom_Cardinal,
308 dims, 4 * workspacesList.size());
311 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
312 otk::OBProperty::Atom_Cardinal, 0, 0);
317 void OBScreen::loadStyle(const otk::Configuration
&config
)
321 // XXX: make stuff redraw!
325 void OBScreen::manageWindow(Window window
)
327 OBClient
*client
= 0;
329 XSetWindowAttributes attrib_set
;
331 // is the window a docking app
332 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
333 if ((wmhint
->flags
& StateHint
) &&
334 wmhint
->initial_state
== WithdrawnState
) {
335 //slit->addClient(w); // XXX: make dock apps work!
342 otk::OBDisplay::grab();
344 // choose the events we want to receive on the CLIENT window
345 attrib_set
.event_mask
= OBClient::event_mask
;
346 attrib_set
.do_not_propagate_mask
= OBClient::no_propagate_mask
;
347 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
348 CWEventMask
|CWDontPropagate
, &attrib_set
);
350 // create the OBClient class, which gets all of the hints on the window
351 client
= new OBClient(_number
, window
);
352 // register for events
353 Openbox::instance
->registerHandler(window
, client
);
354 // add to the wm's map
355 Openbox::instance
->addClient(window
, client
);
357 // we dont want a border on the client
358 client
->toggleClientBorder(false);
360 // specify that if we exit, the window should not be destroyed and should be
361 // reparented back to root automatically
362 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
364 if (!client
->positionRequested()) {
365 // XXX: position the window intelligenty
368 // create the decoration frame for the client window
369 client
->frame
= new OBFrame(client
, &_style
);
371 // add to the wm's map
372 Openbox::instance
->addClient(client
->frame
->window(), client
);
373 Openbox::instance
->addClient(client
->frame
->plate(), client
);
374 Openbox::instance
->addClient(client
->frame
->titlebar(), client
);
375 Openbox::instance
->addClient(client
->frame
->label(), client
);
376 Openbox::instance
->addClient(client
->frame
->button_max(), client
);
377 Openbox::instance
->addClient(client
->frame
->button_iconify(), client
);
378 Openbox::instance
->addClient(client
->frame
->button_stick(), client
);
379 Openbox::instance
->addClient(client
->frame
->button_close(), client
);
380 Openbox::instance
->addClient(client
->frame
->handle(), client
);
381 Openbox::instance
->addClient(client
->frame
->grip_left(), client
);
382 Openbox::instance
->addClient(client
->frame
->grip_right(), client
);
384 // XXX: if on the current desktop..
385 client
->frame
->show();
387 // XXX: handle any requested states such as shaded/maximized
389 otk::OBDisplay::ungrab();
391 // add to the screen's list
392 clients
.push_back(client
);
393 // update the root properties
398 void OBScreen::unmanageWindow(OBClient
*client
)
400 OBFrame
*frame
= client
->frame
;
402 // XXX: pass around focus if this window was focused
404 // remove from the wm's map
405 Openbox::instance
->removeClient(client
->window());
406 Openbox::instance
->removeClient(frame
->window());
407 Openbox::instance
->removeClient(frame
->plate());
408 Openbox::instance
->removeClient(frame
->titlebar());
409 Openbox::instance
->removeClient(frame
->label());
410 Openbox::instance
->removeClient(frame
->button_max());
411 Openbox::instance
->removeClient(frame
->button_iconify());
412 Openbox::instance
->removeClient(frame
->button_stick());
413 Openbox::instance
->removeClient(frame
->button_close());
414 Openbox::instance
->removeClient(frame
->handle());
415 Openbox::instance
->removeClient(frame
->grip_left());
416 Openbox::instance
->removeClient(frame
->grip_right());
417 // unregister for handling events
418 Openbox::instance
->clearHandler(client
->window());
420 // remove the window from our save set
421 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
423 // we dont want events no more
424 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
428 // give the client its border back
429 client
->toggleClientBorder(true);
431 delete client
->frame
;
434 // remove from the screen's list
435 clients
.remove(client
);
438 // update the root properties