using std::string;
using std::abs;
-// change this to change what modifier keys openbox uses for mouse bindings
-// for example: Mod1Mask | ControlMask
-// or: ControlMask| ShiftMask
-const unsigned int ModMask = Mod1Mask;
-
/*
* Initializes the class with default values/the window's set initial values.
*/
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.border_w = 1;
frame.window = frame.plate = frame.title = frame.handle = None;
- frame.close_button = frame.iconify_button = frame.maximize_button = None;
+ frame.close_button = frame.iconify_button = frame.maximize_button =
+ frame.stick_button = None;
frame.right_grip = frame.left_grip = None;
frame.ulabel_pixel = frame.flabel_pixel = frame.utitle_pixel =
frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None;
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.normal_hint_flags = 0;
client.window_group = None;
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.
*/
timer = new BTimer(blackbox, this);
timer->setTimeout(blackbox->getAutoRaiseDelay());
- windowmenu = new Windowmenu(this);
-
// get size, aspect, minimum/maximum size and other hints set by the
// client
- if (! getBlackboxHints()) {
- getMWMHints();
+ if (! getBlackboxHints())
getNetWMHints();
- }
getWMProtocols();
getWMHints();
blackbox->saveWindowSearch(frame.window, this);
- frame.plate = createChildWindow(frame.window);
+ frame.plate = createChildWindow(frame.window, ExposureMask);
blackbox->saveWindowSearch(frame.plate, this);
// determine if this is a transient window
// 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:
- case Type_Dock:
- case Type_Menu:
- case Type_Toolbar:
- case Type_Utility:
- case Type_Splash:
- // none of these windows are decorated or manipulated by the window manager
- decorations = 0;
- functions = 0;
- blackbox_attrib.workspace = 0; // we do need to belong to a workspace
- flags.stuck = True; // we show up on all workspaces
- 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_Dialog:
- // dialogs cannot be maximized, and don't display a handle
- decorations &= ~(Decor_Maximize | Decor_Handle);
- functions &= ~Func_Maximize;
- break;
+ case Type_Toolbar:
+ case Type_Utility:
+ // these windows get less functionality
+ functions &= ~(Func_Maximize | Func_Resize | Func_Iconify);
+ break;
- case Type_Normal:
- // normal windows retain all of the possible decorations and functionality
- 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;
+ }
+ } else {
+ getMWMHints();
}
- setAllowedActions();
-
// 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);
}
+ setAllowedActions();
+
+ setupDecor();
+
if (decorations & Decor_Titlebar)
createTitlebar();
screen->addStrut(&client.strut);
updateStrut();
-#ifdef SHAPE
- if (blackbox->hasShapeExtensions() && flags.shaped)
- configureShape();
-#endif // SHAPE
-
- // get the window's title before adding it to the workspace
- getWMName();
- getWMIconName();
-
- if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
- screen->getCurrentWorkspace()->addWindow(this, place_window);
- else
- screen->getWorkspace(blackbox_attrib.workspace)->
- addWindow(this, place_window);
-
/*
the server needs to be grabbed here to prevent client's from sending
events while we are in the process of configuring their window.
blackbox->saveWindowSearch(client.window, this);
+ if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
+ screen->getCurrentWorkspace()->addWindow(this, place_window);
+ else
+ screen->getWorkspace(blackbox_attrib.workspace)->
+ addWindow(this, place_window);
+
if (! place_window) {
// don't need to call configure if we are letting the workspace
// place the window
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();
if (flags.maximized && (functions & Func_Maximize))
remaximize();
+
+ // 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.background_pixmap = None;
attrib_create.colormap = screen->getColormap();
attrib_create.override_redirect = True;
- attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
- ButtonMotionMask | EnterWindowMask;
+ attrib_create.event_mask = EnterWindowMask | LeaveWindowMask;
return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(),
0, 0, 1, 1, frame.border_w, screen->getDepth(),
* Creates a child window, and optionally associates a given cursor with
* the new window.
*/
-Window BlackboxWindow::createChildWindow(Window parent, Cursor cursor) {
+Window BlackboxWindow::createChildWindow(Window parent,
+ unsigned long event_mask,
+ Cursor cursor) {
XSetWindowAttributes attrib_create;
unsigned long create_mask = CWBackPixmap | CWBorderPixel |
CWEventMask;
attrib_create.background_pixmap = None;
- attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
- ButtonMotionMask | ExposureMask;
+ attrib_create.event_mask = event_mask;
if (cursor) {
create_mask |= CWCursor;
void BlackboxWindow::associateClientWindow(void) {
XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, 0);
+ getWMName();
+ getWMIconName();
XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeInsert);
}
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::createHandle(void) {
- frame.handle = createChildWindow(frame.window);
+ frame.handle = createChildWindow(frame.window,
+ ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | ExposureMask);
blackbox->saveWindowSearch(frame.handle, this);
frame.left_grip =
- createChildWindow(frame.handle, blackbox->getLowerLeftAngleCursor());
+ createChildWindow(frame.handle,
+ ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | ExposureMask,
+ blackbox->getLowerLeftAngleCursor());
blackbox->saveWindowSearch(frame.left_grip, this);
frame.right_grip =
- createChildWindow(frame.handle, blackbox->getLowerRightAngleCursor());
+ createChildWindow(frame.handle,
+ ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | ExposureMask,
+ blackbox->getLowerRightAngleCursor());
blackbox->saveWindowSearch(frame.right_grip, this);
}
void BlackboxWindow::createTitlebar(void) {
- frame.title = createChildWindow(frame.window);
- frame.label = createChildWindow(frame.title);
+ frame.title = createChildWindow(frame.window,
+ ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | ExposureMask);
+ frame.label = createChildWindow(frame.title,
+ ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | ExposureMask);
blackbox->saveWindowSearch(frame.title, this);
blackbox->saveWindowSearch(frame.label, this);
if (frame.maximize_button)
destroyMaximizeButton();
+ if (frame.stick_button)
+ destroyStickyButton();
+
if (frame.ftitle)
screen->getImageControl()->removeImage(frame.ftitle);
void BlackboxWindow::createCloseButton(void) {
if (frame.title != None) {
- frame.close_button = createChildWindow(frame.title);
+ frame.close_button = createChildWindow(frame.title,
+ ButtonPressMask |
+ ButtonReleaseMask |
+ ButtonMotionMask | ExposureMask);
blackbox->saveWindowSearch(frame.close_button, this);
}
}
void BlackboxWindow::createIconifyButton(void) {
if (frame.title != None) {
- frame.iconify_button = createChildWindow(frame.title);
+ frame.iconify_button = createChildWindow(frame.title,
+ ButtonPressMask |
+ ButtonReleaseMask |
+ ButtonMotionMask | ExposureMask);
blackbox->saveWindowSearch(frame.iconify_button, this);
}
}
void BlackboxWindow::createMaximizeButton(void) {
if (frame.title != None) {
- frame.maximize_button = createChildWindow(frame.title);
+ frame.maximize_button = createChildWindow(frame.title,
+ ButtonPressMask |
+ ButtonReleaseMask |
+ ButtonMotionMask | ExposureMask);
blackbox->saveWindowSearch(frame.maximize_button, this);
}
}
frame.maximize_button = None;
}
+void BlackboxWindow::createStickyButton(void) {
+ if (frame.title != None) {
+ frame.stick_button = createChildWindow(frame.title,
+ ButtonPressMask |
+ ButtonReleaseMask |
+ ButtonMotionMask | ExposureMask);
+ blackbox->saveWindowSearch(frame.stick_button, this);
+ }
+}
+
+void BlackboxWindow::destroyStickyButton(void) {
+ blackbox->removeWindowSearch(frame.stick_button);
+ XDestroyWindow(blackbox->getXDisplay(), frame.stick_button);
+ frame.stick_button = None;
+}
void BlackboxWindow::positionButtons(bool redecorate_label) {
string layout = blackbox->getTitlebarLayout();
string parsed;
- bool hasclose, hasiconify, hasmaximize, haslabel;
- hasclose = hasiconify = hasmaximize = haslabel = false;
+ bool hasclose, hasiconify, hasmaximize, haslabel, hasstick;
+ hasclose = hasiconify = hasmaximize = haslabel = hasstick = false;
string::const_iterator it, end;
for (it = layout.begin(), end = layout.end(); it != end; ++it) {
parsed += *it;
}
break;
+ case 'S':
+ if (!hasstick) {
+ hasstick = true;
+ parsed += *it;
+ }
+ break;
case 'M':
if (! hasmaximize && (decorations & Decor_Maximize)) {
hasmaximize = true;
haslabel = true;
parsed += *it;
}
+ break;
}
}
+
if (! hasclose && frame.close_button)
destroyCloseButton();
if (! hasiconify && frame.iconify_button)
destroyIconifyButton();
if (! hasmaximize && frame.maximize_button)
destroyMaximizeButton();
+ if (! hasstick && frame.stick_button)
+ destroyStickyButton();
if (! haslabel)
parsed += 'L'; // require that the label be in the layout
frame.button_w, frame.button_w);
x += frame.button_w + bsep;
break;
+ case 'S':
+ if (! frame.stick_button) createStickyButton();
+ XMoveResizeWindow(blackbox->getXDisplay(), frame.stick_button, x, by,
+ frame.button_w, frame.button_w);
+ x += frame.button_w + bsep;
+ break;
case 'M':
if (! frame.maximize_button) createMaximizeButton();
XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, x, by,
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,
screen->allowScrollLock());
if (functions & Func_Move)
- blackbox->grabButton(Button1, ModMask, frame.window, True,
+ blackbox->grabButton(Button1, mod_mask, frame.window, True,
ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
GrabModeAsync, frame.window, None,
screen->allowScrollLock());
if (functions & Func_Resize)
- blackbox->grabButton(Button3, ModMask, frame.window, True,
+ 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, ModMask, frame.window, True,
+ blackbox->grabButton(Button2, mod_mask, frame.window, True,
ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
- frame.window, None,
- screen->allowScrollLock());
+ frame.window, None, screen->allowScrollLock());
}
void BlackboxWindow::ungrabButtons(void) {
blackbox->ungrabButton(Button1, 0, frame.plate);
- blackbox->ungrabButton(Button1, ModMask, frame.window);
- blackbox->ungrabButton(Button2, ModMask, frame.window);
- blackbox->ungrabButton(Button3, ModMask, frame.window);
+ blackbox->ungrabButton(Button1, mod_mask, frame.window);
+ blackbox->ungrabButton(Button2, mod_mask, frame.window);
+ blackbox->ungrabButton(Button3, mod_mask, frame.window);
}
}
-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;
}
client.title = i18n(WindowSet, WindowUnnamed, "Unnamed");
xatom->setValue(client.window, XAtom::net_wm_visible_name, XAtom::utf8,
client.title);
+
+#ifdef DEBUG_WITH_ID
+ // the 16 is the 8 chars of the debug text plus the number
+ char *tmp = new char[client.title.length() + 16];
+ sprintf(tmp, "%s; id: 0x%lx", client.title.c_str(), client.window);
+ client.title = tmp;
+ delete tmp;
+#endif
}
client.max_aspect_x = client.max_aspect_y = 1;
#endif
- /*
- use the full screen, not the strut modified size. otherwise when the
- availableArea changes max_width/height will be incorrect and lead to odd
- rendering bugs.
- */
- const Rect& screen_area = screen->getRect();
- client.max_width = screen_area.width();
- client.max_height = screen_area.height();
+ // don't limit the size of a window, the default max width is the biggest
+ // possible
+ client.max_width = (unsigned) -1;
+ client.max_height = (unsigned) -1;
+
if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window,
&sizehint, &icccm_mask))
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;
}
}
if (blackbox_hint->flags & AttribDecoration) {
switch (blackbox_hint->decoration) {
case DecorNone:
- decorations = 0;
+ blackbox_attrib.decoration = DecorNone;
break;
case DecorTiny:
- decorations |= Decor_Titlebar | Decor_Iconify;
- decorations &= ~(Decor_Border | Decor_Handle | Decor_Maximize);
- functions &= ~(Func_Resize | Func_Maximize);
-
- break;
-
case DecorTool:
- decorations |= Decor_Titlebar;
- decorations &= ~(Decor_Iconify | Decor_Border | Decor_Handle);
- functions &= ~(Func_Resize | Func_Maximize | Func_Iconify);
-
- break;
-
case DecorNormal:
default:
- decorations |= Decor_Titlebar | Decor_Border | Decor_Handle |
- Decor_Iconify | Decor_Maximize;
+ // blackbox_attrib.decoration defaults to DecorNormal
break;
}
-
- reconfigure();
}
delete [] blackbox_hint;
}
// 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;
+ }
+
+ 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;
+ }
}
ShapeBounding, 0, 0, xrect, num,
ShapeUnion, Unsorted);
}
+
+
+void BlackboxWindow::clearShape(void) {
+ XShapeCombineMask(blackbox->getXDisplay(), frame.window, ShapeBounding,
+ frame.margin.left - frame.border_w,
+ frame.margin.top - frame.border_w,
+ None, ShapeSet);
+}
#endif // SHAPE
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;
void BlackboxWindow::iconify(void) {
- if (flags.iconic) return;
+ if (flags.iconic || ! (functions & Func_Iconify)) return;
// We don't need to worry about resizing because resizing always grabs the X
// server. This should only ever happen if using opaque moving.
// 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 (raise)
void BlackboxWindow::close(void) {
+ if (! (functions & Func_Close)) return;
+
XEvent ce;
ce.xclient.type = ClientMessage;
ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
void BlackboxWindow::maximize(unsigned int button) {
+ if (! (functions & Func_Maximize)) return;
+
// We don't need to worry about resizing because resizing always grabs the X
// server. This should only ever happen if using opaque moving.
if (flags.moving)
setState(current_state);
}
+
+ redrawAllButtons();
+
// go up the chain
if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
client.transient_for->isStuck() != flags.stuck)
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 (flags.focused)
blackbox->setFocusedWindow(this);
if (net->flags & AttribDecoration) {
switch (net->decoration) {
case DecorNone:
- decorations = 0;
-
+ enableDecor(False);
break;
+ /* since tools only let you toggle this anyways, we'll just make that all
+ it supports for now.
+ */
default:
case DecorNormal:
- decorations |= Decor_Titlebar | Decor_Handle | Decor_Border |
- Decor_Iconify | Decor_Maximize;
-
- break;
-
case DecorTiny:
- decorations |= Decor_Titlebar | Decor_Iconify;
- decorations &= ~(Decor_Border | Decor_Handle | Decor_Maximize);
-
- break;
-
case DecorTool:
- decorations |= Decor_Titlebar;
- decorations &= ~(Decor_Iconify | Decor_Border | Decor_Handle);
-
+ enableDecor(True);
break;
}
-
- // sanity check the new decor
- if (! (functions & Func_Resize) || isTransient())
- decorations &= ~(Decor_Maximize | Decor_Handle);
- if (! (functions & Func_Maximize))
- decorations &= ~Decor_Maximize;
-
- if (decorations & Decor_Titlebar) {
- if (functions & Func_Close) // close button is controlled by function
- decorations |= Decor_Close; // not decor type
- } else {
- if (flags.shaded) // we can not be shaded if we lack a titlebar
- shade();
- }
-
- if (flags.visible && frame.window) {
- XMapSubwindows(blackbox->getXDisplay(), frame.window);
- XMapWindow(blackbox->getXDisplay(), frame.window);
- }
-
- reconfigure();
- setState(current_state);
}
// with the state set it will then be the map event's job to read the
if (frame.iconify_button) redrawIconifyButton(False);
if (frame.maximize_button) redrawMaximizeButton(flags.maximized);
if (frame.close_button) redrawCloseButton(False);
+ if (frame.stick_button) redrawStickyButton(flags.stuck);
}
XClearWindow(blackbox->getXDisplay(), frame.close_button);
BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
- screen->getWindowStyle()->b_pic_unfocus);
+ screen->getWindowStyle()->b_pic_unfocus, 0, 2);
XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2, 2, (frame.button_w - 3), (frame.button_w - 3));
XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
}
+void BlackboxWindow::redrawStickyButton(bool pressed) const {
+ if (! pressed) {
+ if (flags.focused) {
+ if (frame.fbutton)
+ XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
+ frame.stick_button, frame.fbutton);
+ else
+ XSetWindowBackground(blackbox->getXDisplay(), frame.stick_button,
+ frame.fbutton_pixel);
+ } else {
+ if (frame.ubutton)
+ XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
+ frame.stick_button, frame.ubutton);
+ else
+ XSetWindowBackground(blackbox->getXDisplay(), frame.stick_button,
+ frame.ubutton_pixel);
+ }
+ } else {
+ if (frame.pbutton)
+ XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
+ frame.stick_button, frame.pbutton);
+ else
+ XSetWindowBackground(blackbox->getXDisplay(), frame.stick_button,
+ frame.pbutton_pixel);
+ }
+ XClearWindow(blackbox->getXDisplay(), frame.stick_button);
+
+ BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
+ screen->getWindowStyle()->b_pic_unfocus);
+
+ XFillRectangle(blackbox->getXDisplay(), frame.stick_button, pen.gc(),
+ frame.button_w/2 - 1, frame.button_w/2 -1, 2, 2 );
+}
+
void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) {
if (re->window != client.window)
return;
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();
if (isNormal()) {
if (! blackbox->isStartup()) {
XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped
- if (screen->doFocusNew()|| (isTransient() && getTransientFor() &&
- getTransientFor()->isFocused())) {
+ if (screen->doFocusNew() || (isTransient() && getTransientFor() &&
+ getTransientFor()->isFocused())) {
setInputFocus();
}
if (screen->getPlacementPolicy() == BScreen::ClickMousePlacement) {
void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) {
- if (pe->state == PropertyDelete)
+ if (pe->state == PropertyDelete || ! validateClient())
return;
-#ifdef DEBUG
+#if 0
fprintf(stderr, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
client.window);
#endif
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();
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 {
- if (! isTransient()) {
- decorations |= Decor_Maximize | Decor_Handle;
+ if (! isTransient())
functions |= Func_Maximize;
- }
functions |= Func_Resize;
}
grabButtons();
setAllowedActions();
+ setupDecor();
}
Rect old_rect = frame.rect;
void BlackboxWindow::exposeEvent(const XExposeEvent *ee) {
-#ifdef DEBUG
+#if 0
fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window);
#endif
redrawMaximizeButton(flags.maximized);
else if (frame.iconify_button == ee->window)
redrawIconifyButton(False);
+ else if (frame.stick_button == ee->window)
+ redrawStickyButton(flags.stuck);
}
client.old_bw = cr->border_width;
if (cr->value_mask & (CWX | CWY | CWWidth | CWHeight)) {
- Rect req = frame.rect;
+ frame.changing = frame.rect;
if (cr->value_mask & (CWX | CWY)) {
if (cr->value_mask & CWX)
if (cr->value_mask & CWY)
client.rect.setY(cr->y);
- applyGravity(req);
+ applyGravity(frame.changing);
}
- if (cr->value_mask & CWWidth)
- req.setWidth(cr->width + frame.margin.left + frame.margin.right);
+ if (cr->value_mask & (CWWidth | CWHeight)) {
+ if (cr->value_mask & CWWidth)
+ frame.changing.setWidth(cr->width +
+ frame.margin.left + frame.margin.right);
- if (cr->value_mask & CWHeight)
- req.setHeight(cr->height + frame.margin.top + frame.margin.bottom);
+ if (cr->value_mask & CWHeight)
+ frame.changing.setHeight(cr->height +
+ frame.margin.top + frame.margin.bottom);
- configure(req.x(), req.y(), req.width(), req.height());
+ /*
+ if a position change has been specified, then that position will be
+ used instead of determining a position based on the window's gravity.
+ */
+ if (! (cr->value_mask & (CWX | CWY))) {
+ Corner corner;
+ switch (client.win_gravity) {
+ case NorthEastGravity:
+ case EastGravity:
+ corner = TopRight;
+ break;
+ case SouthWestGravity:
+ case SouthGravity:
+ corner = BottomLeft;
+ break;
+ case SouthEastGravity:
+ corner = BottomRight;
+ break;
+ default: // NorthWest, Static, etc
+ corner = TopLeft;
+ }
+ constrain(corner);
+ }
+ }
+
+ configure(frame.changing.x(), frame.changing.y(),
+ frame.changing.width(), frame.changing.height());
}
if (cr->value_mask & CWStackMode && !isDesktop()) {
if (frame.maximize_button == be->window && be->button <= 3) {
redrawMaximizeButton(True);
- } else if (be->button == 1 || (be->button == 3 && be->state == ModMask)) {
+ } else if (be->button == 1 || (be->button == 3 && be->state == mod_mask)) {
if (! flags.focused)
setInputFocus();
redrawIconifyButton(True);
} else if (frame.close_button == be->window) {
redrawCloseButton(True);
+ } else if (frame.stick_button == be->window) {
+ redrawStickyButton(True);
} else if (frame.plate == be->window) {
if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
}
} else if (be->button == 2 && (be->window != frame.iconify_button) &&
- (be->window != frame.close_button)) {
+ (be->window != frame.close_button) &&
+ (be->window != frame.stick_button)) {
screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
} else if (windowmenu && be->button == 3 &&
(frame.title == be->window || frame.label == be->window ||
be->window == frame.title ||
be->window == frame.maximize_button ||
be->window == frame.iconify_button ||
- be->window == frame.close_button) &&
+ be->window == frame.close_button ||
+ be->window == frame.stick_button) &&
! flags.shaded)
shade();
// mouse wheel down
be->window == frame.title ||
be->window == frame.maximize_button ||
be->window == frame.iconify_button ||
- be->window == frame.close_button) &&
+ be->window == frame.close_button ||
+ be->window == frame.stick_button) &&
flags.shaded)
shade();
}
} else {
redrawIconifyButton(False);
}
+ } else if (re->window == frame.stick_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))) {
+ stick();
+ } else {
+ redrawStickyButton(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)))
} else if (flags.resizing) {
endResize();
} else if (re->window == frame.window) {
- if (re->button == 2 && re->state == ModMask)
+ if (re->button == 2 && re->state == mod_mask)
XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
}
}
void BlackboxWindow::beginMove(int x_root, int y_root) {
+ if (! (functions & Func_Move)) return;
+
assert(! (flags.resizing || flags.moving));
/*
dx -= frame.border_w;
dy -= frame.border_w;
- if (screen->doWorkspaceWarping()) {
- // workspace warping
- bool warp = False;
- unsigned int dest = screen->getCurrentWorkspaceID();
- if (x_root <= 0) {
- warp = True;
+ doWindowSnapping(dx, dy);
- if (dest > 0) dest--;
- else dest = screen->getNumberOfWorkspaces() - 1;
+ if (screen->doOpaqueMove()) {
+ if (screen->doWorkspaceWarping())
+ doWorkspaceWarping(x_root, y_root, dx);
- } else if (x_root >= screen->getRect().right()) {
- warp = True;
+ 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 (dest < screen->getNumberOfWorkspaces() - 1) dest++;
- else dest = 0;
- }
- if (warp) {
- endMove();
- bool focus = flags.focused; // had focus while moving?
- if (! flags.stuck)
- screen->reassociateWindow(this, dest, False);
- screen->changeWorkspaceID(dest);
- if (focus)
- setInputFocus();
+ if (screen->doWorkspaceWarping())
+ doWorkspaceWarping(x_root, y_root, dx);
- /*
- If the XWarpPointer is done after the configure, we can end up
- grabbing another window, so made sure you do it first.
- */
- int dest_x;
- if (x_root <= 0) {
- dest_x = screen->getRect().right() - 1;
- XWarpPointer(blackbox->getXDisplay(), None,
- screen->getRootWindow(), 0, 0, 0, 0,
- dest_x, y_root);
-
- configure(dx + (screen->getRect().width() - 1), dy,
- frame.rect.width(), frame.rect.height());
- } else {
- dest_x = 0;
- XWarpPointer(blackbox->getXDisplay(), None,
- screen->getRootWindow(), 0, 0, 0, 0,
- dest_x, y_root);
+ frame.changing.setPos(dx, dy);
- configure(dx - (screen->getRect().width() - 1), dy,
- frame.rect.width(), frame.rect.height());
- }
+ XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
+ screen->getOpGC(),
+ frame.changing.x(),
+ frame.changing.y(),
+ frame.changing.width() - 1,
+ frame.changing.height() - 1);
+ }
- beginMove(dest_x, y_root);
- return;
- }
+ 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 (focus)
+ setInputFocus();
+
+}
+
+
+void BlackboxWindow::doWindowSnapping(int &dx, int &dy) {
// how much resistance to edges to provide
- const int resistance_size = screen->getEdgeSnapThreshold();
+ const int resistance_size = screen->getResistanceSize();
- if (resistance_size > 0) {
+ // 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;
+
+ // window corners
+ const int wleft = dx,
+ wright = dx + frame.rect.width() - 1,
+ wtop = dy,
+ wbottom = dy + frame.rect.height() - 1;
+
+ if (snap_to_windows) {
RectList rectlist;
- // the amount of space away from the edge to provide resistance
- const int resistance_offset = screen->getEdgeSnapThreshold();
-
- // find the geomeetery where the moving window currently is
- const Rect &moving = screen->doOpaqueMove() ? frame.rect : frame.changing;
-
- // window corners
- const int wleft = dx,
- wright = dx + frame.rect.width() - 1,
- wtop = dy,
- wbottom = dy + frame.rect.height() - 1;
-
- if (screen->getWindowToWindowSnap()) {
- 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)
+ 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);
- }
+ // 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);
- }
+ 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;
-
+ 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 = wright - winrect.left(),
- dright = winrect.right() - wleft,
- dtop = wbottom - winrect.top(),
- dbottom = winrect.bottom() - wtop;
- // 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)) {
+ 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) {
- dx = winrect.left() - frame.rect.width();
+ 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) {
- dx = winrect.right() + 1;
+ 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());
- if (snapped) {
- if (screen->getWindowCornerSnap()) {
- // try corner-snap to its other sides
+ // snap left of other window?
+ if (dleft < snap_distance && dleft <= dright) {
+ dx = offsetrect.left() - frame.rect.width();
+ snapped = True;
+ }
+ // snap right of other window?
+ else if (dright < snap_distance) {
+ dx = offsetrect.right() + 1;
+ snapped = True;
+ }
+ }
+
+ 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 (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 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 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 >= 0 && dtop < resistance_size) {
- dy = winrect.top() - frame.rect.height();
+ if (dtop < snap_distance && dtop <= dbottom) {
+ dy = offsetrect.top() - frame.rect.height();
snapped = True;
}
// snap bottom of other window?
- else if (dbottom > 0 && dbottom < resistance_size) {
- dy = winrect.bottom() + 1;
+ else if (dbottom < snap_distance) {
+ dy = offsetrect.bottom() + 1;
snapped = True;
}
- if (snapped) {
- if (screen->getWindowCornerSnap()) {
- // try corner-snap to its other sides
+ }
+
+ 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 (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;
}
}
}
+ }
- // snap to the screen edges (and screen boundaries for xinerama)
- rectlist.clear();
+ 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(),
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;
+ }
- // if we're not in the rectangle then don't snap to it.
- if (! srect.contains(moving))
- continue;
-
- int dleft = srect.left() - wleft,
- dright = wright - srect.right(),
- dtop = srect.top() - wtop,
- dbottom = wbottom - srect.bottom();
+ 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 = srect.left();
+ dx = offsetrect.left();
// snap right?
else if (dright > 0 && dright < resistance_size)
- dx = srect.right() - frame.rect.width() + 1;
+ dx = offsetrect.right() - frame.rect.width() + 1;
// snap top?
if (dtop > 0 && dtop < resistance_size)
- dy = srect.top();
+ dy = offsetrect.top();
// snap bottom?
else if (dbottom > 0 && dbottom < resistance_size)
- dy = srect.bottom() - frame.rect.height() + 1;
- }
- }
+ 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());
- 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);
+ // 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;
- XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
- screen->getOpGC(),
- frame.changing.x(),
- frame.changing.y(),
- frame.changing.width() - 1,
- frame.changing.height() - 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);
}
void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) {
+ if (! (functions & Func_Resize)) return;
+
assert(! (flags.resizing || flags.moving));
/*
- Only one window can be moved/resized at a time. If another window is already
- being moved or resized, then stop it before whating to work with this one.
+ Only one window can be moved/resized at a time. If another window is
+ already being moved or resized, then stop it before whating to work with
+ this one.
*/
BlackboxWindow *changing = blackbox->getChangingWindow();
if (changing && changing != this) {
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;
+ int dx, dy; // the amount of change in the size of the window
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));
+ dx = - (x_root - frame.grab_x);
+ dy = + (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));
+ dx = + (x_root - frame.grab_x);
+ dy = + (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));
+ dx = - (x_root - frame.grab_x);
+ dy = - (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));
+ dx = + (x_root - frame.grab_x);
+ dy = - (y_root - frame.grab_y);
break;
default:
assert(false); // unhandled Corner
return; // unreachable, for the compiler
}
-
+
+ // make sure the user cant resize the window smaller than 0, which makes it
+ // wrap around and become huge
+ if (dx < -(signed)client.rect.width()) dx = -(signed)client.rect.width();
+ if (dy < -(signed)client.rect.height()) dy = -(signed)client.rect.height();
+
+ frame.changing.setSize(frame.rect.width() + dx, frame.rect.height() + dy);
+
constrain(anchor, &gw, &gh);
XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) {
-#ifdef DEBUG
+#if 0
fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
client.window);
#endif
} else if (flags.resizing) {
doResize(me->x_root, me->y_root);
} else {
- if (!flags.resizing && me->state & Button1Mask && (functions & Func_Move) &&
+ 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 & ModMask &&
- me->window == frame.window)) {
+ ((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;
}
+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) {
+ if (! 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) {
- configureShape();
+void BlackboxWindow::shapeEvent(XShapeEvent *e) {
+ if (blackbox->hasShapeExtensions()) {
+ if (! e->shaped && flags.shaped) {
+ clearShape();
+ flags.shaped = False;
+ } else if (e->shaped) {
+ configureShape();
+ flags.shaped = True;
+ }
}
}
#endif // SHAPE
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);
if (net->flags & AttribDecoration) {
switch (net->decoration) {
case DecorNone:
- decorations = 0;
-
+ 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 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;
+ // constrain, but only if the min/max are being used. if they aren't, then
+ // this resize is going to be from a ConfigureRequest because the window
+ // isn't allowed to be resized by the user. And in that case, we don't want
+ // to limit what the app can do
+ if (client.max_width > client.min_width ||
+ client.max_height > client.min_height) {
+ 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;
+ }
- dw -= base_width;
- dw /= client.width_inc;
- dh -= base_height;
- dh /= client.height_inc;
+ assert(dw >= base_width && dh >= base_height);
- if (pw) {
- if (client.width_inc == 1)
- *pw = dw + base_width;
- else
- *pw = dw;
+ 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);
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;