[twm] Add option of drawing window title and click menu

Kimiaki Kuno knokmki612 at gmail.com
Fri Apr 8 08:29:32 UTC 2016


That detail is able to change title of position to right or bottom
or left, and menu of direction to selectable horizontal or vertical.

This additional code was written by Atsuo Ohki in 2008, but it
wasn't maintained until now. I think this option is very useful,
so I taked a diff, updated part of original twm code,
and fixed a few bug part of additional code.

I have already contacted to Atsuo Ohki, and got OK that he have no
problem with merge his code.

Atsuo Ohki's mod twm source is here:
http://www2.gssm.otsuka.tsukuba.ac.jp/staff/ohki/twm-4.4.0-lr.tgz

Signed-off-by: Kimiaki Kuno <knokmki612 at gmail.com>
---
 configure.ac     |   2 +-
 man/twm.man      |  49 ++++++
 src/add_window.c | 129 ++++++++++++++--
 src/events.c     |  84 ++++++++++-
 src/events.h     |   1 +
 src/gram.y       |  71 +++++++++
 src/iconmgr.c    |  33 +++-
 src/menus.c      | 325 ++++++++++++++++++++++++++++++++++------
 src/menus.h      |   2 +
 src/parse.c      |  27 ++++
 src/parse.h      |   2 +
 src/resize.c     | 448 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/resize.h     |   2 +
 src/screen.h     |  15 ++
 src/twm.c        |  31 +++-
 src/twm.h        |  15 ++
 src/util.c       | 123 ++++++++++++++-
 src/util.h       |   7 +-
 18 files changed, 1259 insertions(+), 107 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0da57db..e527304 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,7 +49,7 @@ AC_PROG_LEX
 AC_CHECK_FUNCS([mkstemp])
 
 # Checks for pkg-config packages
-PKG_CHECK_MODULES(TWM, x11 xext xt xmu ice sm xproto >= 7.0.17)
+PKG_CHECK_MODULES(TWM, x11 xext xt xmu ice sm xproto >= 7.0.17 xrandr >= 1.2.0)
 
 AC_CONFIG_FILES([Makefile
 		src/Makefile
diff --git a/man/twm.man b/man/twm.man
index d1dbaa0..c724529 100644
--- a/man/twm.man
+++ b/man/twm.man
@@ -551,6 +551,9 @@ This variable specifies a geometry in which the width and height
 give the maximum size for a given window.  This is typically used to
 restrict windows to the size of the screen.  The default width is 32767 -
 screen width.  The default height is 32767 - screen height.
+.IP "\fBMenuAtLeft\fP" 8
+When this variable is set,
+pull-down menus including cascated ones will be placed at the left side.
 .IP "\fBMenuBackground\fP \fIstring\fP" 8
 This variable specifies the background color used for menus,
 and can only be specified inside of a
@@ -562,6 +565,9 @@ inside of a
 .IP "\fBMenuBorderWidth\fP \fIpixels\fP" 8
 This variable specifies the width in pixels of the border surrounding
 menu windows.  The default is 2.
+.IP "\fBMenuBottomUp\fP" 8
+equivalent to set variables both \fBMenuAtLeft\fP and \fBMenuUpward\fP.
+(OBSOLETE!)
 .IP "\fBMenuFont\fP \fIstring\fP" 8
 This variable specifies the font to use when displaying menus.  The default
 is "variable".
@@ -569,6 +575,12 @@ is "variable".
 This variable specifies the foreground color used for menus,
 and can only be specified inside of a
 \fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list.  The default is "black".
+.IP "\fBMenuRuns\fP  \fIstring\fP" 8
+This variable specifies the direction of menus displayed,
+"t2b" means top to bottom (downward (default)),
+"b2t" bottom to top (upward),
+"r2l" right to left (leftward),
+"l2r" left to right (rightward), respectively.
 .IP "\fBMenuShadowColor\fP \fIstring\fP" 8
 This variable specifies the color of the shadow behind pull-down menus
 and can only be specified inside of a
@@ -583,6 +595,11 @@ This variable specifies the foreground color for \fBf.title\fP entries in
 menus and
 can only be specified inside of a
 \fBColor\fP or \fBMonochrome\fP list.  The default is "black".
+.IP "\fBMenuUpward\fP" 8
+When this variable is set,
+pull-down menus including cascated ones will be extended upward and
+menu items appear in reverse order.
+(OBSOLETE!)
 .IP "\fBMonochrome\fP { \fIcolors\fP }" 8
 This variable specifies a list of color assignments that should be made if
 the screen has a depth of 1.  See the description of \fBColors\fP.
@@ -756,6 +773,7 @@ for \fBright\fP.  For example:
         "emacs" right           0       0
 }
 .EE
+The window name "*" works as a wildcard.
 The \fBDontSqueezeTitle\fP list can be used to turn off squeezing on
 certain titles.
 .IP "\fBStartIconified\fP [{ \fIwin-list\fP }] " 8
@@ -764,6 +782,15 @@ icons until explicitly deiconified by the user.  If the optional \fIwin-list\fP
 is given, only those windows will be started iconic.  This is useful for
 programs that do not support an \fI-iconic\fP command line option or
 resource.
+.IP "\fBTitleAtBottom\fP [{ \fIwin-list\fP }] " 8
+.IP "\fBTitleAtLeft\fP [{ \fIwin-list\fP }] " 8
+.IP "\fBTitleAtRight\fP [{ \fIwin-list\fP }] " 8
+.IP "\fBTitleAtTop\fP [{ \fIwin-list\fP }] " 8
+These variables indicates the position of the title bar of client windows.
+If the optional \fIwin-list\fP is given, only those windows will
+have the title bar at the specified position.
+You can override the position of the title bar at runtime
+with \fBf.titlepos\fP function.
 .IP "\fBTitleBackground\fP \fIstring\fP [{ \fIwin-list\fP }]" 8
 This variable specifies the background color used in titlebars,
 and may only be specified inside of a
@@ -811,6 +838,14 @@ older toolkits.
 This variable indicates that the pointer should be warped into windows when
 they are deiconified.  If the optional \fIwin-list\fP is given, the pointer
 will only be warped when those windows are deiconified.
+.IP "\fBWarpCursorPos\fP \fInumber\fP or \fIstring\fP" 8
+This variable specifies the position of the pointer when windows are
+deiconified.
+1 (or NW) means upper left (NorthWest), 2 (or W) means middle left (West),
+3 (or SW) means lower left (SouthWest), 4 (or S) means middle bottom (South),
+5 (or SE) means lower right (SouthEast), 6 (or E) means middle right (East),
+7 (or NE) means upper right (NorthEast), 8 (or N) means middle top (North).
+The pointer is located middle of the window by default.
 .IP "\fBWindowRing\fP { \fIwin-list\fP }" 8
 This variable specifies a list of windows along which the \fBf.warpring\fP
 function cycles.
@@ -1134,6 +1169,20 @@ See the variable \fBSortIconManager\fP.
 .IP "\fBf.title\fP" 8
 This function provides a centered, unselectable item in a menu definition.  It
 should not be used in any other context.
+.IP "\fBf.titlepos\fP \fIstring\fP" 8
+This function specifies the position of the title bar of clients windows
+at runtime.
+If \fIstring\fP is "top", "left", "bottom" or "right",
+every clients invoked after this function will have its title bar
+at the specified position regardless of the setting of `.twmrc' .
+If \fIstring\fP is not "top", "left", "bottom" nor "right",
+the setting of `.twmrc' becomes effective again.
+If this function is invoked from title context,
+the titlebar of that window is repositioned.
+.IP "\fBf.titlesqz\fP \fIstring\fP" 8
+When this function is invoked from title context,
+the justification style of squeezed title bar is changed.
+A \fIstring\fP must be one of "left", "center", "right" or "none"
 .IP "\fBf.topzoom\fP" 8
 This variable is similar to the \fBf.bottomzoom\fP function except that
 the selected window is only resized to the top half of the display.
diff --git a/src/add_window.c b/src/add_window.c
index 99481b0..c76f04e 100644
--- a/src/add_window.c
+++ b/src/add_window.c
@@ -331,8 +331,12 @@ AddWindow(Window w, int iconm, IconMgr *iconp)
 			  &tmp_win->class);
 	    if (!tmp_win->squeeze_info) {
 		static SqueezeInfo default_squeeze = { J_LEFT, 0, 0 };
-		if (Scr->SqueezeTitle)
-		  tmp_win->squeeze_info = &default_squeeze;
+		if (Scr->SqueezeTitle) {
+		    tmp_win->squeeze_info = (SqueezeInfo *)
+			    LookInList (Scr->SqueezeTitleL, "*", NULL);
+		    if (!tmp_win->squeeze_info)
+			tmp_win->squeeze_info = &default_squeeze;
+		}
 	    }
 	}
       }
@@ -358,6 +362,27 @@ AddWindow(Window w, int iconm, IconMgr *iconp)
     if (tmp_win->transient && !Scr->DecorateTransients)
 	tmp_win->title_height = 0;
 
+    tmp_win->title_pixmap = None;
+    /* find specified title bar position */
+    if (tmp_win->title_height > 0) {
+	if (Scr->TitlePosDynamic != -1)
+	    tmp_win->title_pos = Scr->TitlePosDynamic;
+	else if (LookInList(Scr->TitlePosTopL,
+			    tmp_win->full_name, &tmp_win->class))
+	    tmp_win->title_pos = TP_TOP;
+	else if (LookInList(Scr->TitlePosLeftL,
+			    tmp_win->full_name, &tmp_win->class))
+	    tmp_win->title_pos = TP_LEFT;
+	else if (LookInList(Scr->TitlePosBottomL,
+			    tmp_win->full_name, &tmp_win->class))
+	    tmp_win->title_pos = TP_BOTTOM;
+	else if (LookInList(Scr->TitlePosRightL,
+			    tmp_win->full_name, &tmp_win->class))
+	    tmp_win->title_pos = TP_RIGHT;
+	else
+	    tmp_win->title_pos = Scr->TitlePos;
+    } else
+	tmp_win->title_pos = TP_TOP;
     if (LookInList(Scr->StartIconified, tmp_win->full_name, &tmp_win->class))
     {
 	if (!tmp_win->wmhints)
@@ -490,9 +515,14 @@ AddWindow(Window w, int iconm, IconMgr *iconp)
 				    SIZE_HINDENT,
 				    SIZE_VINDENT + Scr->SizeFont.ascent,
 				    tmp_win->name, namelen);
-
+	  if (tmp_win->title_pos == TP_TOP ||
+	      tmp_win->title_pos == TP_BOTTOM) {
 	    AddingW = tmp_win->attr.width + bw2;
 	    AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
+	  } else {
+	    AddingW = tmp_win->attr.width + tmp_win->title_height + bw2;
+	    AddingH = tmp_win->attr.height + bw2;
+	  }
 
   	    if (Scr->DontMoveOff) {
   		/*
@@ -510,7 +540,8 @@ AddWindow(Window w, int iconm, IconMgr *iconp)
   	    }
 
 	    MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
-	      	        tmp_win->frame_bw, tmp_win->title_height);
+			tmp_win->frame_bw, tmp_win->title_height,
+			tmp_win->title_pos);
 
 	    while (TRUE)
 		{
@@ -576,7 +607,8 @@ AddWindow(Window w, int iconm, IconMgr *iconp)
 		}
 
 		MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
-			    tmp_win->frame_bw, tmp_win->title_height);
+			    tmp_win->frame_bw, tmp_win->title_height,
+			    tmp_win->title_pos);
 
 	    }
 
@@ -599,8 +631,14 @@ AddWindow(Window w, int iconm, IconMgr *iconp)
 		    if (dx < HALF_AVE_CURSOR_SIZE) dx = HALF_AVE_CURSOR_SIZE;
 		    if (dy < HALF_AVE_CURSOR_SIZE) dy = HALF_AVE_CURSOR_SIZE;
 #undef HALF_AVE_CURSOR_SIZE
+		  if (tmp_win->title_pos == TP_TOP ||
+		      tmp_win->title_pos == TP_BOTTOM ) {
 		    dx += (tmp_win->frame_bw + 1);
 		    dy += (bw2 + tmp_win->title_height + 1);
+		  } else {
+		    dx += (bw2 + tmp_win->title_height + 1);
+		    dy += (tmp_win->frame_bw + 1);
+		  }
 		    if (AddingX + dx >= Scr->MyDisplayWidth)
 		      dx = Scr->MyDisplayWidth - AddingX - 1;
 		    if (AddingY + dy >= Scr->MyDisplayHeight)
@@ -678,22 +716,35 @@ AddWindow(Window w, int iconm, IconMgr *iconp)
 		XMaskEvent(dpy, ButtonReleaseMask, &event);
 	    }
 
-	    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+	    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0, 0);
 	    XUnmapWindow(dpy, Scr->SizeWindow);
 	    UninstallRootColormap();
 	    XUngrabPointer(dpy, CurrentTime);
 
+	  if (tmp_win->title_pos == TP_TOP ||
+	      tmp_win->title_pos == TP_BOTTOM) {
 	    tmp_win->attr.x = AddingX;
-	    tmp_win->attr.y = AddingY + tmp_win->title_height;
+	    tmp_win->attr.y = AddingY;
+	    if (tmp_win->title_pos == TP_TOP)
+		tmp_win->attr.y += tmp_win->title_height;
 	    tmp_win->attr.width = AddingW - bw2;
 	    tmp_win->attr.height = AddingH - tmp_win->title_height - bw2;
+	  } else {
+	    tmp_win->attr.x = AddingX;
+	    if (tmp_win->title_pos == TP_LEFT)
+		tmp_win->attr.x += tmp_win->title_height;
+	    tmp_win->attr.y = AddingY;
+	    tmp_win->attr.width = AddingW - tmp_win->title_height - bw2;
+	    tmp_win->attr.height = AddingH - bw2;
+	  }
 
 	    XUngrabServer(dpy);
 	}
       }
     } else {				/* put it where asked, mod title bar */
 	/* if the gravity is towards the top, move it by the title height */
-	if (gravy < 0) tmp_win->attr.y -= gravy * tmp_win->title_height;
+	if (tmp_win->title_pos == TP_TOP && gravy < 0)
+	    tmp_win->attr.y -= gravy * tmp_win->title_height;
     }
 
 
