X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2FWindow.cc;h=dcbb5f08afc55654e5c2f1806fd7d6cbaf33670a;hb=7f001973a8154b1fa9db110092c438b862f81c3b;hp=4b6aa493fce6ea8d82c7f337589b85101b254f1c;hpb=328b861d19a9ff2612fd1ef6ddd40e5002343a80;p=chaz%2Fopenbox diff --git a/src/Window.cc b/src/Window.cc index 4b6aa493..dcbb5f08 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -128,7 +128,8 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { 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 = @@ -179,7 +180,7 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { 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 @@ -212,7 +213,8 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { 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 { @@ -473,9 +475,13 @@ Window BlackboxWindow::createToplevelWindow(void) { 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 | + ButtonPress; + /* + We catch button presses because other wise they get passed down to the + root window, which will then cause root menus to show when you click the + window's frame. + */ return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(), 0, 0, 1, 1, frame.border_w, screen->getDepth(), @@ -488,14 +494,15 @@ Window BlackboxWindow::createToplevelWindow(void) { * 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; @@ -646,15 +653,23 @@ void BlackboxWindow::decorateLabel(void) { 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); } @@ -686,8 +701,12 @@ void BlackboxWindow::destroyHandle(void) { 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); @@ -707,6 +726,9 @@ void BlackboxWindow::destroyTitlebar(void) { if (frame.maximize_button) destroyMaximizeButton(); + if (frame.stick_button) + destroyStickyButton(); + if (frame.ftitle) screen->getImageControl()->removeImage(frame.ftitle); @@ -739,7 +761,10 @@ void BlackboxWindow::destroyTitlebar(void) { 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); } } @@ -754,7 +779,10 @@ void BlackboxWindow::destroyCloseButton(void) { 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); } } @@ -769,7 +797,10 @@ void BlackboxWindow::destroyIconifyButton(void) { 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); } } @@ -781,13 +812,28 @@ void BlackboxWindow::destroyMaximizeButton(void) { 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) { @@ -804,6 +850,12 @@ void BlackboxWindow::positionButtons(bool redecorate_label) { parsed += *it; } break; + case 'S': + if (!hasstick) { + hasstick = true; + parsed += *it; + } + break; case 'M': if (! hasmaximize && (decorations & Decor_Maximize)) { hasmaximize = true; @@ -815,14 +867,18 @@ void BlackboxWindow::positionButtons(bool redecorate_label) { 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 @@ -848,6 +904,12 @@ void BlackboxWindow::positionButtons(bool redecorate_label) { 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, @@ -908,8 +970,7 @@ void BlackboxWindow::grabButtons(void) { // 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()); } @@ -1069,6 +1130,14 @@ void BlackboxWindow::getWMName(void) { 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 } @@ -1189,14 +1258,11 @@ void BlackboxWindow::getWMNormalHints(void) { 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)) @@ -1605,6 +1671,14 @@ void BlackboxWindow::configureShape(void) { 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 @@ -2043,6 +2117,9 @@ void BlackboxWindow::stick(void) { setState(current_state); } + + redrawAllButtons(); + // go up the chain if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul && client.transient_for->isStuck() != flags.stuck) @@ -2508,6 +2585,7 @@ void BlackboxWindow::redrawAllButtons(void) const { 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); } @@ -2617,6 +2695,40 @@ void BlackboxWindow::redrawCloseButton(bool pressed) const { } +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; @@ -2630,7 +2742,8 @@ void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) { 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() && + if (! flags.stuck && + blackbox_attrib.workspace != screen->getCurrentWorkspaceID() && blackbox_attrib.workspace < screen->getWorkspaceCount()) if (current_state == NormalState) current_state = WithdrawnState; @@ -2831,6 +2944,8 @@ void BlackboxWindow::exposeEvent(const XExposeEvent *ee) { redrawMaximizeButton(flags.maximized); else if (frame.iconify_button == ee->window) redrawIconifyButton(False); + else if (frame.stick_button == ee->window) + redrawStickyButton(flags.stuck); } @@ -2863,10 +2978,10 @@ void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent *cr) { frame.margin.top + frame.margin.bottom); /* - if a position change ha been specified, then that position will be used - instead of determining a position based on the window's gravity. + 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)) { + if (! (cr->value_mask & (CWX | CWY))) { Corner corner; switch (client.win_gravity) { case NorthEastGravity: @@ -2924,6 +3039,8 @@ void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) { 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(); @@ -2947,7 +3064,8 @@ void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) { 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 || @@ -2995,7 +3113,8 @@ void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) { 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 @@ -3004,7 +3123,8 @@ void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) { 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(); } @@ -3032,6 +3152,13 @@ void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) { } else { redrawIconifyButton(False); } + } else if (re->window == frame.stick_button && re->button == 1) { + if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && + (re->y >= 0 && re->y <= static_cast(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(frame.button_w)) && (re->y >= 0 && re->y <= static_cast(frame.button_w))) @@ -3595,34 +3722,42 @@ void BlackboxWindow::doResize(int x_root, int y_root) { 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(), @@ -3731,10 +3866,15 @@ void BlackboxWindow::enterNotifyEvent(const XCrossingEvent* ce) { bool success = setInputFocus(); if (success) // if focus succeeded install the colormap installColormap(True); // XXX: shouldnt we honour no install? - } - if (screen->doAutoRaise()) - timer->start(); + /* + We only auto-raise when the window wasn't focused because otherwise + we run into problems with gtk+ drop-down lists. The window ends up + raising over the list. + */ + if (screen->doAutoRaise()) + timer->start(); + } } } @@ -3751,9 +3891,15 @@ void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent*) { #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 @@ -3985,11 +4131,17 @@ void BlackboxWindow::constrain(Corner anchor, 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);