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 =
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
break;
case Type_Normal:
- // normal windows retain all of the possible decorations and functionality
+ // normal windows retain all of the possible decorations and
+ // functionality
break;
}
} else {
attrib_create.background_pixmap = None;
attrib_create.colormap = screen->getColormap();
attrib_create.override_redirect = True;
- attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
- ButtonMotionMask |
- EnterWindowMask | LeaveWindowMask;
+ 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::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,
// alt+middle lowers the window
blackbox->grabButton(Button2, mod_mask, frame.window, True,
ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
- frame.window, None,
- screen->allowScrollLock());
+ frame.window, None, screen->allowScrollLock());
}
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))
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
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.
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)
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;
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)
+ frame.changing.setHeight(cr->height +
+ frame.margin.top + frame.margin.bottom);
- if (cr->value_mask & CWHeight)
- req.setHeight(cr->height + frame.margin.top + frame.margin.bottom);
+ /*
+ 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(req.x(), req.y(), req.width(), req.height());
+ configure(frame.changing.x(), frame.changing.y(),
+ frame.changing.width(), frame.changing.height());
}
if (cr->value_mask & CWStackMode && !isDesktop()) {
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)))
void BlackboxWindow::beginMove(int x_root, int y_root) {
+ if (! (functions & Func_Move)) return;
+
assert(! (flags.resizing || flags.moving));
/*
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) {
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(),
}
}
- if ((! leave || inferior) && ! isFocused()) {
- bool success = setInputFocus();
- if (success) // if focus succeeded install the colormap
- installColormap(True); // XXX: shouldnt we honour no install?
- }
+ 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();
+ if (screen->doAutoRaise())
+ timer->start();
+ }
}
#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
base_height = (client.base_height) ? client.base_height :
client.min_height;
- // constrain
- 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;
+ // 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;
+ }
assert(dw >= base_width && dh >= base_height);