@@ -787,12 +838,21 @@ AddWindow(Window w, int iconm, IconMgr *iconp)
 
 
     /* create windows */
-
+  if (tmp_win->title_pos == TP_TOP || tmp_win->title_pos == TP_BOTTOM) {
     tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->frame_bw;
-    tmp_win->frame_y = tmp_win->attr.y - tmp_win->title_height +
-	tmp_win->old_bw - tmp_win->frame_bw;
+    tmp_win->frame_y = tmp_win->attr.y + tmp_win->old_bw - tmp_win->frame_bw;
+    if (tmp_win->title_pos == TP_TOP)
+	tmp_win->frame_y -= tmp_win->title_height;
     tmp_win->frame_width = tmp_win->attr.width;
     tmp_win->frame_height = tmp_win->attr.height + tmp_win->title_height;
+  } else {
+    tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->frame_bw;
+    if (tmp_win->title_pos == TP_LEFT)
+	tmp_win->frame_x -= tmp_win->title_height;
+    tmp_win->frame_y = tmp_win->attr.y + tmp_win->old_bw - tmp_win->frame_bw;
+    tmp_win->frame_width = tmp_win->attr.width + tmp_win->title_height;
+    tmp_win->frame_height = tmp_win->attr.height;
+  }
 
     valuemask = CWBackPixmap | CWBorderPixel | CWCursor | CWEventMask;
     attributes.background_pixmap = None;
@@ -825,7 +885,11 @@ AddWindow(Window w, int iconm, IconMgr *iconp)
 	tmp_win->title_w = XCreateWindow (dpy, tmp_win->frame,
 					  -tmp_win->frame_bw,
 					  -tmp_win->frame_bw,
+	    (tmp_win->title_pos == TP_LEFT || tmp_win->title_pos == TP_RIGHT)?
+					  (unsigned int) Scr->TitleHeight :
 					  (unsigned int) tmp_win->attr.width,
+	    (tmp_win->title_pos == TP_LEFT || tmp_win->title_pos == TP_RIGHT)?
+					  (unsigned int) tmp_win->attr.height :
 					  (unsigned int) Scr->TitleHeight,
 					  (unsigned int) tmp_win->frame_bw,
 					  Scr->d_depth,
@@ -888,7 +952,18 @@ AddWindow(Window w, int iconm, IconMgr *iconp)
     if (!tmp_win->iconmgr)
 	XAddToSaveSet(dpy, tmp_win->w);
 
+  switch (tmp_win->title_pos) {
+  case TP_TOP:
     XReparentWindow(dpy, tmp_win->w, tmp_win->frame, 0, tmp_win->title_height);
+    break;
+  case TP_BOTTOM:
+  case TP_RIGHT:
+    XReparentWindow(dpy, tmp_win->w, tmp_win->frame, 0, 0);
+    break;
+  case TP_LEFT:
+    XReparentWindow(dpy, tmp_win->w, tmp_win->frame, tmp_win->title_height, 0);
+    break;
+  }
     /*
      * Reparenting generates an UnmapNotify event, followed by a MapNotify.
      * Set the map state to FALSE to prevent a transition back to
@@ -1150,12 +1225,18 @@ static Window CreateHighlightWindow (TwmWindow *tmp_win)
 	valuemask = CWBackPixel;
 	attributes.background_pixel = tmp_win->title.fore;
     }
-
+  if (tmp_win->title_pos == TP_TOP || tmp_win->title_pos == TP_BOTTOM)
     w = XCreateWindow (dpy, tmp_win->title_w, 0, Scr->FramePadding,
 		       (unsigned int) Scr->TBInfo.width, (unsigned int) h,
 		       (unsigned int) 0,
 		       Scr->d_depth, (unsigned int) CopyFromParent,
 		       Scr->d_visual, valuemask, &attributes);
+  else
+    w = XCreateWindow (dpy, tmp_win->title_w, Scr->FramePadding, 0,
+		       (unsigned int) h, (unsigned int) Scr->TBInfo.width,
+		       (unsigned int) 0,
+		       Scr->d_depth, (unsigned int) CopyFromParent,
+		       Scr->d_visual, valuemask, &attributes);
     if (pm) XFreePixmap (dpy, pm);
     return w;
 }
@@ -1212,6 +1293,9 @@ void ComputeTitleLocation (register TwmWindow *tmp)
 	int maxwidth = tmp->frame_width;
 	int tw = tmp->title_width;
 
+	if (tmp->title_pos == TP_LEFT || tmp->title_pos == TP_RIGHT) {
+	    maxwidth = tmp->attr.height;
+	}
 	/*
 	 * figure label base from squeeze info (justification fraction)
 	 */
@@ -1246,8 +1330,15 @@ void ComputeTitleLocation (register TwmWindow *tmp)
 	  basex = maxwidth - tw + 1;
 	if (basex < 0) basex = 0;
 
+      if (tmp->title_pos == TP_LEFT || tmp->title_pos == TP_RIGHT)
+	tmp->title_y = basex - tmp->frame_bw;
+      else
 	tmp->title_x = basex - tmp->frame_bw;
     }
+    if (tmp->title_pos == TP_BOTTOM)
+	tmp->title_y += tmp->attr.height + tmp->frame_bw;
+    else if (tmp->title_pos == TP_RIGHT)
+	tmp->title_x += tmp->attr.width + tmp->frame_bw;
 }
 
 
@@ -1270,7 +1361,10 @@ static void CreateWindowTitlebarButtons (TwmWindow *tmp_win)
      * create the title bar windows; let the event handler deal with painting
      * so that we don't have to spend two pixmaps (or deal with hashing)
      */
-    ComputeWindowTitleOffsets (tmp_win, tmp_win->attr.width, False);
+    ComputeWindowTitleOffsets (tmp_win,
+	    (tmp_win->title_pos == TP_TOP || tmp_win->title_pos == TP_BOTTOM)?
+		    tmp_win->attr.width : tmp_win->attr.height,
+		False);
 
     leftx = y = Scr->TBInfo.leftx;
     rightx = tmp_win->rightx;
@@ -1302,13 +1396,20 @@ static void CreateWindowTitlebarButtons (TwmWindow *tmp_win)
 		if (tb->rightside) {
 		    x = rightx;
 		    rightx += boxwidth;
+		  if (tmp_win->title_pos == TP_LEFT ||
+		      tmp_win->title_pos == TP_RIGHT)
+		    attributes.win_gravity = SouthWestGravity;
+		  else
 		    attributes.win_gravity = NorthEastGravity;
 		} else {
 		    x = leftx;
 		    leftx += boxwidth;
 		    attributes.win_gravity = NorthWestGravity;
 		}
-		tbw->window = XCreateWindow (dpy, tmp_win->title_w, x, y, h, h,
+		tbw->window = XCreateWindow (dpy, tmp_win->title_w,
+    (tmp_win->title_pos == TP_TOP || tmp_win->title_pos == TP_BOTTOM)?  x : y,
+    (tmp_win->title_pos == TP_TOP || tmp_win->title_pos == TP_BOTTOM)?  y : x,
+					     h, h,
 					     (unsigned int) Scr->TBInfo.border,
 					     0, (unsigned int) CopyFromParent,
 					     (Visual *) CopyFromParent,
diff --git a/src/events.c b/src/events.c
index ac26d88..9d31d29 100644
--- a/src/events.c
+++ b/src/events.c
@@ -170,6 +170,8 @@ InitEvents(void)
     EventHandler[VisibilityNotify] = HandleVisibilityNotify;
     if (HasShape)
 	EventHandler[ShapeEventBase+ShapeNotify] = HandleShapeNotify;
+    if (HasRandr)
+	EventHandler[RandrEventBase+RRScreenChangeNotify] = HandleRandrNotify;
 }
 
 
@@ -1074,6 +1076,13 @@ HandleExpose(void)
 	    MyFont_ChangeGC(Tmp_win->title.fore, Tmp_win->title.back,
 		&Scr->TitleBarFont);
 
+	  if (Tmp_win->title_pos == TP_LEFT || Tmp_win->title_pos == TP_RIGHT)
+	    MyFont_DrawString_Rotated (dpy, Tmp_win->title_w,
+		&Scr->TitleBarFont,
+		Scr->NormalGC, Scr->TBInfo.titlex,
+		Scr->TitleHeight - Scr->TitleBarFont.height,
+		Tmp_win->name, strlen(Tmp_win->name), &Tmp_win->title_pixmap);
+	  else
 	    MyFont_DrawString (dpy, Tmp_win->title_w, &Scr->TitleBarFont,
 		Scr->NormalGC, Scr->TBInfo.titlex, Scr->TitleBarFont.y,
 		Tmp_win->name, strlen(Tmp_win->name));
@@ -1230,6 +1239,7 @@ HandleDestroyNotify(void)
      *     11. window ring
      */
     if (Tmp_win->gray) XFreePixmap (dpy, Tmp_win->gray);
+    if (Tmp_win->title_pixmap) XFreePixmap(dpy, Tmp_win->title_pixmap);
 
     XDestroyWindow(dpy, Tmp_win->frame);
     if (Tmp_win->icon_w && !Tmp_win->icon_not_ours) {
@@ -1510,7 +1520,7 @@ HandleButtonRelease(void)
 
     if (DragWindow != None)
     {
-	MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+	MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0, 0);
 
 	if (XFindContext(dpy, DragWindow, TwmContext, &context_data) == 0)
 	    Tmp_win = (TwmWindow *) context_data;
@@ -1733,7 +1743,7 @@ HandleButtonPress(void)
 	  if (Scr->OpaqueMove && DragWindow != None) {
 	    XMoveWindow (dpy, DragWindow, origDragX, origDragY);
 	  } else {
-	    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+	    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0, 0);
 	  }
 	}
 	XUnmapWindow(dpy, Scr->SizeWindow);
@@ -1804,8 +1814,14 @@ HandleButtonPress(void)
 		Event.xbutton.x, Event.xbutton.y,
 		&JunkX, &JunkY, &JunkChild);
 
+	  if (Tmp_win->title_pos == TP_TOP ||
+	      Tmp_win->title_pos == TP_BOTTOM) {
 	    Event.xbutton.x = JunkX;
 	    Event.xbutton.y = JunkY - Tmp_win->title_height;
+	  } else {
+	    Event.xbutton.x = JunkX - Tmp_win->title_height;
+	    Event.xbutton.y = JunkY;
+	  }
 	    Event.xany.window = Tmp_win->w;
 	    Context = C_WINDOW;
 	}
@@ -1833,6 +1849,9 @@ HandleButtonPress(void)
 	     */
 	    if (Event.xbutton.subwindow == Tmp_win->w) {
 	      Event.xbutton.window = Tmp_win->w;
+	    if (Tmp_win->title_pos == TP_LEFT)
+	       Event.xbutton.x -= Tmp_win->title_height;
+	    if (Tmp_win->title_pos == TP_TOP)
               Event.xbutton.y -= Tmp_win->title_height;
 /*****
               Event.xbutton.x -= Tmp_win->frame_bw;
@@ -2075,7 +2094,8 @@ HandleEnterNotify(void)
 			if (Tmp_win->title_w && Scr->TitleFocus &&	/* 4 */
 			    Tmp_win->wmhints && Tmp_win->wmhints->input)
 			  SetFocus (Tmp_win, ewp->time);
-			if (Scr->NoTitlebar && Scr->TitleFocus &&	/*4a */
+			if ((Scr->NoTitlebar || Scr->NoTitle != NULL) &&
+			    Scr->TitleFocus &&  /*4a */
 			    Tmp_win->wmhints && Tmp_win->wmhints->input)
 			  SetFocus (Tmp_win, ewp->time);
 			if (Tmp_win->protocols & DoesWmTakeFocus)	/* 5 */
@@ -2084,10 +2104,14 @@ HandleEnterNotify(void)
 		    } else if (ewp->window == Tmp_win->w) {
 			/*
 			 * If we are entering the application window, install
-			 * its colormap(s).
+			 * its colormap(s), unless it is icon stack.
 			 */
-			if (!scanArgs.leaves || scanArgs.inferior)
+			if ((!scanArgs.leaves || scanArgs.inferior) &&
+			    Scr->iconmgr.twm_win != Tmp_win) {
 			    InstallWindowColormaps(EnterNotify, Tmp_win);
+			    SetFocus (Tmp_win, ewp->time);      /* XXX */
+			    Scr->Focus = Tmp_win;
+			}
 		    }
 		}			/* end if Tmp_win->mapped */
 		if (Tmp_win->wmhints != NULL &&
@@ -2341,7 +2365,13 @@ HandleConfigureRequest(void)
 	    x += gravx * bwdelta;	/* change default values only */
 	    y += gravy * bwdelta;	/* ditto */
 	    bw = cre->border_width;
-	    if (Tmp_win->title_height) height += bwdelta;
+	    if (Tmp_win->title_height) {
+		if (Tmp_win->title_pos == TP_TOP ||
+		    Tmp_win->title_pos == TP_BOTTOM)
+		    height += bwdelta;
+		else
+		    width += bwdelta;
+	    }
 	    x += (gravx < 0) ? bwdelta : -bwdelta;
 	    y += (gravy < 0) ? bwdelta : -bwdelta;
 	}
@@ -2349,16 +2379,24 @@ HandleConfigureRequest(void)
     }
 
     if (cre->value_mask & CWX) {	/* override even if border change */
-	x = cre->x - bw;
+      if (Tmp_win->title_pos == TP_LEFT || Tmp_win->title_pos == TP_RIGHT)
+	x = cre->x - ((gravx < 0) ? 0 : Tmp_win->title_height) - bw;
     }
     if (cre->value_mask & CWY) {
+      if (Tmp_win->title_pos == TP_TOP || Tmp_win->title_pos == TP_BOTTOM)
 	y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw;
     }
 
     if (cre->value_mask & CWWidth) {
+      if (Tmp_win->title_pos == TP_LEFT || Tmp_win->title_pos == TP_RIGHT)
+	width = cre->width + Tmp_win->title_height;
+      else
 	width = cre->width;
     }
     if (cre->value_mask & CWHeight) {
+      if (Tmp_win->title_pos == TP_LEFT || Tmp_win->title_pos == TP_RIGHT)
+	height = cre->height;
+      else
 	height = cre->height + Tmp_win->title_height;
     }
 
