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"
26 #include "otk/display.hh"
29 static int anotherWMRunning(Display
*display
, XErrorEvent
*) {
30 printf(_("Another window manager already running on display %s.\n"),
31 DisplayString(display
));
40 OBScreen::OBScreen(int screen
, const otk::Configuration
&config
)
44 assert(screen
>= 0); assert(screen
< ScreenCount(otk::OBDisplay::display
));
45 _info
= otk::OBDisplay::screenInfo(screen
);
48 XErrorHandler old
= XSetErrorHandler(::anotherWMRunning
);
49 XSelectInput(otk::OBDisplay::display
, _info
->rootWindow(),
50 OBScreen::event_mask
);
51 XSync(otk::OBDisplay::display
, false);
52 XSetErrorHandler(old
);
54 _managed
= !::running
;
55 if (! _managed
) return; // was unable to manage the screen
57 printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
58 _number
, XVisualIDFromVisual(_info
->visual()), _info
->depth());
60 Openbox::instance
->property()->set(_info
->rootWindow(),
61 otk::OBProperty::openbox_pid
,
62 otk::OBProperty::Atom_Cardinal
,
63 (unsigned long) getpid());
65 // set the mouse cursor for the root window (the default cursor)
66 XDefineCursor(otk::OBDisplay::display
, _info
->rootWindow(),
67 Openbox::instance
->cursors().session
);
69 // initialize the shit that is used for all drawing on the screen
70 _image_control
= new otk::BImageControl(Openbox::instance
->timerManager(),
72 _image_control
->installRootColormap();
73 _root_cmap_installed
= True
;
75 // initialize the screen's style
76 _style
.setImageControl(_image_control
);
80 // Set the netwm atoms for geomtery and viewport
81 unsigned long geometry
[] = { _info
->width(),
83 Openbox::instance
->property()->set(_info
->rootWindow(),
84 otk::OBProperty::net_desktop_geometry
,
85 otk::OBProperty::Atom_Cardinal
,
87 unsigned long viewport
[] = { 0, 0 };
88 Openbox::instance
->property()->set(_info
->rootWindow(),
89 otk::OBProperty::net_desktop_viewport
,
90 otk::OBProperty::Atom_Cardinal
,
93 // create the window which gets focus when no clients get it
94 XSetWindowAttributes attr
;
95 attr
.override_redirect
= true;
96 _focuswindow
= XCreateWindow(otk::OBDisplay::display
, _info
->rootWindow(),
97 -100, -100, 1, 1, 0, 0, InputOnly
,
98 _info
->visual(), CWOverrideRedirect
, &attr
);
99 XMapWindow(otk::OBDisplay::display
, _focuswindow
);
101 // these may be further updated if any pre-existing windows are found in
102 // the manageExising() function
103 setClientList(); // initialize the client lists, which will be empty
104 calcArea(); // initialize the available working area
108 OBScreen::~OBScreen()
110 if (! _managed
) return;
112 // unmanage all windows
113 while (!clients
.empty())
114 unmanageWindow(clients
.front());
116 delete _image_control
;
120 void OBScreen::manageExisting()
122 unsigned int i
, j
, nchild
;
123 Window r
, p
, *children
;
124 XQueryTree(otk::OBDisplay::display
, _info
->rootWindow(), &r
, &p
,
127 // preen the window list of all icon windows... for better dockapp support
128 for (i
= 0; i
< nchild
; i
++) {
129 if (children
[i
] == None
) continue;
131 XWMHints
*wmhints
= XGetWMHints(otk::OBDisplay::display
,
135 if ((wmhints
->flags
& IconWindowHint
) &&
136 (wmhints
->icon_window
!= children
[i
])) {
137 for (j
= 0; j
< nchild
; j
++) {
138 if (children
[j
] == wmhints
->icon_window
) {
149 // manage shown windows
150 for (i
= 0; i
< nchild
; ++i
) {
151 if (children
[i
] == None
)
154 XWindowAttributes attrib
;
155 if (XGetWindowAttributes(otk::OBDisplay::display
, children
[i
], &attrib
)) {
156 if (attrib
.override_redirect
) continue;
158 if (attrib
.map_state
!= IsUnmapped
) {
159 manageWindow(children
[i
]);
168 //! Adds a window's strut to the screen's list of reserved spaces
169 void OBScreen::addStrut(otk::Strut
*strut
)
171 _struts
.push_back(strut
);
175 //! Removes a window's strut from the screen's list of reserved spaces
176 void OBScreen::removeStrut(otk::Strut
*strut
)
178 _struts
.remove(strut
);
182 void OBScreen::calcArea()
184 otk::Rect old_area
= _area
;
188 // reset to the full areas
189 if (isXineramaActive())
190 xineramaUsableArea = getXineramaAreas();
194 /* these values represent offsets from the screen edge
195 * we look for the biggest offset on each edge and then apply them
197 * do not be confused by the similarity to the names of Rect's members
199 unsigned int current_left
= 0, current_right
= 0, current_top
= 0,
202 StrutList::const_iterator it
= _struts
.begin(), end
= _struts
.end();
204 for(; it
!= end
; ++it
) {
205 otk::Strut
*strut
= *it
;
206 if (strut
->left
> current_left
)
207 current_left
= strut
->left
;
208 if (strut
->top
> current_top
)
209 current_top
= strut
->top
;
210 if (strut
->right
> current_right
)
211 current_right
= strut
->right
;
212 if (strut
->bottom
> current_bottom
)
213 current_bottom
= strut
->bottom
;
216 _area
.setRect(current_left
, current_top
,
217 _info
->width() - (current_left
+ current_right
),
218 _info
->height() - (current_top
+ current_bottom
));
222 if (isXineramaActive()) {
223 // keep each of the ximerama-defined areas inside the strut
224 RectList::iterator xit, xend = xineramaUsableArea.end();
225 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
226 if (xit->x() < usableArea.x()) {
227 xit->setX(usableArea.x());
228 xit->setWidth(xit->width() - usableArea.x());
230 if (xit->y() < usableArea.y()) {
231 xit->setY(usableArea.y());
232 xit->setHeight(xit->height() - usableArea.y());
234 if (xit->x() + xit->width() > usableArea.width())
235 xit->setWidth(usableArea.width() - xit->x());
236 if (xit->y() + xit->height() > usableArea.height())
237 xit->setHeight(usableArea.height() - xit->y());
243 if (old_area
!= _area
)
244 // XXX: re-maximize windows
250 void OBScreen::setClientList()
254 // create an array of the window ids
255 if (clients
.size() > 0) {
258 windows
= new Window
[clients
.size()];
260 ClientList::const_iterator it
= clients
.begin();
261 const ClientList::const_iterator end
= clients
.end();
262 for (; it
!= end
; ++it
, ++win_it
)
263 *win_it
= (*it
)->window();
265 windows
= (Window
*) 0;
267 Openbox::instance
->property()->set(_info
->rootWindow(),
268 otk::OBProperty::net_client_list
,
269 otk::OBProperty::Atom_Window
,
270 windows
, clients
.size());
279 void OBScreen::setStackingList()
281 // The below comment is wrong now hopefully :> but ill keep it here for
284 Get the stacking order from all of the workspaces.
285 We start with the current workspace so that the sticky windows will be
286 in the right order on the current workspace.
289 Openbox::instance->property()->set(_info->getRootWindow(),
290 otk::OBProperty::net_client_list_stacking,
291 otk::OBProperty::Atom_Window,
292 _stacking, _stacking.size());
297 void OBScreen::setWorkArea() {
298 unsigned long area
[] = { _area
.x(), _area
.y(),
299 _area
.width(), _area
.height() };
300 Openbox::instance
->property()->set(_info
->rootWindow(),
301 otk::OBProperty::net_workarea
,
302 otk::OBProperty::Atom_Cardinal
,
305 if (workspacesList.size() > 0) {
306 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
307 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
308 // XXX: this could be different for each workspace
309 const otk::Rect &area = availableArea();
310 dims[(i * 4) + 0] = area.x();
311 dims[(i * 4) + 1] = area.y();
312 dims[(i * 4) + 2] = area.width();
313 dims[(i * 4) + 3] = area.height();
315 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
316 otk::OBProperty::Atom_Cardinal,
317 dims, 4 * workspacesList.size());
320 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
321 otk::OBProperty::Atom_Cardinal, 0, 0);
326 void OBScreen::loadStyle(const otk::Configuration
&config
)
330 // XXX: make stuff redraw!
334 void OBScreen::manageWindow(Window window
)
336 OBClient
*client
= 0;
338 XSetWindowAttributes attrib_set
;
340 // is the window a docking app
341 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
342 if ((wmhint
->flags
& StateHint
) &&
343 wmhint
->initial_state
== WithdrawnState
) {
344 //slit->addClient(w); // XXX: make dock apps work!
351 otk::OBDisplay::grab();
353 // choose the events we want to receive on the CLIENT window
354 attrib_set
.event_mask
= OBClient::event_mask
;
355 attrib_set
.do_not_propagate_mask
= OBClient::no_propagate_mask
;
356 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
357 CWEventMask
|CWDontPropagate
, &attrib_set
);
359 // create the OBClient class, which gets all of the hints on the window
360 client
= new OBClient(_number
, window
);
361 // register for events
362 Openbox::instance
->registerHandler(window
, client
);
363 // add to the wm's map
364 Openbox::instance
->addClient(window
, client
);
366 // we dont want a border on the client
367 client
->toggleClientBorder(false);
369 // specify that if we exit, the window should not be destroyed and should be
370 // reparented back to root automatically
371 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
373 if (!client
->positionRequested()) {
374 // XXX: position the window intelligenty
377 // create the decoration frame for the client window
378 client
->frame
= new OBFrame(client
, &_style
);
380 // add to the wm's map
381 Openbox::instance
->addClient(client
->frame
->window(), client
);
382 Openbox::instance
->addClient(client
->frame
->plate(), client
);
383 Openbox::instance
->addClient(client
->frame
->titlebar(), client
);
384 Openbox::instance
->addClient(client
->frame
->label(), client
);
385 Openbox::instance
->addClient(client
->frame
->button_max(), client
);
386 Openbox::instance
->addClient(client
->frame
->button_iconify(), client
);
387 Openbox::instance
->addClient(client
->frame
->button_stick(), client
);
388 Openbox::instance
->addClient(client
->frame
->button_close(), client
);
389 Openbox::instance
->addClient(client
->frame
->handle(), client
);
390 Openbox::instance
->addClient(client
->frame
->grip_left(), client
);
391 Openbox::instance
->addClient(client
->frame
->grip_right(), client
);
393 // XXX: if on the current desktop..
394 client
->frame
->show();
396 // XXX: handle any requested states such as shaded/maximized
398 otk::OBDisplay::ungrab();
400 // add to the screen's list
401 clients
.push_back(client
);
402 // update the root properties
407 void OBScreen::unmanageWindow(OBClient
*client
)
409 OBFrame
*frame
= client
->frame
;
411 // XXX: pass around focus if this window was focused
413 // remove from the wm's map
414 Openbox::instance
->removeClient(client
->window());
415 Openbox::instance
->removeClient(frame
->window());
416 Openbox::instance
->removeClient(frame
->plate());
417 Openbox::instance
->removeClient(frame
->titlebar());
418 Openbox::instance
->removeClient(frame
->label());
419 Openbox::instance
->removeClient(frame
->button_max());
420 Openbox::instance
->removeClient(frame
->button_iconify());
421 Openbox::instance
->removeClient(frame
->button_stick());
422 Openbox::instance
->removeClient(frame
->button_close());
423 Openbox::instance
->removeClient(frame
->handle());
424 Openbox::instance
->removeClient(frame
->grip_left());
425 Openbox::instance
->removeClient(frame
->grip_right());
426 // unregister for handling events
427 Openbox::instance
->clearHandler(client
->window());
429 // remove the window from our save set
430 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
432 // we dont want events no more
433 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
437 // give the client its border back
438 client
->toggleClientBorder(true);
440 delete client
->frame
;
443 // remove from the screen's list
444 clients
.remove(client
);
447 // update the root properties