X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2FWindow.cc;h=32fe86c75c373205b0ea01d379cf1bc96749deb1;hb=5033ce0a24336668f4705a17063f27d842da461b;hp=99e19e4dadb4c2d245ef7dfe623375e9edc5bb6a;hpb=d94e8c506850bc8a74ebc7b2c63e8ad242242faa;p=chaz%2Fopenbox diff --git a/src/Window.cc b/src/Window.cc index 99e19e4d..32fe86c7 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -62,11 +62,6 @@ extern "C" { 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. */ @@ -126,8 +121,8 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { 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; @@ -145,9 +140,9 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { 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; @@ -155,8 +150,10 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { 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. */ @@ -168,15 +165,11 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { 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(); @@ -186,7 +179,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 @@ -194,46 +187,51 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { // 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(); @@ -257,21 +255,6 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { 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. @@ -284,6 +267,12 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { 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 @@ -296,6 +285,11 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { 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(); @@ -338,6 +332,9 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { if (flags.maximized && (functions & Func_Maximize)) remaximize(); + + // create this last so it only needs to be configured once + windowmenu = new Windowmenu(this); } @@ -350,6 +347,9 @@ BlackboxWindow::~BlackboxWindow(void) { if (! timer) // window not managed... return; + if (flags.moving) + endMove(); + screen->removeStrut(&client.strut); screen->updateAvailableArea(); @@ -369,18 +369,16 @@ BlackboxWindow::~BlackboxWindow(void) { // 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) @@ -403,6 +401,66 @@ BlackboxWindow::~BlackboxWindow(void) { } +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. @@ -416,8 +474,7 @@ 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; + attrib_create.event_mask = EnterWindowMask | LeaveWindowMask; return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(), 0, 0, 1, 1, frame.border_w, screen->getDepth(), @@ -430,14 +487,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; @@ -452,6 +510,8 @@ Window BlackboxWindow::createChildWindow(Window parent, Cursor cursor) { void BlackboxWindow::associateClientWindow(void) { XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, 0); + getWMName(); + getWMIconName(); XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeInsert); @@ -530,13 +590,8 @@ void BlackboxWindow::decorate(void) { } 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) { @@ -591,15 +646,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); } @@ -631,8 +694,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); @@ -684,7 +751,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); } } @@ -699,7 +769,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); } } @@ -714,7 +787,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); } } @@ -832,6 +908,8 @@ void BlackboxWindow::reconfigure(void) { 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, @@ -839,28 +917,27 @@ void BlackboxWindow::grabButtons(void) { 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); } @@ -947,37 +1024,51 @@ void BlackboxWindow::updateStrut(void) { } -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; } @@ -998,6 +1089,15 @@ void BlackboxWindow::getWMName(void) { client.title = i18n(WindowSet, WindowUnnamed, "Unnamed"); xatom->setValue(client.window, XAtom::net_wm_visible_name, XAtom::utf8, client.title); + +#define DEBUG_WITH_ID 1 +#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 } @@ -1118,14 +1218,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)) @@ -1249,21 +1346,21 @@ void BlackboxWindow::getMWMHints(void) { 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; } } @@ -1336,31 +1433,16 @@ bool BlackboxWindow::getBlackboxHints(void) { 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; @@ -1377,7 +1459,7 @@ void BlackboxWindow::getTransientInfo(void) { } // 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, @@ -1417,9 +1499,24 @@ void BlackboxWindow::getTransientInfo(void) { 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; + } } @@ -1534,6 +1631,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 @@ -1559,9 +1664,8 @@ bool BlackboxWindow::setInputFocus(void) { 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; @@ -1598,7 +1702,7 @@ bool BlackboxWindow::setInputFocus(void) { 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. @@ -1692,9 +1796,8 @@ void BlackboxWindow::deiconify(bool reassoc, bool raise) { // 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) @@ -1703,6 +1806,8 @@ void BlackboxWindow::deiconify(bool reassoc, bool 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); @@ -1748,6 +1853,8 @@ void BlackboxWindow::withdraw(void) { 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) @@ -2064,18 +2171,13 @@ void BlackboxWindow::redrawWindowFrame(void) const { 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); @@ -2261,51 +2363,19 @@ void BlackboxWindow::restoreAttributes(void) { 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 @@ -2573,7 +2643,7 @@ void BlackboxWindow::redrawCloseButton(bool pressed) const { 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(), @@ -2590,6 +2660,14 @@ void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) { 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(); @@ -2608,8 +2686,8 @@ void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) { 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) { @@ -2670,10 +2748,10 @@ void BlackboxWindow::reparentNotifyEvent(const XReparentEvent *re) { 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 @@ -2685,14 +2763,18 @@ void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) { 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(); @@ -2728,17 +2810,15 @@ void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) { 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; @@ -2773,7 +2853,7 @@ void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) { void BlackboxWindow::exposeEvent(const XExposeEvent *ee) { -#ifdef DEBUG +#if 0 fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window); #endif @@ -2796,7 +2876,7 @@ void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent *cr) { 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) @@ -2804,16 +2884,45 @@ void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent *cr) { 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 ha 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()) { @@ -2841,7 +2950,7 @@ void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) { 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(); @@ -2967,7 +3076,7 @@ void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) { } 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); } } @@ -2975,6 +3084,8 @@ void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) { void BlackboxWindow::beginMove(int x_root, int y_root) { + if (! (functions & Func_Move)) return; + assert(! (flags.resizing || flags.moving)); /* @@ -3027,189 +3138,305 @@ void BlackboxWindow::doMove(int x_root, int y_root) { 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(); + + // 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; - if (resistance_size > 0) { + // 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(); - - // 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 (screen->doOpaqueMove()) { - if (winrect.intersects(frame.rect)) - continue; - } else { - if (winrect.intersects(frame.changing)) - continue; - } - - int dleft = wright - winrect.left(), - dright = winrect.right() - wleft, - dtop = wbottom - winrect.top(), - dbottom = winrect.bottom() - wtop; + if (winrect.intersects(moving)) + continue; - // 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 we're already past the top edge, then don't provide + // resistance + if (moving.top() >= winrect.top()) + dy = winrect.top(); + } else if (dbottom > 0 && dbottom < resistance_size) { + // if we're already past the bottom edge, then don't provide + // resistance + if (moving.bottom() <= winrect.bottom()) + dy = winrect.bottom() - frame.rect.height() + 1; + } + } else { // BScreen::WindowSnap dtop = abs(wtop - winrect.top()); dbottom = abs(wbottom - winrect.bottom()); - if (dtop < resistance_size && dtop <= dbottom) + if (dtop < snap_distance && dtop <= dbottom) dy = winrect.top(); - else if (dbottom < resistance_size) + 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) { - dy = winrect.top() - frame.rect.height(); + 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) { - dy = winrect.bottom() + 1; + else if (dbottom >= 0 && dbottom < resistance_size && + dbottom < (wbottom - wtop)) { + dy = offsetrect.bottom() + 1; + snapped = True; + } + } else { // BScreen::WindowSnap + dtop = abs(wbottom - offsetrect.top()); + dbottom = abs(wtop - offsetrect.bottom()); + + // snap top of other window? + if (dtop < snap_distance && dtop <= dbottom) { + dy = offsetrect.top() - frame.rect.height(); snapped = True; } + // snap bottom of other window? + 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 we're already past the left edge, then don't provide + // resistance + if (moving.left() >= winrect.left()) + dx = winrect.left(); + } else if (dright > 0 && dright < resistance_size) { + // if we're already past the right edge, then don't provide + // resistance + if (moving.right() <= winrect.right()) + dx = winrect.right() - frame.rect.width() + 1; + } + } else { // BScreen::WindowSnap dleft = abs(wleft - winrect.left()); dright = abs(wright - winrect.right()); - if (dleft < resistance_size && dleft <= dright) + if (dleft < snap_distance && dleft <= dright) dx = winrect.left(); - else if (dright < resistance_size) + 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(), @@ -3222,54 +3449,64 @@ void BlackboxWindow::doMove(int x_root, int y_root) { 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.intersects(Rect(wleft, wtop, frame.rect.width(), - frame.rect.height()))) - continue; - - int dleft = wleft - srect.left(), - dright = wright - srect.right(), - dtop = wtop - srect.top(), - 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; - } - } - - 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); + 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()); - 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); } @@ -3310,11 +3547,14 @@ void BlackboxWindow::endMove(void) { 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) { @@ -3363,7 +3603,7 @@ void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) { flags.resizing = True; blackbox->setChangingWindow(this); - int gw, gh; + unsigned int gw, gh; frame.changing = frame.rect; constrain(anchor, &gw, &gh); @@ -3387,36 +3627,44 @@ void BlackboxWindow::doResize(int x_root, int y_root) { 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(), @@ -3458,7 +3706,7 @@ void BlackboxWindow::endResize(void) { void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) { -#ifdef DEBUG +#if 0 fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n", client.window); #endif @@ -3468,15 +3716,17 @@ void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) { } 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; @@ -3503,10 +3753,55 @@ void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) { } +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 @@ -3538,6 +3833,12 @@ void BlackboxWindow::restore(bool remap) { 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); @@ -3613,58 +3914,16 @@ void BlackboxWindow::changeBlackboxHints(const BlackboxHints *net) { 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); } } @@ -3754,11 +4013,14 @@ void BlackboxWindow::upsize(void) { * 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, @@ -3766,39 +4028,42 @@ void BlackboxWindow::constrain(Corner anchor, int *pw, int *ph) { 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(client.min_width)) dw = client.min_width; - if (dh < static_cast(client.min_height)) dh = client.min_height; - if (dw > static_cast(client.max_width)) dw = client.max_width; - if (dh > static_cast(client.max_height)) dh = client.max_height; - - dw -= base_width; - dw /= client.width_inc; - dh -= base_height; - dh /= client.height_inc; - - if (pw) { - if (client.width_inc == 1) - *pw = dw + base_width; - else - *pw = dw; + if (dw < client.min_width) dw = client.min_width; + if (dh < client.min_height) dh = client.min_height; + if (dw > client.max_width) dw = client.max_width; + if (dh > client.max_height) dh = client.max_height; + + assert(dw >= base_width && dh >= base_height); + + if (client.width_inc > 1) { + dw -= base_width; + dw /= client.width_inc; } - if (ph) { - if (client.height_inc == 1) - *ph = dh + base_height; - else - *ph = dh; + if (client.height_inc > 1) { + dh -= base_height; + dh /= client.height_inc; } - dw *= client.width_inc; - dw += base_width; - dh *= client.height_inc; - dh += base_height; + if (pw) + *pw = dw; + + if (ph) + *ph = dh; + + if (client.width_inc > 1) { + dw *= client.width_inc; + dw += base_width; + } + if (client.height_inc > 1) { + dh *= client.height_inc; + dh += base_height; + } frame.changing.setSize(dw, dh); @@ -3887,13 +4152,10 @@ BWindowGroup::find(BScreen *screen, bool allow_transients) const { 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; @@ -3902,10 +4164,9 @@ BWindowGroup::find(BScreen *screen, bool allow_transients) const { 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;