@@ -2376,6 +2414,37 @@ HandleConfigureRequest(void)
 }
 
 
+/***********************************************************************
+ *
+ *  Procedure:
+ *     RRScreenChangeNotify - Randr Screen Change event handler
+ *
+ ***********************************************************************
+ */
+void
+HandleRandrNotify ()
+{
+    XRRScreenChangeNotifyEvent *rrev = (XRRScreenChangeNotifyEvent *) &Event;
+    extern ScreenInfo **ScreenList;
+    extern int NumScreens;
+    int i;
+    ScreenInfo *scp;
+
+    for (i = 0; i< NumScreens; i++) {
+	if (ScreenList[i]->Root == rrev->root) {
+	    if (ScreenList[i]->MyDisplayWidth != rrev->width) {
+		/* swap MaxWindowWidth/Height */
+		int tmp =  ScreenList[i]->MaxWindowWidth;
+		ScreenList[i]->MaxWindowWidth = ScreenList[i]->MaxWindowHeight;
+		ScreenList[i]->MaxWindowHeight = tmp;
+	    }
+	    ScreenList[i]->MyDisplayWidth = rrev->width;
+	    ScreenList[i]->MyDisplayHeight = rrev->height;
+	    break;
+	}
+    }
+}
+
 
 /**
  * shape notification event handler
@@ -2688,4 +2757,3 @@ dumpevent (XEvent *e)
     }
 }
 #endif /* TRACE */
-
diff --git a/src/events.h b/src/events.h
index e6bcfc9..6c281ea 100644
--- a/src/events.h
+++ b/src/events.h
@@ -97,6 +97,7 @@ extern void HandleEnterNotify ( void );
 extern void HandleLeaveNotify ( void );
 extern void HandleConfigureRequest ( void );
 extern void HandleShapeNotify ( void );
+extern void HandleRandrNotify ( void );
 extern void HandleUnknown ( void );
 extern int Transient ( Window w, Window *propw );
 extern ScreenInfo * FindScreenInfo ( Window w );
diff --git a/src/gram.y b/src/gram.y
index ca40d1c..8d7ce0f 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -91,6 +91,8 @@ static Bool CheckWarpRingArg ( char *s );
 static Bool CheckColormapArg ( char *s );
 static void RemoveDQuote ( char *str );
 
+static int nsew ( char *s);
+
 static char *ptr;
 static name_list **list;
 static int cont = 0;
@@ -122,13 +124,17 @@ static void yyerror ( const char *s );
 %token <num> NUMBER KEYWORD NKEYWORD CKEYWORD CLKEYWORD FKEYWORD FSKEYWORD
 %token <num> SKEYWORD DKEYWORD JKEYWORD WINDOW_RING WARP_CURSOR ERRORTOKEN
 %token <num> NO_STACKMODE
+%token <num> WARP_CURSOR_POS
 %token <ptr> STRING
+%token <num> TITLE_AT_TOP TITLE_AT_BOTTOM TITLE_AT_LEFT TITLE_AT_RIGHT
+%token <num> MENU_RUNS
 
 %type <ptr> string
 %type <num> pixmap_list cursor_list color_list save_color_list stmt
 %type <num> win_color_list iconm_list win_list icon_list function menu
 %type <num> noarg sarg error narg squeeze color_entry
 %type <num> action button number signed_number full fullkey
+%type <num> titlepos
 
 %start twmrc
 
@@ -145,6 +151,18 @@ stmt		: error
 		| sarg
 		| narg
 		| squeeze
+		| titlepos
+		| MENU_RUNS string	{ if (strcmp($2, "t2b")== 0)
+					    Scr->MenuRuns = MenuRuns_T2B;
+					  else if (strcmp($2, "b2t")== 0)
+					    Scr->MenuRuns = MenuRuns_B2T;
+					  else if (strcmp($2, "r2l")== 0)
+					    Scr->MenuRuns = MenuRuns_R2L;
+					  else if (strcmp($2, "l2r")== 0)
+					    Scr->MenuRuns = MenuRuns_L2R;
+					  else fprintf(stderr,
+					    "MenuRuns \"{t2b|b2t|r2l|l2r}\"\n");
+					}
 		| ICON_REGION string DKEYWORD DKEYWORD number number
 					{ AddIconRegion($2, $3, $4, $5, $6); }
 		| ICONMGR_GEOMETRY string number	{ if (Scr->FirstTime)
@@ -274,6 +292,12 @@ stmt		: error
 		  win_list
 		| WARP_CURSOR		{ if (Scr->FirstTime)
 					    Scr->WarpCursor = TRUE; }
+		| WARP_CURSOR_POS number
+					{ if (Scr->FirstTime)
+					    Scr->WarpCursorPos = $2; }
+		| WARP_CURSOR_POS string
+					{ if (Scr->FirstTime)
+					    Scr->WarpCursorPos = nsew($2); }
 		| WINDOW_RING		{ list = &Scr->WindowRingL; }
 		  win_list
 		;
@@ -509,6 +533,40 @@ squeeze		: SQUEEZE_TITLE {
 		  win_list
 		;
 
+titlepos	: TITLE_AT_TOP {
+				     Scr->TitlePos = TP_TOP;
+				}
+		| TITLE_AT_TOP { list = &Scr->TitlePosTopL;
+				 if (Scr->TitlePos == -1)
+				   Scr->TitlePos = TP_TOP;
+				}
+		  win_list
+		| TITLE_AT_LEFT {
+				     Scr->TitlePos = TP_LEFT;
+				}
+		| TITLE_AT_LEFT { list = &Scr->TitlePosLeftL;
+				  if (Scr->TitlePos == -1)
+				    Scr->TitlePos = TP_LEFT;
+				}
+		  win_list
+		| TITLE_AT_BOTTOM {
+				     Scr->TitlePos = TP_BOTTOM;
+				}
+		| TITLE_AT_BOTTOM { list = &Scr->TitlePosBottomL;
+				    if (Scr->TitlePos == -1)
+				      Scr->TitlePos = TP_BOTTOM;
+				}
+		  win_list
+		| TITLE_AT_RIGHT {
+				     Scr->TitlePos = TP_RIGHT;
+				}
+		| TITLE_AT_RIGHT { list = &Scr->TitlePosRightL;
+				   if (Scr->TitlePos == -1)
+				     Scr->TitlePos = TP_RIGHT;
+				}
+		  win_list
+		;
+
 win_sqz_entries	: /* Empty */
 		| win_sqz_entries string JKEYWORD signed_number number	{
 				if (Scr->FirstTime) {
@@ -874,6 +932,19 @@ static Bool CheckColormapArg (char *s)
     return False;
 }
 
+static int nsew(s)
+    register char *s;
+{
+    if (strcasecmp(s, "nw") == 0) return 1;
+    if (strcasecmp(s, "w" ) == 0) return 2;
+    if (strcasecmp(s, "sw") == 0) return 3;
+    if (strcasecmp(s, "s" ) == 0) return 4;
+    if (strcasecmp(s, "se") == 0) return 5;
+    if (strcasecmp(s, "e" ) == 0) return 6;
+    if (strcasecmp(s, "ne") == 0) return 7;
+    if (strcasecmp(s, "n" ) == 0) return 8;
+    return 0;
+}
 
 void
 twmrc_error_prefix (void)
diff --git a/src/iconmgr.c b/src/iconmgr.c
index d9c4e76..e3490c5 100644
--- a/src/iconmgr.c
+++ b/src/iconmgr.c
@@ -175,7 +175,7 @@ void MoveIconManager(int dir)
     int row_inc, col_inc;
     int got_it;
 
-    if (!Active) return;
+    if (!Active || !Active->iconmgr) return; /* XXX */
 
     cur_row = Active->row;
     cur_col = Active->col;
@@ -227,14 +227,26 @@ void MoveIconManager(int dir)
     {
 	new_row += row_inc;
 	new_col += col_inc;
-	if (new_row < 0)
+	if (new_row < 0) {
 	    new_row = ip->cur_rows - 1;
-	if (new_col < 0)
+	    if (--new_col < 0)
+		new_col = ip->cur_columns -1;
+	}
+	if (new_col < 0) {
 	    new_col = ip->cur_columns - 1;
-	if (new_row >= ip->cur_rows)
+	    if (--new_row < 0)
+		new_row = ip->cur_rows - 1;
+	}
+	if (new_row >= ip->cur_rows) {
 	    new_row = 0;
-	if (new_col >= ip->cur_columns)
+	    if (++new_col >= ip->cur_columns)
+		new_col = 0;
+	}
+	if (new_col >= ip->cur_columns) {
 	    new_col = 0;
+	    if (++new_row >= ip->cur_rows)
+		new_row = 0;
+	}
 
 	/* Now let's go through the list to see if there is an entry with this
 	 * new position
@@ -291,7 +303,7 @@ void JumpIconManager(int dir)
     ScreenInfo *sp;
     int screen;
 
-    if (!Active) return;
+    if (!Active || !Active->iconmgr) return; /* XXX */
 
 
 #define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev)
@@ -683,9 +695,16 @@ void PackIconManager(IconMgr *ip)
     XResizeWindow(dpy, ip->w, newwidth, ip->height);
 
     savewidth = ip->width;
-    if (ip->twm_win)
+    if (ip->twm_win) {
+     if (ip->twm_win->title_pos == TP_TOP ||
+	 ip->twm_win->title_pos == TP_BOTTOM)
       SetupWindow (ip->twm_win,
 		   ip->twm_win->frame_x, ip->twm_win->frame_y,
 		   newwidth, ip->height + ip->twm_win->title_height, -1);
+     else
+      SetupWindow (ip->twm_win,
+		   ip->twm_win->frame_x, ip->twm_win->frame_y,
+		   newwidth + ip->twm_win->title_height, ip->height, -1);
+    }
     ip->width = savewidth;
 }
diff --git a/src/menus.c b/src/menus.c
index ada9c41..8bfb93c 100644
--- a/src/menus.c
+++ b/src/menus.c
@@ -127,6 +127,38 @@ static void WarpToWindow ( TwmWindow *t );
 
 #define SHADOWWIDTH 5			/* in pixels */
 
+static void
+set_pos(int *x, int *y, TwmWindow *p, int how)
+{
+   int height = p->attr.height;
+   int width = p->attr.width;
+   switch (how) {
+   case 1: /* upper left */
+     *x = 2; *y = 5; break;
+   case 2: /* middle left */
+     *x = 2; *y = height / 2; break;
+   case 3: /* lower left */
+     *x = 2; *y = height - 5; break;
+   case 4: /* middle bottom */
+     *x = width / 2 ; *y = height - 5; break;
+   case 5: /* lower right */
+     *x = width - 2 ; *y = height - 5; break;
+   case 6: /* middle right */
+     *x = width - 2 ; *y = height / 2; break;
+   case 7: /* upper right */
+     *x = width - 2 ; *y = 5; break;
+   case 8: /* middle top */
+     *x = width / 2 ; *y = 5; break;
+   default: /* middle */
+     *x = width / 2 ; *y = height / 2; break;
+   }
+   if (p->title_height > 0) {
+     if (p->title_pos == TP_TOP)
+       *y += Scr->TitleHeight;
+     if (p->title_pos == TP_LEFT)
+       *x += Scr->TitleHeight;
+   }
+}
 
 
 
@@ -367,6 +399,7 @@ void
 PaintEntry(MenuRoot *mr, MenuItem *mi, int exposure)
 {
     int y_offset;
+    int y_offset_x;
     int text_y;
     GC gc;
 
@@ -375,6 +408,7 @@ PaintEntry(MenuRoot *mr, MenuItem *mi, int exposure)
 #endif
     y_offset = mi->item_num * Scr->EntryHeight;
     text_y = y_offset + Scr->MenuFont.y;
+    y_offset_x = y_offset + (Scr->EntryHeight - Scr->MenuFont.height);
 
     if (mi->func != F_TITLE)
     {
@@ -384,13 +418,24 @@ PaintEntry(MenuRoot *mr, MenuItem *mi, int exposure)
 	{
 	    XSetForeground(dpy, Scr->NormalGC, mi->hi_back);
 
-	    XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
-		mr->width, Scr->EntryHeight);
+	    if (VMenu(Scr))
+	      XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
+			     mr->width, Scr->EntryHeight);
+	    else
+	      XFillRectangle(dpy, mr->w, Scr->NormalGC, y_offset, 0,
+			     Scr->EntryHeight, mr->width);
 
 	    MyFont_ChangeGC(mi->hi_fore, mi->hi_back, &Scr->MenuFont);
 
-	    MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, Scr->NormalGC, mi->x,
-		text_y, mi->item, mi->strlen);
+	    if (VMenu(Scr))
+	      MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, Scr->NormalGC,
+				mi->x, text_y,
+				mi->item, mi->strlen);
+	    else
+	      MyFont_DrawString_Rotated(dpy, mr->w, &Scr->MenuFont,
+					Scr->NormalGC,
+					mi->x, y_offset_x,
+					mi->item, mi->strlen, &mi->pixmap_1);
 
 	    gc = Scr->NormalGC;
 	}
@@ -400,8 +445,12 @@ PaintEntry(MenuRoot *mr, MenuItem *mi, int exposure)
 	    {
 		XSetForeground(dpy, Scr->NormalGC, mi->back);
 
-		XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
-		    mr->width, Scr->EntryHeight);
+		if (VMenu(Scr))
+		  XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
+				 mr->width, Scr->EntryHeight);
+		else
+		  XFillRectangle(dpy, mr->w, Scr->NormalGC, y_offset, 0,
+				 Scr->EntryHeight, mr->width);
 
 		MyFont_ChangeGC(mi->fore, mi->back, &Scr->MenuFont);
 		gc = Scr->NormalGC;
@@ -409,8 +458,13 @@ PaintEntry(MenuRoot *mr, MenuItem *mi, int exposure)
 	    else
 		gc = Scr->MenuGC;
 
-	    MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, gc,
-		    mi->x, text_y, mi->item, mi->strlen);
+	    if (VMenu(Scr))
+	      MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, gc,
+				mi->x, text_y, mi->item, mi->strlen);
+	    else
+	      MyFont_DrawString_Rotated(dpy, mr->w, &Scr->MenuFont, gc,
+					mi->x, y_offset_x,
+					mi->item, mi->strlen, &mi->pixmap_0);
 
 	}
 
