activate = TRUE;
}
+ /* remove the client's border */
+ XSetWindowBorderWidth(ob_display, self->window, 0);
+
/* adjust the frame to the client's size before showing or placing
the window */
frame_adjust_area(self->frame, FALSE, TRUE, FALSE);
g_free(settings);
ob_debug("Managed window 0x%lx plate 0x%x (%s)\n",
- window, self->frame->plate, self->class);
+ window, self->frame->window, self->class);
return;
}
GSList *it;
ob_debug("Unmanaging window: 0x%x plate 0x%x (%s) (%s)\n",
- self->window, self->frame->plate,
+ self->window, self->frame->window,
self->class, self->title ? self->title : "");
g_assert(self != NULL);
self->functions = OB_CLIENT_FUNC_MOVE | OB_CLIENT_FUNC_RESIZE;
self->decorations = 0; /* unmanaged windows have no decor */
+ /* give the client its border back */
+ XSetWindowBorderWidth(ob_display, self->window, self->border_width);
+
client_move_resize(self, a.x, a.y, a.width, a.height);
}
{
client_configure(self, self->area.x, self->area.y,
self->area.width, self->area.height,
- self->border_width, FALSE, TRUE);
+ FALSE, TRUE);
}
void client_update_wmhints(ObClient *self)
do this before applying the states so they have the correct
pre-max/pre-fullscreen values
*/
- client_configure(self, x, y, w, h, self->border_width, FALSE, TRUE);
+ client_configure(self, x, y, w, h, FALSE, TRUE);
ob_debug("placed window 0x%x at %d, %d with size %d x %d\n",
self->window, self->area.x, self->area.y,
self->area.width, self->area.height);
}
-void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b,
+void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
gboolean user, gboolean final)
{
gint oldw, oldh;
/* figure out if we moved or resized or what */
moved = x != self->area.x || y != self->area.y;
- resized = w != self->area.width || h != self->area.height ||
- b != self->border_width;
+ resized = w != self->area.width || h != self->area.height;
oldw = self->area.width;
oldh = self->area.height;
RECT_SET(self->area, x, y, w, h);
- self->border_width = b;
/* for app-requested resizes, always resize if 'resized' is true.
for user-requested ones, only resize if final is true, or when
/* if the client is enlarging, then resize the client before the frame */
if (send_resize_client && (w > oldw || h > oldh)) {
- XWindowChanges changes;
- changes.x = -self->border_width;
- changes.y = -self->border_width;
- changes.width = MAX(w, oldw);
- changes.height = MAX(h, oldh);
- changes.border_width = self->border_width;
- XConfigureWindow(ob_display, self->window,
- CWX|CWY|CWWidth|CWHeight|CWBorderWidth,
- &changes);
- /* resize the plate to show the client padding color underneath */
+ XResizeWindow(ob_display, self->window, MAX(w, oldw), MAX(h, oldh));
frame_adjust_client_area(self->frame);
}
/* if the client is shrinking, then resize the frame before the client */
if (send_resize_client && (w <= oldw && h <= oldh)) {
- /* resize the plate to show the client padding color underneath */
frame_adjust_client_area(self->frame);
-
- if (send_resize_client) {
- XWindowChanges changes;
- changes.x = -self->border_width;
- changes.y = -self->border_width;
- changes.width = w;
- changes.height = h;
- changes.border_width = self->border_width;
- XConfigureWindow(ob_display, self->window,
- CWX|CWY|CWWidth|CWHeight|CWBorderWidth,
- &changes);
- }
+ XResizeWindow(ob_display, self->window, w, h);
}
XFlush(ob_display);
gint w, gint h);
#define client_move(self, x, y) \
- client_configure(self, x, y, self->area.width, self->area.height, \
- self->border_width, TRUE, TRUE)
+ client_configure(self, x, y, self->area.width, self->area.height, TRUE, TRUE)
#define client_resize(self, w, h) \
- client_configure(self, self->area.x, self->area.y, w, h, \
- self->border_width, TRUE, TRUE)
+ client_configure(self, self->area.x, self->area.y, w, h, TRUE, TRUE)
#define client_move_resize(self, x, y, w, h) \
- client_configure(self, x, y, w, h, self->border_width, TRUE, TRUE)
+ client_configure(self, x, y, w, h, TRUE, TRUE)
/*! Figure out where a window will end up and what size it will be if you
told it to move/resize to these coordinates.
@param force_reply Send a ConfigureNotify to the client regardless of if
the position changed.
*/
-void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b,
+void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
gboolean user, gboolean final);
void client_reconfigure(ObClient *self);
/* This means focus reverted off of a client */
else if (detail == NotifyPointerRoot ||
detail == NotifyDetailNone ||
- detail == NotifyInferior)
+ detail == NotifyInferior ||
+ /* This means focus got here from another screen */
+ detail == NotifyNonlinear)
return TRUE;
else
return FALSE;
} else if (e->type == FocusIn) {
if (e->xfocus.detail == NotifyPointerRoot ||
e->xfocus.detail == NotifyDetailNone ||
- e->xfocus.detail == NotifyInferior)
+ e->xfocus.detail == NotifyInferior ||
+ e->xfocus.detail == NotifyNonlinear)
{
XEvent ce;
- ob_debug_type(OB_DEBUG_FOCUS, "Focus went to pointer root/none or"
- " the frame window\n");
+ ob_debug_type(OB_DEBUG_FOCUS, "Focus went to root, "
+ "pointer root/none or "
+ "the frame window\n");
+
+ if (e->xfocus.detail == NotifyInferior ||
+ e->xfocus.detail == NotifyNonlinear)
+ {
+ focus_left_screen = FALSE;
+ }
/* If another FocusIn is in the queue then don't fallback yet. This
fixes the fun case of:
also you can't compress stacking events
*/
- gint x, y, w, h, b;
+ gint x, y, w, h;
gboolean move = FALSE;
gboolean resize = FALSE;
- gboolean border = FALSE;
/* get the current area */
RECT_TO_DIMS(client->area, x, y, w, h);
- b = client->border_width;
ob_debug("ConfigureRequest for \"%s\" desktop %d wmstate %d "
"visibile %d\n"
" x %d y %d w %d h %d b %d\n",
client->title,
screen_desktop, client->wmstate, client->frame->visible,
- x, y, w, h, b);
+ x, y, w, h, client->border_width);
if (e->xconfigurerequest.value_mask & CWBorderWidth)
if (client->border_width != e->xconfigurerequest.border_width) {
- b = e->xconfigurerequest.border_width;
- border = TRUE;
+ client->border_width = e->xconfigurerequest.border_width;
+
+ /* if the border width is changing then that is the same
+ as requesting a resize, but we don't actually change
+ the client's border, so it will change their root
+ coordiantes (since they include the border width) and
+ we need to a notify then */
+ move = TRUE;
}
notify is sent or not */
}
- if (move || resize || border) {
+ if (move || resize) {
gint lw,lh;
- if (move || resize) {
- client_try_configure(client, &x, &y, &w, &h, &lw, &lh, FALSE);
+ client_try_configure(client, &x, &y, &w, &h, &lw, &lh, FALSE);
- /* if x was not given, then use gravity to figure out the new
- x. the reference point should not be moved */
- if ((e->xconfigurerequest.value_mask & CWWidth &&
- !(e->xconfigurerequest.value_mask & CWX)))
- client_gravity_resize_w(client, &x, client->area.width, w);
- /* if y was not given, then use gravity to figure out the new
- y. the reference point should not be moved */
- if ((e->xconfigurerequest.value_mask & CWHeight &&
- !(e->xconfigurerequest.value_mask & CWY)))
- client_gravity_resize_h(client, &y, client->area.height,h);
+ /* if x was not given, then use gravity to figure out the new
+ x. the reference point should not be moved */
+ if ((e->xconfigurerequest.value_mask & CWWidth &&
+ !(e->xconfigurerequest.value_mask & CWX)))
+ client_gravity_resize_w(client, &x, client->area.width, w);
+ /* if y was not given, then use gravity to figure out the new
+ y. the reference point should not be moved */
+ if ((e->xconfigurerequest.value_mask & CWHeight &&
+ !(e->xconfigurerequest.value_mask & CWY)))
+ client_gravity_resize_h(client, &y, client->area.height,h);
+
+ client_find_onscreen(client, &x, &y, w, h, FALSE);
- client_find_onscreen(client, &x, &y, w, h, FALSE);
- }
/* if they requested something that moves the window, or if
the window is actually being changed then configure it and
send a configure notify to them */
- if (move || !RECT_EQUAL_DIMS(client->area, x, y, w, h) ||
- border)
- {
- ob_debug("Granting ConfigureRequest x %d y %d w %d h %d "
- "b %d\n",
- x, y, w, h, b);
- client_configure(client, x, y, w, h, b, FALSE, TRUE);
+ if (move || !RECT_EQUAL_DIMS(client->area, x, y, w, h)) {
+ ob_debug("Granting ConfigureRequest x %d y %d w %d h %d\n",
+ x, y, w, h);
+ client_configure(client, x, y, w, h, FALSE, TRUE);
}
/* ignore enter events caused by these like ob actions do */
break;
case ReparentNotify:
/* this is when the client is first taken captive in the frame */
- if (e->xreparent.parent == client->frame->plate) break;
+ if (e->xreparent.parent == client->frame->window) break;
/*
This event is quite rare and is usually handled in unmapHandler.
client_find_onscreen(client, &x, &y, w, h, FALSE);
- client_configure(client, x, y, w, h, client->border_width,
- FALSE, TRUE);
+ client_configure(client, x, y, w, h, FALSE, TRUE);
client->gravity = ograv;
actions should not rely on being able to move focus during an
interactive grab.
*/
- if (keyboard_interactively_grabbed())
- keyboard_interactive_cancel();
+ event_cancel_all_key_grabs();
/* when nothing will be focused, send focus to the backup target */
XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
#include "screen.h"
#include "render/theme.h"
-#define PLATE_EVENTMASK (SubstructureRedirectMask | FocusChangeMask)
#define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
- ButtonPressMask | ButtonReleaseMask)
+ ButtonPressMask | ButtonReleaseMask | \
+ SubstructureRedirectMask | FocusChangeMask)
#define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \
ButtonMotionMask | PointerMotionMask | \
EnterWindowMask | LeaveWindowMask)
-/* The inner window does not need enter/leave events.
- If it does get them, then it needs its own context for enter events
- because sloppy focus will focus the window when you enter the inner window
- from the frame. */
-#define INNER_EVENTMASK (ButtonPressMask)
#define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
#define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
/* create the non-visible decor windows */
- mask = CWEventMask;
+ mask = 0;
if (visual) {
/* client has a 32-bit visual */
mask |= CWColormap | CWBackPixel | CWBorderPixel;
attrib.background_pixel = BlackPixel(ob_display, ob_screen);
attrib.border_pixel = BlackPixel(ob_display, ob_screen);
}
- attrib.event_mask = FRAME_EVENTMASK;
self->window = createWindow(RootWindow(ob_display, ob_screen), visual,
mask, &attrib);
- attrib.event_mask = INNER_EVENTMASK;
- self->inner = createWindow(self->window, visual, mask, &attrib);
-
- mask &= ~CWEventMask;
- self->plate = createWindow(self->inner, visual, mask, &attrib);
-
/* create the visible decor windows */
- mask = CWEventMask;
+ mask = 0;
if (visual) {
/* client has a 32-bit visual */
mask |= CWColormap | CWBackPixel | CWBorderPixel;
attrib.colormap = RrColormap(ob_rr_inst);
}
+
+ self->backback = createWindow(self->window, NULL, mask, &attrib);
+ self->backfront = createWindow(self->backback, NULL, mask, &attrib);
+
+ mask |= CWEventMask;
attrib.event_mask = ELEMENT_EVENTMASK;
self->title = createWindow(self->window, NULL, mask, &attrib);
self->titleleft = createWindow(self->window, NULL, mask, &attrib);
self->left = createWindow(self->window, NULL, mask, &attrib);
self->right = createWindow(self->window, NULL, mask, &attrib);
+ self->innerleft = createWindow(self->window, NULL, mask, &attrib);
+ self->innertop = createWindow(self->window, NULL, mask, &attrib);
+ self->innerright = createWindow(self->window, NULL, mask, &attrib);
+ self->innerbottom = createWindow(self->window, NULL, mask, &attrib);
+
self->label = createWindow(self->title, NULL, mask, &attrib);
self->max = createWindow(self->title, NULL, mask, &attrib);
self->close = createWindow(self->title, NULL, mask, &attrib);
self->focused = FALSE;
/* the other stuff is shown based on decor settings */
- XMapWindow(ob_display, self->plate);
- XMapWindow(ob_display, self->inner);
XMapWindow(ob_display, self->label);
+ XMapWindow(ob_display, self->backback);
+ XMapWindow(ob_display, self->backfront);
self->max_press = self->close_press = self->desk_press =
self->iconify_press = self->shade_press = FALSE;
/* position/size and map/unmap all the windows */
if (!fake) {
+ if (self->cbwidth_x) {
+ XMoveResizeWindow(ob_display, self->innerleft,
+ self->size.left - self->cbwidth_x,
+ self->size.top,
+ self->cbwidth_x, self->client->area.height);
+ XMoveResizeWindow(ob_display, self->innerright,
+ self->size.left + self->client->area.width,
+ self->size.top,
+ self->cbwidth_x, self->client->area.height);
+
+ XMapWindow(ob_display, self->innerleft);
+ XMapWindow(ob_display, self->innerright);
+ } else {
+ XUnmapWindow(ob_display, self->innerleft);
+ XUnmapWindow(ob_display, self->innerright);
+ }
+
+ if (self->cbwidth_y) {
+ XMoveResizeWindow(ob_display, self->innertop,
+ self->size.left - self->cbwidth_x,
+ self->size.top - self->cbwidth_y,
+ self->client->area.width +
+ self->cbwidth_x * 2, self->cbwidth_y);
+ XMoveResizeWindow(ob_display, self->innerbottom,
+ self->size.left - self->cbwidth_x,
+ self->size.top + self->client->area.height,
+ self->client->area.width +
+ self->cbwidth_x * 2, self->cbwidth_y);
+
+ XMapWindow(ob_display, self->innertop);
+ XMapWindow(ob_display, self->innerbottom);
+ } else {
+ XUnmapWindow(ob_display, self->innertop);
+ XUnmapWindow(ob_display, self->innerbottom);
+ }
+
if (self->bwidth) {
gint titlesides;
} else
XUnmapWindow(ob_display, self->right);
- /* move and resize the inner border window which contains the plate
- */
- XMoveResizeWindow(ob_display, self->inner,
- 0,
- self->size.top - self->cbwidth_y,
- self->client->area.width +
- self->cbwidth_x * 2 +
- (!self->max_horz ? self->bwidth * 2 : 0),
- self->client->area.height +
- self->cbwidth_y * 2);
-
- /* move the plate */
- XMoveWindow(ob_display, self->plate,
- (!self->max_horz ? self->bwidth : 0) + self->cbwidth_x,
- self->cbwidth_y);
+ XMoveResizeWindow(ob_display, self->backback,
+ self->size.left, self->size.top,
+ self->client->area.width,
+ self->client->area.height);
/* when the client has StaticGravity, it likes to move around. */
XMoveWindow(ob_display, self->client->window,
- -self->client->border_width,
- -self->client->border_width);
+ self->size.left, self->size.top);
}
}
XChangeWindowAttributes(ob_display, self->handle, CWCursor, &a);
XChangeWindowAttributes(ob_display, self->handletop, CWCursor, &a);
XChangeWindowAttributes(ob_display, self->handlebottom, CWCursor, &a);
+ XChangeWindowAttributes(ob_display, self->innerbottom, CWCursor, &a);
/* these ones don't */
a.cursor = ob_cursor(r ? OB_CURSOR_NORTHWEST : OB_CURSOR_NONE);
XChangeWindowAttributes(ob_display, self->titleright, CWCursor, &a);
a.cursor = ob_cursor(r ? OB_CURSOR_WEST : OB_CURSOR_NONE);
XChangeWindowAttributes(ob_display, self->left, CWCursor, &a);
+ XChangeWindowAttributes(ob_display, self->innerleft, CWCursor, &a);
a.cursor = ob_cursor(r ? OB_CURSOR_EAST : OB_CURSOR_NONE);
XChangeWindowAttributes(ob_display, self->right, CWCursor, &a);
+ XChangeWindowAttributes(ob_display, self->innerright, CWCursor, &a);
a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHWEST : OB_CURSOR_NONE);
XChangeWindowAttributes(ob_display, self->lgrip, CWCursor, &a);
XChangeWindowAttributes(ob_display, self->handleleft, CWCursor, &a);
void frame_adjust_client_area(ObFrame *self)
{
- /* resize the plate */
- XResizeWindow(ob_display, self->plate,
- self->client->area.width, self->client->area.height);
+ /* adjust the window which is there to prevent flashing on unmap */
+ XMoveResizeWindow(ob_display, self->backfront, 0, 0,
+ self->client->area.width,
+ self->client->area.height);
}
void frame_adjust_state(ObFrame *self)
*/
/* reparent the client to the frame */
- XReparentWindow(ob_display, self->client->window, self->plate,
- -self->client->border_width, -self->client->border_width);
+ XReparentWindow(ob_display, self->client->window, self->window, 0, 0);
/*
When reparenting the client window, it is usually not mapped yet, since
/* select the event mask on the client's parent (to receive config/map
req's) the ButtonPress is to catch clicks on the client border */
- XSelectInput(ob_display, self->plate, PLATE_EVENTMASK);
+ XSelectInput(ob_display, self->window, FRAME_EVENTMASK);
/* set all the windows for the frame in the window_map */
g_hash_table_insert(window_map, &self->window, self->client);
- g_hash_table_insert(window_map, &self->plate, self->client);
- g_hash_table_insert(window_map, &self->inner, self->client);
+ g_hash_table_insert(window_map, &self->backback, self->client);
+ g_hash_table_insert(window_map, &self->backfront, self->client);
+ g_hash_table_insert(window_map, &self->innerleft, self->client);
+ g_hash_table_insert(window_map, &self->innertop, self->client);
+ g_hash_table_insert(window_map, &self->innerright, self->client);
+ g_hash_table_insert(window_map, &self->innerbottom, self->client);
g_hash_table_insert(window_map, &self->title, self->client);
g_hash_table_insert(window_map, &self->label, self->client);
g_hash_table_insert(window_map, &self->max, self->client);
Reparent events that are generated by us are just discarded here.
They are of no consequence to us anyhow.
*/
- if (ev.xreparent.parent != self->plate) {
+ if (ev.xreparent.parent != self->window) {
reparent = FALSE;
XPutBackEvent(ob_display, &ev);
break;
/* remove all the windows for the frame from the window_map */
g_hash_table_remove(window_map, &self->window);
- g_hash_table_remove(window_map, &self->plate);
- g_hash_table_remove(window_map, &self->inner);
+ g_hash_table_remove(window_map, &self->backback);
+ g_hash_table_remove(window_map, &self->backfront);
+ g_hash_table_remove(window_map, &self->innerleft);
+ g_hash_table_remove(window_map, &self->innertop);
+ g_hash_table_remove(window_map, &self->innerright);
+ g_hash_table_remove(window_map, &self->innerbottom);
g_hash_table_remove(window_map, &self->title);
g_hash_table_remove(window_map, &self->label);
g_hash_table_remove(window_map, &self->max);
}
self = client->frame;
- if (win == self->inner || win == self->plate) {
- /* conceptually, this is the desktop, as far as users are
- concerned */
- if (client->type == OB_CLIENT_TYPE_DESKTOP)
- return OB_FRAME_CONTEXT_DESKTOP;
- return OB_FRAME_CONTEXT_CLIENT;
- }
/* when the user clicks in the corners of the titlebar and the client
is fully maximized, then treat it like they clicked in the
if (win == self->rgriptop) return OB_FRAME_CONTEXT_BLCORNER;
if (win == self->rgripbottom) return OB_FRAME_CONTEXT_BLCORNER;
if (win == self->title) return OB_FRAME_CONTEXT_TITLEBAR;
+ if (win == self->titlebottom) return OB_FRAME_CONTEXT_TITLEBAR;
if (win == self->titleleft) return OB_FRAME_CONTEXT_TLCORNER;
if (win == self->titletopleft) return OB_FRAME_CONTEXT_TLCORNER;
if (win == self->titleright) return OB_FRAME_CONTEXT_TRCORNER;
if (win == self->trrresize) return OB_FRAME_CONTEXT_TRCORNER;
if (win == self->left) return OB_FRAME_CONTEXT_LEFT;
if (win == self->right) return OB_FRAME_CONTEXT_RIGHT;
+ if (win == self->innertop) return OB_FRAME_CONTEXT_TITLEBAR;
+ if (win == self->innerleft) return OB_FRAME_CONTEXT_LEFT;
+ if (win == self->innerbottom) return OB_FRAME_CONTEXT_BOTTOM;
+ if (win == self->innerright) return OB_FRAME_CONTEXT_RIGHT;
if (win == self->max) return OB_FRAME_CONTEXT_MAXIMIZE;
if (win == self->iconify) return OB_FRAME_CONTEXT_ICONIFY;
if (win == self->close) return OB_FRAME_CONTEXT_CLOSE;
struct _ObClient *client;
Window window;
- Window plate;
Strut size;
Rect area;
guint functions;
guint decorations;
- Window inner; /*!< The window for drawing the inner client border */
Window title;
Window label;
Window max;
Window rgriptop;
Window rgripright;
Window rgripbottom;
+ Window innerleft; /*!< For drawing the inner client border */
+ Window innertop; /*!< For drawing the inner client border */
+ Window innerright; /*!< For drawing the inner client border */
+ Window innerbottom; /*!< For drawing the inner client border */
+ Window backback; /*!< A colored window shown while resizing */
+ Window backfront; /*!< An undrawn-in window, to prevent flashing on
+ unmap */
/* These are resize handles inside the titlebar */
Window topresize;
px = (self->focused ?
RrColorPixel(ob_rr_theme->cb_focused_color) :
RrColorPixel(ob_rr_theme->cb_unfocused_color));
- XSetWindowBackground(ob_display, self->inner, px);
- XClearWindow(ob_display, self->inner);
+
+ XSetWindowBackground(ob_display, self->backback, px);
+ XClearWindow(ob_display, self->backback);
+ XSetWindowBackground(ob_display, self->innerleft, px);
+ XClearWindow(ob_display, self->innerleft);
+ XSetWindowBackground(ob_display, self->innertop, px);
+ XClearWindow(ob_display, self->innertop);
+ XSetWindowBackground(ob_display, self->innerright, px);
+ XClearWindow(ob_display, self->innerright);
+ XSetWindowBackground(ob_display, self->innerbottom, px);
+ XClearWindow(ob_display, self->innerbottom);
px = (self->focused ?
RrColorPixel(ob_rr_theme->frame_focused_border_color) :
mode = GrabModeAsync;
mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
} else if (CLIENT_CONTEXT(i, client)) {
- win = client->frame->plate;
+ win = client->window;
mode = GrabModeSync; /* this is handled in event */
mask = ButtonPressMask; /* can't catch more than this with Sync
mode the release event is
client_configure(moveresize_client, x, y,
(cancel ? start_cw : cur_x),
(cancel ? start_ch : cur_y),
- moveresize_client->border_width, TRUE, TRUE);
+ TRUE, TRUE);
}
moveresize_in_progress = FALSE;
client_configure(moveresize_client, cur_x, cur_y,
moveresize_client->area.width,
moveresize_client->area.height,
- moveresize_client->border_width, TRUE, FALSE);
+ TRUE, FALSE);
if (config_resize_popup_show == 2) /* == "Always" */
popup_coords(moveresize_client, "%d x %d",
moveresize_client->frame->area.x,
#endif
get_resize_position(&x, &y, FALSE);
- client_configure(moveresize_client, x, y, cur_x, cur_y,
- moveresize_client->border_width, TRUE, FALSE);
+ client_configure(moveresize_client, x, y, cur_x, cur_y, TRUE, FALSE);
/* this would be better with a fixed width font ... XXX can do it better
if there are 2 text boxes */