current_state = NormalState;
+ windowmenu = 0;
+
/*
get the initial size and location of client window (relative to the
_root window_). This position is the reference point used with the
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
screen->addStrut(&client.strut);
updateStrut();
-#ifdef SHAPE
- if (blackbox->hasShapeExtensions() && flags.shaped)
- configureShape();
-#endif // SHAPE
-
- // get the window's title before adding it to the workspace
- getWMName();
- getWMIconName();
-
- if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
- screen->getCurrentWorkspace()->addWindow(this, place_window);
- else
- screen->getWorkspace(blackbox_attrib.workspace)->
- addWindow(this, place_window);
-
/*
the server needs to be grabbed here to prevent client's from sending
events while we are in the process of configuring their window.
blackbox->saveWindowSearch(client.window, this);
+ if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
+ screen->getCurrentWorkspace()->addWindow(this, place_window);
+ else
+ screen->getWorkspace(blackbox_attrib.workspace)->
+ addWindow(this, place_window);
+
if (! place_window) {
// don't need to call configure if we are letting the workspace
// place the window
XUngrabServer(blackbox->getXDisplay());
+#ifdef SHAPE
+ if (blackbox->hasShapeExtensions() && flags.shaped)
+ configureShape();
+#endif // SHAPE
+
// now that we know where to put the window and what it should look like
// we apply the decorations
decorate();
if (flags.maximized && (functions & Func_Maximize))
remaximize();
+
+ // create this last so it only needs to be configured once
+ windowmenu = new Windowmenu(this);
}
// 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)
attrib_create.colormap = screen->getColormap();
attrib_create.override_redirect = True;
attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
- ButtonMotionMask | EnterWindowMask;
+ ButtonMotionMask |
+ EnterWindowMask | LeaveWindowMask;
return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(),
0, 0, 1, 1, frame.border_w, screen->getDepth(),
void BlackboxWindow::associateClientWindow(void) {
XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, 0);
+ getWMName();
+ getWMIconName();
XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeInsert);
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;
+ }
}
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;
// reassociate and deiconify all transients
if (reassoc && client.transientList.size() > 0) {
BlackboxWindowList::iterator it, end = client.transientList.end();
- for (it = client.transientList.begin(); it != end; ++it) {
+ for (it = client.transientList.begin(); it != end; ++it)
(*it)->deiconify(True, False);
- }
}
if (raise)
void BlackboxWindow::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);
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 = 0;
+ const int snap_offset = screen->getSnapOffset();
// find the geomeetery where the moving window currently is
const Rect &moving = screen->doOpaqueMove() ? frame.rect : frame.changing;
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)
- rectlist.push_back( (*st_it)->frameRect() );
+ 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)
dright = offsetrect.right() - wleft;
// snap left of other window?
- if (dleft >= 0 && dleft < resistance_size) {
+ 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) {
+ else if (dright >= 0 && dright < resistance_size &&
+ dright < (wright - wleft)) {
dx = offsetrect.right() + 1;
snapped = True;
}
dbottom = offsetrect.bottom() - wtop;
// snap top of other window?
- if (dtop >= 0 && dtop < resistance_size) {
+ 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) {
+ else if (dbottom >= 0 && dbottom < resistance_size &&
+ dbottom < (wbottom - wtop)) {
dy = offsetrect.bottom() + 1;
snapped = True;
}
flags.resizing = True;
blackbox->setChangingWindow(this);
- int gw, gh;
+ unsigned int gw, gh;
frame.changing = frame.rect;
constrain(anchor, &gw, &gh);
screen->getOpGC(), frame.changing.x(), frame.changing.y(),
frame.changing.width() - 1, frame.changing.height() - 1);
- int gw, gh;
+ unsigned int gw, gh;
Corner anchor;
switch (resize_dir) {
}
+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) && ! 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) {
* The logical width and height are placed into pw and ph, if they
* are non-zero. Logical size refers to the users perception of
* the window size (for example an xterm resizes in cells, not in pixels).
+ * pw and ph are then used to display the geometry during window moves, resize,
+ * etc.
*
* The physical geometry is placed into frame.changing_{x,y,width,height}.
* Physical geometry refers to the geometry of the window in pixels.
*/
-void BlackboxWindow::constrain(Corner anchor, int *pw, int *ph) {
+void BlackboxWindow::constrain(Corner anchor,
+ unsigned int *pw, unsigned int *ph) {
// frame.changing represents the requested frame size, we need to
// strip the frame margin off and constrain the client size
frame.changing.setCoords(frame.changing.left() + frame.margin.left,
frame.changing.right() - frame.margin.right,
frame.changing.bottom() - frame.margin.bottom);
- int dw = frame.changing.width(), dh = frame.changing.height(),
+ unsigned int dw = frame.changing.width(), dh = frame.changing.height(),
base_width = (client.base_width) ? client.base_width : client.min_width,
base_height = (client.base_height) ? client.base_height :
client.min_height;
// constrain
- if (dw < static_cast<signed>(client.min_width)) dw = client.min_width;
- if (dh < static_cast<signed>(client.min_height)) dh = client.min_height;
- if (dw > static_cast<signed>(client.max_width)) dw = client.max_width;
- if (dh > static_cast<signed>(client.max_height)) dh = client.max_height;
-
- 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);
BlackboxWindow *ret = blackbox->getFocusedWindow();
// does the focus window match (or any transient_fors)?
- while (ret) {
- if (ret->getScreen() == screen && ret->getGroupWindow() == group) {
- if (ret->isTransient() && allow_transients) break;
- else if (! ret->isTransient()) break;
- }
-
- ret = ret->getTransientFor();
+ for (; ret; ret = ret->getTransientFor()) {
+ if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
+ (! ret->isTransient() || allow_transients))
+ break;
}
if (ret) return ret;
BlackboxWindowList::const_iterator it, end = windowList.end();
for (it = windowList.begin(); it != end; ++it) {
ret = *it;
- if (ret->getScreen() == screen && ret->getGroupWindow() == group) {
- if (ret->isTransient() && allow_transients) break;
- else if (! ret->isTransient()) break;
- }
+ if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
+ (! ret->isTransient() || allow_transients))
+ break;
}
return ret;