@@ -424,8 +478,21 @@ PaintEntry(MenuRoot *mr, MenuItem *mi, int exposure)
 	    }
 	    x = mr->width - Scr->pullW - 5;
 	    y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2);
-	    XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
-		Scr->pullW, Scr->pullH, x, y, 1);
+	    if (VMenu(Scr)) {
+	      if (Scr->MenuAtLeft == TRUE)
+		XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
+			   Scr->pullW, Scr->pullH, 5, y, 1);
+	      else
+		XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
+			   Scr->pullW, Scr->pullH, x, y, 1);
+	    } else {
+	      if (Scr->MenuAtLeft == TRUE)
+		XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
+			   Scr->pullW, Scr->pullH, y+4, 5, 1);
+	      else
+		XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
+			   Scr->pullW, Scr->pullH, y+4, x, 1);
+	    }
 	}
     }
     else
@@ -435,23 +502,40 @@ PaintEntry(MenuRoot *mr, MenuItem *mi, int exposure)
 	XSetForeground(dpy, Scr->NormalGC, mi->back);
 
 	/* fill the rectangle with the title background color */
-	XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
-	    mr->width, Scr->EntryHeight);
+	if (VMenu(Scr))
+	  XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
+			 mr->width, Scr->EntryHeight);
+	else
+	  XFillRectangle(dpy, mr->w, Scr->NormalGC, y_offset, 0,
+			 Scr->EntryHeight, mr->width);
 
 	{
 	    XSetForeground(dpy, Scr->NormalGC, mi->fore);
 	    /* now draw the dividing lines */
-	    if (y_offset)
-	      XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset,
-			 mr->width, y_offset);
-	    y = ((mi->item_num+1) * Scr->EntryHeight)-1;
-	    XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
+	    if (VMenu(Scr)) {
+	      if (y_offset)
+		XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset,
+			   mr->width, y_offset);
+	      y = ((mi->item_num+1) * Scr->EntryHeight)-1;
+	      XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
+	    }
 	}
 
 	MyFont_ChangeGC(mi->fore, mi->back, &Scr->MenuFont);
 	/* finally render the title */
-	MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, Scr->NormalGC, mi->x,
-	    text_y, mi->item, mi->strlen);
+	if (VMenu(Scr))
+	  MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, Scr->NormalGC, mi->x,
+			    text_y, mi->item, mi->strlen);
+	else {
+	  MyFont_DrawString_Rotated(dpy, mr->w, &Scr->MenuFont, Scr->NormalGC,
+				    mi->x, y_offset_x,
+				    mi->item, mi->strlen, &mi->pixmap_0);
+	  if (y_offset)
+	    XDrawLine (dpy, mr->w, Scr->NormalGC, y_offset, 0,
+		       y_offset, mr->width);
+	  y = ((mi->item_num+1) * Scr->EntryHeight)-1;
+	  XDrawLine(dpy, mr->w, Scr->NormalGC, y, 0, y, mr->width);
+	}
     }
 }
 
@@ -468,8 +552,10 @@ PaintMenu(MenuRoot *mr, XEvent *e)
 	/* be smart about handling the expose, redraw only the entries
 	 * that we need to
 	 */
-	if (e->xexpose.y < (y_offset + Scr->EntryHeight) &&
-	    (e->xexpose.y + e->xexpose.height) > y_offset)
+	if (VMenu(Scr) && e->xexpose.y < (y_offset + Scr->EntryHeight) &&
+	    (e->xexpose.y + e->xexpose.height) > y_offset ||
+	    HMenu(Scr) && e->xexpose.x < (y_offset + Scr->EntryHeight) &&
+	    (e->xexpose.x + e->xexpose.width) > y_offset)
 	{
 	    PaintEntry(mr, mi, True);
 	}
@@ -537,7 +623,8 @@ UpdateMenu(void)
 	    Scr = (struct ScreenInfo *) context_data;
 
 	if (x < 0 || y < 0 ||
-	    x >= ActiveMenu->width || y >= ActiveMenu->height)
+	    (VMenu(Scr) && (x >= ActiveMenu->width || y >= ActiveMenu->height)) ||
+	    (HMenu(Scr) && (x >= ActiveMenu->height || y >= ActiveMenu->width)))
 	{
 	    if (ActiveItem && ActiveItem->func != F_TITLE)
 	    {
@@ -549,7 +636,10 @@ UpdateMenu(void)
 	}
 
 	/* look for the entry that the mouse is in */
-	entry = y / Scr->EntryHeight;
+	if (VMenu(Scr))
+	  entry = y / Scr->EntryHeight;
+	else
+	  entry = x / Scr->EntryHeight;
 	for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next)
 	{
 	    if (i == entry)
@@ -588,18 +678,28 @@ UpdateMenu(void)
 
 	/* now check to see if we were over the arrow of a pull right entry */
 	if (ActiveItem && ActiveItem->func == F_MENU &&
-	    ((ActiveMenu->width - x) < (ActiveMenu->width >> 1)))
+	    ( VMenu(Scr) &&
+	      ( (((Scr->MenuAtLeft == FALSE)?(ActiveMenu->width - x):(x)))
+		< (ActiveMenu->width * 2 / 5)) ||
+	      HMenu(Scr) &&
+	      ( (((Scr->MenuAtLeft == FALSE)?(ActiveMenu->width - y):(y)))
+		< (ActiveMenu->width * 2 / 5))))
 	{
 	    MenuRoot *save = ActiveMenu;
 	    int savex = MenuOrigins[MenuDepth - 1].x;
 	    int savey = MenuOrigins[MenuDepth - 1].y;
 
 	    if (MenuDepth < MAXMENUDEPTH) {
+	      if (VMenu(Scr))
 		PopUpMenu (ActiveItem->sub,
 			   (savex + (ActiveMenu->width >> 1)),
-			   (savey + ActiveItem->item_num * Scr->EntryHeight)
-			   /*(savey + ActiveItem->item_num * Scr->EntryHeight +
-			    (Scr->EntryHeight >> 1))*/, False);
+			   (savey + ActiveItem->item_num * Scr->EntryHeight),
+			   False);
+	      else
+		PopUpMenu (ActiveItem->sub,
+			   (savex + ActiveItem->item_num * Scr->EntryHeight),
+			   (savey + (ActiveMenu->width >> 1)),
+			   False);
 	    } else if (!badItem) {
 		Bell(XkbBI_MinorError,0,None);
 		badItem = ActiveItem;
@@ -699,6 +799,7 @@ AddToMenu(MenuRoot *menu, const char *item, const char *action,
 
     tmp = malloc(sizeof(MenuItem));
     tmp->root = menu;
+    tmp->pixmap_0 = tmp->pixmap_1 = None;
 
     if (menu->first == NULL)
     {
@@ -745,7 +846,27 @@ AddToMenu(MenuRoot *menu, const char *item, const char *action,
 	menu->pull = TRUE;
     }
     tmp->item_num = menu->items++;
-
+    /* move last entry (i.e. tmp) to head */
+    if ((Scr->MenuRuns == MenuRuns_B2T || Scr->MenuRuns == MenuRuns_R2L)
+	&& menu->first != menu->last) {
+	int i;
+	MenuItem *mi;
+
+	/* remove last entry (i.e. tmp) */
+	menu->last = tmp->prev;
+	menu->last->next = NULL;
+	/* put tmp at head */
+	menu->first->prev = tmp;
+	tmp->next = menu->first;
+	tmp->prev = NULL;
+	menu->first = tmp;
+	tmp->prev = NULL;
+	/* set sequence number */
+	for (i = 0, mi = menu->first; mi; mi = mi->next)
+	    mi->item_num = i++;
+	if (i != menu->items)
+	   fprintf(stderr, "AddToMenu(): items count mismatch!\n");
+    }
     return (tmp);
 }
 
@@ -795,7 +916,12 @@ MakeMenu(MenuRoot *mr)
 	for (cur = mr->first; cur != NULL; cur = cur->next)
 	{
 	    if (cur->func != F_TITLE)
-		cur->x = 5;
+		{
+		    if (Scr->MenuAtLeft == TRUE && mr->pull == TRUE)
+			cur->x = 5 + 16;
+		    else
+			cur->x = 5;
+		}
 	    else
 	    {
 		cur->x = width - MyFont_TextWidth(&Scr->MenuFont, cur->item,
@@ -820,8 +946,8 @@ MakeMenu(MenuRoot *mr)
 		attributes.save_under = True;
 	    }
 	    mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0,
-					(unsigned int) mr->width,
-					(unsigned int) mr->height,
+		VMenu(Scr) ? (unsigned int) mr->width : (unsigned int) mr->height,
+		VMenu(Scr) ? (unsigned int) mr->height : (unsigned int) mr->width,
 					(unsigned int)0,
 					CopyFromParent,
 					(unsigned int) CopyFromParent,
@@ -841,14 +967,14 @@ MakeMenu(MenuRoot *mr)
 	    valuemask |= CWBackingStore;
 	    attributes.backing_store = Always;
 	}
-	mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
-			       (unsigned int) mr->height,
+	mr->w = XCreateWindow (dpy, Scr->Root, 0, 0,
+		VMenu(Scr) ? (unsigned int) mr->width : (unsigned int) mr->height,
+		VMenu(Scr) ? (unsigned int) mr->height : (unsigned int) mr->width,
 			       (unsigned int) Scr->MenuBorderWidth,
 			       CopyFromParent, (unsigned int) CopyFromParent,
 			       (Visual *) CopyFromParent,
 			       valuemask, &attributes);
 
-
 	XSaveContext(dpy, mr->w, MenuContext, (caddr_t)mr);
 	XSaveContext(dpy, mr->w, ScreenContext, (caddr_t)Scr);
 
@@ -1050,20 +1176,54 @@ PopUpMenu (MenuRoot *menu, int x, int y, Bool center)
     menu->entered = FALSE;
 
     if (center) {
+      if (VMenu(Scr)) {
 	x -= (menu->width / 2);
 	y -= (Scr->EntryHeight / 2);	/* sticky menus would be nice here */
+      } else {
+	y -= (menu->width / 2);
+	x -= (Scr->EntryHeight / 2);	/* sticky menus would be nice here */
+      }
+
+      if (Scr->MenuAtLeft == TRUE) {
+	if (VMenu(Scr))
+	  x -= menu->width / 4;
+	else
+	  y -= menu->width / 4;
+      } else {
+	if (VMenu(Scr))
+	  x += menu->width / 4;
+	else
+	  y += menu->width / 4;
+      }
+    } else {
+      if (Scr->MenuAtLeft == TRUE) {
+	if (VMenu(Scr))
+	  x -= menu->width;
+	else
+	  y -= menu->width;
+      }
     }
+    if (Scr->MenuRuns == MenuRuns_B2T)
+      y -= menu->height - Scr->EntryHeight;
+    else if (Scr->MenuRuns == MenuRuns_R2L)
+      x -= menu->height - Scr->EntryHeight;
 
     /*
      * clip to screen
      */
-    if (x + menu->width > Scr->MyDisplayWidth) {
+    if (VMenu(Scr) && x + menu->width > Scr->MyDisplayWidth) {
 	x = Scr->MyDisplayWidth - menu->width;
     }
+    if (HMenu(Scr) && x + menu->height > Scr->MyDisplayWidth) {
+	x = Scr->MyDisplayWidth - menu->height;
+    }
     if (x < 0) x = 0;
-    if (y + menu->height > Scr->MyDisplayHeight) {
+    if (VMenu(Scr) && y + menu->height > Scr->MyDisplayHeight) {
 	y = Scr->MyDisplayHeight - menu->height;
     }
+    if (HMenu(Scr) && y + menu->width > Scr->MyDisplayHeight) {
+	y = Scr->MyDisplayHeight - menu->width;
+    }
     if (y < 0) y = 0;
 
     MenuOrigins[MenuDepth].x = x;
@@ -1178,8 +1338,13 @@ resizeFromCenter(Window w, TwmWindow *tmp_win)
   namelen = strlen (tmp_win->name);
 #endif
   bw2 = tmp_win->frame_bw * 2;
-  AddingW = tmp_win->attr.width + bw2;
-  AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
+  if (tmp_win->title_pos == TP_TOP || tmp_win->title_pos == TP_BOTTOM) {
+    AddingW = tmp_win->attr.width + bw2;
+    AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
+  } else {
+    AddingW = tmp_win->attr.width + tmp_win->title_height + bw2;
+    AddingH = tmp_win->attr.height + bw2;
+  }
 #if 0
   width = (SIZE_HINDENT + MyFont_TextWidth (&Scr->SizeFont,
 					     tmp_win->name, namelen));
@@ -1205,12 +1370,20 @@ resizeFromCenter(Window w, TwmWindow *tmp_win)
   lastx = -10000;
   lasty = -10000;
 #if 0
+#if 1
+  MoveOutline(Scr->Root,
+	      origDragX - JunkBW, origDragY - JunkBW,
+	      DragWidth * JunkBW, DragHeight * JunkBW,
+	      tmp_win->frame_bw,
+	      tmp_win->title_height, tmp_win->title_pos);
+#else
   MoveOutline(Scr->Root,
 	      origDragX - JunkBW, origDragY - JunkBW,
 	      DragWidth * JunkBW, DragHeight * JunkBW,
 	      tmp_win->frame_bw,
 	      tmp_win->title_height);
 #endif
+#endif
   MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight);
   while (TRUE)
     {
@@ -1614,7 +1787,8 @@ ExecuteFunction(int func, const char *action, Window w, TwmWindow *tmp_win,
 		    origDragX - JunkBW, origDragY - JunkBW,
 		    DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW,
 		    tmp_win->frame_bw,
-		    moving_icon ? 0 : tmp_win->title_height);
+		    moving_icon ? 0 : tmp_win->title_height,
+		    tmp_win->title_pos);
 		/*
 		 * This next line causes HandleReleaseNotify to call
 		 * XRaiseWindow().  This is solely to preserve the
@@ -1671,7 +1845,7 @@ ExecuteFunction(int func, const char *action, Window w, TwmWindow *tmp_win,
 		    if (Scr->OpaqueMove)
 		      XMoveWindow (dpy, DragWindow, origDragX, origDragY);
 		    else
-		        MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+		        MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0, 0);
 		    DragWindow = None;
                 }
 	    }
@@ -1696,7 +1870,7 @@ ExecuteFunction(int func, const char *action, Window w, TwmWindow *tmp_win,
 	    }
 	    if (Event.type == releaseEvent)
 	    {
-		MoveOutline(rootw, 0, 0, 0, 0, 0, 0);
+		MoveOutline(rootw, 0, 0, 0, 0, 0, 0, 0);
 		if (moving_icon &&
 		    ((CurrentDragX != origDragX ||
 		      CurrentDragY != origDragY)))
@@ -1784,7 +1958,8 @@ ExecuteFunction(int func, const char *action, Window w, TwmWindow *tmp_win,
 		    else
 			MoveOutline(eventp->xmotion.root, xl, yt, w, h,
 			    tmp_win->frame_bw,
-			    moving_icon ? 0 : tmp_win->title_height);
+			    moving_icon ? 0 : tmp_win->title_height,
+			    tmp_win->title_pos);
 		}
 	    }
 	    else if (DragWindow != None)
@@ -1824,7 +1999,8 @@ ExecuteFunction(int func, const char *action, Window w, TwmWindow *tmp_win,
 		else
 		    MoveOutline(eventp->xmotion.root, xl, yt, w, h,
 			tmp_win->frame_bw,
-			moving_icon ? 0 : tmp_win->title_height);
+			moving_icon ? 0 : tmp_win->title_height,
+			tmp_win->title_pos);
 	    }
 
 	}
@@ -2092,14 +2268,25 @@ ExecuteFunction(int func, const char *action, Window w, TwmWindow *tmp_win,
 
     case F_WARPTO:
 	{
+	    static TwmWindow *last_win = NULL;
 	    register TwmWindow *t;
 	    int len;
 
 	    len = strlen(action);
 
-	    for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
+	    for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
+		if (t == last_win) break;
+	    if (t) for (t = t->next; t != NULL; t = t->next) {
 		if (!strncmp(action, t->name, len))
                     if (WarpThere(t)) break;
+		if (!strncmp(action, t->icon_name, len))
+		    if (WarpThere(t)) break;
+	    }
+	    if (!t) for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
+	        if (!strncmp(action, t->name, len))
+		    if (WarpThere(t)) break;
+		if (!strncmp(action, t->icon_name, len))
+		    if (WarpThere(t)) break;
 	    }
 	    if (!t) {
 		for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
@@ -2116,6 +2303,8 @@ ExecuteFunction(int func, const char *action, Window w, TwmWindow *tmp_win,
 
 	    if (!t)
 		Bell(XkbBI_MinorError,0,None);
+	    else
+		last_win = t;
 	}
 	break;
 
@@ -2247,6 +2436,38 @@ ExecuteFunction(int func, const char *action, Window w, TwmWindow *tmp_win,
 	fprintf (stderr, "%s:  unable to start:  %s\n", ProgramName, *Argv);
 	break;
 
+   case  F_TITLEPOS:
+      { int pos = -1;
+	if (strcasecmp(action, "top") == 0)
+	    pos = TP_TOP;
+	else if (strcasecmp(action, "left") == 0)
+	    pos = TP_LEFT;
+	else if (strcasecmp(action, "bottom") == 0)
+	    pos = TP_BOTTOM;
+	else if (strcasecmp(action, "right") == 0)
+	    pos = TP_RIGHT;
+	if (context == C_TITLE) {
+	   if (pos != tmp_win->title_pos)
+		ChangeTitlePos(tmp_win, pos);
+	} else {
+	    Scr->TitlePosDynamic = pos;
+	}
+      }
+	break;
+
+   case  F_TITLESQZ:
+	if (context != C_TITLE)
+		break;
+	if (strcasecmp(action, "left") == 0)
+	    ChangeSqueeze(tmp_win, J_LEFT);
+	else if (strcasecmp(action, "center") == 0)
+	    ChangeSqueeze(tmp_win, J_CENTER);
+	else if (strcasecmp(action, "right") == 0)
+	    ChangeSqueeze(tmp_win, J_RIGHT);
+	else if (strcasecmp(action, "none") == 0)
+	    ChangeSqueeze(tmp_win, -1);
+
+	break;
     }
 
     if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime);
@@ -2818,6 +3039,14 @@ DestroyMenu (MenuRoot *menu)
     for (item = menu->first; item; ) {
 	MenuItem *tmp = item;
 	item = item->next;
+	if (tmp->pixmap_0) {
+	  XFreePixmap(dpy, tmp->pixmap_0);
+	  tmp->pixmap_0 = None;
+	}
+	if (tmp->pixmap_1) {
+	  XFreePixmap(dpy, tmp->pixmap_1);
+	  tmp->pixmap_1 = None;
+	}
 	free (tmp);
     }
 }
@@ -2864,13 +3093,14 @@ WarpAlongRing (XButtonEvent *ev, Bool forward)
 	    p->ring.cursor_valid = True;
 	    p->ring.curs_x = ev->x_root - t->frame_x;
 	    p->ring.curs_y = ev->y_root - t->frame_y;
+	    p->ring.curs_x -= t->frame_bw;
+	    p->ring.curs_y -= t->frame_bw;
 	    if (p->ring.curs_x < -p->frame_bw ||
 		p->ring.curs_x >= p->frame_width + p->frame_bw ||
 		p->ring.curs_y < -p->frame_bw ||
 		p->ring.curs_y >= p->frame_height + p->frame_bw) {
 		/* somehow out of window */
-		p->ring.curs_x = p->frame_width / 2;
-		p->ring.curs_y = p->frame_height / 2;
+		set_pos(&p->ring.curs_x, &p->ring.curs_y, p, Scr->WarpCursorPos);
 	    }
 	}
     }
@@ -2888,8 +3118,7 @@ WarpToWindow (TwmWindow *t)
 	x = t->ring.curs_x;
 	y = t->ring.curs_y;
     } else {
-	x = t->frame_width / 2;
-	y = t->frame_height / 2;
+	set_pos(&x, &y, t, Scr->WarpCursorPos);
     }
     XWarpPointer (dpy, None, t->frame, 0, 0, 0, 0, x, y);
 }
