#include "i18n.hh"
#include "blackbox.hh"
+#include "Font.hh"
#include "GCCache.hh"
#include "Iconmenu.hh"
#include "Image.hh"
#include "Windowmenu.hh"
#include "Workspace.hh"
#include "Slit.hh"
-#include "XAtom.hh"
-#include "Input.hh"
using std::string;
client.window = w;
screen = s;
xatom = blackbox->getXAtom();
- input = blackbox->getInput();
if (! validateClient()) {
delete this;
frame.fgrip_pixel = 0;
frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None;
frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None;
- frame.pbutton = frame.ugrip = frame.fgrip = decorations;
+ frame.pbutton = frame.ugrip = frame.fgrip = None;
decorations = Decor_Titlebar | Decor_Border | Decor_Handle |
Decor_Iconify | Decor_Maximize;
functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
client.wm_hint_flags = client.normal_hint_flags = 0;
+ client.window_group = None;
client.transient_for = 0;
/*
blackbox->saveWindowSearch(frame.plate, this);
blackbox->saveWindowSearch(client.window, this);
- screen->addStrut(&client.strut);
- updateStrut();
-
// determine if this is a transient window
getTransientInfo();
client.normal_hint_flags & (PPosition|USPosition)) {
applyGravity(frame.rect);
- if (blackbox->isStartup() ||
- client.rect.intersects(screen->availableArea()))
+ if (blackbox->isStartup() || client.rect.intersects(screen->getRect()))
place_window = False;
}
+ // add the window's strut. note this is done *after* placing the window.
+ screen->addStrut(&client.strut);
+ updateStrut();
+
if (decorations & Decor_Titlebar)
createTitlebar();
}
#endif // SHAPE
- grabButtons();
-
- positionWindows();
- decorate();
-
- if (decorations & Decor_Titlebar)
- XMapSubwindows(blackbox->getXDisplay(), frame.title);
- XMapSubwindows(blackbox->getXDisplay(), frame.window);
-
windowmenu = new Windowmenu(this);
if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
if (flags.shaded) {
flags.shaded = False;
+ unsigned long orig_state = current_state;
shade();
/*
- Because the iconic'ness of shaded windows is lost, we need to set the
- state to NormalState so that shaded windows on other workspaces will not
- get shown on the first workspace.
At this point in the life of a window, current_state should only be set
to IconicState if the window was an *icon*, not if it was shaded.
*/
- current_state = NormalState;
+ if (orig_state != IconicState)
+ current_state = NormalState;
}
if (flags.stuck) {
fact never set to Iconic since there is no way for us to tell if a sticky
window was iconified previously.
*/
+
+ positionWindows();
+ decorate();
+ grabButtons();
+
+ XMapSubwindows(blackbox->getXDisplay(), frame.window);
redrawWindowFrame();
}
void BlackboxWindow::reconfigure(void) {
+ restoreGravity(client.rect);
upsize();
-
- client.rect.setPos(frame.rect.left() + frame.margin.left,
- frame.rect.top() + frame.margin.top);
-
+ applyGravity(frame.rect);
positionWindows();
decorate();
-
redrawWindowFrame();
- configure(frame.rect.x(), frame.rect.y(),
- frame.rect.width(), frame.rect.height());
+ ungrabButtons();
+ grabButtons();
if (windowmenu) {
windowmenu->move(windowmenu->getX(), frame.rect.y() + frame.title_h);
}
+void BlackboxWindow::grabButtons(void) {
+ if ((! screen->isSloppyFocus()) || screen->doClickRaise())
+ // grab button 1 for changing focus/raising
+ blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
+ GrabModeSync, GrabModeSync, frame.plate, None);
+
+ if (functions & Func_Move)
+ blackbox->grabButton(Button1, Mod1Mask, frame.window, True,
+ ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
+ GrabModeAsync, frame.window,
+ blackbox->getMoveCursor());
+ if (functions & Func_Resize)
+ blackbox->grabButton(Button3, Mod1Mask, frame.window, True,
+ ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
+ GrabModeAsync, frame.window, None);
+ // alt+middle lowers the window
+ blackbox->grabButton(Button2, Mod1Mask, frame.window, True,
+ ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
+ frame.window, None);
+}
+
+
+void BlackboxWindow::ungrabButtons(void) {
+ if ((! screen->isSloppyFocus()) || screen->doClickRaise())
+ blackbox->ungrabButton(Button1, 0, frame.plate);
+
+ blackbox->ungrabButton(Button1, Mod1Mask, frame.window);
+ blackbox->ungrabButton(Button2, Mod1Mask, frame.window);
+ blackbox->ungrabButton(Button3, Mod1Mask, frame.window);
+}
+
+
void BlackboxWindow::positionWindows(void) {
XMoveResizeWindow(blackbox->getXDisplay(), frame.window,
frame.rect.x(), frame.rect.y(), frame.inside_w,
client.rect.width(), client.rect.height());
XMoveResizeWindow(blackbox->getXDisplay(), client.window,
0, 0, client.rect.width(), client.rect.height());
+ // ensure client.rect contains the real location
+ client.rect.setPos(frame.rect.left() + frame.margin.left,
+ frame.rect.top() + frame.margin.top);
if (decorations & Decor_Titlebar) {
if (frame.title == None) createTitlebar();
} else if (frame.handle) {
destroyHandle();
}
+ XSync(blackbox->getXDisplay(), False);
}
client.min_width = client.min_height =
client.width_inc = client.height_inc = 1;
client.base_width = client.base_height = 0;
+ client.win_gravity = NorthWestGravity;
+#if 0
+ client.min_aspect_x = client.min_aspect_y =
+ client.max_aspect_x = client.max_aspect_y = 1;
+#endif
/*
use the full screen, not the strut modified size. otherwise when the
*/
const Rect& screen_area = screen->getRect();
client.max_width = screen_area.width();
-
client.max_height = screen_area.height();
- client.min_aspect_x = client.min_aspect_y =
- client.max_aspect_x = client.max_aspect_y = 1;
- client.win_gravity = NorthWestGravity;
if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window,
&sizehint, &icccm_mask))
client.normal_hint_flags = sizehint.flags;
if (sizehint.flags & PMinSize) {
- client.min_width = sizehint.min_width;
- client.min_height = sizehint.min_height;
+ if (sizehint.min_width >= 0)
+ client.min_width = sizehint.min_width;
+ if (sizehint.min_height >= 0)
+ client.min_height = sizehint.min_height;
}
if (sizehint.flags & PMaxSize) {
- client.max_width = sizehint.max_width;
- client.max_height = sizehint.max_height;
+ if (sizehint.max_width > static_cast<signed>(client.min_width))
+ client.max_width = sizehint.max_width;
+ else
+ client.max_width = client.min_width;
+
+ if (sizehint.max_height > static_cast<signed>(client.min_height))
+ client.max_height = sizehint.max_height;
+ else
+ client.max_height = client.min_height;
}
if (sizehint.flags & PResizeInc) {
client.height_inc = sizehint.height_inc;
}
+#if 0 // we do not support this at the moment
if (sizehint.flags & PAspect) {
client.min_aspect_x = sizehint.min_aspect.x;
client.min_aspect_y = sizehint.min_aspect.y;
client.max_aspect_x = sizehint.max_aspect.x;
client.max_aspect_y = sizehint.max_aspect.y;
}
+#endif
if (sizehint.flags & PBaseSize) {
client.base_width = sizehint.base_width;
num = PropMwmHintsElements;
if (! xatom->getValue(client.window, XAtom::motif_wm_hints,
XAtom::motif_wm_hints, num,
- (unsigned long **)&mwm_hint) ||
- num < PropMwmHintsElements)
+ (unsigned long **)&mwm_hint))
+ return;
+ if (num < PropMwmHintsElements) {
+ delete [] mwm_hint;
return;
+ }
if (mwm_hint->flags & MwmHintsDecorations) {
if (mwm_hint->decorations & MwmDecorAll) {
functions |= Func_Close;
}
}
- delete mwm_hint;
+ delete [] mwm_hint;
}
num = PropBlackboxHintsElements;
if (! xatom->getValue(client.window, XAtom::blackbox_hints,
XAtom::blackbox_hints, num,
- (unsigned long **)&blackbox_hint) ||
- num < PropBlackboxHintsElements)
+ (unsigned long **)&blackbox_hint))
return False;
+ if (num < PropBlackboxHintsElements) {
+ delete [] blackbox_hint;
+ return False;
+ }
if (blackbox_hint->flags & AttribShaded)
flags.shaded = (blackbox_hint->attrib & AttribShaded);
reconfigure();
}
- delete blackbox_hint;
+ delete [] blackbox_hint;
return True;
}
}
+/*
+ * This function is responsible for updating both the client and the frame
+ * rectangles.
+ * According to the ICCCM a client message is not sent for a resize, only a
+ * move.
+ */
void BlackboxWindow::configure(int dx, int dy,
unsigned int dw, unsigned int dh) {
- bool send_event = False;
+ bool send_event = ((frame.rect.x() != dx || frame.rect.y() != dy) &&
+ ! flags.moving);
if (dw != frame.rect.width() || dh != frame.rect.height()) {
frame.rect.setRect(dx, dy, dw, dh);
positionWindows();
decorate();
redrawWindowFrame();
- } else if (frame.rect.x() != dx || frame.rect.y() != dy) {
- send_event = True;
-
+ } else {
frame.rect.setPos(dx, dy);
XMoveWindow(blackbox->getXDisplay(), frame.window,
frame.rect.x(), frame.rect.y());
+ /*
+ we may have been called just after an opaque window move, so even though
+ the old coords match the new ones no ConfigureNotify has been sent yet.
+ There are likely other times when this will be relevant as well.
+ */
+ if (! flags.moving) send_event = True;
}
- if (send_event && ! flags.moving) {
+ if (send_event) {
+ // if moving, the update and event will occur when the move finishes
client.rect.setPos(frame.rect.left() + frame.margin.left,
frame.rect.top() + frame.margin.top);
XSendEvent(blackbox->getXDisplay(), client.window, False,
StructureNotifyMask, &event);
-
screen->updateNetizenConfigNotify(&event);
+ XFlush(blackbox->getXDisplay());
}
}
bool BlackboxWindow::setInputFocus(void) {
if (flags.focused) return True;
- assert(! flags.iconic);
-
+ assert(! flags.iconic &&
+ (flags.stuck || // window must be on the current workspace or sticky
+ blackbox_attrib.workspace == screen->getCurrentWorkspaceID()));
+#if 0
// if the window is not visible, mark the window as wanting focus rather
// than give it focus.
if (! flags.visible) {
wkspc->setLastFocusedWindow(this);
return True;
}
-
+#endif
if (! frame.rect.intersects(screen->getRect())) {
// client is outside the screen, move it to the center
configure((screen->getWidth() - frame.rect.width()) / 2,
ce.xclient.data.l[4] = 0l;
XSendEvent(blackbox->getXDisplay(), client.window, False,
NoEventMask, &ce);
+ XFlush(blackbox->getXDisplay());
}
return ret;
if (! (*it)->flags.iconic) (*it)->iconify();
}
}
+ screen->updateStackingList();
}
XMapWindow(blackbox->getXDisplay(), client.window);
XMapSubwindows(blackbox->getXDisplay(), frame.window);
XMapWindow(blackbox->getXDisplay(), frame.window);
+
+#ifdef DEBUG
+ int real_x, real_y;
+ Window child;
+ XTranslateCoordinates(blackbox->getXDisplay(), client.window,
+ screen->getRootWindow(),
+ 0, 0, &real_x, &real_y, &child);
+ fprintf(stderr, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
+ client.rect.left(), client.rect.top(), real_x, real_y);
+ assert(client.rect.left() == real_x && client.rect.top() == real_y);
+#endif
}
-void BlackboxWindow::deiconify(bool reassoc, bool doraise) {
+void BlackboxWindow::deiconify(bool reassoc, bool raise) {
if (flags.iconic || reassoc)
screen->reassociateWindow(this, BSENTINEL, False);
- else if (blackbox_attrib.workspace != screen->getCurrentWorkspace()->getID())
+ else if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID())
return;
show();
}
}
- if (doraise)
- raise();
-}
-
-
-void BlackboxWindow::raise(void) {
- screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
-}
-
-
-void BlackboxWindow::lower(void) {
- screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
+ if (raise)
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
}
ce.xclient.data.l[3] = 0l;
ce.xclient.data.l[4] = 0l;
XSendEvent(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce);
+ XFlush(blackbox->getXDisplay());
}
configure(frame.changing.x(), frame.changing.y(),
frame.changing.width(), frame.changing.height());
if (flags.focused)
- raise();
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
redrawAllButtons(); // in case it is not called in configure()
setState(current_state);
}
void BlackboxWindow::setWorkspace(unsigned int n) {
blackbox_attrib.flags |= AttribWorkspace;
blackbox_attrib.workspace = n;
+ if (n == BSENTINEL) { // iconified window
+ /*
+ we set the workspace to 'all workspaces' so that taskbars will show the
+ window. otherwise, it made uniconifying a window imposible without the
+ blackbox workspace menu
+ */
+ n = 0xffffffff;
+ }
xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, n);
}
(unsigned long **)&net))
return;
if (num < PropBlackboxAttributesElements) {
- delete net;
+ delete [] net;
return;
}
if (net->flags & AttribShaded && net->attrib & AttribShaded) {
flags.shaded = False;
+ unsigned long orig_state = current_state;
shade();
/*
- Because the iconic'ness of shaded windows is lost, we need to set the
- state to NormalState so that shaded windows on other workspaces will not
- get shown on the first workspace.
At this point in the life of a window, current_state should only be set
to IconicState if the window was an *icon*, not if it was shaded.
*/
- current_state = NormalState;
+ if (orig_state != IconicState)
+ current_state = WithdrawnState;
}
- if ((net->workspace != screen->getCurrentWorkspaceID()) &&
- (net->workspace < screen->getWorkspaceCount()))
+ if (net->workspace != screen->getCurrentWorkspaceID() &&
+ net->workspace < screen->getWorkspaceCount())
screen->reassociateWindow(this, net->workspace, True);
if ((blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) &&
// with the state set it will then be the map event's job to read the
// window's state and behave accordingly
- delete net;
+ delete [] net;
}
case NorthEastGravity:
case SouthEastGravity:
case EastGravity:
- r.setX(client.rect.x() - frame.margin.left - frame.margin.right);
+ r.setX(client.rect.x() - frame.margin.left - frame.margin.right + 2);
break;
case ForgetGravity:
case SouthWestGravity:
case SouthEastGravity:
case SouthGravity:
- r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom);
+ r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom + 2);
break;
case ForgetGravity:
case NorthEastGravity:
case SouthEastGravity:
case EastGravity:
- r.setX(frame.rect.x() + frame.margin.left + frame.margin.right);
+ r.setX(frame.rect.x() + frame.margin.left + frame.margin.right - 2);
break;
case ForgetGravity:
case SouthWestGravity:
case SouthEastGravity:
case SouthGravity:
- r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom);
+ r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom - 2);
break;
case ForgetGravity:
WindowStyle *style = screen->getWindowStyle();
- int pos = frame.bevel_w * 2,
- dlen = style->doJustify(client.title.c_str(), pos, frame.label_w,
- frame.bevel_w * 4, i18n.multibyte());
-
- BPen pen((flags.focused) ? style->l_text_focus : style->l_text_unfocus,
- style->font);
- if (i18n.multibyte())
- XmbDrawString(blackbox->getXDisplay(), frame.label, style->fontset,
- pen.gc(), pos,
- (1 - style->fontset_extents->max_ink_extent.y),
- client.title.c_str(), dlen);
- else
- XDrawString(blackbox->getXDisplay(), frame.label, pen.gc(), pos,
- (style->font->ascent + 1), client.title.c_str(), dlen);
+ int pos = frame.bevel_w * 2;
+ style->doJustify(client.title.c_str(), pos, frame.label_w, frame.bevel_w * 4);
+ style->font->drawString(frame.label, pos, 1,
+ (flags.focused ? style->l_text_focus :
+ style->l_text_unfocus),
+ client.title);
}
case ZoomState:
default:
show();
- raise();
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
if (! blackbox->isStartup() && (isTransient() || screen->doFocusNew())) {
XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped..
setInputFocus();
}
-void BlackboxWindow::propertyNotifyEvent(Atom atom) {
- switch(atom) {
+void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) {
+ if (pe->state == PropertyDelete)
+ return;
+
+#ifdef DEBUG
+ fprintf(stderr, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
+ client.window);
+#endif
+
+ switch(pe->atom) {
case XA_WM_CLASS:
case XA_WM_CLIENT_MACHINE:
case XA_WM_COMMAND:
if ((client.normal_hint_flags & PMinSize) &&
(client.normal_hint_flags & PMaxSize)) {
+ // the window now can/can't resize itself, so the buttons need to be
+ // regrabbed.
+ ungrabButtons();
if (client.max_width <= client.min_width &&
client.max_height <= client.min_height) {
decorations &= ~(Decor_Maximize | Decor_Handle);
functions &= ~(Func_Resize | Func_Maximize);
} else {
- decorations |= Decor_Maximize | Decor_Handle;
- functions |= Func_Resize | Func_Maximize;
+ if (! isTransient()) {
+ decorations |= Decor_Maximize | Decor_Handle;
+ functions |= Func_Maximize;
+ }
+ functions |= Func_Resize;
}
+ grabButtons();
setAllowedActions();
}
}
default:
- if (atom == xatom->getAtom(XAtom::wm_protocols)) {
+ if (pe->atom == xatom->getAtom(XAtom::wm_protocols)) {
getWMProtocols();
if ((decorations & Decor_Close) && (! frame.close_button)) {
}
if (windowmenu) windowmenu->reconfigure();
}
- } else if (atom == xatom->getAtom(XAtom::net_wm_strut)) {
+ } else if (pe->atom == xatom->getAtom(XAtom::net_wm_strut)) {
updateStrut();
}
void BlackboxWindow::exposeEvent(const XExposeEvent *ee) {
+#ifdef DEBUG
+ fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window);
+#endif
+
if (frame.label == ee->window && (decorations & Decor_Titlebar))
redrawLabel();
else if (frame.close_button == ee->window)
switch (cr->detail) {
case Below:
case BottomIf:
- lower();
+ screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
break;
case Above:
case TopIf:
default:
- raise();
- break;
- }
- }
-}
-
-
-void BlackboxWindow::grabButtons(void) {
- const BInput::MouseBindingList &mbindings = input->getMouseBindings();
-
- BInput::MouseBindingList::const_iterator mit = mbindings.begin();
- const BInput::MouseBindingList::const_iterator mend = mbindings.end();
- for (; mit != mend; ++mit) {
- // dont grab for an action the window can't perform
- //if (! (mit->action == BInput::BeginMove && functions & Func_Move) &&
- // ! (mit->action == BInput::BeginResize && functions & Func_Resize)) {
- switch (mit->event) {
- case BInput::WindowClientPress:
- blackbox->grabButton(mit->button, mit->state, frame.plate, True,
- ButtonPressMask, GrabModeSync, GrabModeSync,
- frame.plate, None);
- break;
- case BInput::WindowDrag:
- blackbox->grabButton(mit->button, mit->state, frame.window, True,
- ButtonMotionMask, GrabModeAsync, GrabModeAsync,
- frame.window, None);
- default:
- break;
- }
- }
-}
-
-
-void BlackboxWindow::ungrabButtons(void) {
- const BInput::MouseBindingList &mbindings = input->getMouseBindings();
-
- BInput::MouseBindingList::const_iterator mit = mbindings.begin();
- const BInput::MouseBindingList::const_iterator mend = mbindings.end();
- for (; mit != mend; ++mit) {
- switch (mit->event) {
- case BInput::WindowClientPress:
- blackbox->ungrabButton(mit->button, mit->state, frame.plate);
- break;
- case BInput::WindowDrag:
- blackbox->ungrabButton(mit->button, mit->state, frame.window);
- default:
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
break;
}
}
void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) {
- if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
-
+#ifdef DEBUG
+ fprintf(stderr, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
+ client.window);
+#endif
+
if (frame.maximize_button == be->window) {
- if (input->hasAction(be->button, be->state, BInput::MaximizeButtonClick))
- redrawMaximizeButton(True);
- } else if (frame.iconify_button == be->window) {
- if (input->hasAction(be->button, be->state, BInput::IconifyButtonClick))
+ redrawMaximizeButton(True);
+ } else if (be->button == 1 || (be->button == 3 && be->state == Mod1Mask)) {
+ if (! flags.focused)
+ setInputFocus();
+
+ if (frame.iconify_button == be->window) {
redrawIconifyButton(True);
- } else if (frame.close_button == be->window) {
- if (input->hasAction(be->button, be->state, BInput::CloseButtonClick))
+ } else if (frame.close_button == be->window) {
redrawCloseButton(True);
- } else if (frame.title == be->window || frame.label == be->window) {
- if (be->time - lastButtonPressTime <= blackbox->getDoubleClickInterval()) {
- lastButtonPressTime = 0;
- input->doAction(this, be->button, be->state,
- BInput::WindowTitleDoublePress);
- } else {
- lastButtonPressTime = be->time;
- input->doAction(this, be->button, be->state,
- BInput::WindowTitlePress);
- }
- } else if (frame.plate == be->window) {
- input->doAction(this, be->button, be->state, BInput::WindowClientPress);
- // buttons on the client window are grabbed in Sync mode, so we need to let
- // events back through again
- XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time);
- } else if (frame.window == be->window || frame.handle == be->window) {
- input->doAction(this, be->button, be->state, BInput::WindowFramePress);
- }
-}
+ } else if (frame.plate == be->window) {
+ if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
-void BlackboxWindow::showWindowMenu(int root_x, int root_y) {
- if (! windowmenu || windowmenu->isVisible())
- return;
-
- root_x -= windowmenu->getWidth() / 2;
- root_y -= windowmenu->getHeight() / 2;
-
- // snap the window menu into a corner/side if necessary
- int left_edge, right_edge, top_edge, bottom_edge;
-
- left_edge = frame.rect.x();
- right_edge = frame.rect.right() - windowmenu->getWidth() - frame.border_w - 1;
- if (decorations & Decor_Titlebar)
- top_edge = frame.rect.y() + frame.title_h + frame.border_w;
- else
- top_edge = frame.rect.y() + frame.border_w;
- if (decorations & Decor_Handle)
- bottom_edge = frame.rect.bottom() - frame.handle_h - (frame.border_w * 3) -
- windowmenu->getHeight();
- else
- bottom_edge = frame.rect.bottom() - windowmenu->getHeight() -
- frame.border_w + 1;
-
- if (root_x > right_edge)
- root_x = right_edge;
- if (root_x < left_edge)
- root_x = left_edge;
-
- if (root_y > bottom_edge)
- root_y = bottom_edge;
- if (root_y < top_edge)
- root_y = top_edge;
+ XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time);
+ } else {
+ if (frame.title == be->window || frame.label == be->window) {
+ if (((be->time - lastButtonPressTime) <=
+ blackbox->getDoubleClickInterval()) ||
+ (be->state == ControlMask)) {
+ lastButtonPressTime = 0;
+ shade();
+ } else {
+ lastButtonPressTime = be->time;
+ }
+ }
+ if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
- windowmenu->move(root_x, root_y);
- windowmenu->show();
- XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID());
- XRaiseWindow(blackbox->getXDisplay(),
- windowmenu->getSendToMenu()->getWindowID());
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
+ }
+ } else if (be->button == 2 && (be->window != frame.iconify_button) &&
+ (be->window != frame.close_button)) {
+ screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
+ } else if (windowmenu && be->button == 3 &&
+ (frame.title == be->window || frame.label == be->window ||
+ frame.handle == be->window || frame.window == be->window)) {
+ if (windowmenu->isVisible()) {
+ windowmenu->hide();
+ } else {
+ int mx = be->x_root - windowmenu->getWidth() / 2,
+ my = be->y_root - windowmenu->getHeight() / 2;
+
+ // snap the window menu into a corner/side if necessary
+ int left_edge, right_edge, top_edge, bottom_edge;
+
+ /*
+ the " + (frame.border_w * 2) - 1" bits are to get the proper width
+ and height of the menu, as the sizes returned by it do not include
+ the borders.
+ */
+ left_edge = frame.rect.x();
+ right_edge = frame.rect.right() -
+ (windowmenu->getWidth() + (frame.border_w * 2) - 1);
+ top_edge = client.rect.top() - (frame.border_w + frame.mwm_border_w);
+ bottom_edge = client.rect.bottom() -
+ (windowmenu->getHeight() + (frame.border_w * 2) - 1) +
+ (frame.border_w + frame.mwm_border_w);
+
+ if (mx < left_edge)
+ mx = left_edge;
+ if (mx > right_edge)
+ mx = right_edge;
+ if (my < top_edge)
+ my = top_edge;
+ if (my > bottom_edge)
+ my = bottom_edge;
+
+ windowmenu->move(mx, my);
+ windowmenu->show();
+ XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID());
+ XRaiseWindow(blackbox->getXDisplay(),
+ windowmenu->getSendToMenu()->getWindowID());
+ }
+ // mouse wheel up
+ } else if (be->button == 4) {
+ if ((be->window == frame.label ||
+ be->window == frame.title) &&
+ ! flags.shaded)
+ shade();
+ // mouse wheel down
+ } else if (be->button == 5) {
+ if ((be->window == frame.label ||
+ be->window == frame.title) &&
+ flags.shaded)
+ shade();
+ }
}
void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) {
- // get the proper state, without the button that was released
- unsigned int state;
- switch (re->button) {
- case Button1:
- state = re->state & ~Button1Mask;
- break;
- case Button2:
- state = re->state & ~Button2Mask;
- break;
- case Button3:
- state = re->state & ~Button3Mask;
- break;
- case Button4:
- state = re->state & ~Button4Mask;
- break;
- case Button5:
- state = re->state & ~Button5Mask;
- break;
- default:
- assert(false); // unhandled button
- }
+#ifdef DEBUG
+ fprintf(stderr, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
+ client.window);
+#endif
- if (frame.maximize_button == re->window) {
- if ((re->x < 0 || re->x >= static_cast<signed>(frame.button_w)) ||
- (re->y < 0 || re->y >= static_cast<signed>(frame.button_w)) ||
- ! input->doAction(this, re->button, state,
- BInput::MaximizeButtonClick))
+ if (re->window == frame.maximize_button) {
+ if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
+ (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
+ maximize(re->button);
+ } else {
redrawMaximizeButton(flags.maximized);
- } else if (frame.iconify_button == re->window) {
- if ((re->x < 0 || re->x >= static_cast<signed>(frame.button_w)) ||
- (re->y < 0 || re->y >= static_cast<signed>(frame.button_w)) ||
- ! input->doAction(this, re->button, state,
- BInput::IconifyButtonClick))
+ }
+ } else if (re->window == frame.iconify_button) {
+ if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
+ (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
+ iconify();
+ } else {
redrawIconifyButton(False);
- } else if (frame.close_button == re->window) {
- if (! ((re->x < 0 || re->x >= static_cast<signed>(frame.button_w)) ||
- (re->y < 0 || re->y >= static_cast<signed>(frame.button_w))))
- input->doAction(this, re->button, state, BInput::CloseButtonClick);
- redrawCloseButton(False);
+ }
+ } else if (re->window == frame.close_button) {
+ if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
+ (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w)))
+ close();
+ redrawCloseButton(False);
} else if (flags.moving) {
endMove();
} else if (flags.resizing) {
endResize();
+ } else if (re->window == frame.window) {
+ if (re->button == 2 && re->state == Mod1Mask)
+ XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
}
}
-void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) {
- // get the button that is being used
- // get the proper state, without the button that is being used
- unsigned int button;
- unsigned int state;
- if (me->state & Button1Mask) {
- button = Button1;
- state = me->state & ~Button1Mask;
- } else if (me->state & Button2Mask) {
- button = Button2;
- state = me->state & ~Button2Mask;
- } else if (me->state & Button3Mask) {
- button = Button3;
- state = me->state & ~Button3Mask;
- } else if (me->state & Button4Mask) {
- button = Button4;
- state = me->state & ~Button4Mask;
- } else if (me->state & Button5Mask) {
- button = Button5;
- state = me->state & ~Button5Mask;
- } else {
- return;
- }
-
- if (flags.moving) {
- doMove(me->x_root, me->y_root);
- } else if (flags.resizing) {
- doResize(me->x_root, me->y_root);
- } else {
- if (frame.title == me->window || frame.label == me->window)
- input->doAction(this, button, state, BInput::WindowTitleDrag);
- else if (frame.handle == me->window)
- input->doAction(this, button, state, BInput::WindowHandleDrag);
- else if (frame.left_grip == me->window)
- input->doAction(this, button, state, BInput::WindowLeftGripDrag);
- else if (frame.right_grip == me->window)
- input->doAction(this, button, state, BInput::WindowRightGripDrag);
- else if (frame.window == me->window)
- input->doAction(this, button, state, BInput::WindowDrag);
- }
-}
-
void BlackboxWindow::beginMove(int x_root, int y_root) {
assert(! (flags.resizing || flags.moving));
default:
assert(false); // unhandled Corner
+ return; // unreachable, for the compiler
}
XGrabServer(blackbox->getXDisplay());
Corner anchor;
switch (resize_dir) {
- case BottomLeft:
- anchor = TopRight;
- frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
- frame.rect.height() + (y_root - frame.grab_y));
- break;
- case BottomRight:
- anchor = TopLeft;
- frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
- frame.rect.height() + (y_root - frame.grab_y));
- break;
- case TopLeft:
- anchor = BottomRight;
- frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
- frame.rect.height() - (y_root - frame.grab_y));
- break;
- case TopRight:
- anchor = BottomLeft;
- frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
- frame.rect.height() - (y_root - frame.grab_y));
- break;
+ case BottomLeft:
+ anchor = TopRight;
+ frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
+ frame.rect.height() + (y_root - frame.grab_y));
+ break;
+ case BottomRight:
+ anchor = TopLeft;
+ frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
+ frame.rect.height() + (y_root - frame.grab_y));
+ break;
+ case TopLeft:
+ anchor = BottomRight;
+ frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
+ frame.rect.height() - (y_root - frame.grab_y));
+ break;
+ case TopRight:
+ anchor = BottomLeft;
+ frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
+ frame.rect.height() - (y_root - frame.grab_y));
+ break;
- default:
- assert(false); // unhandled Corner
+ default:
+ assert(false); // unhandled Corner
+ return; // unreachable, for the compiler
}
constrain(anchor, &gw, &gh);
}
+void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) {
+#ifdef DEBUG
+ fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
+ client.window);
+#endif
+
+ if (flags.moving) {
+ doMove(me->x_root, me->y_root);
+ } else if (flags.resizing) {
+ doResize(me->x_root, me->y_root);
+ } else {
+ if (!flags.resizing && me->state & Button1Mask && (functions & Func_Move) &&
+ (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 & Mod1Mask &&
+ me->window == frame.window)) {
+ unsigned int zones = screen->getResizeZones();
+ Corner corner;
+
+ if (me->window == frame.left_grip) {
+ corner = BottomLeft;
+ } else if (me->window == frame.right_grip || zones == 1) {
+ corner = BottomRight;
+ } else {
+ bool top;
+ bool left = (me->x_root - frame.rect.x() <=
+ static_cast<signed>(frame.rect.width() / 2));
+ if (zones == 2)
+ top = False;
+ else // (zones == 4)
+ top = (me->y_root - frame.rect.y() <=
+ static_cast<signed>(frame.rect.height() / 2));
+ corner = (top ? (left ? TopLeft : TopRight) :
+ (left ? BottomLeft : BottomRight));
+ }
+
+ beginResize(me->x_root, me->y_root, corner);
+ }
+ }
+}
+
+
#ifdef SHAPE
void BlackboxWindow::shapeEvent(XShapeEvent *) {
if (blackbox->hasShapeExtensions() && flags.shaped) {
XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask);
+ // do not leave a shaded window as an icon unless it was an icon
+ if (flags.shaded && ! flags.iconic) setState(NormalState);
+
restoreGravity(client.rect);
XUnmapWindow(blackbox->getXDisplay(), frame.window);
// timer for autoraise
void BlackboxWindow::timeout(void) {
- raise();
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
}
withdraw();
} else {
show();
- raise();
+ screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
}
}
// the height of the titlebar is based upon the height of the font being
// used to display the window's title
WindowStyle *style = screen->getWindowStyle();
- if (i18n.multibyte())
- frame.title_h = (style->fontset_extents->max_ink_extent.height +
- (frame.bevel_w * 2) + 2);
- else
- frame.title_h = (style->font->ascent + style->font->descent +
- (frame.bevel_w * 2) + 2);
+ frame.title_h = style->font->height() + (frame.bevel_w * 2) + 2;
frame.label_h = frame.title_h - (frame.bevel_w * 2);
frame.button_w = (frame.label_h - 2);
}
-int WindowStyle::doJustify(const char *text, int &start_pos,
- unsigned int max_length, unsigned int modifier,
- bool multibyte) const {
- size_t text_len = strlen(text);
+void WindowStyle::doJustify(const std::string &text, int &start_pos,
+ unsigned int max_length,
+ unsigned int modifier) const {
+ size_t text_len = text.size();
unsigned int length;
do {
- if (multibyte) {
- XRectangle ink, logical;
- XmbTextExtents(fontset, text, text_len, &ink, &logical);
- length = logical.width;
- } else {
- length = XTextWidth(font, text, text_len);
- }
- length += modifier;
+ length = font->measureString(string(text, 0, text_len)) + modifier;
} while (length > max_length && text_len-- > 0);
switch (justify) {
default:
break;
}
-
- return text_len;
}