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 // create the window which gets focus when no clients get it
93 XSetWindowAttributes attr
;
94 attr
.override_redirect
= true;
95 _focuswindow
= XCreateWindow(otk::OBDisplay::display
, _info
->rootWindow(),
96 -100, -100, 1, 1, 0, 0, InputOnly
,
97 _info
->visual(), CWOverrideRedirect
, &attr
);
98 XMapWindow(otk::OBDisplay::display
, _focuswindow
);
100 // these may be further updated if any pre-existing windows are found in
101 // the manageExising() function
102 setClientList(); // initialize the client lists, which will be empty
103 calcArea(); // initialize the available working area
107 OBScreen::~OBScreen()
109 if (! _managed
) return;
111 // unmanage all windows
112 while (!clients
.empty())
113 unmanageWindow(clients
.front());
115 delete _image_control
;
119 void OBScreen::manageExisting()
121 unsigned int i
, j
, nchild
;
122 Window r
, p
, *children
;
123 XQueryTree(otk::OBDisplay::display
, _info
->rootWindow(), &r
, &p
,
126 // preen the window list of all icon windows... for better dockapp support
127 for (i
= 0; i
< nchild
; i
++) {
128 if (children
[i
] == None
) continue;
130 XWMHints
*wmhints
= XGetWMHints(otk::OBDisplay::display
,
134 if ((wmhints
->flags
& IconWindowHint
) &&
135 (wmhints
->icon_window
!= children
[i
])) {
136 for (j
= 0; j
< nchild
; j
++) {
137 if (children
[j
] == wmhints
->icon_window
) {
148 // manage shown windows
149 for (i
= 0; i
< nchild
; ++i
) {
150 if (children
[i
] == None
)
153 XWindowAttributes attrib
;
154 if (XGetWindowAttributes(otk::OBDisplay::display
, children
[i
], &attrib
)) {
155 if (attrib
.override_redirect
) continue;
157 if (attrib
.map_state
!= IsUnmapped
) {
158 manageWindow(children
[i
]);
167 //! Adds a window's strut to the screen's list of reserved spaces
168 void OBScreen::addStrut(otk::Strut
*strut
)
170 _struts
.push_back(strut
);
174 //! Removes a window's strut from the screen's list of reserved spaces
175 void OBScreen::removeStrut(otk::Strut
*strut
)
177 _struts
.remove(strut
);
181 void OBScreen::calcArea()
183 otk::Rect old_area
= _area
;
187 // reset to the full areas
188 if (isXineramaActive())
189 xineramaUsableArea = getXineramaAreas();
193 /* these values represent offsets from the screen edge
194 * we look for the biggest offset on each edge and then apply them
196 * do not be confused by the similarity to the names of Rect's members
198 unsigned int current_left
= 0, current_right
= 0, current_top
= 0,
201 StrutList::const_iterator it
= _struts
.begin(), end
= _struts
.end();
203 for(; it
!= end
; ++it
) {
204 otk::Strut
*strut
= *it
;
205 if (strut
->left
> current_left
)
206 current_left
= strut
->left
;
207 if (strut
->top
> current_top
)
208 current_top
= strut
->top
;
209 if (strut
->right
> current_right
)
210 current_right
= strut
->right
;
211 if (strut
->bottom
> current_bottom
)
212 current_bottom
= strut
->bottom
;
215 _area
.setRect(current_left
, current_top
,
216 _info
->width() - (current_left
+ current_right
),
217 _info
->height() - (current_top
+ current_bottom
));
221 if (isXineramaActive()) {
222 // keep each of the ximerama-defined areas inside the strut
223 RectList::iterator xit, xend = xineramaUsableArea.end();
224 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
225 if (xit->x() < usableArea.x()) {
226 xit->setX(usableArea.x());
227 xit->setWidth(xit->width() - usableArea.x());
229 if (xit->y() < usableArea.y()) {
230 xit->setY(usableArea.y());
231 xit->setHeight(xit->height() - usableArea.y());
233 if (xit->x() + xit->width() > usableArea.width())
234 xit->setWidth(usableArea.width() - xit->x());
235 if (xit->y() + xit->height() > usableArea.height())
236 xit->setHeight(usableArea.height() - xit->y());
242 if (old_area
!= _area
)
243 // XXX: re-maximize windows
249 void OBScreen::setClientList()
253 // create an array of the window ids
254 if (clients
.size() > 0) {
257 windows
= new Window
[clients
.size()];
259 ClientList::const_iterator it
= clients
.begin();
260 const ClientList::const_iterator end
= clients
.end();
261 for (; it
!= end
; ++it
, ++win_it
)
262 *win_it
= (*it
)->window();
264 windows
= (Window
*) 0;
266 Openbox::instance
->property()->set(_info
->rootWindow(),
267 otk::OBProperty::net_client_list
,
268 otk::OBProperty::Atom_Window
,
269 windows
, clients
.size());
278 void OBScreen::setStackingList()
280 // The below comment is wrong now hopefully :> but ill keep it here for
283 Get the stacking order from all of the workspaces.
284 We start with the current workspace so that the sticky windows will be
285 in the right order on the current workspace.
288 Openbox::instance->property()->set(_info->getRootWindow(),
289 otk::OBProperty::net_client_list_stacking,
290 otk::OBProperty::Atom_Window,
291 _stacking, _stacking.size());
296 void OBScreen::setWorkArea() {
297 unsigned long area
[] = { _area
.x(), _area
.y(),
298 _area
.width(), _area
.height() };
299 Openbox::instance
->property()->set(_info
->rootWindow(),
300 otk::OBProperty::net_workarea
,
301 otk::OBProperty::Atom_Cardinal
,
304 if (workspacesList.size() > 0) {
305 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
306 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
307 // XXX: this could be different for each workspace
308 const otk::Rect &area = availableArea();
309 dims[(i * 4) + 0] = area.x();
310 dims[(i * 4) + 1] = area.y();
311 dims[(i * 4) + 2] = area.width();
312 dims[(i * 4) + 3] = area.height();
314 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
315 otk::OBProperty::Atom_Cardinal,
316 dims, 4 * workspacesList.size());
319 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
320 otk::OBProperty::Atom_Cardinal, 0, 0);
325 void OBScreen::loadStyle(const otk::Configuration
&config
)
329 // XXX: make stuff redraw!
333 void OBScreen::manageWindow(Window window
)
335 OBClient
*client
= 0;
337 XSetWindowAttributes attrib_set
;
339 // is the window a docking app
340 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
341 if ((wmhint
->flags
& StateHint
) &&
342 wmhint
->initial_state
== WithdrawnState
) {
343 //slit->addClient(w); // XXX: make dock apps work!
350 otk::OBDisplay::grab();
352 // choose the events we want to receive on the CLIENT window
353 attrib_set
.event_mask
= OBClient::event_mask
;
354 attrib_set
.do_not_propagate_mask
= OBClient::no_propagate_mask
;
355 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
356 CWEventMask
|CWDontPropagate
, &attrib_set
);
358 // create the OBClient class, which gets all of the hints on the window
359 client
= new OBClient(_number
, window
);
360 // register for events
361 Openbox::instance
->registerHandler(window
, client
);
362 // add to the wm's map
363 Openbox::instance
->addClient(window
, client
);
365 // we dont want a border on the client
366 client
->toggleClientBorder(false);
368 // specify that if we exit, the window should not be destroyed and should be
369 // reparented back to root automatically
370 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
372 if (!client
->positionRequested()) {
373 // XXX: position the window intelligenty
376 // create the decoration frame for the client window
377 client
->frame
= new OBFrame(client
, &_style
);
379 // add to the wm's map
380 Openbox::instance
->addClient(client
->frame
->window(), client
);
381 Openbox::instance
->addClient(client
->frame
->plate(), client
);
382 Openbox::instance
->addClient(client
->frame
->titlebar(), client
);
383 Openbox::instance
->addClient(client
->frame
->label(), client
);
384 Openbox::instance
->addClient(client
->frame
->button_max(), client
);
385 Openbox::instance
->addClient(client
->frame
->button_iconify(), client
);
386 Openbox::instance
->addClient(client
->frame
->button_stick(), client
);
387 Openbox::instance
->addClient(client
->frame
->button_close(), client
);
388 Openbox::instance
->addClient(client
->frame
->handle(), client
);
389 Openbox::instance
->addClient(client
->frame
->grip_left(), client
);
390 Openbox::instance
->addClient(client
->frame
->grip_right(), client
);
392 // XXX: if on the current desktop..
393 client
->frame
->show();
395 // XXX: handle any requested states such as shaded/maximized
397 otk::OBDisplay::ungrab();
399 // add to the screen's list
400 clients
.push_back(client
);
401 // update the root properties
406 void OBScreen::unmanageWindow(OBClient
*client
)
408 OBFrame
*frame
= client
->frame
;
410 // XXX: pass around focus if this window was focused
412 // remove from the wm's map
413 Openbox::instance
->removeClient(client
->window());
414 Openbox::instance
->removeClient(frame
->window());
415 Openbox::instance
->removeClient(frame
->plate());
416 Openbox::instance
->removeClient(frame
->titlebar());
417 Openbox::instance
->removeClient(frame
->label());
418 Openbox::instance
->removeClient(frame
->button_max());
419 Openbox::instance
->removeClient(frame
->button_iconify());
420 Openbox::instance
->removeClient(frame
->button_stick());
421 Openbox::instance
->removeClient(frame
->button_close());
422 Openbox::instance
->removeClient(frame
->handle());
423 Openbox::instance
->removeClient(frame
->grip_left());
424 Openbox::instance
->removeClient(frame
->grip_right());
425 // unregister for handling events
426 Openbox::instance
->clearHandler(client
->window());
428 // remove the window from our save set
429 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
431 // we dont want events no more
432 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
436 // give the client its border back
437 client
->toggleClientBorder(true);
439 delete client
->frame
;
442 // remove from the screen's list
443 clients
.remove(client
);
446 // update the root properties