diff --git a/src/menus.h b/src/menus.h
index cadffaf..99c1449 100644
--- a/src/menus.h
+++ b/src/menus.h
@@ -72,6 +72,8 @@ typedef struct MenuItem
     struct MenuItem *prev;	/* prev menu item */
     struct MenuRoot *sub;	/* MenuRoot of a pull right menu */
     struct MenuRoot *root;	/* back pointer to my MenuRoot */
+    Pixmap pixmap_0;		/* rotated string pixel for state == 0 */
+    Pixmap pixmap_1;		/* rotated string pixel for state == 1 */
     const char *item;		/* the character string displayed */
     const char *action;		/* action to be performed */
     Pixel fore;			/* foreground color */
diff --git a/src/parse.c b/src/parse.c
index 787e1b1..e1b45f2 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -334,6 +334,9 @@ typedef struct _TwmKeyword {
 #define kw0_NoCaseSensitive		23
 #define kw0_NoRaiseOnWarp		24
 #define kw0_WarpUnmapped		25
+#define kw0_MenuBottomUp		26
+#define kw0_MenuAtLeft			27
+#define kw0_MenuUpward			28
 
 #define kws_UsePPosition		1
 #define kws_IconFont			2
@@ -464,6 +467,8 @@ static TwmKeyword keytable[] = {
     { "f.source",		FSKEYWORD, F_BEEP },  /* XXX - don't work */
     { "f.startwm",		FSKEYWORD, F_STARTWM },
     { "f.title",		FKEYWORD, F_TITLE },
+    { "f.titlepos",		FSKEYWORD, F_TITLEPOS },
+    { "f.titlesqz",		FSKEYWORD, F_TITLESQZ },
     { "f.topzoom",		FKEYWORD, F_TOPZOOM },
     { "f.twmrc",		FKEYWORD, F_RESTART },
     { "f.unfocus",		FKEYWORD, F_UNFOCUS },
@@ -514,14 +519,18 @@ static TwmKeyword keytable[] = {
     { "maketitle",		MAKE_TITLE, 0 },
     { "maxwindowsize",		SKEYWORD, kws_MaxWindowSize },
     { "menu",			MENU, 0 },
+    { "menuatleft",		KEYWORD, kw0_MenuAtLeft },
     { "menubackground",		CKEYWORD, kwc_MenuBackground },
     { "menubordercolor",	CKEYWORD, kwc_MenuBorderColor },
     { "menuborderwidth",	NKEYWORD, kwn_MenuBorderWidth },
+    { "menubottomup",		KEYWORD, kw0_MenuBottomUp },
     { "menufont",		SKEYWORD, kws_MenuFont },
     { "menuforeground",		CKEYWORD, kwc_MenuForeground },
+    { "menuruns",		MENU_RUNS, 0},
     { "menushadowcolor",	CKEYWORD, kwc_MenuShadowColor },
     { "menutitlebackground",	CKEYWORD, kwc_MenuTitleBackground },
     { "menutitleforeground",	CKEYWORD, kwc_MenuTitleForeground },
+    { "menuupward",		KEYWORD, kw0_MenuUpward },
     { "meta",			META, 0 },
     { "mod",			META, 0 },  /* fake it */
     { "monochrome",		MONOCHROME, 0 },
@@ -569,6 +578,10 @@ static TwmKeyword keytable[] = {
     { "starticonified",		START_ICONIFIED, 0 },
     { "t",			TITLE, 0 },
     { "title",			TITLE, 0 },
+    { "titleatbottom",		TITLE_AT_BOTTOM, 0},
+    { "titleatleft",		TITLE_AT_LEFT, 0},
+    { "titleatright",		TITLE_AT_RIGHT, 0},
+    { "titleattop",		TITLE_AT_TOP, 0},
     { "titlebackground",	CLKEYWORD, kwcl_TitleBackground },
     { "titlebuttonborderwidth",	NKEYWORD, kwn_TitleButtonBorderWidth },
     { "titlefont",		SKEYWORD, kws_TitleFont },
@@ -580,6 +593,7 @@ static TwmKeyword keytable[] = {
     { "w",			WINDOW, 0 },
     { "wait",			WAIT, 0 },
     { "warpcursor",		WARP_CURSOR, 0 },
+    { "warpcursorpos",		WARP_CURSOR_POS, 0 },
     { "warpunmapped",		KEYWORD, kw0_WarpUnmapped },
     { "west",			DKEYWORD, D_WEST },
     { "window",			WINDOW, 0 },
@@ -721,6 +735,19 @@ int do_single_keyword (int keyword)
       case kw0_WarpUnmapped:
 	Scr->WarpUnmapped = TRUE;
 	return 1;
+
+      case kw0_MenuBottomUp:
+	Scr->MenuAtLeft = TRUE;
+	Scr->MenuRuns = MenuRuns_B2T;
+	return 1;
+
+      case kw0_MenuAtLeft:
+	Scr->MenuAtLeft = TRUE;
+	return 1;
+
+      case kw0_MenuUpward:
+	Scr->MenuRuns = MenuRuns_B2T;
+	return 1;
     }
 
     return 0;
diff --git a/src/parse.h b/src/parse.h
index e461e19..d87610b 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -146,6 +146,8 @@ extern int mods;
 #define F_COLORMAP		110	/* string */
 #define F_PRIORITY		111	/* string */
 #define F_STARTWM		114	/* string */
+#define F_TITLEPOS		115	/* string */
+#define F_TITLESQZ		116	/* string */
 
 #define D_NORTH			1
 #define D_SOUTH			2
diff --git a/src/resize.c b/src/resize.c
index 7cb4aa6..6ea63fc 100644
--- a/src/resize.c
+++ b/src/resize.c
@@ -184,7 +184,7 @@ StartResize(XEvent *evp, TwmWindow *tmp_win, Bool fromtitlebar)
     MoveOutline (Scr->Root, dragx - tmp_win->frame_bw,
 		 dragy - tmp_win->frame_bw, dragWidth + 2 * tmp_win->frame_bw,
 		 dragHeight + 2 * tmp_win->frame_bw,
-		 tmp_win->frame_bw, tmp_win->title_height);
+		 tmp_win->frame_bw, tmp_win->title_height, tmp_win->title_pos);
 }
 
 
@@ -216,13 +216,14 @@ MenuStartResize(TwmWindow *tmp_win, int x, int y, int w, int h)
 		 dragy - tmp_win->frame_bw,
 		 dragWidth + 2 * tmp_win->frame_bw,
 		 dragHeight + 2 * tmp_win->frame_bw,
-		 tmp_win->frame_bw, tmp_win->title_height);
+		 tmp_win->frame_bw, tmp_win->title_height, tmp_win->title_pos);
 }
 
 /**
  * begin a windorew resize operation from AddWindow
  *  \param tmp_win the TwmWindow pointer
  */
+
 void
 AddStartResize(TwmWindow *tmp_win, int x, int y, int w, int h)
 {
@@ -347,7 +348,7 @@ MenuDoResize(int x_root, int y_root, TwmWindow *tmp_win)
             dragy - tmp_win->frame_bw,
             dragWidth + 2 * tmp_win->frame_bw,
             dragHeight + 2 * tmp_win->frame_bw,
-	    tmp_win->frame_bw, tmp_win->title_height);
+	    tmp_win->frame_bw, tmp_win->title_height, tmp_win->title_pos);
     }
 
     DisplaySize(tmp_win, dragWidth, dragHeight);
@@ -462,7 +463,7 @@ DoResize(int x_root, int y_root, TwmWindow *tmp_win)
             dragy - tmp_win->frame_bw,
             dragWidth + 2 * tmp_win->frame_bw,
             dragHeight + 2 * tmp_win->frame_bw,
-	    tmp_win->frame_bw, tmp_win->title_height);
+	    tmp_win->frame_bw, tmp_win->title_height, tmp_win->title_pos);
     }
 
     DisplaySize(tmp_win, dragWidth, dragHeight);
@@ -488,8 +489,13 @@ DisplaySize(TwmWindow *tmp_win, int width, int height)
     last_width = width;
     last_height = height;
 
