# include <stdio.h>
# endif // HAVE_STDIO_H
#endif // DEBUG
-}
-#include <cstdlib>
+#ifdef HAVE_STDLIB_H
+ #include <stdlib.h>
+#endif // HAVE_STDLIB_H
+}
#include "i18n.hh"
#include "blackbox.hh"
+#include "Clientmenu.hh"
+#include "Font.hh"
#include "GCCache.hh"
#include "Iconmenu.hh"
#include "Image.hh"
#include "Windowmenu.hh"
#include "Workspace.hh"
#include "Slit.hh"
-#include "XAtom.hh"
-#include "Input.hh"
using std::string;
+using std::abs;
/*
* Initializes the class with default values/the window's set initial values.
client.window = w;
screen = s;
xatom = blackbox->getXAtom();
- input = blackbox->getInput();
if (! validateClient()) {
delete this;
return;
}
- // set the eventmask early in the game so that we make sure we get
- // all the events we are interested in
- XSetWindowAttributes attrib_set;
- attrib_set.event_mask = PropertyChangeMask | FocusChangeMask |
- StructureNotifyMask;
- attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
- ButtonMotionMask;
- XChangeWindowAttributes(blackbox->getXDisplay(), client.window,
- CWEventMask|CWDontPropagate, &attrib_set);
-
// fetch client size and placement
XWindowAttributes wattrib;
- if ((! XGetWindowAttributes(blackbox->getXDisplay(),
- client.window, &wattrib)) ||
- (! wattrib.screen) || wattrib.override_redirect) {
+ if (! XGetWindowAttributes(blackbox->getXDisplay(),
+ client.window, &wattrib) ||
+ ! wattrib.screen || wattrib.override_redirect) {
#ifdef DEBUG
fprintf(stderr,
"BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
return;
}
+ // set the eventmask early in the game so that we make sure we get
+ // all the events we are interested in
+ XSetWindowAttributes attrib_set;
+ attrib_set.event_mask = PropertyChangeMask | FocusChangeMask |
+ StructureNotifyMask;
+ attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask;
+ XChangeWindowAttributes(blackbox->getXDisplay(), client.window,
+ CWEventMask|CWDontPropagate, &attrib_set);
+
flags.moving = flags.resizing = flags.shaded = flags.visible =
flags.iconic = flags.focused = flags.stuck = flags.modal =
flags.send_focus_message = flags.shaped = flags.skip_taskbar =
blackbox_attrib.workspace = window_number = BSENTINEL;
- blackbox_attrib.flags = blackbox_attrib.attrib = blackbox_attrib.stack
- = blackbox_attrib.decoration = 0l;
+ blackbox_attrib.flags = blackbox_attrib.attrib = blackbox_attrib.stack = 0l;
+ blackbox_attrib.decoration = DecorNormal;
blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
frame.fgrip_pixel = 0;
frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None;
frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None;
- frame.pbutton = frame.ugrip = frame.fgrip = decorations;
+ frame.pbutton = frame.ugrip = frame.fgrip = None;
- decorations = Decor_Titlebar | Decor_Border | Decor_Handle |
- Decor_Iconify | Decor_Maximize;
functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
+ mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
+ Decor_Iconify | Decor_Maximize;
- client.wm_hint_flags = client.normal_hint_flags = 0;
+ client.normal_hint_flags = 0;
+ client.window_group = None;
client.transient_for = 0;
+ current_state = NormalState;
+
+ windowmenu = 0;
+
/*
- get the initial size and location of client window (relative to the
+ set the initial size and location of client window (relative to the
_root window_). This position is the reference point used with the
window's gravity to find the window's initial position.
*/
client.rect.setRect(wattrib.x, wattrib.y, wattrib.width, wattrib.height);
client.old_bw = wattrib.border_width;
- windowmenu = 0;
lastButtonPressTime = 0;
timer = new BTimer(blackbox, this);
timer->setTimeout(blackbox->getAutoRaiseDelay());
- if (! getBlackboxHints()) {
- getMWMHints();
- getNetWMHints();
- }
-
// get size, aspect, minimum/maximum size and other hints set by the
// client
+
+ if (! getBlackboxHints())
+ getNetWMHints();
+
getWMProtocols();
getWMHints();
getWMNormalHints();
- if (client.initial_state == WithdrawnState) {
- screen->getSlit()->addClient(client.window);
- delete this;
- return;
- }
-
- if (isKDESystrayWindow()) {
- screen->addSystrayWindow(client.window);
- delete this;
- return;
- }
-
frame.window = createToplevelWindow();
- frame.plate = createChildWindow(frame.window);
- associateClientWindow();
blackbox->saveWindowSearch(frame.window, this);
+
+ frame.plate = createChildWindow(frame.window);
blackbox->saveWindowSearch(frame.plate, this);
- blackbox->saveWindowSearch(client.window, this);
- screen->addStrut(&client.strut);
- updateStrut();
-
// determine if this is a transient window
getTransientInfo();
// determine the window's type, so we can decide its decorations and
// functionality, or if we should not manage it at all
- getWindowType();
-
- // adjust the window decorations/behavior based on the window type
- switch (window_type) {
- case Type_Desktop:
- // desktop windows are not managed by us, we just make sure they stay on the
- // bottom.
- return;
-
- case Type_Dock:
- // docks (such as kicker) cannot be moved, and appear on all workspaces
- functions &= ~(Func_Move);
- flags.stuck = True;
- case Type_Toolbar:
- case Type_Menu:
- case Type_Utility:
- // these windows have minimal decorations, only a titlebar, and cannot
- // be resized or iconified
- decorations &= ~(Decor_Maximize | Decor_Handle | Decor_Border |
- Decor_Iconify);
- functions &= ~(Func_Resize | Func_Maximize | Func_Iconify);
- break;
+ if (getWindowType()) {
+ // adjust the window decorations/behavior based on the window type
+ switch (window_type) {
+ case Type_Desktop:
+ case Type_Dock:
+ case Type_Menu:
+ blackbox_attrib.workspace = 0; // we do need to belong to a workspace
+ flags.stuck = True; // we show up on all workspaces
+ case Type_Splash:
+ // none of these windows are manipulated by the window manager
+ functions = 0;
+ break;
- case Type_Splash:
- // splash screens have no functionality or decorations, they are left up
- // to the application which created them
- decorations = 0;
- functions = 0;
- break;
+ case Type_Toolbar:
+ case Type_Utility:
+ // these windows get less functionality
+ functions &= ~(Func_Maximize | Func_Resize | Func_Iconify);
+ break;
- case Type_Dialog:
- // dialogs cannot be maximized, and don't display a handle
- decorations &= ~(Decor_Maximize | Decor_Handle);
- functions &= ~Func_Maximize;
- break;
+ case Type_Dialog:
+ // dialogs cannot be maximized
+ functions &= ~Func_Maximize;
+ break;
- case Type_Normal:
- // normal windows retain all of the possible decorations and functionality
- break;
+ case Type_Normal:
+ // normal windows retain all of the possible decorations and functionality
+ break;
+ }
+ } else {
+ getMWMHints();
}
-
+
// further adjeust the window's decorations/behavior based on window sizes
if ((client.normal_hint_flags & PMinSize) &&
(client.normal_hint_flags & PMaxSize) &&
client.max_width <= client.min_width &&
client.max_height <= client.min_height) {
- decorations &= ~(Decor_Maximize | Decor_Handle);
functions &= ~(Func_Resize | Func_Maximize);
}
- upsize();
-
+
setAllowedActions();
- bool place_window = True;
- if (blackbox->isStartup() || isTransient() ||
- client.normal_hint_flags & (PPosition|USPosition)) {
- applyGravity(frame.rect);
-
- if (blackbox->isStartup() ||
- client.rect.intersects(screen->availableArea()))
- place_window = False;
- }
-
+ setupDecor();
+
if (decorations & Decor_Titlebar)
createTitlebar();
if (decorations & Decor_Handle)
createHandle();
-#ifdef SHAPE
- if (blackbox->hasShapeExtensions() && flags.shaped) {
- configureShape();
+ // apply the size and gravity hint to the frame
+
+ upsize();
+
+ bool place_window = True;
+ if (blackbox->isStartup() || isTransient() ||
+ client.normal_hint_flags & (PPosition|USPosition)) {
+ applyGravity(frame.rect);
+
+ if (blackbox->isStartup() || client.rect.intersects(screen->getRect()))
+ place_window = False;
}
-#endif // SHAPE
- grabButtons();
+ // add the window's strut. note this is done *after* placing the window.
+ screen->addStrut(&client.strut);
+ updateStrut();
+
+ /*
+ the server needs to be grabbed here to prevent client's from sending
+ events while we are in the process of configuring their window.
+ We hold the grab until after we are done moving the window around.
+ */
- positionWindows();
- decorate();
+ XGrabServer(blackbox->getXDisplay());
- if (decorations & Decor_Titlebar)
- XMapSubwindows(blackbox->getXDisplay(), frame.title);
- XMapSubwindows(blackbox->getXDisplay(), frame.window);
+ associateClientWindow();
- windowmenu = new Windowmenu(this);
+ blackbox->saveWindowSearch(client.window, this);
if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
screen->getCurrentWorkspace()->addWindow(this, place_window);
// place the window
configure(frame.rect.x(), frame.rect.y(),
frame.rect.width(), frame.rect.height());
+
}
+ positionWindows();
+
+ XUngrabServer(blackbox->getXDisplay());
+
+#ifdef SHAPE
+ if (blackbox->hasShapeExtensions() && flags.shaped)
+ configureShape();
+#endif // SHAPE
+
+ // now that we know where to put the window and what it should look like
+ // we apply the decorations
+ decorate();
+
+ grabButtons();
+
+ XMapSubwindows(blackbox->getXDisplay(), frame.window);
+
+ // this ensures the title, buttons, and other decor are properly displayed
+ redrawWindowFrame();
+
// preserve the window's initial state on first map, and its current state
// across a restart
- if (! getState()) {
- if (client.wm_hint_flags & StateHint)
- current_state = client.initial_state;
- else
- current_state = NormalState;
- }
+ unsigned long initial_state = current_state;
+ if (! getState())
+ current_state = initial_state;
// get sticky state from our parent window if we've got one
if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
client.transient_for->isStuck() != flags.stuck)
- stick();
+ flags.stuck = True;
if (flags.shaded) {
flags.shaded = False;
+ initial_state = current_state;
shade();
/*
- Because the iconic'ness of shaded windows is lost, we need to set the
- state to NormalState so that shaded windows on other workspaces will not
- get shown on the first workspace.
At this point in the life of a window, current_state should only be set
to IconicState if the window was an *icon*, not if it was shaded.
*/
- current_state = NormalState;
+ if (initial_state != IconicState)
+ current_state = NormalState;
}
if (flags.stuck) {
stick();
}
- if (flags.maximized && (functions & Func_Maximize)) {
+ if (flags.maximized && (functions & Func_Maximize))
remaximize();
- }
-
- /*
- When the window is mapped (and also when its attributes are restored), the
- current_state that was set here will be used.
- It is set to Normal if the window is to be mapped or it is set to Iconic
- if the window is to be iconified.
- *Note* that for sticky windows, the same rules apply here, they are in
- fact never set to Iconic since there is no way for us to tell if a sticky
- window was iconified previously.
- */
- redrawWindowFrame();
+ // create this last so it only needs to be configured once
+ windowmenu = new Windowmenu(this);
}
if (! timer) // window not managed...
return;
+ if (flags.moving)
+ endMove();
+
screen->removeStrut(&client.strut);
screen->updateAvailableArea();
// remove ourselves from our transient_for
if (isTransient()) {
- if (client.transient_for != (BlackboxWindow *) ~0ul) {
+ if (client.transient_for != (BlackboxWindow *) ~0ul)
client.transient_for->client.transientList.remove(this);
- }
client.transient_for = (BlackboxWindow*) 0;
}
if (client.transientList.size() > 0) {
// reset transient_for for all transients
BlackboxWindowList::iterator it, end = client.transientList.end();
- for (it = client.transientList.begin(); it != end; ++it) {
+ for (it = client.transientList.begin(); it != end; ++it)
(*it)->client.transient_for = (BlackboxWindow*) 0;
- }
}
if (frame.title)
}
+void BlackboxWindow::enableDecor(bool enable) {
+ blackbox_attrib.flags |= AttribDecoration;
+ blackbox_attrib.decoration = enable ? DecorNormal : DecorNone;
+ setupDecor();
+
+ // we can not be shaded if we lack a titlebar
+ if (! (decorations & Decor_Titlebar) && flags.shaded)
+ shade();
+
+ if (flags.visible && frame.window) {
+ XMapSubwindows(blackbox->getXDisplay(), frame.window);
+ XMapWindow(blackbox->getXDisplay(), frame.window);
+ }
+
+ reconfigure();
+ setState(current_state);
+}
+
+
+void BlackboxWindow::setupDecor() {
+ if (blackbox_attrib.decoration != DecorNone) {
+ // start with everything on
+ decorations = Decor_Close |
+ (mwm_decorations & Decor_Titlebar ? Decor_Titlebar : 0) |
+ (mwm_decorations & Decor_Border ? Decor_Border : 0) |
+ (mwm_decorations & Decor_Handle ? Decor_Handle : 0) |
+ (mwm_decorations & Decor_Iconify ? Decor_Iconify : 0) |
+ (mwm_decorations & Decor_Maximize ? Decor_Maximize : 0);
+
+ if (! (functions & Func_Close)) decorations &= ~Decor_Close;
+ if (! (functions & Func_Maximize)) decorations &= ~Decor_Maximize;
+ if (! (functions & Func_Iconify)) decorations &= ~Decor_Iconify;
+ if (! (functions & Func_Resize)) decorations &= ~Decor_Handle;
+
+ switch (window_type) {
+ case Type_Desktop:
+ case Type_Dock:
+ case Type_Menu:
+ case Type_Splash:
+ // none of these windows are decorated by the window manager at all
+ decorations = 0;
+ break;
+
+ case Type_Toolbar:
+ case Type_Utility:
+ decorations &= ~(Decor_Border);
+ break;
+
+ case Type_Dialog:
+ decorations &= ~Decor_Handle;
+ break;
+
+ case Type_Normal:
+ break;
+ }
+ } else {
+ decorations = 0;
+ }
+}
+
/*
* Creates a new top level window, with a given location, size, and border
* width.
attrib_create.colormap = screen->getColormap();
attrib_create.override_redirect = True;
attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
- ButtonMotionMask | EnterWindowMask;
+ ButtonMotionMask |
+ EnterWindowMask | LeaveWindowMask;
return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(),
- -1, -1, 1, 1, frame.border_w, screen->getDepth(),
+ 0, 0, 1, 1, frame.border_w, screen->getDepth(),
InputOutput, screen->getVisual(), create_mask,
&attrib_create);
}
XSelectInput(blackbox->getXDisplay(), frame.plate, SubstructureRedirectMask);
- XGrabServer(blackbox->getXDisplay());
- XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
- XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0);
+ /*
+ note we used to grab around this call to XReparentWindow however the
+ server is now grabbed before this method is called
+ */
+ unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
+ StructureNotifyMask;
XSelectInput(blackbox->getXDisplay(), client.window,
- PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
- XUngrabServer(blackbox->getXDisplay());
+ event_mask & ~StructureNotifyMask);
+ XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0);
+ XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
XRaiseWindow(blackbox->getXDisplay(), frame.plate);
XMapSubwindows(blackbox->getXDisplay(), frame.plate);
-
#ifdef SHAPE
if (blackbox->hasShapeExtensions()) {
XShapeSelectInput(blackbox->getXDisplay(), client.window,
}
if (decorations & Decor_Border) {
- frame.fborder_pixel = screen->getWindowStyle()->f_focus.pixel();
- frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.pixel();
- blackbox_attrib.flags |= AttribDecoration;
- blackbox_attrib.decoration = DecorNormal;
- } else {
- blackbox_attrib.flags |= AttribDecoration;
- blackbox_attrib.decoration = DecorNone;
+ frame.fborder_pixel = screen->getWindowStyle()->f_focus.color().pixel();
+ frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.color().pixel();
}
if (decorations & Decor_Handle) {
void BlackboxWindow::reconfigure(void) {
+ restoreGravity(client.rect);
upsize();
-
- client.rect.setPos(frame.rect.left() + frame.margin.left,
- frame.rect.top() + frame.margin.top);
-
+ applyGravity(frame.rect);
positionWindows();
decorate();
-
redrawWindowFrame();
- configure(frame.rect.x(), frame.rect.y(),
- frame.rect.width(), frame.rect.height());
+ ungrabButtons();
+ grabButtons();
if (windowmenu) {
windowmenu->move(windowmenu->getX(), frame.rect.y() + frame.title_h);
}
+void BlackboxWindow::grabButtons(void) {
+ mod_mask = blackbox->getMouseModMask();
+
+ if (! screen->isSloppyFocus() || screen->doClickRaise())
+ // grab button 1 for changing focus/raising
+ blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
+ GrabModeSync, GrabModeSync, frame.plate, None,
+ screen->allowScrollLock());
+
+ if (functions & Func_Move)
+ blackbox->grabButton(Button1, mod_mask, frame.window, True,
+ ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
+ GrabModeAsync, frame.window, None,
+ screen->allowScrollLock());
+ if (functions & Func_Resize)
+ blackbox->grabButton(Button3, mod_mask, frame.window, True,
+ ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
+ GrabModeAsync, frame.window, None,
+ screen->allowScrollLock());
+ // alt+middle lowers the window
+ blackbox->grabButton(Button2, mod_mask, frame.window, True,
+ ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
+ frame.window, None,
+ screen->allowScrollLock());
+}
+
+
+void BlackboxWindow::ungrabButtons(void) {
+ blackbox->ungrabButton(Button1, 0, frame.plate);
+ blackbox->ungrabButton(Button1, mod_mask, frame.window);
+ blackbox->ungrabButton(Button2, mod_mask, frame.window);
+ blackbox->ungrabButton(Button3, mod_mask, frame.window);
+}
+
+
void BlackboxWindow::positionWindows(void) {
XMoveResizeWindow(blackbox->getXDisplay(), frame.window,
frame.rect.x(), frame.rect.y(), frame.inside_w,
client.rect.width(), client.rect.height());
XMoveResizeWindow(blackbox->getXDisplay(), client.window,
0, 0, client.rect.width(), client.rect.height());
+ // ensure client.rect contains the real location
+ client.rect.setPos(frame.rect.left() + frame.margin.left,
+ frame.rect.top() + frame.margin.top);
if (decorations & Decor_Titlebar) {
if (frame.title == None) createTitlebar();
} else if (frame.handle) {
destroyHandle();
}
+ XSync(blackbox->getXDisplay(), False);
}
}
-void BlackboxWindow::getWindowType(void) {
- unsigned long val;
+bool BlackboxWindow::getWindowType(void) {
+ window_type = (WindowType) -1;
+
+ unsigned long *val;
+ unsigned long num = (unsigned) -1;
if (xatom->getValue(client.window, XAtom::net_wm_window_type, XAtom::atom,
- val)) {
- if (val == xatom->getAtom(XAtom::net_wm_window_type_desktop))
- window_type = Type_Desktop;
- else if (val == xatom->getAtom(XAtom::net_wm_window_type_dock))
- window_type = Type_Dock;
- else if (val == xatom->getAtom(XAtom::net_wm_window_type_toolbar))
- window_type = Type_Toolbar;
- else if (val == xatom->getAtom(XAtom::net_wm_window_type_menu))
- window_type = Type_Menu;
- else if (val == xatom->getAtom(XAtom::net_wm_window_type_utility))
- window_type = Type_Utility;
- else if (val == xatom->getAtom(XAtom::net_wm_window_type_splash))
- window_type = Type_Splash;
- else if (val == xatom->getAtom(XAtom::net_wm_window_type_dialog))
+ num, &val)) {
+ for (unsigned long i = 0; i < num; ++i) {
+ if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_desktop))
+ window_type = Type_Desktop;
+ else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dock))
+ window_type = Type_Dock;
+ else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_toolbar))
+ window_type = Type_Toolbar;
+ else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_menu))
+ window_type = Type_Menu;
+ else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_utility))
+ window_type = Type_Utility;
+ else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_splash))
+ window_type = Type_Splash;
+ else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dialog))
+ window_type = Type_Dialog;
+ else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_normal))
+ window_type = Type_Normal;
+ else if (val[i] ==
+ xatom->getAtom(XAtom::kde_net_wm_window_type_override))
+ mwm_decorations = 0; // prevent this window from getting any decor
+ }
+ delete val;
+ }
+
+ if (window_type == (WindowType) -1) {
+ /*
+ * the window type hint was not set, which means we either classify ourself
+ * as a normal window or a dialog, depending on if we are a transient.
+ */
+ if (isTransient())
window_type = Type_Dialog;
- else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
+ else
window_type = Type_Normal;
- return;
- }
- /*
- * the window type hint was not set, which means we either classify ourself
- * as a normal window or a dialog, depending on if we are a transient.
- */
- if (isTransient())
- window_type = Type_Dialog;
+ return False;
+ }
- window_type = Type_Normal;
+ return True;
}
*/
void BlackboxWindow::getWMHints(void) {
focus_mode = F_Passive;
- client.initial_state = NormalState;
// remove from current window group
if (client.window_group) {
}
if (wmhint->flags & StateHint)
- client.initial_state = wmhint->initial_state;
+ current_state = wmhint->initial_state;
if (wmhint->flags & WindowGroupHint) {
client.window_group = wmhint->window_group;
// add window to the appropriate group
BWindowGroup *group = blackbox->searchGroup(client.window_group);
- if (! group) // no group found, create it!
- group = new BWindowGroup(blackbox, client.window_group);
- group->addWindow(this);
+ if (! group) { // no group found, create it!
+ new BWindowGroup(blackbox, client.window_group);
+ group = blackbox->searchGroup(client.window_group);
+ }
+ if (group)
+ group->addWindow(this);
}
- client.wm_hint_flags = wmhint->flags;
XFree(wmhint);
}
client.min_width = client.min_height =
client.width_inc = client.height_inc = 1;
client.base_width = client.base_height = 0;
+ client.win_gravity = NorthWestGravity;
+#if 0
+ client.min_aspect_x = client.min_aspect_y =
+ client.max_aspect_x = client.max_aspect_y = 1;
+#endif
/*
use the full screen, not the strut modified size. otherwise when the
*/
const Rect& screen_area = screen->getRect();
client.max_width = screen_area.width();
-
client.max_height = screen_area.height();
- client.min_aspect_x = client.min_aspect_y =
- client.max_aspect_x = client.max_aspect_y = 1;
- client.win_gravity = NorthWestGravity;
if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window,
&sizehint, &icccm_mask))
client.normal_hint_flags = sizehint.flags;
if (sizehint.flags & PMinSize) {
- client.min_width = sizehint.min_width;
- client.min_height = sizehint.min_height;
+ if (sizehint.min_width >= 0)
+ client.min_width = sizehint.min_width;
+ if (sizehint.min_height >= 0)
+ client.min_height = sizehint.min_height;
}
if (sizehint.flags & PMaxSize) {
- client.max_width = sizehint.max_width;
- client.max_height = sizehint.max_height;
+ if (sizehint.max_width > static_cast<signed>(client.min_width))
+ client.max_width = sizehint.max_width;
+ else
+ client.max_width = client.min_width;
+
+ if (sizehint.max_height > static_cast<signed>(client.min_height))
+ client.max_height = sizehint.max_height;
+ else
+ client.max_height = client.min_height;
}
if (sizehint.flags & PResizeInc) {
client.height_inc = sizehint.height_inc;
}
+#if 0 // we do not support this at the moment
if (sizehint.flags & PAspect) {
client.min_aspect_x = sizehint.min_aspect.x;
client.min_aspect_y = sizehint.min_aspect.y;
client.max_aspect_x = sizehint.max_aspect.x;
client.max_aspect_y = sizehint.max_aspect.y;
}
+#endif
if (sizehint.flags & PBaseSize) {
client.base_width = sizehint.base_width;
num = PropMwmHintsElements;
if (! xatom->getValue(client.window, XAtom::motif_wm_hints,
XAtom::motif_wm_hints, num,
- (unsigned long **)&mwm_hint) ||
- num < PropMwmHintsElements)
+ (unsigned long **)&mwm_hint))
return;
+ if (num < PropMwmHintsElements) {
+ delete [] mwm_hint;
+ return;
+ }
if (mwm_hint->flags & MwmHintsDecorations) {
if (mwm_hint->decorations & MwmDecorAll) {
- decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
- Decor_Iconify | Decor_Maximize | Decor_Close;
+ mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
+ Decor_Iconify | Decor_Maximize;
} else {
- decorations = 0;
+ mwm_decorations = 0;
if (mwm_hint->decorations & MwmDecorBorder)
- decorations |= Decor_Border;
+ mwm_decorations |= Decor_Border;
if (mwm_hint->decorations & MwmDecorHandle)
- decorations |= Decor_Handle;
+ mwm_decorations |= Decor_Handle;
if (mwm_hint->decorations & MwmDecorTitle)
- decorations |= Decor_Titlebar;
+ mwm_decorations |= Decor_Titlebar;
if (mwm_hint->decorations & MwmDecorIconify)
- decorations |= Decor_Iconify;
+ mwm_decorations |= Decor_Iconify;
if (mwm_hint->decorations & MwmDecorMaximize)
- decorations |= Decor_Maximize;
+ mwm_decorations |= Decor_Maximize;
}
}
functions |= Func_Close;
}
}
- delete mwm_hint;
+ delete [] mwm_hint;
}
num = PropBlackboxHintsElements;
if (! xatom->getValue(client.window, XAtom::blackbox_hints,
XAtom::blackbox_hints, num,
- (unsigned long **)&blackbox_hint) ||
- num < PropBlackboxHintsElements)
+ (unsigned long **)&blackbox_hint))
+ return False;
+ if (num < PropBlackboxHintsElements) {
+ delete [] blackbox_hint;
return False;
+ }
if (blackbox_hint->flags & AttribShaded)
flags.shaded = (blackbox_hint->attrib & AttribShaded);
if (blackbox_hint->flags & AttribDecoration) {
switch (blackbox_hint->decoration) {
case DecorNone:
- // clear all decorations except close
- decorations &= Decor_Close;
- // clear all functions except close
- functions &= Func_Close;
-
+ blackbox_attrib.decoration = DecorNone;
break;
case DecorTiny:
- decorations |= Decor_Titlebar | Decor_Iconify;
- decorations &= ~(Decor_Border | Decor_Handle | Decor_Maximize);
- functions |= Func_Move | Func_Iconify;
- functions &= ~(Func_Resize | Func_Maximize);
-
- break;
-
case DecorTool:
- decorations |= Decor_Titlebar;
- decorations &= ~(Decor_Iconify | Decor_Border | Decor_Handle);
- functions |= Func_Move;
- functions &= ~(Func_Resize | Func_Maximize | Func_Iconify);
-
- break;
-
case DecorNormal:
default:
- decorations |= Decor_Titlebar | Decor_Border | Decor_Handle |
- Decor_Iconify | Decor_Maximize;
- functions |= Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
-
+ // blackbox_attrib.decoration defaults to DecorNormal
break;
}
-
- reconfigure();
}
- delete blackbox_hint;
+ delete [] blackbox_hint;
return True;
}
void BlackboxWindow::getTransientInfo(void) {
if (client.transient_for &&
client.transient_for != (BlackboxWindow *) ~0ul) {
- // the transient for hint was removed, so we need to tell our
- // previous transient_for that we are going away
+ // reset transient_for in preparation of looking for a new owner
client.transient_for->client.transientList.remove(this);
}
// we have no transient_for until we find a new one
- client.transient_for = 0;
+ client.transient_for = (BlackboxWindow *) 0;
Window trans_for;
if (! XGetTransientForHint(blackbox->getXDisplay(), client.window,
return;
}
- // register ourselves with our new transient_for
- client.transient_for->client.transientList.push_back(this);
- flags.stuck = client.transient_for->flags.stuck;
-}
-
+ // Check for a circular transient state: this can lock up Blackbox
+ // when it tries to find the non-transient window for a transient.
+ BlackboxWindow *w = this;
+ while(w->client.transient_for &&
+ w->client.transient_for != (BlackboxWindow *) ~0ul) {
+ if(w->client.transient_for == this) {
+ client.transient_for = (BlackboxWindow*) 0;
+ break;
+ }
+ w = w->client.transient_for;
+ }
-bool BlackboxWindow::isKDESystrayWindow(void) {
- Window systray;
- if (xatom->getValue(client.window, XAtom::kde_net_wm_system_tray_window_for,
- XAtom::window, systray) && systray)
- return True;
- return False;
+ if (client.transient_for &&
+ client.transient_for != (BlackboxWindow *) ~0ul) {
+ // register ourselves with our new transient_for
+ client.transient_for->client.transientList.push_back(this);
+ flags.stuck = client.transient_for->flags.stuck;
+ }
}
}
+/*
+ * This function is responsible for updating both the client and the frame
+ * rectangles.
+ * According to the ICCCM a client message is not sent for a resize, only a
+ * move.
+ */
void BlackboxWindow::configure(int dx, int dy,
unsigned int dw, unsigned int dh) {
- bool send_event = False;
+ bool send_event = ((frame.rect.x() != dx || frame.rect.y() != dy) &&
+ ! flags.moving);
if (dw != frame.rect.width() || dh != frame.rect.height()) {
frame.rect.setRect(dx, dy, dw, dh);
positionWindows();
decorate();
redrawWindowFrame();
- } else if (frame.rect.x() != dx || frame.rect.y() != dy) {
- send_event = True;
-
+ } else {
frame.rect.setPos(dx, dy);
XMoveWindow(blackbox->getXDisplay(), frame.window,
frame.rect.x(), frame.rect.y());
+ /*
+ we may have been called just after an opaque window move, so even though
+ the old coords match the new ones no ConfigureNotify has been sent yet.
+ There are likely other times when this will be relevant as well.
+ */
+ if (! flags.moving) send_event = True;
}
- if (send_event && ! flags.moving) {
+ if (send_event) {
+ // if moving, the update and event will occur when the move finishes
client.rect.setPos(frame.rect.left() + frame.margin.left,
frame.rect.top() + frame.margin.top);
XSendEvent(blackbox->getXDisplay(), client.window, False,
StructureNotifyMask, &event);
-
screen->updateNetizenConfigNotify(&event);
+ XFlush(blackbox->getXDisplay());
}
}
bool BlackboxWindow::setInputFocus(void) {
if (flags.focused) return True;
- assert(! flags.iconic);
+ assert(flags.stuck || // window must be on the current workspace or sticky
+ blackbox_attrib.workspace == screen->getCurrentWorkspaceID());
- // if the window is not visible, mark the window as wanting focus rather
- // than give it focus.
- if (! flags.visible) {
- Workspace *wkspc = screen->getWorkspace(blackbox_attrib.workspace);
- wkspc->setLastFocusedWindow(this);
- return True;
- }
-
- if (! frame.rect.intersects(screen->getRect())) {
- // client is outside the screen, move it to the center
- configure((screen->getWidth() - frame.rect.width()) / 2,
- (screen->getHeight() - frame.rect.height()) / 2,
- frame.rect.width(), frame.rect.height());
- }
+ /*
+ We only do this check for normal windows and dialogs because other windows
+ do this on purpose, such as kde's kicker, and we don't want to go moving
+ it.
+ */
+ if (window_type == Type_Normal || window_type == Type_Dialog)
+ if (! frame.rect.intersects(screen->getRect())) {
+ // client is outside the screen, move it to the center
+ configure((screen->getWidth() - frame.rect.width()) / 2,
+ (screen->getHeight() - frame.rect.height()) / 2,
+ frame.rect.width(), frame.rect.height());
+ }
if (client.transientList.size() > 0) {
// transfer focus to any modal transients
BlackboxWindowList::iterator it, end = client.transientList.end();
- for (it = client.transientList.begin(); it != end; ++it) {
+ for (it = client.transientList.begin(); it != end; ++it)
if ((*it)->flags.modal) return (*it)->setInputFocus();
- }
}
bool ret = True;
if (focus_mode == F_LocallyActive || focus_mode == F_Passive) {
XSetInputFocus(blackbox->getXDisplay(), client.window,
RevertToPointerRoot, CurrentTime);
-
- blackbox->setFocusedWindow(this);
} else {
/* we could set the focus to none, since the window doesn't accept focus,
* but we shouldn't set focus to nothing since this would surely make
ce.xclient.data.l[4] = 0l;
XSendEvent(blackbox->getXDisplay(), client.window, False,
NoEventMask, &ce);
+ XFlush(blackbox->getXDisplay());
}
return ret;
* split second, leaving us with a ghost window... so, we need to do this
* while the X server is grabbed
*/
+ unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
+ StructureNotifyMask;
XGrabServer(blackbox->getXDisplay());
- XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
- XUnmapWindow(blackbox->getXDisplay(), client.window);
XSelectInput(blackbox->getXDisplay(), client.window,
- PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
+ event_mask & ~StructureNotifyMask);
+ XUnmapWindow(blackbox->getXDisplay(), client.window);
+ XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
XUngrabServer(blackbox->getXDisplay());
XUnmapWindow(blackbox->getXDisplay(), frame.window);
setState(IconicState);
screen->getWorkspace(blackbox_attrib.workspace)->removeWindow(this);
+ if (flags.stuck) {
+ for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
+ if (i != blackbox_attrib.workspace)
+ screen->getWorkspace(i)->removeWindow(this, True);
+ }
if (isTransient()) {
if (client.transient_for != (BlackboxWindow *) ~0ul &&
if (! (*it)->flags.iconic) (*it)->iconify();
}
}
+ screen->updateStackingList();
}
XMapWindow(blackbox->getXDisplay(), client.window);
XMapSubwindows(blackbox->getXDisplay(), frame.window);
XMapWindow(blackbox->getXDisplay(), frame.window);
+
+#if 0
+ int real_x, real_y;
+ Window child;
+ XTranslateCoordinates(blackbox->getXDisplay(), client.window,
+ screen->getRootWindow(),
+ 0, 0, &real_x, &real_y, &child);
+ fprintf(stderr, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
+ client.rect.left(), client.rect.top(), real_x, real_y);
+ assert(client.rect.left() == real_x && client.rect.top() == real_y);
+#endif
}
-void BlackboxWindow::deiconify(bool reassoc, bool doraise) {
+void BlackboxWindow::deiconify(bool reassoc, bool raise) {
if (flags.iconic || reassoc)
screen->reassociateWindow(this, BSENTINEL, False);
- else if (blackbox_attrib.workspace != screen->getCurrentWorkspace()->getID())
+ else if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID())
return;
show();
// reassociate and deiconify all transients
if (reassoc && client.transientList.size() > 0) {
BlackboxWindowList::iterator it, end = client.transientList.end();
- for (it = client.transientList.begin(); it != end; ++it) {
+ for (it = client.transientList.begin(); it != end; ++it)
(*it)->deiconify(True, False);
- }
}
- if (doraise)
- raise();
-}
-
-
-void BlackboxWindow::raise(void) {
- screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
-}
-
-
-void BlackboxWindow::lower(void) {
- screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
+ if (raise)
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
}
ce.xclient.data.l[3] = 0l;
ce.xclient.data.l[4] = 0l;
XSendEvent(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce);
+ XFlush(blackbox->getXDisplay());
}
XGrabServer(blackbox->getXDisplay());
- XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
- XUnmapWindow(blackbox->getXDisplay(), client.window);
+ unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
+ StructureNotifyMask;
XSelectInput(blackbox->getXDisplay(), client.window,
- PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
+ event_mask & ~StructureNotifyMask);
+ XUnmapWindow(blackbox->getXDisplay(), client.window);
+ XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
XUngrabServer(blackbox->getXDisplay());
blackbox_attrib.premax_h =
client.rect.height() + frame.margin.top + frame.margin.bottom;
- const Rect &screen_area = screen->availableArea();
- frame.changing = screen_area;
+#ifdef XINERAMA
+ if (screen->isXineramaActive() && blackbox->doXineramaMaximizing()) {
+ // find the area to use
+ RectList availableAreas = screen->allAvailableAreas();
+ RectList::iterator it, end = availableAreas.end();
+
+ for (it = availableAreas.begin(); it != end; ++it)
+ if (it->intersects(frame.rect)) break;
+ if (it == end) // the window isn't inside an area
+ it = availableAreas.begin(); // so just default to the first one
+
+ frame.changing = *it;
+ } else
+#endif // XINERAMA
+ frame.changing = screen->availableArea();
switch(button) {
case 1:
configure(frame.changing.x(), frame.changing.y(),
frame.changing.width(), frame.changing.height());
if (flags.focused)
- raise();
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
redrawAllButtons(); // in case it is not called in configure()
setState(current_state);
}
// re-maximizes the window to take into account availableArea changes
void BlackboxWindow::remaximize(void) {
+ if (flags.shaded) {
+ // we only update the window's attributes otherwise we lose the shade bit
+ switch(flags.maximized) {
+ case 1:
+ blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
+ blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
+ break;
+
+ case 2:
+ blackbox_attrib.flags |= AttribMaxVert;
+ blackbox_attrib.attrib |= AttribMaxVert;
+ break;
+
+ case 3:
+ blackbox_attrib.flags |= AttribMaxHoriz;
+ blackbox_attrib.attrib |= AttribMaxHoriz;
+ break;
+ }
+ return;
+ }
+
// save the original dimensions because maximize will wipe them out
int premax_x = blackbox_attrib.premax_x,
premax_y = blackbox_attrib.premax_y,
void BlackboxWindow::setWorkspace(unsigned int n) {
blackbox_attrib.flags |= AttribWorkspace;
blackbox_attrib.workspace = n;
+ if (n == BSENTINEL) { // iconified window
+ /*
+ we set the workspace to 'all workspaces' so that taskbars will show the
+ window. otherwise, it made uniconifying a window imposible without the
+ blackbox workspace menu
+ */
+ n = 0xffffffff;
+ }
xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, n);
}
blackbox_attrib.attrib ^= AttribOmnipresent;
flags.stuck = False;
+
+ for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
+ if (i != blackbox_attrib.workspace)
+ screen->getWorkspace(i)->removeWindow(this, True);
if (! flags.iconic)
screen->reassociateWindow(this, BSENTINEL, True);
- else
- // temporary fix since sticky windows suck. set the hint to what we
- // actually hold in our data.
- xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
- blackbox_attrib.workspace);
+ // temporary fix since sticky windows suck. set the hint to what we
+ // actually hold in our data.
+ xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
+ blackbox_attrib.workspace);
setState(current_state);
} else {
// value than that contained in the class' data.
xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
0xffffffff);
+
+ for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
+ if (i != blackbox_attrib.workspace)
+ screen->getWorkspace(i)->addWindow(this, False, True);
setState(current_state);
}
void BlackboxWindow::setFocusFlag(bool focus) {
// only focus a window if it is visible
- if (focus && !flags.visible)
+ if (focus && ! flags.visible)
return;
flags.focused = focus;
redrawWindowFrame();
- if (screen->isSloppyFocus() && screen->doAutoRaise()) {
- if (isFocused()) timer->start();
- else timer->stop();
- }
-
- if (isFocused())
+ if (flags.focused)
blackbox->setFocusedWindow(this);
+
+ if (! flags.iconic) {
+ // iconic windows arent in a workspace menu!
+ if (flags.stuck)
+ screen->getCurrentWorkspace()->setFocused(this, isFocused());
+ else
+ screen->getWorkspace(blackbox_attrib.workspace)->
+ setFocused(this, flags.focused);
+ }
}
(unsigned long **)&net))
return;
if (num < PropBlackboxAttributesElements) {
- delete net;
+ delete [] net;
return;
}
if (net->flags & AttribShaded && net->attrib & AttribShaded) {
flags.shaded = False;
+ unsigned long orig_state = current_state;
shade();
/*
- Because the iconic'ness of shaded windows is lost, we need to set the
- state to NormalState so that shaded windows on other workspaces will not
- get shown on the first workspace.
At this point in the life of a window, current_state should only be set
to IconicState if the window was an *icon*, not if it was shaded.
*/
- current_state = NormalState;
+ if (orig_state != IconicState)
+ current_state = WithdrawnState;
}
- if ((net->workspace != screen->getCurrentWorkspaceID()) &&
- (net->workspace < screen->getWorkspaceCount()))
+ if (net->workspace != screen->getCurrentWorkspaceID() &&
+ net->workspace < screen->getWorkspaceCount())
screen->reassociateWindow(this, net->workspace, True);
if ((blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) &&
current_state = NormalState;
}
- if (net->flags & AttribOmnipresent && net->attrib & AttribOmnipresent) {
- flags.stuck = False;
+ if (net->flags & AttribOmnipresent && net->attrib & AttribOmnipresent &&
+ ! flags.stuck) {
stick();
// if the window was on another workspace, it was going to be hidden. this
blackbox_attrib.premax_h = h;
}
+ if (net->flags & AttribDecoration) {
+ switch (net->decoration) {
+ case DecorNone:
+ enableDecor(False);
+ break;
+
+ /* since tools only let you toggle this anyways, we'll just make that all
+ it supports for now.
+ */
+ default:
+ case DecorNormal:
+ case DecorTiny:
+ case DecorTool:
+ enableDecor(True);
+ break;
+ }
+ }
+
// with the state set it will then be the map event's job to read the
// window's state and behave accordingly
- delete net;
+ delete [] net;
}
case NorthEastGravity:
case SouthEastGravity:
case EastGravity:
- r.setX(client.rect.x() - frame.margin.left - frame.margin.right);
+ r.setX(client.rect.x() - frame.margin.left - frame.margin.right + 2);
break;
case ForgetGravity:
case SouthWestGravity:
case SouthEastGravity:
case SouthGravity:
- r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom);
+ r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom + 2);
break;
case ForgetGravity:
case NorthEastGravity:
case SouthEastGravity:
case EastGravity:
- r.setX(frame.rect.x() + frame.margin.left + frame.margin.right);
+ r.setX(frame.rect.x() + frame.margin.left + frame.margin.right - 2);
break;
case ForgetGravity:
case SouthWestGravity:
case SouthEastGravity:
case SouthGravity:
- r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom);
+ r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom - 2);
break;
case ForgetGravity:
WindowStyle *style = screen->getWindowStyle();
- int pos = frame.bevel_w * 2,
- dlen = style->doJustify(client.title.c_str(), pos, frame.label_w,
- frame.bevel_w * 4, i18n.multibyte());
-
- BPen pen((flags.focused) ? style->l_text_focus : style->l_text_unfocus,
- style->font);
- if (i18n.multibyte())
- XmbDrawString(blackbox->getXDisplay(), frame.label, style->fontset,
- pen.gc(), pos,
- (1 - style->fontset_extents->max_ink_extent.y),
- client.title.c_str(), dlen);
- else
- XDrawString(blackbox->getXDisplay(), frame.label, pen.gc(), pos,
- (style->font->ascent + 1), client.title.c_str(), dlen);
+ int pos = frame.bevel_w * 2;
+ style->doJustify(client.title.c_str(), pos, frame.label_w, frame.bevel_w * 4);
+ style->font->drawString(frame.label, pos, 1,
+ (flags.focused ? style->l_text_focus :
+ style->l_text_unfocus),
+ client.title);
}
client.window);
#endif // DEBUG
+ /*
+ Even though the window wants to be shown, if it is not on the current
+ workspace, then it isn't going to be shown right now.
+ */
+ if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID() &&
+ blackbox_attrib.workspace < screen->getWorkspaceCount())
+ if (current_state == NormalState) current_state = WithdrawnState;
+
switch (current_state) {
case IconicState:
iconify();
case ZoomState:
default:
show();
- raise();
- if (! blackbox->isStartup() && (isTransient() || screen->doFocusNew())) {
- XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped..
- setInputFocus();
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
+ if (isNormal()) {
+ if (! blackbox->isStartup()) {
+ XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped
+ if (screen->doFocusNew() || (isTransient() && getTransientFor() &&
+ getTransientFor()->isFocused())) {
+ setInputFocus();
+ }
+ if (screen->getPlacementPolicy() == BScreen::ClickMousePlacement) {
+ int x, y, rx, ry;
+ Window c, r;
+ unsigned int m;
+ XQueryPointer(blackbox->getXDisplay(), screen->getRootWindow(),
+ &r, &c, &rx, &ry, &x, &y, &m);
+ beginMove(rx, ry);
+ }
+ }
}
break;
}
}
-void BlackboxWindow::propertyNotifyEvent(Atom atom) {
- switch(atom) {
+void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) {
+ if (pe->state == PropertyDelete || ! validateClient())
+ return;
+
+#if 0
+ fprintf(stderr, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
+ client.window);
+#endif
+
+ switch(pe->atom) {
case XA_WM_CLASS:
case XA_WM_CLIENT_MACHINE:
case XA_WM_COMMAND:
break;
case XA_WM_TRANSIENT_FOR: {
+ bool s = flags.stuck;
+
// determine if this is a transient window
getTransientInfo();
+ if (flags.stuck != s) stick();
+
// adjust the window decorations based on transience
if (isTransient()) {
- decorations &= ~(Decor_Maximize | Decor_Handle);
functions &= ~Func_Maximize;
setAllowedActions();
+ setupDecor();
}
reconfigure();
if ((client.normal_hint_flags & PMinSize) &&
(client.normal_hint_flags & PMaxSize)) {
+ // the window now can/can't resize itself, so the buttons need to be
+ // regrabbed.
+ ungrabButtons();
if (client.max_width <= client.min_width &&
client.max_height <= client.min_height) {
- decorations &= ~(Decor_Maximize | Decor_Handle);
functions &= ~(Func_Resize | Func_Maximize);
} else {
- decorations |= Decor_Maximize | Decor_Handle;
- functions |= Func_Resize | Func_Maximize;
+ if (! isTransient())
+ functions |= Func_Maximize;
+ functions |= Func_Resize;
}
+ grabButtons();
setAllowedActions();
+ setupDecor();
}
Rect old_rect = frame.rect;
}
default:
- if (atom == xatom->getAtom(XAtom::wm_protocols)) {
+ if (pe->atom == xatom->getAtom(XAtom::wm_protocols)) {
getWMProtocols();
if ((decorations & Decor_Close) && (! frame.close_button)) {
}
if (windowmenu) windowmenu->reconfigure();
}
- } else if (atom == xatom->getAtom(XAtom::net_wm_strut)) {
+ } else if (pe->atom == xatom->getAtom(XAtom::net_wm_strut)) {
updateStrut();
}
void BlackboxWindow::exposeEvent(const XExposeEvent *ee) {
+#if 0
+ fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window);
+#endif
+
if (frame.label == ee->window && (decorations & Decor_Titlebar))
redrawLabel();
else if (frame.close_button == ee->window)
configure(req.x(), req.y(), req.width(), req.height());
}
- if (cr->value_mask & CWStackMode) {
+ if (cr->value_mask & CWStackMode && !isDesktop()) {
switch (cr->detail) {
case Below:
case BottomIf:
- lower();
+ screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
break;
case Above:
case TopIf:
default:
- raise();
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
break;
}
}
}
-void BlackboxWindow::grabButtons(void) {
- const BInput::MouseBindingList &mbindings = input->getMouseBindings();
-
- BInput::MouseBindingList::const_iterator mit = mbindings.begin();
- const BInput::MouseBindingList::const_iterator mend = mbindings.end();
- for (; mit != mend; ++mit) {
- // dont grab for an action the window can't perform
- //if (! (mit->action == BInput::BeginMove && functions & Func_Move) &&
- // ! (mit->action == BInput::BeginResize && functions & Func_Resize)) {
- switch (mit->event) {
- case BInput::WindowClientPress:
- blackbox->grabButton(mit->button, mit->state, frame.plate, True,
- ButtonPressMask, GrabModeSync, GrabModeSync,
- frame.plate, None);
- break;
- case BInput::WindowDrag:
- blackbox->grabButton(mit->button, mit->state, frame.window, True,
- ButtonMotionMask, GrabModeAsync, GrabModeAsync,
- frame.window, None);
- default:
- break;
- }
- }
-}
-
-
-void BlackboxWindow::ungrabButtons(void) {
- const BInput::MouseBindingList &mbindings = input->getMouseBindings();
-
- BInput::MouseBindingList::const_iterator mit = mbindings.begin();
- const BInput::MouseBindingList::const_iterator mend = mbindings.end();
- for (; mit != mend; ++mit) {
- switch (mit->event) {
- case BInput::WindowClientPress:
- blackbox->ungrabButton(mit->button, mit->state, frame.plate);
- break;
- case BInput::WindowDrag:
- blackbox->ungrabButton(mit->button, mit->state, frame.window);
- default:
- break;
- }
- }
-}
+void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) {
+#ifdef DEBUG
+ fprintf(stderr, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
+ client.window);
+#endif
+ if (frame.maximize_button == be->window && be->button <= 3) {
+ redrawMaximizeButton(True);
+ } else if (be->button == 1 || (be->button == 3 && be->state == mod_mask)) {
+ if (! flags.focused)
+ setInputFocus();
-void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) {
- if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
-
- if (frame.maximize_button == be->window) {
- if (input->hasAction(be->button, be->state, BInput::MaximizeButtonClick))
- redrawMaximizeButton(True);
- } else if (frame.iconify_button == be->window) {
- if (input->hasAction(be->button, be->state, BInput::IconifyButtonClick))
+ if (frame.iconify_button == be->window) {
redrawIconifyButton(True);
- } else if (frame.close_button == be->window) {
- if (input->hasAction(be->button, be->state, BInput::CloseButtonClick))
+ } else if (frame.close_button == be->window) {
redrawCloseButton(True);
- } else if (frame.title == be->window || frame.label == be->window) {
- if (be->time - lastButtonPressTime <= blackbox->getDoubleClickInterval()) {
- lastButtonPressTime = 0;
- input->doAction(this, be->button, be->state,
- BInput::WindowTitleDoublePress);
- } else {
- lastButtonPressTime = be->time;
- input->doAction(this, be->button, be->state,
- BInput::WindowTitlePress);
- }
- } else if (frame.plate == be->window) {
- input->doAction(this, be->button, be->state, BInput::WindowClientPress);
- // buttons on the client window are grabbed in Sync mode, so we need to let
- // events back through again
- XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time);
- } else if (frame.window == be->window || frame.handle == be->window) {
- input->doAction(this, be->button, be->state, BInput::WindowFramePress);
- }
-}
-
-
-void BlackboxWindow::showWindowMenu(int root_x, int root_y) {
- if (! windowmenu || windowmenu->isVisible())
- return;
-
- root_x -= windowmenu->getWidth() / 2;
- root_y -= windowmenu->getHeight() / 2;
+ } else if (frame.plate == be->window) {
+ if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
- // snap the window menu into a corner/side if necessary
- int left_edge, right_edge, top_edge, bottom_edge;
-
- left_edge = frame.rect.x();
- right_edge = frame.rect.right() - windowmenu->getWidth() - frame.border_w - 1;
- if (decorations & Decor_Titlebar)
- top_edge = frame.rect.y() + frame.title_h + frame.border_w;
- else
- top_edge = frame.rect.y() + frame.border_w;
- if (decorations & Decor_Handle)
- bottom_edge = frame.rect.bottom() - frame.handle_h - (frame.border_w * 3) -
- windowmenu->getHeight();
- else
- bottom_edge = frame.rect.bottom() - windowmenu->getHeight() -
- frame.border_w + 1;
-
- if (root_x > right_edge)
- root_x = right_edge;
- if (root_x < left_edge)
- root_x = left_edge;
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
- if (root_y > bottom_edge)
- root_y = bottom_edge;
- if (root_y < top_edge)
- root_y = top_edge;
+ XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time);
+ } else {
+ if (frame.title == be->window || frame.label == be->window) {
+ if (((be->time - lastButtonPressTime) <=
+ blackbox->getDoubleClickInterval()) ||
+ (be->state == ControlMask)) {
+ lastButtonPressTime = 0;
+ shade();
+ } else {
+ lastButtonPressTime = be->time;
+ }
+ }
+ if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
- windowmenu->move(root_x, root_y);
- windowmenu->show();
- XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID());
- XRaiseWindow(blackbox->getXDisplay(),
- windowmenu->getSendToMenu()->getWindowID());
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
+ }
+ } else if (be->button == 2 && (be->window != frame.iconify_button) &&
+ (be->window != frame.close_button)) {
+ screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
+ } else if (windowmenu && be->button == 3 &&
+ (frame.title == be->window || frame.label == be->window ||
+ frame.handle == be->window || frame.window == be->window)) {
+ if (windowmenu->isVisible()) {
+ windowmenu->hide();
+ } else {
+ int mx = be->x_root - windowmenu->getWidth() / 2,
+ my = be->y_root - windowmenu->getHeight() / 2;
+
+ // snap the window menu into a corner/side if necessary
+ int left_edge, right_edge, top_edge, bottom_edge;
+
+ /*
+ the " + (frame.border_w * 2) - 1" bits are to get the proper width
+ and height of the menu, as the sizes returned by it do not include
+ the borders.
+ */
+ left_edge = frame.rect.x();
+ right_edge = frame.rect.right() -
+ (windowmenu->getWidth() + (frame.border_w * 2) - 1);
+ top_edge = client.rect.top() - (frame.border_w + frame.mwm_border_w);
+ bottom_edge = client.rect.bottom() -
+ (windowmenu->getHeight() + (frame.border_w * 2) - 1) +
+ (frame.border_w + frame.mwm_border_w);
+
+ if (mx < left_edge)
+ mx = left_edge;
+ if (mx > right_edge)
+ mx = right_edge;
+ if (my < top_edge)
+ my = top_edge;
+ if (my > bottom_edge)
+ my = bottom_edge;
+
+ windowmenu->move(mx, my);
+ windowmenu->show();
+ XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID());
+ XRaiseWindow(blackbox->getXDisplay(),
+ windowmenu->getSendToMenu()->getWindowID());
+ }
+ // mouse wheel up
+ } else if (be->button == 4) {
+ if ((be->window == frame.label ||
+ be->window == frame.title ||
+ be->window == frame.maximize_button ||
+ be->window == frame.iconify_button ||
+ be->window == frame.close_button) &&
+ ! flags.shaded)
+ shade();
+ // mouse wheel down
+ } else if (be->button == 5) {
+ if ((be->window == frame.label ||
+ be->window == frame.title ||
+ be->window == frame.maximize_button ||
+ be->window == frame.iconify_button ||
+ be->window == frame.close_button) &&
+ flags.shaded)
+ shade();
+ }
}
void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) {
- // get the proper state, without the button that was released
- unsigned int state;
- switch (re->button) {
- case Button1:
- state = re->state & ~Button1Mask;
- break;
- case Button2:
- state = re->state & ~Button2Mask;
- break;
- case Button3:
- state = re->state & ~Button3Mask;
- break;
- case Button4:
- state = re->state & ~Button4Mask;
- break;
- case Button5:
- state = re->state & ~Button5Mask;
- break;
- default:
- assert(false); // unhandled button
- }
+#ifdef DEBUG
+ fprintf(stderr, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
+ client.window);
+#endif
- if (frame.maximize_button == re->window) {
- if ((re->x < 0 || re->x >= static_cast<signed>(frame.button_w)) ||
- (re->y < 0 || re->y >= static_cast<signed>(frame.button_w)) ||
- ! input->doAction(this, re->button, state,
- BInput::MaximizeButtonClick))
+ if (re->window == frame.maximize_button &&
+ re->button >= 1 && re->button <= 3) {
+ if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
+ (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
+ maximize(re->button);
+ } else {
redrawMaximizeButton(flags.maximized);
- } else if (frame.iconify_button == re->window) {
- if ((re->x < 0 || re->x >= static_cast<signed>(frame.button_w)) ||
- (re->y < 0 || re->y >= static_cast<signed>(frame.button_w)) ||
- ! input->doAction(this, re->button, state,
- BInput::IconifyButtonClick))
+ }
+ } else if (re->window == frame.iconify_button && re->button == 1) {
+ if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
+ (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
+ iconify();
+ } else {
redrawIconifyButton(False);
- } else if (frame.close_button == re->window) {
- if (! ((re->x < 0 || re->x >= static_cast<signed>(frame.button_w)) ||
- (re->y < 0 || re->y >= static_cast<signed>(frame.button_w))))
- input->doAction(this, re->button, state, BInput::CloseButtonClick);
- redrawCloseButton(False);
+ }
+ } else if (re->window == frame.close_button & re->button == 1) {
+ if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
+ (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w)))
+ close();
+ redrawCloseButton(False);
} else if (flags.moving) {
endMove();
} else if (flags.resizing) {
endResize();
+ } else if (re->window == frame.window) {
+ if (re->button == 2 && re->state == mod_mask)
+ XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
}
}
-void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) {
- // get the button that is being used
- // get the proper state, without the button that is being used
- unsigned int button;
- unsigned int state;
- if (me->state & Button1Mask) {
- button = Button1;
- state = me->state & ~Button1Mask;
- } else if (me->state & Button2Mask) {
- button = Button2;
- state = me->state & ~Button2Mask;
- } else if (me->state & Button3Mask) {
- button = Button3;
- state = me->state & ~Button3Mask;
- } else if (me->state & Button4Mask) {
- button = Button4;
- state = me->state & ~Button4Mask;
- } else if (me->state & Button5Mask) {
- button = Button5;
- state = me->state & ~Button5Mask;
- } else {
- return;
- }
-
- if (flags.moving) {
- doMove(me->x_root, me->y_root);
- } else if (flags.resizing) {
- doResize(me->x_root, me->y_root);
- } else {
- if (frame.title == me->window || frame.label == me->window)
- input->doAction(this, button, state, BInput::WindowTitleDrag);
- else if (frame.handle == me->window)
- input->doAction(this, button, state, BInput::WindowHandleDrag);
- else if (frame.left_grip == me->window)
- input->doAction(this, button, state, BInput::WindowLeftGripDrag);
- else if (frame.right_grip == me->window)
- input->doAction(this, button, state, BInput::WindowRightGripDrag);
- else if (frame.window == me->window)
- input->doAction(this, button, state, BInput::WindowDrag);
- }
-}
-
void BlackboxWindow::beginMove(int x_root, int y_root) {
assert(! (flags.resizing || flags.moving));
dx -= frame.border_w;
dy -= frame.border_w;
- const int snap_distance = screen->getEdgeSnapThreshold();
+ doWindowSnapping(dx, dy);
+
+ if (screen->doOpaqueMove()) {
+ if (screen->doWorkspaceWarping())
+ doWorkspaceWarping(x_root, y_root, dx);
+
+ configure(dx, dy, frame.rect.width(), frame.rect.height());
+ } else {
+ XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
+ screen->getOpGC(),
+ frame.changing.x(),
+ frame.changing.y(),
+ frame.changing.width() - 1,
+ frame.changing.height() - 1);
+
+ if (screen->doWorkspaceWarping())
+ doWorkspaceWarping(x_root, y_root, dx);
+
+ frame.changing.setPos(dx, dy);
+
+ XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
+ screen->getOpGC(),
+ frame.changing.x(),
+ frame.changing.y(),
+ frame.changing.width() - 1,
+ frame.changing.height() - 1);
+ }
+
+ screen->showPosition(dx, dy);
+}
+
+
+void BlackboxWindow::doWorkspaceWarping(int x_root, int y_root, int &dx) {
+ // workspace warping
+ bool warp = False;
+ unsigned int dest = screen->getCurrentWorkspaceID();
+ if (x_root <= 0) {
+ warp = True;
+
+ if (dest > 0) dest--;
+ else dest = screen->getNumberOfWorkspaces() - 1;
+
+ } else if (x_root >= screen->getRect().right()) {
+ warp = True;
+
+ if (dest < screen->getNumberOfWorkspaces() - 1) dest++;
+ else dest = 0;
+ }
+ if (! warp)
+ return;
+
+ bool focus = flags.focused; // had focus while moving?
+
+ int dest_x = x_root;
+ if (x_root <= 0) {
+ dest_x += screen->getRect().width() - 1;
+ dx += screen->getRect().width() - 1;
+ } else {
+ dest_x -= screen->getRect().width() - 1;
+ dx -= screen->getRect().width() - 1;
+ }
+
+ if (! flags.stuck)
+ screen->reassociateWindow(this, dest, False);
+ screen->changeWorkspaceID(dest);
+
+ if (screen->doOpaqueMove())
+ XGrabServer(blackbox->getXDisplay());
+
+ XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
+ XWarpPointer(blackbox->getXDisplay(), None,
+ screen->getRootWindow(), 0, 0, 0, 0,
+ dest_x, y_root);
+ XGrabPointer(blackbox->getXDisplay(), frame.window, False,
+ PointerMotionMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync,
+ None, blackbox->getMoveCursor(), CurrentTime);
+
+ if (screen->doOpaqueMove())
+ XUngrabServer(blackbox->getXDisplay());
- if (snap_distance) {
- // window corners
- const int wleft = dx,
- wright = dx + frame.rect.width() - 1,
- wtop = dy,
- wbottom = dy + frame.rect.height() - 1;
+ if (focus)
+ setInputFocus();
- if (screen->getWindowToWindowSnap()) {
- Workspace *w = screen->getWorkspace(getWorkspaceNumber());
- assert(w);
+}
+
+
+void BlackboxWindow::doWindowSnapping(int &dx, int &dy) {
+ // how much resistance to edges to provide
+ const int resistance_size = screen->getResistanceSize();
+
+ // how far away to snap
+ const int snap_distance = screen->getSnapThreshold();
+
+ // how to snap windows
+ const int snap_to_windows = screen->getWindowToWindowSnap();
+ const int snap_to_edges = screen->getWindowToEdgeSnap();
+ // the amount of space away from the edge to provide resistance/snap
+ const int snap_offset = screen->getSnapOffset();
+
+ // find the geomeetery where the moving window currently is
+ const Rect &moving = screen->doOpaqueMove() ? frame.rect : frame.changing;
- // try snap to another window
- for (unsigned int i = 0, c = w->getCount(); i < c; ++i) {
- BlackboxWindow *snapwin = w->getWindow(i);
- if (snapwin == this)
- continue; // don't snap to self
+ // window corners
+ const int wleft = dx,
+ wright = dx + frame.rect.width() - 1,
+ wtop = dy,
+ wbottom = dy + frame.rect.height() - 1;
- bool snapped = False;
-
- const Rect &winrect = snapwin->frameRect();
- int dleft = std::abs(wright - winrect.left()),
- dright = std::abs(wleft - winrect.right()),
- dtop = std::abs(wbottom - winrect.top()),
- dbottom = std::abs(wtop - winrect.bottom());
+ if (snap_to_windows) {
+ RectList rectlist;
- if (wtop >= (signed)(winrect.y() - frame.rect.height() + 1) &&
- wtop < (signed)(winrect.y() + winrect.height() - 1)) {
+ Workspace *w = screen->getWorkspace(getWorkspaceNumber());
+ assert(w);
+
+ // add windows on the workspace to the rect list
+ const BlackboxWindowList& stack_list = w->getStackingList();
+ BlackboxWindowList::const_iterator st_it, st_end = stack_list.end();
+ for (st_it = stack_list.begin(); st_it != st_end; ++st_it)
+ if (*st_it != this) // don't snap to ourself
+ rectlist.push_back( (*st_it)->frameRect() );
+
+ // add the toolbar and the slit to the rect list.
+ // (only if they are not hidden)
+ Toolbar *tbar = screen->getToolbar();
+ Slit *slit = screen->getSlit();
+ Rect tbar_rect, slit_rect;
+ unsigned int bwidth = screen->getBorderWidth() * 2;
+
+ if (! (screen->doHideToolbar() || tbar->isHidden())) {
+ tbar_rect.setRect(tbar->getX(), tbar->getY(), tbar->getWidth() + bwidth,
+ tbar->getHeight() + bwidth);
+ rectlist.push_back(tbar_rect);
+ }
+
+ if (! slit->isHidden()) {
+ slit_rect.setRect(slit->getX(), slit->getY(), slit->getWidth() + bwidth,
+ slit->getHeight() + bwidth);
+ rectlist.push_back(slit_rect);
+ }
+
+ RectList::const_iterator it, end = rectlist.end();
+ for (it = rectlist.begin(); it != end; ++it) {
+ bool snapped = False;
+ const Rect &winrect = *it;
+ Rect offsetrect;
+ offsetrect.setCoords(winrect.left() - snap_offset,
+ winrect.top() - snap_offset,
+ winrect.right() + snap_offset,
+ winrect.bottom() + snap_offset);
+
+ if (snap_to_windows == BScreen::WindowResistance)
+ // if the window is already over top of this snap target, then
+ // resistance is futile, so just ignore it
+ if (winrect.intersects(moving))
+ continue;
+
+ int dleft, dright, dtop, dbottom;
+
+ // if the windows are in the same plane vertically
+ if (wtop >= (signed)(winrect.y() - frame.rect.height() + 1) &&
+ wtop < (signed)(winrect.y() + winrect.height() - 1)) {
+
+ if (snap_to_windows == BScreen::WindowResistance) {
+ dleft = wright - offsetrect.left();
+ dright = offsetrect.right() - wleft;
+
+ // snap left of other window?
+ if (dleft >= 0 && dleft < resistance_size &&
+ dleft < (wright - wleft)) {
+ dx = offsetrect.left() - frame.rect.width();
+ snapped = True;
+ }
+ // snap right of other window?
+ else if (dright >= 0 && dright < resistance_size &&
+ dright < (wright - wleft)) {
+ dx = offsetrect.right() + 1;
+ snapped = True;
+ }
+ } else { // BScreen::WindowSnap
+ dleft = abs(wright - offsetrect.left());
+ dright = abs(wleft - offsetrect.right());
// snap left of other window?
if (dleft < snap_distance && dleft <= dright) {
- dx = winrect.left() - frame.rect.width();
+ dx = offsetrect.left() - frame.rect.width();
snapped = True;
}
// snap right of other window?
else if (dright < snap_distance) {
- dx = winrect.right() + 1;
+ dx = offsetrect.right() + 1;
snapped = True;
- }
+ }
+ }
- if (snapped) {
- if (screen->getWindowCornerSnap()) {
- // try corner-snap to its other sides
- dtop = std::abs(wtop - winrect.top());
- dbottom = std::abs(wbottom - winrect.bottom());
+ if (snapped) {
+ if (screen->getWindowCornerSnap()) {
+ // try corner-snap to its other sides
+ if (snap_to_windows == BScreen::WindowResistance) {
+ dtop = winrect.top() - wtop;
+ dbottom = wbottom - winrect.bottom();
+ if (dtop > 0 && dtop < resistance_size) {
+ // if we're already past the top edge, then don't provide
+ // resistance
+ if (moving.top() >= winrect.top())
+ dy = winrect.top();
+ } else if (dbottom > 0 && dbottom < resistance_size) {
+ // if we're already past the bottom edge, then don't provide
+ // resistance
+ if (moving.bottom() <= winrect.bottom())
+ dy = winrect.bottom() - frame.rect.height() + 1;
+ }
+ } else { // BScreen::WindowSnap
+ dtop = abs(wtop - winrect.top());
+ dbottom = abs(wbottom - winrect.bottom());
if (dtop < snap_distance && dtop <= dbottom)
dy = winrect.top();
else if (dbottom < snap_distance)
dy = winrect.bottom() - frame.rect.height() + 1;
}
-
- continue;
}
+
+ continue;
}
+ }
- if (wleft >= (signed)(winrect.x() - frame.rect.width() + 1) &&
- wleft < (signed)(winrect.x() + winrect.width() - 1)) {
+ // if the windows are on the same plane horizontally
+ if (wleft >= (signed)(winrect.x() - frame.rect.width() + 1) &&
+ wleft < (signed)(winrect.x() + winrect.width() - 1)) {
+
+ if (snap_to_windows == BScreen::WindowResistance) {
+ dtop = wbottom - offsetrect.top();
+ dbottom = offsetrect.bottom() - wtop;
+
+ // snap top of other window?
+ if (dtop >= 0 && dtop < resistance_size && dtop < (wbottom - wtop)) {
+ dy = offsetrect.top() - frame.rect.height();
+ snapped = True;
+ }
+ // snap bottom of other window?
+ else if (dbottom >= 0 && dbottom < resistance_size &&
+ dbottom < (wbottom - wtop)) {
+ dy = offsetrect.bottom() + 1;
+ snapped = True;
+ }
+ } else { // BScreen::WindowSnap
+ dtop = abs(wbottom - offsetrect.top());
+ dbottom = abs(wtop - offsetrect.bottom());
// snap top of other window?
if (dtop < snap_distance && dtop <= dbottom) {
- dy = winrect.top() - frame.rect.height();
+ dy = offsetrect.top() - frame.rect.height();
snapped = True;
}
// snap bottom of other window?
else if (dbottom < snap_distance) {
- dy = winrect.bottom() + 1;
+ dy = offsetrect.bottom() + 1;
snapped = True;
}
- if (snapped) {
- if (screen->getWindowCornerSnap()) {
- // try corner-snap to its other sides
- dleft = std::abs(wleft - winrect.left());
- dright = std::abs(wright - winrect.right());
+ }
+
+ if (snapped) {
+ if (screen->getWindowCornerSnap()) {
+ // try corner-snap to its other sides
+ if (snap_to_windows == BScreen::WindowResistance) {
+ dleft = winrect.left() - wleft;
+ dright = wright - winrect.right();
+ if (dleft > 0 && dleft < resistance_size) {
+ // if we're already past the left edge, then don't provide
+ // resistance
+ if (moving.left() >= winrect.left())
+ dx = winrect.left();
+ } else if (dright > 0 && dright < resistance_size) {
+ // if we're already past the right edge, then don't provide
+ // resistance
+ if (moving.right() <= winrect.right())
+ dx = winrect.right() - frame.rect.width() + 1;
+ }
+ } else { // BScreen::WindowSnap
+ dleft = abs(wleft - winrect.left());
+ dright = abs(wright - winrect.right());
if (dleft < snap_distance && dleft <= dright)
dx = winrect.left();
else if (dright < snap_distance)
dx = winrect.right() - frame.rect.width() + 1;
}
-
- continue;
}
+
+ continue;
}
}
}
-
- // try snap to the screen's available area
- Rect srect = screen->availableArea();
-
- int dleft = std::abs(wleft - srect.left()),
- dright = std::abs(wright - srect.right()),
- dtop = std::abs(wtop - srect.top()),
- dbottom = std::abs(wbottom - srect.bottom());
-
- // snap left?
- if (dleft < snap_distance && dleft <= dright)
- dx = srect.left();
- // snap right?
- else if (dright < snap_distance)
- dx = srect.right() - frame.rect.width() + 1;
-
- // snap top?
- if (dtop < snap_distance && dtop <= dbottom)
- dy = srect.top();
- // snap bottom?
- else if (dbottom < snap_distance)
- dy = srect.bottom() - frame.rect.height() + 1;
-
- srect = screen->getRect(); // now get the full screen
-
- dleft = std::abs(wleft - srect.left()),
- dright = std::abs(wright - srect.right()),
- dtop = std::abs(wtop - srect.top()),
- dbottom = std::abs(wbottom - srect.bottom());
-
- // snap left?
- if (dleft < snap_distance && dleft <= dright)
- dx = srect.left();
- // snap right?
- else if (dright < snap_distance)
- dx = srect.right() - frame.rect.width() + 1;
-
- // snap top?
- if (dtop < snap_distance && dtop <= dbottom)
- dy = srect.top();
- // snap bottom?
- else if (dbottom < snap_distance)
- dy = srect.bottom() - frame.rect.height() + 1;
}
- if (screen->doOpaqueMove()) {
- configure(dx, dy, frame.rect.width(), frame.rect.height());
- } else {
- XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
- screen->getOpGC(),
- frame.changing.x(),
- frame.changing.y(),
- frame.changing.width() - 1,
- frame.changing.height() - 1);
-
- frame.changing.setPos(dx, dy);
+ if (snap_to_edges) {
+ RectList rectlist;
+
+ // snap to the screen edges (and screen boundaries for xinerama)
+#ifdef XINERAMA
+ if (screen->isXineramaActive() && blackbox->doXineramaSnapping()) {
+ rectlist.insert(rectlist.begin(),
+ screen->getXineramaAreas().begin(),
+ screen->getXineramaAreas().end());
+ } else
+#endif // XINERAMA
+ rectlist.push_back(screen->getRect());
+
+ RectList::const_iterator it, end = rectlist.end();
+ for (it = rectlist.begin(); it != end; ++it) {
+ const Rect &srect = *it;
+ Rect offsetrect;
+ offsetrect.setCoords(srect.left() + snap_offset,
+ srect.top() + snap_offset,
+ srect.right() - snap_offset,
+ srect.bottom() - snap_offset);
+
+ if (snap_to_edges == BScreen::WindowResistance) {
+ // if we're not in the rectangle then don't snap to it.
+ if (! srect.contains(moving))
+ continue;
+ } else { // BScreen::WindowSnap
+ // if we're not in the rectangle then don't snap to it.
+ if (! srect.intersects(Rect(wleft, wtop, frame.rect.width(),
+ frame.rect.height())))
+ continue;
+ }
- XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
- screen->getOpGC(),
- frame.changing.x(),
- frame.changing.y(),
- frame.changing.width() - 1,
- frame.changing.height() - 1);
+ if (snap_to_edges == BScreen::WindowResistance) {
+ int dleft = offsetrect.left() - wleft,
+ dright = wright - offsetrect.right(),
+ dtop = offsetrect.top() - wtop,
+ dbottom = wbottom - offsetrect.bottom();
+
+ // snap left?
+ if (dleft > 0 && dleft < resistance_size)
+ dx = offsetrect.left();
+ // snap right?
+ else if (dright > 0 && dright < resistance_size)
+ dx = offsetrect.right() - frame.rect.width() + 1;
+
+ // snap top?
+ if (dtop > 0 && dtop < resistance_size)
+ dy = offsetrect.top();
+ // snap bottom?
+ else if (dbottom > 0 && dbottom < resistance_size)
+ dy = offsetrect.bottom() - frame.rect.height() + 1;
+ } else { // BScreen::WindowSnap
+ int dleft = abs(wleft - offsetrect.left()),
+ dright = abs(wright - offsetrect.right()),
+ dtop = abs(wtop - offsetrect.top()),
+ dbottom = abs(wbottom - offsetrect.bottom());
+
+ // snap left?
+ if (dleft < snap_distance && dleft <= dright)
+ dx = offsetrect.left();
+ // snap right?
+ else if (dright < snap_distance)
+ dx = offsetrect.right() - frame.rect.width() + 1;
+
+ // snap top?
+ if (dtop < snap_distance && dtop <= dbottom)
+ dy = offsetrect.top();
+ // snap bottom?
+ else if (dbottom < snap_distance)
+ dy = offsetrect.bottom() - frame.rect.height() + 1;
+ }
+ }
}
-
- screen->showPosition(dx, dy);
}
default:
assert(false); // unhandled Corner
+ return; // unreachable, for the compiler
}
XGrabServer(blackbox->getXDisplay());
flags.resizing = True;
blackbox->setChangingWindow(this);
- int gw, gh;
+ unsigned int gw, gh;
frame.changing = frame.rect;
constrain(anchor, &gw, &gh);
screen->getOpGC(), frame.changing.x(), frame.changing.y(),
frame.changing.width() - 1, frame.changing.height() - 1);
- int gw, gh;
+ unsigned int gw, gh;
Corner anchor;
switch (resize_dir) {
- case BottomLeft:
- anchor = TopRight;
- frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
- frame.rect.height() + (y_root - frame.grab_y));
- break;
- case BottomRight:
- anchor = TopLeft;
- frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
- frame.rect.height() + (y_root - frame.grab_y));
- break;
- case TopLeft:
- anchor = BottomRight;
- frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
- frame.rect.height() - (y_root - frame.grab_y));
- break;
- case TopRight:
- anchor = BottomLeft;
- frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
- frame.rect.height() - (y_root - frame.grab_y));
- break;
+ case BottomLeft:
+ anchor = TopRight;
+ frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
+ frame.rect.height() + (y_root - frame.grab_y));
+ break;
+ case BottomRight:
+ anchor = TopLeft;
+ frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
+ frame.rect.height() + (y_root - frame.grab_y));
+ break;
+ case TopLeft:
+ anchor = BottomRight;
+ frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
+ frame.rect.height() - (y_root - frame.grab_y));
+ break;
+ case TopRight:
+ anchor = BottomLeft;
+ frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
+ frame.rect.height() - (y_root - frame.grab_y));
+ break;
- default:
- assert(false); // unhandled Corner
+ default:
+ assert(false); // unhandled Corner
+ return; // unreachable, for the compiler
}
constrain(anchor, &gw, &gh);
}
+void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) {
+#if 0
+ fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
+ client.window);
+#endif
+
+ if (flags.moving) {
+ doMove(me->x_root, me->y_root);
+ } else if (flags.resizing) {
+ doResize(me->x_root, me->y_root);
+ } else {
+ if ((functions & Func_Move) &&
+ (me->state & Button1Mask) &&
+ (frame.title == me->window || frame.label == me->window ||
+ frame.handle == me->window || frame.window == me->window)) {
+ beginMove(me->x_root, me->y_root);
+ } else if ((functions & Func_Resize) &&
+ ((me->state & Button1Mask) && (me->window == frame.right_grip ||
+ me->window == frame.left_grip)) ||
+ ((me->state & Button3Mask) && (me->state & mod_mask) &&
+ (frame.title == me->window || frame.label == me->window ||
+ frame.handle == me->window || frame.window == me->window))) {
+ unsigned int zones = screen->getResizeZones();
+ Corner corner;
+
+ if (me->window == frame.left_grip) {
+ corner = BottomLeft;
+ } else if (me->window == frame.right_grip || zones == 1) {
+ corner = BottomRight;
+ } else {
+ bool top;
+ bool left = (me->x_root - frame.rect.x() <=
+ static_cast<signed>(frame.rect.width() / 2));
+ if (zones == 2)
+ top = False;
+ else // (zones == 4)
+ top = (me->y_root - frame.rect.y() <=
+ static_cast<signed>(frame.rect.height() / 2));
+ corner = (top ? (left ? TopLeft : TopRight) :
+ (left ? BottomLeft : BottomRight));
+ }
+
+ beginResize(me->x_root, me->y_root, corner);
+ }
+ }
+}
+
+
+void BlackboxWindow::enterNotifyEvent(const XCrossingEvent* ce) {
+ if (! (screen->isSloppyFocus() && isVisible() && isNormal()))
+ return;
+
+ XEvent e;
+ bool leave = False, inferior = False;
+
+ while (XCheckTypedWindowEvent(blackbox->getXDisplay(), ce->window,
+ LeaveNotify, &e)) {
+ if (e.type == LeaveNotify && e.xcrossing.mode == NotifyNormal) {
+ leave = True;
+ inferior = (e.xcrossing.detail == NotifyInferior);
+ }
+ }
+
+ if ((! leave || inferior) && ! isFocused()) {
+ bool success = setInputFocus();
+ if (success) // if focus succeeded install the colormap
+ installColormap(True); // XXX: shouldnt we honour no install?
+ }
+
+ if (screen->doAutoRaise())
+ timer->start();
+}
+
+
+void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent*) {
+ if (! (screen->isSloppyFocus() && screen->doAutoRaise() && isNormal()))
+ return;
+
+ installColormap(False);
+
+ if (timer->isTiming())
+ timer->stop();
+}
+
+
#ifdef SHAPE
void BlackboxWindow::shapeEvent(XShapeEvent *) {
if (blackbox->hasShapeExtensions() && flags.shaped) {
XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask);
+ // do not leave a shaded window as an icon unless it was an icon
+ if (flags.shaded && ! flags.iconic)
+ setState(NormalState);
+
+ // erase the netwm stuff that we read when a window maps, so that it
+ // doesn't persist between mappings.
+ // (these are the ones read in getNetWMFlags().)
+ xatom->eraseValue(client.window, XAtom::net_wm_desktop);
+ xatom->eraseValue(client.window, XAtom::net_wm_state);
+
restoreGravity(client.rect);
XUnmapWindow(blackbox->getXDisplay(), frame.window);
// timer for autoraise
void BlackboxWindow::timeout(void) {
- raise();
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
}
-void BlackboxWindow::changeBlackboxHints(BlackboxHints *net) {
+void BlackboxWindow::changeBlackboxHints(const BlackboxHints *net) {
if ((net->flags & AttribShaded) &&
((blackbox_attrib.attrib & AttribShaded) !=
(net->attrib & AttribShaded)))
withdraw();
} else {
show();
- raise();
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
}
}
if (net->flags & AttribDecoration) {
switch (net->decoration) {
case DecorNone:
- // clear all decorations except close
- decorations &= Decor_Close;
-
+ enableDecor(False);
break;
default:
case DecorNormal:
- decorations |= Decor_Titlebar | Decor_Border | Decor_Iconify;
-
- decorations = ((functions & Func_Resize) && !isTransient() ?
- decorations | Decor_Handle :
- decorations &= ~Decor_Handle);
- decorations = (functions & Func_Maximize ?
- decorations | Decor_Maximize :
- decorations &= ~Decor_Maximize);
-
- break;
-
case DecorTiny:
- decorations |= Decor_Titlebar | Decor_Iconify;
- decorations &= ~(Decor_Border | Decor_Handle);
-
- decorations = (functions & Func_Maximize ?
- decorations | Decor_Maximize :
- decorations &= ~Decor_Maximize);
-
- break;
-
case DecorTool:
- decorations |= Decor_Titlebar;
- decorations &= ~(Decor_Iconify | Decor_Border);
-
- decorations = ((functions & Func_Resize) && !isTransient() ?
- decorations | Decor_Handle :
- decorations &= ~Decor_Handle);
- decorations = (functions & Func_Maximize ?
- decorations | Decor_Maximize :
- decorations &= ~Decor_Maximize);
-
+ enableDecor(True);
break;
}
-
- // we can not be shaded if we lack a titlebar
- if (flags.shaded && ! (decorations & Decor_Titlebar))
- shade();
-
- if (flags.visible && frame.window) {
- XMapSubwindows(blackbox->getXDisplay(), frame.window);
- XMapWindow(blackbox->getXDisplay(), frame.window);
- }
-
- reconfigure();
- setState(current_state);
}
}
// the height of the titlebar is based upon the height of the font being
// used to display the window's title
WindowStyle *style = screen->getWindowStyle();
- if (i18n.multibyte())
- frame.title_h = (style->fontset_extents->max_ink_extent.height +
- (frame.bevel_w * 2) + 2);
- else
- frame.title_h = (style->font->ascent + style->font->descent +
- (frame.bevel_w * 2) + 2);
+ frame.title_h = style->font->height() + (frame.bevel_w * 2) + 2;
frame.label_h = frame.title_h - (frame.bevel_w * 2);
frame.button_w = (frame.label_h - 2);
* The logical width and height are placed into pw and ph, if they
* are non-zero. Logical size refers to the users perception of
* the window size (for example an xterm resizes in cells, not in pixels).
+ * pw and ph are then used to display the geometry during window moves, resize,
+ * etc.
*
* The physical geometry is placed into frame.changing_{x,y,width,height}.
* Physical geometry refers to the geometry of the window in pixels.
*/
-void BlackboxWindow::constrain(Corner anchor, int *pw, int *ph) {
+void BlackboxWindow::constrain(Corner anchor,
+ unsigned int *pw, unsigned int *ph) {
// frame.changing represents the requested frame size, we need to
// strip the frame margin off and constrain the client size
frame.changing.setCoords(frame.changing.left() + frame.margin.left,
frame.changing.right() - frame.margin.right,
frame.changing.bottom() - frame.margin.bottom);
- int dw = frame.changing.width(), dh = frame.changing.height(),
+ unsigned int dw = frame.changing.width(), dh = frame.changing.height(),
base_width = (client.base_width) ? client.base_width : client.min_width,
base_height = (client.base_height) ? client.base_height :
client.min_height;
// constrain
- if (dw < static_cast<signed>(client.min_width)) dw = client.min_width;
- if (dh < static_cast<signed>(client.min_height)) dh = client.min_height;
- if (dw > static_cast<signed>(client.max_width)) dw = client.max_width;
- if (dh > static_cast<signed>(client.max_height)) dh = client.max_height;
-
- dw -= base_width;
- dw /= client.width_inc;
- dh -= base_height;
- dh /= client.height_inc;
-
- if (pw) {
- if (client.width_inc == 1)
- *pw = dw + base_width;
- else
- *pw = dw;
+ if (dw < client.min_width) dw = client.min_width;
+ if (dh < client.min_height) dh = client.min_height;
+ if (dw > client.max_width) dw = client.max_width;
+ if (dh > client.max_height) dh = client.max_height;
+
+ assert(dw >= base_width && dh >= base_height);
+
+ if (client.width_inc > 1) {
+ dw -= base_width;
+ dw /= client.width_inc;
}
- if (ph) {
- if (client.height_inc == 1)
- *ph = dh + base_height;
- else
- *ph = dh;
+ if (client.height_inc > 1) {
+ dh -= base_height;
+ dh /= client.height_inc;
}
- dw *= client.width_inc;
- dw += base_width;
- dh *= client.height_inc;
- dh += base_height;
+ if (pw)
+ *pw = dw;
+
+ if (ph)
+ *ph = dh;
+
+ if (client.width_inc > 1) {
+ dw *= client.width_inc;
+ dw += base_width;
+ }
+ if (client.height_inc > 1) {
+ dh *= client.height_inc;
+ dh += base_height;
+ }
frame.changing.setSize(dw, dh);
}
-int WindowStyle::doJustify(const char *text, int &start_pos,
- unsigned int max_length, unsigned int modifier,
- bool multibyte) const {
- size_t text_len = strlen(text);
+void WindowStyle::doJustify(const std::string &text, int &start_pos,
+ unsigned int max_length,
+ unsigned int modifier) const {
+ size_t text_len = text.size();
unsigned int length;
do {
- if (multibyte) {
- XRectangle ink, logical;
- XmbTextExtents(fontset, text, text_len, &ink, &logical);
- length = logical.width;
- } else {
- length = XTextWidth(font, text, text_len);
- }
- length += modifier;
+ length = font->measureString(string(text, 0, text_len)) + modifier;
} while (length > max_length && text_len-- > 0);
switch (justify) {
default:
break;
}
-
- return text_len;
}
return;
}
- /*
- watch for destroy notify on the group window (in addition to
- any other events we are looking for)
-
- since some managed windows can also be window group controllers,
- we need to make sure that we don't clobber the event mask for the
- managed window
- */
XSelectInput(blackbox->getXDisplay(), group,
- wattrib.your_event_mask | StructureNotifyMask);
+ PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
blackbox->saveGroupSearch(group, this);
}
BlackboxWindow *ret = blackbox->getFocusedWindow();
// does the focus window match (or any transient_fors)?
- while (ret) {
- if (ret->getScreen() == screen && ret->getGroupWindow() == group) {
- if (ret->isTransient() && allow_transients) break;
- else if (! ret->isTransient()) break;
- }
-
- ret = ret->getTransientFor();
+ for (; ret; ret = ret->getTransientFor()) {
+ if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
+ (! ret->isTransient() || allow_transients))
+ break;
}
if (ret) return ret;
BlackboxWindowList::const_iterator it, end = windowList.end();
for (it = windowList.begin(); it != end; ++it) {
ret = *it;
- if (ret->getScreen() == screen && ret->getGroupWindow() == group) {
- if (ret->isTransient() && allow_transients) break;
- else if (! ret->isTransient()) break;
- }
+ if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
+ (! ret->isTransient() || allow_transients))
+ break;
}
return ret;