screen_number = num;
root_window = RootWindow(basedisplay->getXDisplay(), screen_number);
- depth = DefaultDepth(basedisplay->getXDisplay(), screen_number);
rect.setSize(WidthOfScreen(ScreenOfDisplay(basedisplay->getXDisplay(),
screen_number)),
HeightOfScreen(ScreenOfDisplay(basedisplay->getXDisplay(),
screen_number)));
+ /*
+ If the default depth is at least 15 we will use that,
+ otherwise we try to find the largest TrueColor visual.
+ Preference is given to 24 bit over larger depths if 24 bit is an option.
+ */
- // search for a TrueColor Visual... if we can't find one... we will use the
- // default visual for the screen
- XVisualInfo vinfo_template, *vinfo_return;
- int vinfo_nitems;
-
- vinfo_template.screen = screen_number;
- vinfo_template.c_class = TrueColor;
-
- visual = (Visual *) 0;
-
- vinfo_return = XGetVisualInfo(basedisplay->getXDisplay(),
- VisualScreenMask | VisualClassMask,
- &vinfo_template, &vinfo_nitems);
- if (vinfo_return && vinfo_nitems > 0) {
- for (int i = 0; i < vinfo_nitems; i++) {
- if (depth < (vinfo_return + i)->depth) {
- depth = (vinfo_return + i)->depth;
- visual = (vinfo_return + i)->visual;
+ depth = DefaultDepth(basedisplay->getXDisplay(), screen_number);
+ visual = DefaultVisual(basedisplay->getXDisplay(), screen_number);
+ colormap = DefaultColormap(basedisplay->getXDisplay(), screen_number);
+
+ if (depth < 15) {
+ // search for a TrueColor Visual... if we can't find one...
+ // we will use the default visual for the screen
+ XVisualInfo vinfo_template, *vinfo_return;
+ int vinfo_nitems;
+ int best = -1;
+
+ vinfo_template.screen = screen_number;
+ vinfo_template.c_class = TrueColor;
+
+ vinfo_return = XGetVisualInfo(basedisplay->getXDisplay(),
+ VisualScreenMask | VisualClassMask,
+ &vinfo_template, &vinfo_nitems);
+ if (vinfo_return) {
+ int max_depth = 1;
+ for (int i = 0; i < vinfo_nitems; ++i) {
+ if (vinfo_return[i].depth > max_depth) {
+ if (max_depth == 24 && vinfo_return[i].depth > 24)
+ break; // prefer 24 bit over 32
+ max_depth = vinfo_return[i].depth;
+ best = i;
+ }
}
+ if (max_depth < depth) best = -1;
}
- XFree(vinfo_return);
- }
+ if (best != -1) {
+ depth = vinfo_return[best].depth;
+ visual = vinfo_return[best].visual;
+ colormap = XCreateColormap(basedisplay->getXDisplay(), root_window,
+ visual, AllocNone);
+ }
- if (visual) {
- colormap = XCreateColormap(basedisplay->getXDisplay(), root_window,
- visual, AllocNone);
- } else {
- visual = DefaultVisual(basedisplay->getXDisplay(), screen_number);
- colormap = DefaultColormap(basedisplay->getXDisplay(), screen_number);
+ XFree(vinfo_return);
}
// get the default display string and strip the screen number
}
-BasemenuItem::~BasemenuItem(void) {}
-
-
BasemenuItem *Basemenu::find(int index) {
- if (index < 0 || index > static_cast<signed>(menuitems.size()))
+ if (index < 0 || index >= static_cast<signed>(menuitems.size()))
return (BasemenuItem*) 0;
- return *(menuitems.begin() + index);
+ return menuitems[index];
}
void Basemenu::drawItem(int index, bool highlight, bool clear,
- int x, int y, unsigned int w, unsigned int h)
-{
+ int x, int y, unsigned int w, unsigned int h) {
BasemenuItem *item = find(index);
if (! item) return;
f(0), enabled(1),
selected(0) {}
- ~BasemenuItem(void);
-
inline const char *exec(void) const { return e.c_str(); }
inline const char *label(void) const { return l.c_str(); }
inline int function(void) const { return f; }
workspacemenu->setItemSelected(2, True);
+ removeWorkspaceNames(); // do not need them any longer
+
toolbar = new Toolbar(this);
slit = new Slit(this);
else
resource.col_direction = TopBottom;
- removeWorkspaceNames();
if (config->getValue(screenstr + "workspaceNames", s)) {
string::const_iterator it = s.begin(), end = s.end();
while(1) {
if (! current_workspace) return;
if (id != current_workspace->getID()) {
- current_workspace->hideAll();
-
- workspacemenu->setItemSelected(current_workspace->getID() + 2, False);
-
BlackboxWindow *focused = blackbox->getFocusedWindow();
if (focused && focused->getScreen() == this && ! focused->isStuck()) {
if (focused->getWorkspaceNumber() != current_workspace->getID()) {
abort();
}
current_workspace->setLastFocusedWindow(focused);
- blackbox->setFocusedWindow((BlackboxWindow *) 0);
+ } else {
+ // if no window had focus, no need to store a last focus
+ current_workspace->setLastFocusedWindow((BlackboxWindow *) 0);
}
+ // when we switch workspaces, unfocus whatever was focused
+ blackbox->setFocusedWindow((BlackboxWindow *) 0);
+
+ current_workspace->hideAll();
+ workspacemenu->setItemSelected(current_workspace->getID() + 2, False);
current_workspace = getWorkspace(id);
void BScreen::raiseWindows(Window *workspace_stack, unsigned int num) {
- // XXX: why 13??
+ // the 13 represents the number of blackbox windows such as menus
Window *session_stack = new
Window[(num + workspacesList.size() + rootmenuList.size() + 13)];
unsigned int i = 0, k = num;
strut.top = strut.bottom = strut.left = strut.right = 0;
if (! clientList.empty()) {
+ // when not hidden both borders are in use, when hidden only one is
+ unsigned int border_width = screen->getBorderWidth();
+ if (! do_auto_hide)
+ border_width *= 2;
+
switch (direction) {
case Vertical:
switch (placement) {
case TopCenter:
- strut.top = getY() + getExposedHeight() +
- (screen->getBorderWidth() * 2);
+ strut.top = getExposedHeight() + border_width;
break;
case BottomCenter:
- strut.bottom = screen->getHeight() - getY();
+ strut.bottom = getExposedHeight() + border_width;
break;
case TopLeft:
case CenterLeft:
case BottomLeft:
- strut.left = getExposedWidth() + (screen->getBorderWidth() * 2);
+ strut.left = getExposedWidth() + border_width;
break;
case TopRight:
case CenterRight:
case BottomRight:
- strut.right = getExposedWidth() + (screen->getBorderWidth() * 2);
+ strut.right = getExposedWidth() + border_width;
break;
}
break;
case TopCenter:
case TopLeft:
case TopRight:
- strut.top = getY() + getExposedHeight() +
- (screen->getBorderWidth() * 2);
+ strut.top = getExposedHeight() + border_width;
break;
case BottomCenter:
case BottomLeft:
case BottomRight:
- strut.bottom = screen->getHeight() - getY();
+ strut.bottom = getExposedHeight() + border_width;
break;
case CenterLeft:
- strut.left = getExposedWidth() + (screen->getBorderWidth() * 2);
+ strut.left = getExposedWidth() + border_width;
break;
case CenterRight:
- strut.right = getExposedWidth() + (screen->getBorderWidth() * 2);
+ strut.right = getExposedWidth() + border_width;
break;
}
break;
// left and right are always 0
strut.top = strut.bottom = 0;
+ // when hidden only one border is visible
+ unsigned int border_width = screen->getBorderWidth();
+ if (! do_auto_hide)
+ border_width *= 2;
+
if (! screen->doHideToolbar()) {
switch(placement) {
case TopLeft:
case TopCenter:
case TopRight:
- strut.top = getExposedHeight() + (screen->getBorderWidth() * 2);
+ strut.top = getExposedHeight() + border_width;
break;
default:
- strut.bottom = getExposedHeight() + (screen->getBorderWidth() * 2);
+ strut.bottom = getExposedHeight() + border_width;
}
}
fprintf(stderr, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w);
#endif // DEBUG
- // set timer to zero... it is initialized properly later, so we check
- // if timer is zero in the destructor, and assume that the window is not
- // fully constructed if timer is zero...
+ /*
+ set timer to zero... it is initialized properly later, so we check
+ if timer is zero in the destructor, and assume that the window is not
+ fully constructed if timer is zero...
+ */
timer = 0;
blackbox = b;
client.window = w;
client.wm_hint_flags = client.normal_hint_flags = 0;
client.transient_for = 0;
- // get 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.
+ /*
+ get 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.
+ */
client.rect.setRect(wattrib.x, wattrib.y, wattrib.width, wattrib.height);
client.old_bw = wattrib.border_width;
frame.rect.width(), frame.rect.height());
}
+ // preserve the window's initial state on first map, and its current state
+ // across a restart
+ if (! getState()) {
+ if (client.wm_hint_flags & StateHint)
+ current_state = client.initial_state;
+ else
+ current_state = NormalState;
+ }
+
if (flags.shaded) {
flags.shaded = False;
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 (flags.stuck) {
+ flags.stuck = False;
+ stick();
}
if (flags.maximized && (functions & Func_Maximize)) {
remaximize();
}
+ /*
+ When the window is mapped (and also when its attributes are restored), the
+ current_state that was set here will be used.
+ It is set to Normal if the window is to be mapped or it is set to Iconic
+ if the window is to be iconified.
+ *Note* that for sticky windows, the same rules apply here, they are in
+ fact never set to Iconic since there is no way for us to tell if a sticky
+ window was iconified previously.
+ */
+
setFocusFlag(False);
}
bool BlackboxWindow::setInputFocus(void) {
if (flags.focused) return True;
+ assert(! flags.iconic);
+
+ // if the window is not visible, mark the window as wanting focus rather
+ // than give it focus.
+ if (! flags.visible) {
+ Workspace *wkspc = screen->getWorkspace(blackbox_attrib.workspace);
+ wkspc->setLastFocusedWindow(this);
+ return True;
+ }
+
if (! client.rect.intersects(screen->getRect())) {
// client is outside the screen, move it to the center
configure((screen->getWidth() - frame.rect.width()) / 2,
void BlackboxWindow::show(void) {
- setState(NormalState);
+ current_state = (flags.shaded) ? IconicState : NormalState;
+ setState(current_state);
XMapWindow(blackbox->getXDisplay(), client.window);
XMapSubwindows(blackbox->getXDisplay(), frame.window);
XUnmapWindow(blackbox->getXDisplay(), frame.window);
XGrabServer(blackbox->getXDisplay());
+
XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
XUnmapWindow(blackbox->getXDisplay(), client.window);
XSelectInput(blackbox->getXDisplay(), client.window,
PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
- XUngrabServer(blackbox->getXDisplay());
+
+ XUngrabServer(blackbox->getXDisplay());
if (windowmenu) windowmenu->hide();
}
void BlackboxWindow::setFocusFlag(bool focus) {
+ // only focus a window if it is visible
+ if (focus && !flags.visible)
+ return;
+
flags.focused = focus;
if (decorations & Decor_Titlebar) {
void BlackboxWindow::restoreAttributes(void) {
- if (! getState()) current_state = NormalState;
-
Atom atom_return;
int foo;
unsigned long ulfoo, nitems;
if (ret != Success || ! net || nitems != PropBlackboxAttributesElements)
return;
- if (net->flags & AttribShaded &&
- net->attrib & AttribShaded) {
- int save_state =
- ((current_state == IconicState) ? NormalState : current_state);
-
+ if (net->flags & AttribShaded && net->attrib & AttribShaded) {
flags.shaded = False;
shade();
- current_state = save_state;
- }
+ /*
+ 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 ((net->workspace != screen->getCurrentWorkspaceID()) &&
(net->workspace < screen->getWorkspaceCount())) {
screen->reassociateWindow(this, net->workspace, True);
+ // set to WithdrawnState so it will be mapped on the new workspace
if (current_state == NormalState) current_state = WithdrawnState;
} else if (current_state == WithdrawnState) {
+ // the window is on this workspace and is Withdrawn, so it is waiting to
+ // be mapped
current_state = NormalState;
}
- if (net->flags & AttribOmnipresent &&
- net->attrib & AttribOmnipresent) {
+ if (net->flags & AttribOmnipresent && net->attrib & AttribOmnipresent) {
flags.stuck = False;
stick();
- current_state = NormalState;
+ // if the window was on another workspace, it was going to be hidden. this
+ // specifies that the window should be mapped since it is sticky.
+ if (current_state == WithdrawnState) current_state = NormalState;
}
- if ((net->flags & AttribMaxHoriz) ||
- (net->flags & AttribMaxVert)) {
+ if (net->flags & AttribMaxHoriz || net->flags & AttribMaxVert) {
int x = net->premax_x, y = net->premax_y;
unsigned int w = net->premax_w, h = net->premax_h;
flags.maximized = 0;
blackbox_attrib.premax_h = h;
}
- setState(current_state);
+ // with the state set it will then be the map events job to read the window's
+ // state and behave accordingly
XFree((void *) net);
}
client.window);
#endif // DEBUG
- bool get_state_ret = getState();
- if (! (get_state_ret && blackbox->isStartup())) {
- if ((client.wm_hint_flags & StateHint) &&
- (! (current_state == NormalState || current_state == IconicState)))
- current_state = client.initial_state;
- else
- current_state = NormalState;
- } else if (flags.iconic) {
- current_state = NormalState;
- }
-
switch (current_state) {
case IconicState:
iconify();
stackingList.remove(w);
- if (w->isFocused() && ! screen->getBlackbox()->doShutdown()) {
+ // pass focus to the next appropriate window
+ if ((w->isFocused() || w == lastfocus) &&
+ ! screen->getBlackbox()->doShutdown()) {
BlackboxWindow *newfocus = 0;
if (w->isTransient())
newfocus = w->getTransientFor();
if (! newfocus && ! stackingList.empty())
newfocus = stackingList.front();
- if (! newfocus || ! newfocus->setInputFocus())
- screen->getBlackbox()->setFocusedWindow(0);
- }
- if (lastfocus == w)
- lastfocus = (BlackboxWindow *) 0;
+ assert(newfocus != w); // this would be very wrong.
+
+ if (id == screen->getCurrentWorkspaceID()) {
+ /*
+ if the window is on the visible workspace, then try focus it, and fall
+ back to the default focus target if the window won't focus.
+ */
+ if (! newfocus || ! newfocus->setInputFocus())
+ screen->getBlackbox()->setFocusedWindow(0);
+ } else if (lastfocus == w) {
+ /*
+ If this workspace is not the current one do not assume that
+ w == lastfocus. If a sticky window is removed on a workspace other
+ than where it originated, it will fire the removeWindow on a
+ non-visible workspace.
+ */
+
+ /*
+ If the window isn't on the visible workspace, don't focus the new one,
+ just mark it to be focused when the workspace comes into view.
+ */
+ setLastFocusedWindow(newfocus);
+ }
+ }
windowList.remove(w);
clientmenu->remove(w->getWindowNumber());