+  if (tmp_win->title_pos == TP_TOP || tmp_win->title_pos == TP_BOTTOM) {
     dheight = height - tmp_win->title_height;
     dwidth = width;
+  } else {
+    dheight = height;
+    dwidth = width - tmp_win->title_height;
+  }
 
     /*
      * ICCCM says that PMinSize is the default is no PBaseSize is given,
@@ -533,7 +539,7 @@ EndResize(void)
     fprintf(stderr, "EndResize\n");
 #endif
 
-    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0, 0);
     XUnmapWindow(dpy, Scr->SizeWindow);
 
     XFindContext(dpy, ResizeWindow, TwmContext, (caddr_t *)&tmp_win);
@@ -569,7 +575,7 @@ EndResize(void)
 void
 MenuEndResize(TwmWindow *tmp_win)
 {
-    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0, 0);
     XUnmapWindow(dpy, Scr->SizeWindow);
     ConstrainSize (tmp_win, &dragWidth, &dragHeight);
     AddingX = dragx - tmp_win->frame_bw;
@@ -617,6 +623,9 @@ ConstrainSize (TwmWindow *tmp_win, int *widthp, int *heightp)
     int dwidth = *widthp, dheight = *heightp;
 
 
+  if (tmp_win->title_pos == TP_LEFT || tmp_win->title_pos == TP_RIGHT)
+    dwidth -= tmp_win->title_height;
+  else
     dheight -= tmp_win->title_height;
 
     if (tmp_win->hints.flags & PMinSize) {
@@ -724,8 +733,13 @@ ConstrainSize (TwmWindow *tmp_win, int *widthp, int *heightp)
     /*
      * Fourth, account for border width and title height
      */
+  if (tmp_win->title_pos == TP_LEFT || tmp_win->title_pos == TP_RIGHT) {
+    *widthp = dwidth + tmp_win->title_height;
+    *heightp = dheight;
+  } else {
     *widthp = dwidth;
     *heightp = dheight + tmp_win->title_height;
+  }
 }
 
 
@@ -778,8 +792,14 @@ void SetupFrame (TwmWindow *tmp_win, int x, int y, int w, int h, int bw, Bool se
       bw = tmp_win->frame_bw;		/* -1 means current frame width */
 
     if (tmp_win->iconmgr) {
-	tmp_win->iconmgrp->width = w;
-        h = tmp_win->iconmgrp->height + tmp_win->title_height;
+	if (tmp_win->title_pos == TP_TOP ||
+	    tmp_win->title_pos == TP_BOTTOM) {
+	    tmp_win->iconmgrp->width = w;
+	    h = tmp_win->iconmgrp->height + tmp_win->title_height;
+	} else {
+	    tmp_win->iconmgrp->width = w - tmp_win->title_height;
+	    h = tmp_win->iconmgrp->height;
+	}
     }
 
     /*
@@ -796,12 +816,33 @@ void SetupFrame (TwmWindow *tmp_win, int x, int y, int w, int h, int bw, Bool se
     title_width = xwc.width = w;
     title_height = Scr->TitleHeight + bw;
 
+  if (tmp_win->title_pos == TP_LEFT || tmp_win->title_pos == TP_RIGHT) {
+    /* title_width actually means height of title */
+    title_width = h;
+    ComputeWindowTitleOffsets (tmp_win, h, True);
+  } else
     ComputeWindowTitleOffsets (tmp_win, xwc.width, True);
 
     reShape = (tmp_win->wShaped ? TRUE : FALSE);
     if (tmp_win->squeeze_info)		/* check for title shaping */
     {
 	title_width = tmp_win->rightx + Scr->TBInfo.rightoff;
+      if (tmp_win->title_pos == TP_LEFT || tmp_win->title_pos == TP_RIGHT) {
+	if (title_width < h)
+	{
+	    xwc.width = title_width;
+	    if (tmp_win->frame_height != h ||
+		tmp_win->frame_width != w ||
+		tmp_win->frame_bw != bw ||
+		title_width != tmp_win->title_width)
+		reShape = TRUE;
+	}
+	else
+	{
+	    if (!tmp_win->wShaped) reShape = TRUE;
+	    title_width = h;
+	}
+      } else {
 	if (title_width < xwc.width)
 	{
 	    xwc.width = title_width;
@@ -816,6 +857,7 @@ void SetupFrame (TwmWindow *tmp_win, int x, int y, int w, int h, int bw, Bool se
 	    if (!tmp_win->wShaped) reShape = TRUE;
 	    title_width = xwc.width;
 	}
+      }
     }
 
     tmp_win->title_width = title_width;
@@ -828,10 +870,29 @@ void SetupFrame (TwmWindow *tmp_win, int x, int y, int w, int h, int bw, Bool se
 	    tmp_win->title_y = xwc.y = -bw;
 	    xwcm |= (CWX | CWY | CWBorderWidth);
 	}
+	if (tmp_win->squeeze_info == NULL && tmp_win->title_pos != TP_TOP) {
+	    /* can't call ComputeTitleLocation() yet! */
+	    tmp_win->title_x = -bw;
+	    tmp_win->title_y = -bw;
+	    if (tmp_win->title_pos == TP_BOTTOM)
+		tmp_win->title_y += (h - tmp_win->title_height + bw);
+	    if (tmp_win->title_pos == TP_RIGHT)
+		tmp_win->title_x += (w - tmp_win->title_height + bw);
+	    xwc.x = tmp_win->title_x;
+	    xwc.y = tmp_win->title_y;
+	    xwcm |= (CWX | CWY);
+	}
+	if (tmp_win->title_pos == TP_LEFT || tmp_win->title_pos == TP_RIGHT) {
+	    xwcm |= CWHeight;
+	    xwc.height = title_width;
+	    xwcm &= ~CWWidth;
+	    /* xwc.width = Scr->TitleHeight */;
+	}
 
 	XConfigureWindow(dpy, tmp_win->title_w, xwcm, &xwc);
     }
 
+  if (tmp_win->title_pos == TP_TOP || tmp_win->title_pos == TP_BOTTOM) {
     if (tmp_win->attr.width != w)
 	tmp_win->widthEverChangedByUser = True;
 
@@ -840,9 +901,35 @@ void SetupFrame (TwmWindow *tmp_win, int x, int y, int w, int h, int bw, Bool se
 
     tmp_win->attr.width = w;
     tmp_win->attr.height = h - tmp_win->title_height;
+  } else {
+    if (tmp_win->attr.width != (w - tmp_win->title_height))
+	tmp_win->widthEverChangedByUser = True;
 
-    XMoveResizeWindow (dpy, tmp_win->w, 0, tmp_win->title_height,
-		       w, h - tmp_win->title_height);
+    if (tmp_win->attr.height != h)
+	tmp_win->heightEverChangedByUser = True;
+
+    tmp_win->attr.width = w - tmp_win->title_height;
+    tmp_win->attr.height = h;
+  }
+
+    switch (tmp_win->title_pos) {
+    case TP_TOP:
+        XMoveResizeWindow (dpy, tmp_win->w, 0, tmp_win->title_height,
+			   w, h - tmp_win->title_height);
+	break;
+    case TP_BOTTOM:
+	XMoveResizeWindow (dpy, tmp_win->w, 0, 0,
+			   w, h - tmp_win->title_height);
+	break;
+    case TP_LEFT:
+	XMoveResizeWindow (dpy, tmp_win->w, tmp_win->title_height, 0,
+			   w - tmp_win->title_height, h);
+	break;
+    case TP_RIGHT:
+	XMoveResizeWindow (dpy, tmp_win->w, 0, 0,
+			   w - tmp_win->title_height, h);
+	break;
+    }
 
     /*
      * fix up frame and assign size/location values in tmp_win
@@ -874,6 +961,13 @@ void SetupFrame (TwmWindow *tmp_win, int x, int y, int w, int h, int bw, Bool se
         }
 
         xwcm = CWX | CWWidth;
+	if (tmp_win->title_pos == TP_LEFT || tmp_win->title_pos == TP_RIGHT) {
+	   xwcm &= ~CWX;
+	   xwcm |= CWY | CWHeight;
+	   xwc.y = xwc.x;
+	   xwc.height = xwc.width;
+	   xwc.width = (Scr->TitleHeight - 2 * Scr->FramePadding);
+	}
         XConfigureWindow(dpy, tmp_win->hilite_w, xwcm, &xwc);
     }
 
@@ -887,12 +981,38 @@ void SetupFrame (TwmWindow *tmp_win, int x, int y, int w, int h, int bw, Bool se
         client_event.xconfigure.display = dpy;
         client_event.xconfigure.event = tmp_win->w;
         client_event.xconfigure.window = tmp_win->w;
+    switch (tmp_win->title_pos) {
+    case TP_TOP:
         client_event.xconfigure.x = (x + tmp_win->frame_bw - tmp_win->old_bw);
         client_event.xconfigure.y = (y + tmp_win->frame_bw +
 				     tmp_win->title_height - tmp_win->old_bw);
         client_event.xconfigure.width = tmp_win->frame_width;
         client_event.xconfigure.height = tmp_win->frame_height -
                 tmp_win->title_height;
+	break;
+    case TP_BOTTOM:
+        client_event.xconfigure.x = (x + tmp_win->frame_bw - tmp_win->old_bw);
+        client_event.xconfigure.y = (y + tmp_win->frame_bw - tmp_win->old_bw);
+        client_event.xconfigure.width = tmp_win->frame_width;
+        client_event.xconfigure.height = tmp_win->frame_height -
+                tmp_win->title_height;
+	break;
+    case TP_LEFT:
+        client_event.xconfigure.x = (x + tmp_win->frame_bw +
+				     tmp_win->title_height - tmp_win->old_bw);
+        client_event.xconfigure.y = (y + tmp_win->frame_bw - tmp_win->old_bw);
+        client_event.xconfigure.width = tmp_win->frame_width -
+                tmp_win->title_height;
+        client_event.xconfigure.height = tmp_win->frame_height;
+	break;
+    case TP_RIGHT:
+        client_event.xconfigure.x = (x + tmp_win->frame_bw - tmp_win->old_bw);
+        client_event.xconfigure.y = (y + tmp_win->frame_bw - tmp_win->old_bw);
+        client_event.xconfigure.width = tmp_win->frame_width -
+		tmp_win->title_height;
+        client_event.xconfigure.height = tmp_win->frame_height;
+	break;
+    }
         client_event.xconfigure.border_width = tmp_win->old_bw;
         /* Real ConfigureNotify events say we're above title window, so ... */
 	/* what if we don't have a title ????? */
@@ -1026,15 +1146,31 @@ SetFrameShape (TwmWindow *tmp)
 	/*
 	 * need to do general case
 	 */
-	XShapeCombineShape (dpy, tmp->frame, ShapeBounding,
-			    0, tmp->title_height, tmp->w,
-			    ShapeBounding, ShapeSet);
-	if (tmp->title_w) {
+	if (tmp->title_pos == TP_TOP || tmp->title_pos == TP_BOTTOM) {
+	    XShapeCombineShape (dpy, tmp->frame, ShapeBounding,
+				0,
+			    (tmp->title_pos == TP_TOP)?tmp->title_height:0,
+				tmp->w,
+				ShapeBounding, ShapeSet);
+	    if (tmp->title_w) {
+		XShapeCombineShape (dpy, tmp->frame, ShapeBounding,
+				    tmp->title_x + tmp->frame_bw,
+				    tmp->title_y + tmp->frame_bw,
+				    tmp->title_w, ShapeBounding,
+				    ShapeUnion);
+	    }
+	} else {
 	    XShapeCombineShape (dpy, tmp->frame, ShapeBounding,
-				tmp->title_x + tmp->frame_bw,
-				tmp->title_y + tmp->frame_bw,
-				tmp->title_w, ShapeBounding,
-				ShapeUnion);
+			    (tmp->title_pos == TP_LEFT)?tmp->title_height:0,
+				0, tmp->w,
+				ShapeBounding, ShapeSet);
+	    if (tmp->title_w) {
+		XShapeCombineShape (dpy, tmp->frame, ShapeBounding,
+				    tmp->title_x + tmp->frame_bw,
+				    tmp->title_y + tmp->frame_bw,
+				    tmp->title_w, ShapeBounding,
+				    ShapeUnion);
+	    }
 	}
     } else {
 	/*
@@ -1052,28 +1188,64 @@ SetFrameShape (TwmWindow *tmp)
 	     *
 	     * The frame_width and frame_height do *not* include borders.
 	     */
+	  if (tmp->title_pos == TP_TOP || tmp->title_pos == TP_BOTTOM) {
+	    int order = (tmp->title_pos == TP_TOP)?YXBanded:Unsorted;
 	    /* border */
 	    newBounding[0].x = tmp->title_x;
 	    newBounding[0].y = tmp->title_y;
+	    if (tmp->title_pos == TP_BOTTOM)
+		newBounding[0].y += tmp->frame_bw;
 	    newBounding[0].width = tmp->title_width + fbw2;
 	    newBounding[0].height = tmp->title_height;
 	    newBounding[1].x = -tmp->frame_bw;
-	    newBounding[1].y = Scr->TitleHeight;
+	    newBounding[1].y = (tmp->title_pos == TP_TOP)?
+				Scr->TitleHeight : -tmp->frame_bw;
 	    newBounding[1].width = tmp->attr.width + fbw2;
 	    newBounding[1].height = tmp->attr.height + fbw2;
 	    XShapeCombineRectangles (dpy, tmp->frame, ShapeBounding, 0, 0,
-				     newBounding, 2, ShapeSet, YXBanded);
+				     newBounding, 2, ShapeSet, order);
 	    /* insides */
 	    newClip[0].x = tmp->title_x + tmp->frame_bw;
-	    newClip[0].y = 0;
+	    newClip[0].y = (tmp->title_pos == TP_TOP)?
+				0 : tmp->attr.height + tmp->frame_bw;
 	    newClip[0].width = tmp->title_width;
 	    newClip[0].height = Scr->TitleHeight;
 	    newClip[1].x = 0;
-	    newClip[1].y = tmp->title_height;
+	    newClip[1].y = (tmp->title_pos == TP_TOP)?
+				tmp->title_height : 0;
 	    newClip[1].width = tmp->attr.width;
 	    newClip[1].height = tmp->attr.height;
 	    XShapeCombineRectangles (dpy, tmp->frame, ShapeClip, 0, 0,
-				     newClip, 2, ShapeSet, YXBanded);
+				     newClip, 2, ShapeSet, order);
+	  } else {
+	    int order = Unsorted;
+	    /* border */
+	    newBounding[0].x = tmp->title_x;
+	    if (tmp->title_pos == TP_RIGHT)
+		newBounding[0].x += tmp->frame_bw;
+	    newBounding[0].y = tmp->title_y;
+	    newBounding[0].width = tmp->title_height;
+	    newBounding[0].height = tmp->title_width + fbw2;
+	    newBounding[1].x = (tmp->title_pos == TP_LEFT)?
+				Scr->TitleHeight : -tmp->frame_bw;
+	    newBounding[1].y = -tmp->frame_bw;
+	    newBounding[1].width = tmp->attr.width + fbw2;
+	    newBounding[1].height = tmp->attr.height + fbw2;
+	    XShapeCombineRectangles (dpy, tmp->frame, ShapeBounding, 0, 0,
+				     newBounding, 2, ShapeSet, order);
+	    /* insides */
+	    newClip[0].x = (tmp->title_pos == TP_LEFT)?
+				0 : tmp->attr.width + tmp->frame_bw;
+	    newClip[0].y = tmp->title_y + tmp->frame_bw;
+	    newClip[0].width = Scr->TitleHeight;
+	    newClip[0].height = tmp->title_width;
+	    newClip[1].x = (tmp->title_pos == TP_LEFT)?  tmp->title_height : 0;
+	    newClip[1].y = 0;
+	    newClip[1].width = tmp->attr.width;
+	    newClip[1].height = tmp->attr.height;
+	    XShapeCombineRectangles (dpy, tmp->frame, ShapeClip, 0, 0,
+				     newClip, 2, ShapeSet, order);
+	  }
 	} else {
 	    (void) XShapeCombineMask (dpy, tmp->frame, ShapeBounding, 0, 0,
  				      None, ShapeSet);
@@ -1139,3 +1311,233 @@ SetFrameShape (TwmWindow *tmp)
  * are really deltax and deltay to lower right handle corner, so they need
  * to have -1 subtracted from would normally be the actual extents.
  */
+
+
+/***********************************************************************
+ *
+ *  Procedure:
+ *      RelocateBtns - relocate buttons
+ *
+ *  Inputs:
+ *      tmp_win - the TwmWindow pointer
+ *      topbtm - TRUE when top or bottom
+ *
+ ***********************************************************************
+ */
+static void
+RelocateBtns (tmp_win, topbtm)
+    TwmWindow *tmp_win;
+    int topbtm;
+{
+    TBWindow *tbw;
+    TitleButton *tb;
+    XSetWindowAttributes attributes;
+    XWindowChanges xwc;
+    int y, leftx, rightx, boxwidth;
+
+    if (tmp_win->titlebuttons == NULL || topbtm == -1)
+	return;
+
+    leftx = y = Scr->TBInfo.leftx;
+    rightx = tmp_win->rightx;
+    boxwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
+
+    for (tb = Scr->TBInfo.head, tbw = tmp_win->titlebuttons; tb;
+	 tb = tb->next, tbw++) {
+	int x;
+
+	XConfigureWindow(dpy, tbw->window, (CWX|CWY), &xwc);
+	if (tb->rightside) {
+	    x = rightx;
+	    rightx += boxwidth;
+	    if (topbtm == TRUE) {
+		attributes.win_gravity = NorthEastGravity;
+		xwc.x = x;
+		xwc.y = y;
+	    } else {
+		attributes.win_gravity = SouthWestGravity;
+		xwc.x = y;
+		xwc.y = x;
+	    }
+	} else {
+	    x = leftx;
+	    leftx += boxwidth;
+	    if (topbtm == TRUE) {
+		xwc.x = x;
+		xwc.y = y;
+	    } else {
+		xwc.x = y;
+		xwc.y = x;
+	    }
+	    attributes.win_gravity = NorthWestGravity;
+	}
+	XChangeWindowAttributes(dpy, tbw->window, CWWinGravity, &attributes);
+	XConfigureWindow(dpy, tbw->window, (CWX|CWY), &xwc);
+    }
+}
+
+/***********************************************************************
+ *
+ *  Procedure:
+ *      ChangeTitlePos - change the position of titlebar
+ *
+ *  Inputs:
+ *      tmp_win - the TwmWindow pointer
+ *      pos - position of titlebar
+ *
+ ***********************************************************************
+ */
+void
+ChangeTitlePos (tmp_win, pos)
+    TwmWindow *tmp_win;
+    int pos;
+{
+    int h, w;
+    int x, y;
+    int reloc_btns = -1;
+
+
+    if (pos == -1 || tmp_win->title_pos == pos)
+	return; /* nothing to do */
+
+    h = tmp_win->frame_height;
+    w = tmp_win->frame_width;
+
+    /* reconfigure title window if necessary */
+    if (tmp_win->title_w) {
+	XWindowChanges xwc_w, xwc_h;
+	unsigned long xwcm_w, xwcm_h;
+	xwcm_w = xwcm_h = 0;
+	if (tmp_win->title_pos != TP_TOP && pos == TP_TOP) {
+	    xwcm_w |= CWX | CWY;
+	    xwc_w.x = - tmp_win->frame_bw;
+	    xwc_w.y = - tmp_win->frame_bw;
+	}
+	if (tmp_win->title_pos == TP_TOP || tmp_win->title_pos == TP_BOTTOM) {
+	    if (pos == TP_LEFT || pos == TP_RIGHT) {
+		xwcm_w |= CWHeight | CWWidth;
+		xwc_w.height = tmp_win->attr.height;
+		xwc_w.width = Scr->TitleHeight;
+		if (tmp_win->title_height && tmp_win->hilite_w) {
+		    /* SetupWindow() do the real work */
+		    xwcm_h |= CWHeight | CWWidth | CWX | CWY;
+		    xwc_h.height = tmp_win->attr.height;
+		    xwc_h.width = (Scr->TitleHeight - 2 * Scr->FramePadding);
+		    xwc_h.x = Scr->FramePadding;
+		    xwc_h.y = 0;
+		}
+		reloc_btns = FALSE;
+		h -= tmp_win->title_height;
+		w += tmp_win->title_height;
+	    }
+	} else {
+	    if (pos == TP_TOP || pos == TP_BOTTOM) {
+		xwcm_w |= CWHeight | CWWidth;
+		xwc_w.height = Scr->TitleHeight;
+		xwc_w.width = tmp_win->attr.width;
+		if (tmp_win->title_height && tmp_win->hilite_w) {
+		    /* SetupWindow() do the real work */
+		    xwcm_h |= CWHeight | CWWidth | CWX | CWY;
+		    xwc_h.height = (Scr->TitleHeight - 2 * Scr->FramePadding);
+		    xwc_h.width = tmp_win->attr.width;
+		    xwc_h.x = 0;
+		    xwc_h.y = Scr->FramePadding;
+		}
+		reloc_btns = TRUE;
+		h += tmp_win->title_height;
+		w -= tmp_win->title_height;
+	    }
+	}
+	if (xwcm_w)
+	    XConfigureWindow(dpy, tmp_win->title_w, xwcm_w, &xwc_w);
+	if (xwcm_h)
+	    XConfigureWindow(dpy, tmp_win->hilite_w, xwcm_h, &xwc_h);
+    }
+
+    x = tmp_win->frame_x;
+    y = tmp_win->frame_y;
+
+    if (tmp_win->title_pos == TP_TOP)
+	y += tmp_win->title_height;
+    else if (tmp_win->title_pos == TP_LEFT)
+	x += tmp_win->title_height;
+
+    if (pos == TP_TOP)
+	y -= tmp_win->title_height;
+    else if (pos == TP_LEFT)
+	x -= tmp_win->title_height;
+
+    tmp_win->title_pos = pos;
+    tmp_win->title_width = -1; /* force SetFrameShape() */
+
+
+    SetupWindow(tmp_win, x, y, w, h, tmp_win->frame_bw);
+
+    RelocateBtns (tmp_win, reloc_btns);
+}
+
+/***********************************************************************
+ *
+ *  Procedure:
+ *      ChangeSqueeze - change the squeeze status of titlebar
+ *
+ *  Inputs:
+ *      tmp_win - the TwmWindow pointer
+ *      justify - squeeze justify (J_LEFT, J_CENTER, J_RIGHT)
+ *
+ ***********************************************************************
+ */
+void
+ChangeSqueeze (tmp_win, justify)
+    TwmWindow *tmp_win;
+    int justify;
+{
+    static SqueezeInfo default_squeeze[] = {
+	{J_LEFT, 0, 0 },
+	{J_CENTER, 0, 0 },
+	{J_RIGHT, 0, 0 }
+    };
+    int i;
+
+    if (tmp_win->squeeze_info == NULL && justify == -1)
+	return; /* should not happen */
+
+    if (tmp_win->squeeze_info && tmp_win->squeeze_info->justify == justify)
+	return;
+
+    if (justify == -1) {
+	    /* need to resize title bar window */
+	    XWindowChanges xwc;
+	    unsigned long xwcm;
+
+	    if (tmp_win->title_pos == TP_TOP ||
+		tmp_win->title_pos == TP_BOTTOM) {
+		xwcm = CWWidth;
+		xwc.width = tmp_win->attr.width;
+	    } else {
+		xwcm = CWHeight;
+		xwc.height = tmp_win->attr.height;
+	    }
+	    XConfigureWindow(dpy, tmp_win->title_w, xwcm, &xwc);
+	    XConfigureWindow(dpy, tmp_win->hilite_w, xwcm, &xwc);
+
+	    tmp_win->squeeze_info = NULL;
+    } else {
+	for (i=0; i < sizeof(default_squeeze)/sizeof(default_squeeze[0]); i++)
+	    if (default_squeeze[i].justify == justify) {
+		tmp_win->squeeze_info = &default_squeeze[i];
+		break;
+	    }
+	if (i >= sizeof(default_squeeze)/sizeof(default_squeeze[0]))
+	    return;
+    }
+
+    tmp_win->title_width = -1; /* force SetFrameShape() */
+
+    SetupWindow(tmp_win, tmp_win->frame_x, tmp_win->frame_y,
+		tmp_win->frame_width, tmp_win->frame_height,
+		tmp_win->frame_bw);
+
+    if (justify == -1)
+	SetFrameShape(tmp_win);
+}
diff --git a/src/resize.h b/src/resize.h
index e227ed6..fa949ef 100644
--- a/src/resize.h
+++ b/src/resize.h
@@ -74,5 +74,7 @@ extern void SetFrameShape ( TwmWindow *tmp );
 extern void SetupFrame ( TwmWindow *tmp_win, int x, int y, int w, int h, int bw, Bool sendEvent );
 extern void SetupWindow ( TwmWindow *tmp_win, int x, int y, int w, int h, int bw );
 extern void StartResize ( XEvent *evp, TwmWindow *tmp_win, Bool fromtitlebar );
+extern void ChangeTitlePos ( TwmWindow *tmp_win, int pos );
+extern void ChangeSqueeze ( TwmWindow *tmp_win, int justify );
 
 #endif /* _RESIZE_ */
diff --git a/src/screen.h b/src/screen.h
index 2798137..cd94502 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -215,6 +215,21 @@ typedef struct ScreenInfo
     short AutoRelativeResize;	/* start resize relative to position in quad */
     short FocusRoot;		/* is the input focus on the root ? */
     short WarpCursor;		/* warp cursor on de-iconify ? */
+    short WarpCursorPos;	/* pos to warp cursor on de-iconify ? */
+    short MenuAtLeft;		/* place menu on left side */
+    short MenuRuns;		/* place menu items */
+#define MenuRuns_T2B	0		/* Top to Bottom */
+#define MenuRuns_B2T	1		/* Bottom to Top */
+#define MenuRuns_R2L	2		/* Right to Left */
+#define MenuRuns_L2R	3		/* Left to Right */
+#define	VMenu(x) ((((x)->MenuRuns) & 2) == 0)
+#define	HMenu(x) ((((x)->MenuRuns) & 2) == 2)
+    short TitlePos;		/* title bar position */
+    short TitlePosDynamic;	/* title bar position dynamic override */
+    name_list *TitlePosTopL;	/* windows which have title at top */
+    name_list *TitlePosLeftL;	/* windows which have title at left */
+    name_list *TitlePosBottomL;	/* windows which have title at bottom */
+    name_list *TitlePosRightL;	/* windows which have title at right */
     short ForceIcon;		/* force the icon to the user specified */
     short NoGrabServer;		/* don't do server grabs */
     short NoRaiseMove;		/* don't raise window following move */
diff --git a/src/twm.c b/src/twm.c
index 1a6ae95..ea8b7b4 100644
--- a/src/twm.c
+++ b/src/twm.c
@@ -101,6 +101,8 @@ int HasShape;			/* server supports shape extension? */
 int ShapeEventBase, ShapeErrorBase;
 int HasSync;			/* server supports SYNC extension? */
 int SyncEventBase, SyncErrorBase;
+int HasRandr;			/* server supports Randr extension? */
+int RandrEventBase, RandrErrorBase;
 ScreenInfo **ScreenList;	/* structures for each screen */
 ScreenInfo *Scr = NULL;		/* the cur and prev screens */
 int PreviousScreen;		/* last screen that we were on */
@@ -349,6 +351,7 @@ main(int argc, char *argv[])
 
     HasShape = XShapeQueryExtension (dpy, &ShapeEventBase, &ShapeErrorBase);
     HasSync = XSyncQueryExtension(dpy,  &SyncEventBase, &SyncErrorBase);
+    HasRandr = XRRQueryExtension(dpy,  &RandrEventBase, &RandrErrorBase);
     TwmContext = XUniqueContext();
     MenuContext = XUniqueContext();
     IconManagerContext = XUniqueContext();
@@ -462,6 +465,8 @@ main(int argc, char *argv[])
 	Scr->DontSqueezeTitleL = NULL;
 	Scr->WindowRingL = NULL;
 	Scr->WarpCursorL = NULL;
+	if (HasRandr)
+	    XRRSelectInput(dpy, RootWindow(dpy, scrnum), True);
 	/* remember to put an initialization in InitVariables also
 	 */
 
@@ -555,6 +560,15 @@ main(int argc, char *argv[])
 	Scr->tbpm.menu = None;
 	Scr->tbpm.delete = None;
 
+	Scr->WarpCursorPos = 0;
+	Scr->MenuAtLeft = FALSE;
+	Scr->MenuRuns = MenuRuns_T2B;
+	Scr->TitlePos = -1;
+	Scr->TitlePosDynamic = -1;
+	Scr->TitlePosTopL = NULL;
+	Scr->TitlePosLeftL = NULL;
+	Scr->TitlePosBottomL = NULL;
+	Scr->TitlePosRightL = NULL;
 	InitVariables();
 	InitMenus();
 
@@ -562,12 +576,17 @@ main(int argc, char *argv[])
 	ParseTwmrc(InitFile);
 	assign_var_savecolor(); /* storeing pixels for twmrc "entities" */
 	if (Scr->SqueezeTitle == -1) Scr->SqueezeTitle = FALSE;
+	if (Scr->TitlePos == -1) Scr->TitlePos = TP_TOP;
+	if (HMenu(Scr))
+	  NewFontCursor(&Scr->MenuCursor, "sb_up_arrow");
 	if (!Scr->HaveFonts) CreateFonts();
 	CreateGCs();
 	MakeMenus();
 
 	Scr->TitleBarFont.y += Scr->FramePadding;
 	Scr->TitleHeight = Scr->TitleBarFont.height + Scr->FramePadding * 2;
+	if (Scr->TitleBarFont.height < 4)	/* XXX */
+		Scr->TitleHeight = 1;
 	/* make title height be odd so buttons look nice and centered */
 	if (!(Scr->TitleHeight & 1)) Scr->TitleHeight++;
 
@@ -770,6 +789,15 @@ InitVariables(void)
     Scr->FocusRoot = TRUE;
     Scr->Focus = NULL;
     Scr->WarpCursor = FALSE;
+    Scr->WarpCursorPos = 0;
+    Scr->MenuAtLeft = FALSE;
+    Scr->MenuRuns = MenuRuns_T2B;
+    Scr->TitlePos = -1;
+    Scr->TitlePosDynamic = -1;
+    FreeList(&Scr->TitlePosTopL);
+    FreeList(&Scr->TitlePosLeftL);
+    FreeList(&Scr->TitlePosBottomL);
+    FreeList(&Scr->TitlePosRightL);
     Scr->ForceIcon = FALSE;
     Scr->NoGrabServer = FALSE;
     Scr->NoRaiseMove = FALSE;
@@ -854,7 +882,8 @@ RestoreWithdrawnLocation (TwmWindow *tmp)
 		      &JunkWidth, &JunkHeight, &bw, &JunkDepth)) {
 
 	GetGravityOffsets (tmp, &gravx, &gravy);
-	if (gravy < 0) xwc.y -= tmp->title_height;
+	if (tmp->title_pos == TP_TOP && gravy < 0)
+	    xwc.y -= tmp->title_height;
 
 	if (bw != tmp->old_bw) {
 	    int xoff, yoff;
diff --git a/src/twm.h b/src/twm.h
index 8fe2555..b907b86 100644
--- a/src/twm.h
+++ b/src/twm.h
@@ -70,6 +70,7 @@ from The Open Group.
 #include <X11/Xutil.h>
 #include <X11/cursorfont.h>
 #include <X11/extensions/shape.h>
+#include <X11/extensions/Xrandr.h>
 #include <X11/Xfuncs.h>
 #include <X11/StringDefs.h>
 #include <X11/Intrinsic.h>
@@ -226,6 +227,7 @@ typedef struct TwmWindow
     int old_bw;			/* border width before reparenting */
     Window frame;		/* the frame window */
     Window title_w;		/* the title bar window */
+    Pixmap title_pixmap;	/* the title string rotated CW */
     Window hilite_w;		/* the hilite window */
     Pixmap gray;
     Window icon_w;		/* the icon window */
@@ -245,6 +247,15 @@ typedef struct TwmWindow
     int icon_height;		/* height of the icon bitmap */
     int title_height;		/* height of the title bar */
     int title_width;		/* width of the title bar */
+	/*
+	 * title_height & title_width are size of title bar in
+	 * horizontale layout even if title_pos is TP_LEFT or TP_RIGHT
+	 */
+    int title_pos;		/* position of title bar */
+#define TP_TOP          0
+#define TP_LEFT         1
+#define TP_BOTTOM       2
+#define TP_RIGHT        3
     char *full_name;		/* full name of the window */
     char *name;			/* name of the window */
     char *icon_name;		/* name of the icon */
@@ -354,6 +365,7 @@ extern XtAppContext appContext;
 extern Window ResizeWindow;	/* the window we are resizing */
 extern int HasShape;		/* this server supports Shape extension */
 extern int HasSync;		/* this server supports SYNC extension */
+extern int HasRandr;		/* this server supports Randr extension */
 
 extern int PreviousScreen;
 
@@ -410,6 +422,9 @@ extern Bool use_fontset;
 extern int ShapeEventBase;
 extern int ShapeErrorBase;
 
+extern int RandrEventBase;
+extern int RandrErrorBase;
+
 #define _XA_MIT_PRIORITY_COLORS		TwmAtoms[0]
 #define _XA_WM_CHANGE_STATE		TwmAtoms[1]
 #define _XA_WM_STATE			TwmAtoms[2]
diff --git a/src/util.c b/src/util.c
index 8e9dab9..975f73a 100644
--- a/src/util.c
+++ b/src/util.c
@@ -90,7 +90,8 @@ int HotX, HotY;
  *  \param bw           border width of the frame
  *  \param th           title height
  */
-void MoveOutline(Window root, int x, int y, int width, int height, int bw, int th)
+
+void MoveOutline(Window root, int x, int y, int width, int height, int bw, int th, int pos)
 {
     static int	lastx = 0;
     static int	lasty = 0;
@@ -98,13 +99,14 @@ void MoveOutline(Window root, int x, int y, int width, int height, int bw, int t
     static int	lastHeight = 0;
     static int	lastBW = 0;
     static int	lastTH = 0;
+    static int	lastPOS = 0;
     int		xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb;
     int		xthird, ythird;
     XSegment	outline[18];
     register XSegment	*r;
 
     if (x == lastx && y == lasty && width == lastWidth && height == lastHeight
-	&& lastBW == bw && th == lastTH)
+	&& lastBW == bw && th == lastTH && pos == lastPOS)
 	return;
 
     r = outline;
@@ -116,10 +118,27 @@ void MoveOutline(Window root, int x, int y, int width, int height, int bw, int t
 	xr = lastx + lastWidth - 1;			\
 	yt = lasty;					\
 	yb = lasty + lastHeight - 1;			\
+      if (lastPOS == TP_TOP || lastPOS == TP_BOTTOM) {	\
 	xinnerl = xl + lastBW;				\
 	xinnerr = xr - lastBW;				\
-	yinnert = yt + lastTH + lastBW;			\
+	if (lastPOS == TP_TOP) {			\
+	  yinnert = yt + lastTH + lastBW;		\
+	  yinnerb = yb - lastBW;			\
+	} else {					\
+	  yinnert = yt + lastBW;			\
+	  yinnerb = yb - lastTH - lastBW;		\
+	}						\
+      } else {						\
+	yinnert = yt + lastBW;				\
 	yinnerb = yb - lastBW;				\
+	if (lastPOS == TP_LEFT) {			\
+	  xinnerl = xl + lastTH + lastBW;		\
+	  xinnerr = xr - lastBW;			\
+	} else {					\
+	  xinnerl = xl + lastBW;			\
+	  xinnerr = xr - lastTH - lastBW;		\
+	}						\
+      }							\
 	xthird = (xinnerr - xinnerl) / 3;		\
 	ythird = (yinnerb - yinnert) / 3;		\
 							\
@@ -172,10 +191,31 @@ void MoveOutline(Window root, int x, int y, int width, int height, int bw, int t
 	r++;						\
 							\
 	if (lastTH != 0) {				\
+	 if (lastPOS == TP_TOP || lastPOS == TP_BOTTOM) {	\
+	  if (lastPOS == TP_TOP) {			\
 	    r->x1 = xl;					\
 	    r->y1 = yt + lastTH;			\
 	    r->x2 = xr;					\
 	    r->y2 = r->y1;				\
+	  } else {					\
+	    r->x1 = xl;					\
+	    r->y1 = yb - lastTH;			\
+	    r->x2 = xr;					\
+	    r->y2 = r->y1;				\
+	  }						\
+	 } else {					\
+	  if (lastPOS == TP_LEFT) {			\
+	    r->x1 = xl + lastTH;			\
+	    r->y1 = yt;					\
+	    r->x2 = r->x1;				\
+	    r->y2 = yb;					\
+	  } else {					\
+	    r->x1 = xr - lastTH;			\
+	    r->y1 = yt;					\
+	    r->x2 = r->x1;				\
+	    r->y2 = yb;					\
+	  }						\
+	 }						\
 	    r++;					\
 	}						\
     }
@@ -189,6 +229,7 @@ void MoveOutline(Window root, int x, int y, int width, int height, int bw, int t
     lastHeight = height;
     lastBW = bw;
     lastTH = th;
+    lastPOS = pos;
 
     /* draw the new one, if any */
     DRAWIT ();
@@ -681,6 +722,82 @@ MyFont_DrawString(Display *dpy, Drawable d, MyFont *font, GC gc,
 }
 
 void
+MyFont_DrawString_Rotated(Display *dpy, Drawable d, MyFont *font, GC gc,
+			  int x, int y, const char *string, int len,
+			  Pixmap *pixp)
+{
+    int h, w;
+
+    if (len <= 0) return;
+
+    /* h = Scr->EntryHeight; */
+    h = font->height;
+    w = MyFont_TextWidth(font, string, len);
+
+    XImage *title_h, *title_v;
+    Pixmap title_pix;
+    GC MonoGC;
+    int i, j;
+
+    /* draw a title horizontally to a monochrome pixmap */
+    title_pix = XCreatePixmap(dpy, Scr->Root, w, h, 1);
+    MonoGC = XCreateGC(dpy, title_pix, 0, NULL);
+    XSetForeground(dpy, MonoGC, WhitePixel(dpy, Scr->screen));
+    XSetBackground(dpy, MonoGC, WhitePixel(dpy, Scr->screen));
+    XFillRectangle(dpy, title_pix, MonoGC, 0, 0, w, h);
+    if (!use_fontset)
+	XSetFont(dpy, MonoGC, font->font->fid);
+    XSetForeground(dpy, MonoGC, BlackPixel(dpy, Scr->screen));
+
+    MyFont_DrawString (dpy, title_pix, font,
+		       MonoGC, 0, font->y,
+		       string, len);
+
+    title_h = XGetImage(dpy, title_pix, 0, 0, w, h, AllPlanes, XYPixmap);
+    XFreeGC(dpy, MonoGC);
+    XFreePixmap(dpy, title_pix);
+    if (title_h == NULL) {
+	fprintf(stderr,
+		"MyFont_DrawString_Rotated(): can't get title image\n");
+	return;
+    }
+
+    /* allocate XImage for Rotated Title */
+    title_v = XCreateImage(dpy, 0, 1, XYBitmap, 0, NULL, h, w, 8, 0);
+    if (title_v == NULL) {
+	fprintf(stderr, "MyFont_DrawString_Rotated(): can't alloc XImage\n");
+	XDestroyImage(title_h);
+	return;
+    }
+    title_v->data = (char *)calloc(1, title_v->bytes_per_line * w);
+    if (title_v->data == NULL) {
+	fprintf(stderr,
+		"MyFont_DrawString_Rotated(): can't alloc XImage data\n");
+	XDestroyImage(title_h);
+	XDestroyImage(title_v);
+	return;
+    }
+    /* rotate CW */
+    for (i = 0; i < h; i++)
+	for (j = 0; j < w; j++)
+	    XPutPixel(title_v, i, j,
+		      XGetPixel(title_h, j, h-1-i)?0:1);
+    XDestroyImage(title_h);
+
+    /* put image to pixmap */
+    *pixp = XCreatePixmap(dpy, Scr->Root,
+			  h, w, Scr->d_depth);
+    /* XSetForeground(dpy, gc, Gcv.background); */
+    XFillRectangle(dpy, *pixp, gc, 0, 0, h, w);
+    /* XSetForeground(dpy, gc, Gcv.foreground); */
+    XPutImage(dpy, *pixp, gc, title_v,
+	      0, 0, 0, 0, h, w);
+    XDestroyImage(title_v);
+
+    XCopyArea(dpy, *pixp, d, gc, 0, 0, h, w, y, x);
+}
+
+void
 MyFont_ChangeGC(unsigned long fix_fore, unsigned long fix_back,
                 MyFont *fix_font)
 {
diff --git a/src/util.h b/src/util.h
index 4b2d3a8..255ab8e 100644
--- a/src/util.h
+++ b/src/util.h
@@ -62,7 +62,7 @@ in this Software without prior written authorization from The Open Group.
 #define _UTIL_
 
 extern void MoveOutline ( Window root, int x, int y, int width, int height,
-			  int bw, int th );
+			  int bw, int th, int pos );
 extern void Zoom ( Window wf, Window wt );
 extern char * ExpandFilename ( const char *name );
 extern void GetUnknownIcon ( const char *name );
@@ -81,7 +81,10 @@ extern void MyFont_DrawImageString( Display *dpy, Drawable d, MyFont *font,
 				    GC gc, int x, int y, const char * string,
 				    int len);
 extern void MyFont_DrawString( Display *dpy, Drawable d, MyFont *font, GC gc,
-                               int x, int y, const char * string, int len);
+			       int x, int y, const char * string, int len);
+extern void MyFont_DrawString_Rotated( Display *dpy, Drawable d, MyFont *font,
+				       GC gc, int x, int y, const char * string,
+				       int len, Pixmap * pixp);
 extern void MyFont_ChangeGC( unsigned long fix_fore, unsigned long fix_back,
 			     MyFont *fix_font);
 extern Status I18N_FetchName( Display *dpy, Window win, char **winname);
-- 
2.7.3



More information about the xorg-devel mailing list