summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:53 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:53 +0000
commit03cb750f7935722ab77b77128ca5221c5baf8818 (patch)
tree0c535604db3c131fac34783da8bbd22521db44bc
R6.6 is the Xorg base-lineXORG-MAIN
-rw-r--r--man/twm.man1272
-rw-r--r--sample-twmrc/jim.twmrc250
-rw-r--r--sample-twmrc/keith.twmrc223
-rw-r--r--sample-twmrc/lemke.twmrc255
-rw-r--r--src/add_window.c1629
-rw-r--r--src/add_window.h81
-rw-r--r--src/cursor.c175
-rw-r--r--src/events.c2817
-rw-r--r--src/events.h111
-rw-r--r--src/gc.c117
-rw-r--r--src/gc.h68
-rw-r--r--src/gram.y883
-rw-r--r--src/iconmgr.c773
-rw-r--r--src/iconmgr.h93
-rw-r--r--src/icons.c588
-rw-r--r--src/icons.h56
-rw-r--r--src/lex.l145
-rw-r--r--src/list.c258
-rw-r--r--src/list.h75
-rw-r--r--src/menus.c3035
-rw-r--r--src/menus.h178
-rw-r--r--src/parse.c1149
-rw-r--r--src/parse.h135
-rw-r--r--src/resize.c1217
-rw-r--r--src/resize.h77
-rw-r--r--src/screen.h267
-rw-r--r--src/session.c1054
-rw-r--r--src/siconify.bm5
-rw-r--r--src/system.twmrc89
-rw-r--r--src/twm.c898
-rw-r--r--src/twm.h426
-rw-r--r--src/util.c959
-rw-r--r--src/util.h95
-rw-r--r--src/version.c54
-rw-r--r--src/version.h67
35 files changed, 19574 insertions, 0 deletions
diff --git a/man/twm.man b/man/twm.man
new file mode 100644
index 0000000..c14f676
--- /dev/null
+++ b/man/twm.man
@@ -0,0 +1,1272 @@
+.\" $Xorg: twm.man,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+.\" Copyright 1993, 1994, 1998 The Open Group
+.\" Portions copyright 1988 Evans & Sutherland Computer Corporation.
+.\" Portions copyright 1989 Hewlett-Packard Company
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation.
+.\"
+.\" The above copyright notice and this permission notice shall be included
+.\" in all copies or substantial portions of the Software.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+.\" IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+.\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+.\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+.\" OTHER DEALINGS IN THE SOFTWARE.
+.\"
+.\" Except as contained in this notice, the name of The Open Group shall
+.\" not be used in advertising or otherwise to promote the sale, use or
+.\" other dealings in this Software without prior written authorization
+.\" from The Open Group.
+.de EX \"Begin example
+.ne 5
+.if n .sp 1
+.if t .sp .5
+.nf
+.in +.5i
+..
+.de EE
+.fi
+.in -.5i
+.if n .sp 1
+.if t .sp .5
+..
+.ta .3i .6i .9i 1.2i 1.5i 1.8i
+.TH TWM 1 "Release 6.4" "X Version 11"
+.SH NAME
+twm \- Tab Window Manager for the X Window System
+.SH SYNTAX
+\fBtwm \fP[ \fB\-display\fP \fIdpy\fP ] [ \fB\-s\fP ]
+[ \fB\-f\fP \fIinitfile\fP ] [ \fB\-v\fP ]
+.SH DESCRIPTION
+\fITwm\fP is a window manager for the X Window System. It provides
+titlebars, shaped windows,
+several forms of icon management, user-defined macro functions,
+click-to-type and pointer-driven keyboard focus, and user-specified
+key and pointer button bindings.
+.PP
+This program is usually started by the user's session manager or
+startup script. When used from \fIxdm(1)\fP or \fIxinit(1)\fP without
+a session manager, \fItwm\fP is frequently executed in the foreground
+as the last client. When run this way, exiting \fItwm\fP causes the
+session to be terminated (i.e., logged out).
+.PP
+By default, application windows are surrounded by a ``frame'' with a
+titlebar at the top and a special border around the window. The titlebar
+contains the window's name, a rectangle that is lit when the window is
+receiving keyboard input, and function boxes known as ``titlebuttons'' at
+the left and right edges of the titlebar.
+.PP
+Pressing pointer Button1 (usually the left-most
+button unless it has been changed with \fIxmodmap\fP) on a
+titlebutton will invoke the function associated with the button.
+In the default interface, windows are iconified by clicking (pressing
+and then immediately releasing) the left titlebutton (which looks
+like a Dot). Conversely, windows are deiconified by clicking in the
+associated icon or entry in the icon manager
+(see description of the variable
+\fBShowIconManager\fP and of the function \fBf.showiconmgr\fP).
+.PP
+Windows are resized by pressing the right titlebutton (which resembles a
+group of nested squares), dragging the pointer over edge that is to be
+moved, and releasing the pointer when the outline of the window is the desired
+size. Similarly, windows are moved by pressing in the title or highlight
+region, dragging a window outline to the new location, and then releasing
+when the outline is in the desired position. Just
+clicking in the title or highlight region raises the window without moving it.
+.PP
+When new windows are created, \fItwm\fP will honor any size and location
+information requested by the user (usually through \fI-geometry\fP
+command line argument or resources for the individual applications).
+Otherwise, an outline of the window's default size, its titlebar, and lines
+dividing the
+window into a 3x3 grid that track the pointer are displayed.
+Clicking pointer Button1
+will position the window at the current position and give it the default
+size. Pressing pointer Button2 (usually the middle pointer button)
+and dragging the outline
+will give the window its current position but allow the sides to be resized as
+described above. Clicking pointer Button3 (usually the right pointer button)
+will give the window its current position but attempt to make it long enough
+to touch the bottom the screen.
+.SH OPTIONS
+\fITwm\fP accepts the following command line options:
+.PP
+.TP 8
+.B \-display \fIdpy\fP
+This option specifies the X server to use.
+.TP 8
+.B \-s
+This option indicates that only the default screen (as specified by
+\fB\-display\fP or by the \fBDISPLAY\fP environment variable) should be
+managed. By default, \fItwm\fP will attempt to manage
+all screens on the display.
+.TP 8
+.B \-f \fIfilename\fP
+This option specifies the name of the startup file to use. By default,
+\fItwm\fP will look in the user's home directory for files
+named \fI.twmrc.num\fP (where \fInum\fP is a screen number) or \fI.twmrc\fP.
+.TP 8
+.B \-v
+This option indicates that \fItwm\fP should print error messages whenever
+an unexpected X Error event is received. This can be useful when debugging
+applications but can be distracting in regular use.
+.SH CUSTOMIZATION
+.PP
+Much of \fItwm\fP's appearance and behavior can be controlled by providing
+a startup file in one of the following locations (searched in order for
+each screen being managed when \fItwm\fP begins):
+.TP 8
+.B "$HOME/.twmrc.\fIscreennumber\fP"
+The \fIscreennumber\fP is a small positive number (e.g. 0, 1, etc.)
+representing the screen number (e.g. the last number in the DISPLAY environment
+variable \fIhost:displaynum.screennum\fP) that would be used to contact that
+screen of the display. This is intended for displays with multiple screens of
+differing visual types.
+.TP 8
+.B "$HOME/.twmrc"
+This is the usual name for an individual user's startup file.
+.TP 8
+.B "<XRoot>/lib/X11/twm/system.twmrc"
+If neither of the preceding files are found, \fItwm\fP will look in this
+file for a
+default configuration. This is often tailored by the site administrator to
+provide convenient menus or familiar bindings for novice users. <XRoot>
+refers to the root of the X11 install tree.
+.PP
+If no startup files are found, \fItwm\fP will use the built-in defaults
+described above. The only resource used by \fItwm\fP is
+\fIbitmapFilePath\fP for a colon-separated list of directories to search
+when looking for bitmap files (for more information, see the \fIAthena
+Widgets\fP manual and \fIxrdb(1)\fP).
+.PP
+\fITwm\fP startup files are logically broken up into three types of
+specifications: \fIVariables\fP, \fIBindings\fP, \fIMenus\fP. The
+\fIVariables\fP section must come first and is used to describe the
+fonts, colors, cursors, border widths, icon and window placement, highlighting,
+autoraising, layout of titles, warping, use of the icon manager.
+The \fIBindings\fP section usually comes second and is used to specify
+the functions that should be
+to be invoked when keyboard and pointer buttons are pressed in
+windows, icons, titles, and frames. The \fIMenus\fP section gives any
+user-defined menus (containing functions to be invoked or
+commands to be executed).
+.PP
+Variable names and keywords are case-insensitive. Strings must be surrounded
+by double quote characters (e.g. "blue") and are case-sensitive.
+A pound sign (#) outside
+of a string causes the remainder of the line in which the character appears to
+be treated as a comment.
+.SH VARIABLES
+.PP
+Many of the aspects of \fItwm\fP's user interface are controlled by variables
+that may be set in the user's startup file. Some of the options are
+enabled or disabled simply by the presence of a particular keyword. Other
+options require keywords, numbers, strings, or lists of all of these.
+.PP
+Lists are surrounded by braces and are usually separated by
+whitespace or a newline. For example:
+.EX 0
+\fBAutoRaise\fP { "emacs" "XTerm" "Xmh" }
+.EE
+or
+.EX 0
+\fBAutoRaise\fP
+{
+ "emacs"
+ "XTerm"
+ "Xmh"
+}
+.EE
+When a variable containing a list of strings representing windows is searched
+(e.g. to determine whether or not to enable autoraise as shown above), a string
+must be an exact, case-sensitive match to
+the window's name (given by the WM_NAME window property), resource name
+or class name (both given by the WM_CLASS window property). The preceding
+example would enable autoraise on windows named ``emacs'' as well as any
+\fIxterm\fP (since they are of class ``XTerm'') or xmh windows
+(which are of class ``Xmh'').
+.PP
+String arguments that are interpreted as filenames (see the \fBPixmaps\fP,
+\fBCursors\fP, and \fBIconDirectory\fP below) will
+prepend the user's directory
+(specified by the \fBHOME\fP environment variable) if the first character is a
+tilde (~). If, instead, the first character is a colon (:), the name is
+assumed to refer to one of the internal bitmaps that are used to
+create the default titlebars symbols: \fB:xlogo\fP
+or \fB:delete\fP (both refer to the X logo),
+\fB:dot\fP or \fB:iconify\fP (both refer to the dot),
+\fB:resize\fP (the nested squares used by the resize button),
+\fB:menu\fP (a page with lines),
+and \fB:question\fP (the question mark used for non-existent
+bitmap files).
+.PP
+The following variables may be specified at the top of a \fItwm\fP startup
+file. Lists of Window name prefix strings are indicated by \fIwin-list\fP.
+Optional arguments are shown in square brackets:
+.IP "\fBAutoRaise\fP { \fIwin-list\fP }" 8
+This variable specifies a list of windows that should automatically be
+raised whenever the pointer enters the window. This action can be
+interactively
+enabled or disabled on individual windows using the function \fBf.autoraise\fP.
+.IP "\fBAutoRelativeResize\fP" 8
+This variable indicates that dragging out a window size (either when
+initially sizing the window with pointer Button2 or when resizing it)
+should not wait until the pointer has crossed the window edges.
+Instead, moving
+the pointer automatically causes the nearest edge or edges to move by the
+same amount. This allows the resizing of windows that extend off
+the edge of the screen.
+If the pointer is
+in the center of the window, or if the resize is begun by pressing a
+titlebutton, \fItwm\fP will still wait for the pointer to cross a window
+edge (to prevent accidents). This option is
+particularly useful for people who like the press-drag-release method of
+sweeping out window sizes.
+.IP "\fBBorderColor\fP \fIstring\fP [{ \fIwincolorlist\fP }]" 8
+This variable specifies the default color of the border to be placed around
+all
+non-iconified windows, and may only be given within a \fBColor\fP,
+\fBGrayscale\fP or
+\fBMonochrome\fP list. The optional \fIwincolorlist\fP specifies a list
+of window and color name pairs for specifying particular border colors for
+different types of windows. For example:
+.EX 0
+\fBBorderColor\fP "gray50"
+{
+ "XTerm" "red"
+ "xmh" "green"
+}
+.EE
+The default is "black".
+.IP "\fBBorderTileBackground\fP \fIstring\fP [{ \fIwincolorlist\fP }]" 8
+This variable specifies the default background color in the gray pattern
+used in unhighlighted borders (only if \fBNoHighlight\fP hasn't been set),
+and may only be given within a \fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list. The
+optional \fIwincolorlist\fP allows per-window colors to be specified.
+The default is "white".
+.IP "\fBBorderTileForeground\fP \fIstring\fP [{ \fIwincolorlist\fP }]" 8
+This variable specifies the default foreground color in the gray pattern
+used in unhighlighted borders (only
+if \fBNoHighlight\fP hasn't been set), and may only be given within a
+\fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list. The optional \fIwincolorlist\fP allows
+per-window colors to be specified. The default is "black".
+.IP "\fBBorderWidth\fP \fIpixels\fP" 8
+This variable specifies the width in pixels of the border surrounding
+all client window frames if \fBClientBorderWidth\fP has not been specified.
+This value is also used to set the border size of windows created by \fItwm\fP
+(such as the icon manager). The default is 2.
+.IP "\fBButtonIndent\fP \fIpixels\fP" 8
+This variable specifies the amount by which titlebuttons should be
+indented on all sides. Positive values cause the buttons to be smaller than
+the window text and highlight area so that they stand out. Setting this
+and the \fBTitleButtonBorderWidth\fP variables to 0 makes titlebuttons be as
+tall and wide as possible. The default is 1.
+.IP "\fBClientBorderWidth\fP" 8
+This variable indicates that border width of a window's frame should be set to
+the initial border width of the window, rather than to the value of
+\fBBorderWidth\fP.
+.IP "\fBColor\fP { \fIcolors-list\fP }" 8
+This variable specifies a list of color assignments to be made if the default
+display is capable of displaying more than simple black and white. The
+\fIcolors-list\fP is made up of the following color variables and their values:
+\fBDefaultBackground\fP,
+\fBDefaultForeground\fP,
+\fBMenuBackground\fP,
+\fBMenuForeground\fP,
+\fBMenuTitleBackground\fP,
+\fBMenuTitleForeground\fP,
+\fBMenuShadowColor\fP,
+\fBPointerForeground\fP, and
+\fBPointerBackground\fP.
+The following
+color variables may also be given a list of window and color name pairs to
+allow per-window colors to be specified (see \fBBorderColor\fP for details):
+\fBBorderColor\fP,
+\fBIconManagerHighlight\fP,
+\fBBorderTitleBackground\fP,
+\fBBorderTitleForeground\fP,
+\fBTitleBackground\fP,
+\fBTitleForeground\fP,
+\fBIconBackground\fP,
+\fBIconForeground\fP,
+\fBIconBorderColor\fP,
+\fBIconManagerBackground\fP, and
+\fBIconManagerForeground\fP.
+For example:
+.EX 0
+\fBColor\fP
+{
+ MenuBackground "gray50"
+ MenuForeground "blue"
+ BorderColor "red" { "XTerm" "yellow" }
+ TitleForeground "yellow"
+ TitleBackground "blue"
+}
+.EE
+All of these color variables may also be specified for the \fBMonochrome\fP
+variable, allowing the same initialization file to be used on both color and
+monochrome displays.
+.IP "\fBConstrainedMoveTime\fP \fImilliseconds\fP" 8
+This variable specifies the length of time between button clicks needed to
+begin
+a constrained move operation. Double clicking within this amount
+of time when invoking \fBf.move\fP will cause the window to be moved only
+in a horizontal or vertical direction. Setting this value to 0 will disable
+constrained moves. The default is 400 milliseconds.
+.IP "\fBCursors\fP { \fIcursor-list\fP }" 8
+This variable specifies the glyphs that \fItwm\fP should use for various
+pointer cursors. Each cursor
+may be defined either from the \fBcursor\fP font or from two bitmap files.
+Shapes from the \fBcursor\fP font may be specified directly as:
+.EX 0
+ \fIcursorname\fP "\fIstring\fP"
+.EE
+where \fIcursorname\fP is one of the cursor names listed below, and
+\fIstring\fP is the name of a glyph as found in the file
+<XRoot>/include/X11/cursorfont.h (without the ``XC_'' prefix).
+If the cursor is to be defined
+from bitmap files, the following syntax is used instead:
+.EX 0
+ \fIcursorname\fP "\fIimage\fP" "\fImask\fP"
+.EE
+The \fIimage\fP and \fImask\fP strings specify the names of files containing
+the glyph image and mask in \fIbitmap(1)\fP form.
+The bitmap files are located in the same manner as icon bitmap files.
+The following example shows the default cursor definitions:
+.EX 0
+\fBCursors\fP
+{
+ Frame "top_left_arrow"
+ Title "top_left_arrow"
+ Icon "top_left_arrow"
+ IconMgr "top_left_arrow"
+ Move "fleur"
+ Resize "fleur"
+ Menu "sb_left_arrow"
+ Button "hand2"
+ Wait "watch"
+ Select "dot"
+ Destroy "pirate"
+}
+.EE
+.IP "\fBDecorateTransients\fP" 8
+This variable indicates that transient windows (those containing a
+WM_TRANSIENT_FOR property) should have titlebars. By default, transients
+are not reparented.
+.IP "\fBDefaultBackground\fP \fIstring\fP" 8
+This variable specifies the background color to be used for sizing and
+information windows. The default is "white".
+.IP "\fBDefaultForeground\fP \fIstring\fP" 8
+This variable specifies the foreground color to be used for sizing and
+information windows. The default is "black".
+.IP "\fBDontIconifyByUnmapping\fP { \fIwin-list\fP }" 8
+This variable specifies a list of windows that should not be iconified by
+simply unmapping the window (as would be the case if \fBIconifyByUnmapping\fP
+had been set). This is frequently used to force some windows to be treated
+as icons while other windows are handled by the icon manager.
+.IP "\fBDontMoveOff\fP" 8
+This variable indicates that windows should not be allowed to be moved off the
+screen. It can be overridden by the \fBf.forcemove\fP function.
+.IP "\fBDontSqueezeTitle\fP [{ \fIwin-list\fP }] " 8
+This variable indicates that titlebars should not be squeezed to their
+minimum size as described under \fBSqueezeTitle\fP below.
+If the optional window list is supplied, only those windows will be
+prevented from being squeezed.
+.IP "\fBForceIcons\fP" 8
+This variable indicates that icon pixmaps specified in the \fBIcons\fP
+variable should override any client-supplied pixmaps.
+.IP "\fBFramePadding\fP \fIpixels\fP" 8
+This variable specifies the distance between the titlebar decorations (the
+button and text) and the window frame. The default is 2 pixels.
+.IP "\fBGrayscale\fP { \fIcolors\fP }" 8
+This variable specifies a list of color assignments that should be made if
+the screen has a GrayScale default visual. See the description of \fBColors\fP.
+.IP "\fBIconBackground\fP \fIstring\fP [{ \fIwin-list\fP }]" 8
+This variable specifies the background color of icons, and may
+only be specified inside of a \fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list.
+The optional \fIwin-list\fP is a list of window names and colors so that
+per-window colors may be specified. See the \fBBorderColor\fP
+variable for a complete description of the \fIwin-list\fP.
+The default is "white".
+.IP "\fBIconBorderColor\fP \fIstring\fP [{ \fIwin-list\fP }]" 8
+This variable specifies the color of the border used for icon windows, and
+may only be specified inside of a \fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list.
+The optional \fIwin-list\fP is a list of window names and colors so that
+per-window colors may be specified. See the \fBBorderColor\fP
+variable for a complete description of the \fIwin-list\fP.
+The default is "black".
+.IP "\fBIconBorderWidth\fP \fIpixels\fP" 8
+This variable specifies the width in pixels of the border surrounding
+icon windows. The default is 2.
+.IP "\fBIconDirectory\fP \fIstring\fP" 8
+This variable specifies the directory that should be searched if
+if a bitmap file cannot be found in any of the directories
+in the \fBbitmapFilePath\fP resource.
+.IP "\fBIconFont\fP \fIstring\fP" 8
+This variable specifies the font to be used to display icon names within
+icons. The default is "variable".
+.IP "\fBIconForeground\fP \fIstring\fP [{ \fIwin-list\fP }]" 8
+This variable specifies the foreground color to be used when displaying icons,
+and may only be specified inside of a
+\fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list.
+The optional \fIwin-list\fP is a list of window names and colors so that
+per-window colors may be specified. See the \fBBorderColor\fP
+variable for a complete description of the \fIwin-list\fP.
+The default is "black".
+.IP "\fBIconifyByUnmapping [{ \fIwin-list\fP }]\fP" 8
+This variable indicates that windows should be iconified by being unmapped
+without trying to map any icons. This assumes that the user will
+remap the window through the icon manager, the \fBf.warpto\fP function, or
+the \fITwmWindows\fP menu.
+If the optional \fIwin-list\fP is provided, only those windows will be
+iconified by simply unmapping. Windows that have both this and the
+\fBIconManagerDontShow\fP options set may not be accessible if no binding
+to the \fITwmWindows\fP menu is set in the user's startup file.
+.IP "\fBIconManagerBackground\fP \fIstring\fP [{ \fIwin-list\fP }]" 8
+This variable specifies the background color to use for icon manager entries,
+and may only be specified inside of a
+\fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list.
+The optional \fIwin-list\fP is a list of window names and colors so that
+per-window colors may be specified. See the \fBBorderColor\fP
+variable for a complete description of the \fIwin-list\fP.
+The default is "white".
+.IP "\fBIconManagerDontShow\fP [{ \fIwin-list\fP }]" 8
+This variable indicates that the icon manager should not display any
+windows. If the optional \fIwin-list\fP is given, only those windows will
+not be displayed. This variable is used to prevent windows that are rarely
+iconified (such as \fIxclock\fP or \fIxload\fP) from taking up space in
+the icon manager.
+.IP "\fBIconManagerFont\fP \fIstring\fP" 8
+This variable specifies the font to be used when displaying icon manager
+entries. The default is "variable".
+.IP "\fBIconManagerForeground\fP \fIstring\fP [{ \fIwin-list\fP }]" 8
+This variable specifies the foreground color to be used when displaying
+icon manager entries, and may only be specified inside of a
+\fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list.
+The optional \fIwin-list\fP is a list of window names and colors so that
+per-window colors may be specified. See the \fBBorderColor\fP
+variable for a complete description of the \fIwin-list\fP.
+The default is "black".
+.IP "\fBIconManagerGeometry\fP \fIstring\fP [ \fIcolumns\fP ]" 8
+This variable specifies the geometry of the icon manager window. The
+\fIstring\fP argument is standard geometry specification that indicates
+the initial full size of the icon manager. The icon manager window is
+then broken into \fIcolumns\fP pieces and scaled according to the number
+of entries in the icon manager. Extra entries are wrapped to form
+additional rows. The default number of columns is 1.
+.IP "\fBIconManagerHighlight\fP \fIstring\fP [{ \fIwin-list\fP }]" 8
+This variable specifies the border color to be used when highlighting
+the icon manager entry that currently has the focus,
+and can only be specified inside of a
+\fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list.
+The optional \fIwin-list\fP is a list of window names and colors so that
+per-window colors may be specified. See the \fBBorderColor\fP
+variable for a complete description of the \fIwin-list\fP.
+The default is "black".
+.IP "\fBIconManagers\fP { \fIiconmgr-list\fP }" 8
+This variable specifies a list of icon managers to create. Each item in the
+\fIiconmgr-list\fP has the following format:
+.EX 0
+ "\fIwinname\fP" ["\fIiconname\fP"] "\fIgeometry\fP" \fIcolumns\fP
+.EE
+where \fIwinname\fP is the name of the windows that should be put into this
+icon manager, \fIiconname\fP is the name of that icon manager window's icon,
+\fIgeometry\fP is a standard geometry specification, and \fIcolumns\fP is
+the number of columns in this icon manager as described in
+\fBIconManagerGeometry\fP. For example:
+.EX 0
+\fBIconManagers\fP
+{
+ "XTerm" "=300x5+800+5" 5
+ "myhost" "=400x5+100+5" 2
+}
+.EE
+Clients whose name or class is ``XTerm'' will have an entry created
+in the ``XTerm'' icon manager. Clients whose name was ``myhost'' would
+be put into the ``myhost'' icon manager.
+.IP "\fBIconManagerShow\fP { \fIwin-list\fP }" 8
+This variable specifies a list of windows that should appear in the icon
+manager. When used in conjunction with the \fBIconManagerDontShow\fP
+variable, only the windows in this list will be shown in the icon manager.
+.IP "\fBIconRegion\fP \fIgeomstring\fP \fIvgrav hgrav gridwidth gridheight\fP"
+This variable specifies an area on the root window in which icons are placed
+if no specific icon location is provided by the client. The \fIgeomstring\fP
+is a quoted string containing a standard geometry specification.
+If more than one
+\fBIconRegion\fP lines are given,
+icons will be put into the succeeding icon regions when the first is full.
+The \fIvgrav\fP argument should be either \fBNorth\fP or \fBSouth\fP and
+control and is used to control whether icons are first filled in from the
+top or bottom of the icon region. Similarly, the \fIhgrav\fP argument should
+be either \fBEast\fP or \fBWest\fP and is used to control whether icons should
+be filled in from left from the right. Icons are laid out within the region
+in a grid with cells \fIgridwidth\fP pixels wide and \fIgridheight\fP pixels
+high.
+.IP "\fBIcons\fP { \fIwin-list\fP }" 8
+This variable specifies a list of window names and the bitmap filenames that
+should be used as their icons. For example:
+.EX 0
+\fBIcons\fP
+{
+ "XTerm" "xterm.icon"
+ "xfd" "xfd_icon"
+}
+.EE
+Windows that match ``XTerm'' and would not be iconified by unmapping, and
+would try to use
+the icon bitmap in the file ``xterm.icon''. If \fBForceIcons\fP is
+specified, this bitmap will be used even if the client has requested its
+own icon pixmap.
+.IP "\fBInterpolateMenuColors\fP" 8
+This variable indicates that menu entry colors should be interpolated between
+entry specified colors. In the example below:
+.EX 0
+\fBMenu\fP "mymenu"
+{
+ "Title" ("black":"red") f.title
+ "entry1" f.nop
+ "entry2" f.nop
+ "entry3" ("white":"green") f.nop
+ "entry4" f.nop
+ "entry5" ("red":"white") f.nop
+}
+.EE
+the foreground colors for ``entry1'' and ``entry2'' will be interpolated
+between black and white, and the background colors between red and green.
+Similarly, the foreground for ``entry4'' will be half-way between white and
+red, and the background will be half-way between green and white.
+.IP "\fBMakeTitle\fP { \fIwin-list\fP }" 8
+This variable specifies a list of windows on which a titlebar should be placed
+and is used to request titles on specific windows when \fBNoTitle\fP has been
+set.
+.IP "\fBMaxWindowSize\fP \fIstring\fP" 8
+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 "\fBMenuBackground\fP \fIstring\fP" 8
+This variable specifies the background color used for menus,
+and can only be specified inside of a
+\fBColor\fP or \fBMonochrome\fP list. The default is "white".
+.IP "\fBMenuFont\fP \fIstring\fP" 8
+This variable specifies the font to use when displaying menus. The default
+is "variable".
+.IP "\fBMenuForeground\fP \fIstring\fP" 8
+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 "\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
+\fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list. The default is "black".
+.IP "\fBMenuTitleBackground\fP \fIstring\fP" 8
+This variable specifies the background color for \fBf.title\fP entries in
+menus, and
+can only be specified inside of a
+\fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list. The default is "white".
+.IP "\fBMenuTitleForeground\fP \fIstring\fP" 8
+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 "\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.
+.IP "\fBMoveDelta\fP \fIpixels\fP" 8
+This variable specifies the number of pixels the pointer
+must move before the \fBf.move\fP function starts working. Also
+see the \fBf.deltastop\fP function. The default is zero pixels.
+.IP "\fBNoBackingStore\fP" 8
+This variable indicates that \fItwm\fP's menus should not request backing
+store to minimize repainting of menus. This is typically
+used with servers that can repaint faster than they can handle backing store.
+.IP "\fBNoCaseSensitive\fP" 8
+This variable indicates that case should be ignored when sorting icon names
+in an icon manager. This option is typically used with applications that
+capitalize the first letter of their icon name.
+.IP "\fBNoDefaults\fP" 8
+This variable indicates that \fItwm\fP should not supply the default
+titlebuttons and bindings. This option should only be used if the startup
+file contains a completely new set of bindings and definitions.
+.IP "\fBNoGrabServer\fP" 8
+This variable indicates that \fItwm\fP should not grab the server
+when popping up menus and moving opaque windows.
+.IP "\fBNoHighlight\fP [{ \fIwin-list\fP }]" 8
+This variable indicates that borders should not be highlighted to track the
+location of the pointer. If the optional \fIwin-list\fP is given, highlighting
+will only be disabled for those windows.
+When the border is highlighted, it will
+be drawn in the current \fBBorderColor\fP. When the border is not
+highlighted, it will be stippled with a gray pattern using the
+current \fBBorderTileForeground\fP and \fBBorderTileBackground\fP colors.
+.IP "\fBNoIconManagers\fP" 8
+This variable indicates that no icon manager should be created.
+.IP "\fBNoMenuShadows\fP" 8
+This variable indicates that menus should not have drop shadows drawn behind
+them. This is typically used with slower servers since it speeds up menu
+drawing at the expense of making the menu slightly harder to read.
+.IP "\fBNoRaiseOnDeiconify\fP" 8
+This variable indicates that windows that are deiconified should not be
+raised.
+.IP "\fBNoRaiseOnMove\fP" 8
+This variable indicates that windows should not be raised when moved. This
+is typically used to allow windows to slide underneath each other.
+.IP "\fBNoRaiseOnResize\fP" 8
+This variable indicates that windows should not be raised when resized. This
+is typically used to allow windows to be resized underneath each other.
+.IP "\fBNoRaiseOnWarp\fP" 8
+This variable indicates that windows should not be raised when the pointer
+is warped into them with the \fBf.warpto\fP function. If this option is set,
+warping to an occluded window may result in the pointer ending up in the
+occluding window instead the desired window (which causes unexpected behavior
+with \fBf.warpring\fP).
+.IP "\fBNoSaveUnders\fP" 8
+This variable indicates that menus should not request save-unders to minimize
+window repainting following menu selection. It is typically used with displays
+that can repaint faster than they can handle save-unders.
+.IP "\fBNoStackMode\fP [{ \fIwin-list\fP }]" 8
+This variable indicates that client window requests to change stacking order
+should be ignored. If the optional \fIwin-list\fP is given, only requests on
+those windows will be ignored. This is typically used to prevent applications
+from relentlessly popping themselves to the front of the window stack.
+.IP "\fBNoTitle\fP [{ \fIwin-list\fP }] " 8
+This variable indicates that windows should not have titlebars. If the
+optional \fIwin-list\fP is given, only those windows will not have titlebars.
+\fBMakeTitle\fP may be used with this option to force titlebars to be put
+on specific windows.
+.IP "\fBNoTitleFocus\fP" 8
+This variable indicates that \fItwm\fP should not set keyboard input focus to
+each window as it is entered. Normally, \fItwm\fP sets the focus
+so that focus and key events from the titlebar and
+icon managers are delivered to the application. If the pointer is moved
+quickly and \fItwm\fP is slow to respond, input can be directed to the old
+window instead of the new. This option is typically
+used to prevent this ``input lag'' and to
+work around bugs in older applications that have problems with focus events.
+.IP "\fBNoTitleHighlight\fP [{ \fIwin-list\fP }]" 8
+This variable indicates that the highlight area of the titlebar, which is
+used to indicate the window that currently has the input focus, should not
+be displayed. If the optional \fIwin-list\fP is given, only those windows
+will not have highlight areas. This and the \fBSqueezeTitle\fP options
+can be set to substantially reduce the amount of screen space required by
+titlebars.
+.IP "\fBOpaqueMove\fP" 8
+This variable indicates that the \fBf.move\fP function should actually move
+the window instead of just an outline so that the user can immediately see
+what the window will look like in the new position. This option is typically
+used on fast displays (particularly if \fBNoGrabServer\fP is set).
+.IP "\fBPixmaps\fP { \fIpixmaps\fP }" 8
+This variable specifies a list of pixmaps that define the appearance of various
+images. Each entry is a keyword indicating the pixmap to set, followed by a
+string giving the name of the bitmap file. The following pixmaps
+may be specified:
+.EX 0
+\fBPixmaps\fP
+{
+ TitleHighlight "gray1"
+}
+.EE
+The default for \fITitleHighlight\fP is to use an even stipple pattern.
+.IP "\fBPriority\fP \fIpriority\fP" 8
+This variable sets \fItwm\fP's priority. \fIpriority\fP should be an
+unquoted, signed number (e.g. 999). This variable has an effect only
+if the server supports the SYNC extension.
+.IP "\fBRandomPlacement\fP" 8
+This variable indicates that windows with no specified geometry should
+be placed in a pseudo-random location instead of having the user drag out
+an outline.
+.IP "\fBResizeFont\fP \fIstring\fP" 8
+This variable specifies the font to be used for in the dimensions window when
+resizing windows. The default is "fixed".
+.IP "\fBRestartPreviousState\fP" 8
+This variable indicates that
+\fItwm\fP should attempt to use the WM_STATE property on client windows
+to tell which windows should be iconified and which should be left visible.
+This is typically used to try to regenerate the state that the screen
+was in before the previous window manager was shutdown.
+.IP "\fBSaveColor\fP { \fIcolors-list\fP }" 8
+This variable indicates a list of color assignments to be stored as pixel
+values in the root window property _MIT_PRIORITY_COLORS. Clients may elect
+to preserve these values when installing their own colormap. Note that
+use of this mechanism is a way an for application to avoid the "technicolor"
+problem, whereby useful screen objects such as window borders and titlebars
+disappear when a programs custom colors are installed by the window
+manager.
+For example:
+.EX 0
+\fBSaveColor\fP
+{
+ BorderColor
+ TitleBackground
+ TitleForeground
+ "red"
+ "green"
+ "blue"
+}
+.EE
+This would place on the root window 3 pixel values for borders and titlebars,
+as well as the three color strings, all taken from the default colormap.
+.IP "\fBShowIconManager\fP" 8
+This variable indicates that the icon manager window should be displayed when
+\fItwm\fP is started. It can always be brought up using the
+\fBf.showiconmgr\fP function.
+.IP "\fBSortIconManager\fP" 8
+This variable indicates that entries in the icon manager should be
+sorted alphabetically rather than by simply appending new windows to
+the end.
+.IP "\fBSqueezeTitle\fP [{ \fIsqueeze-list\fP }] " 8
+This variable indicates that \fItwm\fP should attempt to use the SHAPE
+extension to make titlebars occupy only as much screen space as they need,
+rather than extending all the way across the top of the window.
+The optional \fIsqueeze-list\fP
+may be used to control the location of the squeezed titlebar along the
+top of the window. It contains entries of the form:
+.EX 0
+ "\fIname\fP" \fIjustification\fP \fInum\fP \fIdenom\fP
+.EE
+where \fIname\fP is a window name, \fIjustification\fP is either \fBleft\fP,
+\fBcenter\fP, or \fBright\fP, and \fInum\fP and \fIdenom\fP
+are numbers specifying a ratio giving the relative position about which
+the titlebar is justified. The ratio is measured from left to right if
+the numerator is positive, and right to left if negative. A denominator
+of 0 indicates that the numerator should be measured in pixels. For
+convenience, the ratio 0/0 is the same as 1/2 for \fBcenter\fP and -1/1
+for \fBright\fP. For example:
+.EX 0
+\fBSqueezeTitle\fP
+{
+ "XTerm" left 0 0
+ "xterm1" left 1 3
+ "xterm2" left 2 3
+ "oclock" center 0 0
+ "emacs" right 0 0
+}
+.EE
+The \fBDontSqueezeTitle\fP list can be used to turn off squeezing on
+certain titles.
+.IP "\fBStartIconified\fP [{ \fIwin-list\fP }] " 8
+This variable indicates that client windows should initially be left as
+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 "\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
+\fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list.
+The optional \fIwin-list\fP is a list of window names and colors so that
+per-window colors may be specified.
+The default is "white".
+.IP "\fBTitleButtonBorderWidth\fP \fIpixels\fP" 8
+This variable specifies the width in pixels of the border surrounding
+titlebuttons. This is typically set to 0 to allow titlebuttons to take up as
+much space as possible and to not have a border.
+The default is 1.
+.IP "\fBTitleFont\fP \fIstring\fP" 8
+This variable specifies the font to be used for displaying window names in
+titlebars. The default is "variable".
+.IP "\fBTitleForeground\fP \fIstring\fP [{ \fIwin-list\fP }]" 8
+This variable specifies the foreground color used in titlebars, and
+may only be specified inside of a
+\fBColor\fP, \fBGrayscale\fP or \fBMonochrome\fP list.
+The optional \fIwin-list\fP is a list of window names and colors so that
+per-window colors may be specified.
+The default is "black".
+.IP "\fBTitlePadding\fP \fIpixels\fP" 8
+This variable specifies the distance between the various buttons, text, and
+highlight areas in the titlebar. The default is 8 pixels.
+.IP "\fBUnknownIcon\fP \fIstring\fP" 8
+This variable specifies the filename of a bitmap file to be
+used as the default icon. This bitmap will be used as the icon of all
+clients which do not provide an icon bitmap and are not listed
+in the \fBIcons\fP list.
+.IP "\fBUsePPosition\fP \fIstring\fP" 8
+This variable specifies whether or not \fItwm\fP should honor
+program-requested locations (given by the \fBPPosition\fP flag in the
+WM_NORMAL_HINTS property) in the absence of a user-specified position.
+The argument \fIstring\fP may have one of three values: \fB"off"\fP
+(the default)
+indicating that \fItwm\fP
+should ignore the program-supplied position,
+\fB"on"\fP indicating that the position
+should be used, and
+\fB"non-zero"\fP indicating that the position should used if
+it is other than (0,0). The latter option is for working around a bug in
+older toolkits.
+.IP "\fBWarpCursor\fP [{ \fIwin-list\fP }]" 8
+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 "\fBWindowRing\fP { \fIwin-list\fP }" 8
+This variable specifies a list of windows along which the \fBf.warpring\fP
+function cycles.
+.IP "\fBWarpUnmapped\fP" 8
+This variable indicates that the \fBf.warpto\fP function should deiconify
+any iconified windows it encounters. This is typically used to make a key
+binding that will pop a particular window (such as \fIxmh\fP), no matter
+where it is. The default is for \fBf.warpto\fP to ignore iconified windows.
+.IP "\fBXorValue\fP \fInumber\fP" 8
+This variable specifies the value to use when drawing window outlines for
+moving and resizing. This should be set to a value that will result in a
+variety of
+of distinguishable colors when exclusive-or'ed with the contents of the
+user's typical screen. Setting this variable to 1 often gives nice results
+if adjacent colors in the default colormap are distinct. By default,
+\fItwm\fP will attempt to cause temporary lines to appear at the opposite
+end of the colormap from the graphics.
+.IP "\fBZoom\fP [ \fIcount\fP ]" 8
+This variable indicates that outlines suggesting movement of a window
+to and from its iconified state should be displayed whenever a window is
+iconified or deiconified. The optional \fIcount\fP argument specifies the
+number of outlines to be drawn. The default count is 8.
+.PP
+The following variables must be set after the fonts have been
+assigned, so it is usually best to put them at the end of the variables
+or beginning of the bindings sections:
+.IP "\fBDefaultFunction\fP \fIfunction\fP" 8
+This variable specifies the function to be executed when a key or button
+event is received for which no binding is provided. This is typically
+bound to \fBf.nop\fP, \fBf.beep\fP, or a menu containing window operations.
+.IP "\fBWindowFunction\fP \fIfunction\fP" 8
+This variable specifies the function to execute when a window is selected
+from the \fBTwmWindows\fP menu. If this variable is not set, the window
+will be deiconified and raised.
+.SH BINDINGS
+.PP
+After the desired variables have been set, functions may be attached
+titlebuttons and key and pointer buttons. Titlebuttons may be added
+from the left or right side and appear in the titlebar from left-to-right
+according to the
+order in which they are specified. Key and pointer button
+bindings may be given in any order.
+.PP
+Titlebuttons specifications must include the name of the pixmap to use in
+the button box and the function to be invoked when a pointer button is
+pressed within them:
+.EX 0
+\fBLeftTitleButton\fP "\fIbitmapname\fP" = \fIfunction\fP
+.EE
+or
+.EX 0
+\fBRightTitleButton\fP "\fIbitmapname\fP" = \fIfunction\fP
+.EE
+The \fIbitmapname\fP may refer to one of the built-in bitmaps
+(which are scaled to match \fBTitleFont\fP) by using the appropriate
+colon-prefixed name described above.
+.PP
+Key and pointer button specifications must give the modifiers that must
+be pressed, over which parts of the screen the pointer must be, and what
+function is to be invoked. Keys are given as strings containing the
+appropriate
+keysym name; buttons are given as the keywords \fBButton1\fP-\fBButton5\fP:
+.EX 0
+"FP1" = \fImodlist\fP : \fIcontext\fP : \fIfunction\fP
+\fBButton1\fP = \fImodlist\fP : \fIcontext\fP : \fIfunction\fP
+.EE
+The \fImodlist\fP is any combination of the modifier names \fBshift\fP,
+\fBcontrol\fP, \fBlock\fP, \fBmeta\fP, \fBmod1\fP, \fBmod2\fP, \fBmod3\fP,
+\fBmod4\fP, or \fBmod5\fP (which may be abbreviated as
+\fBs\fP, \fBc\fP, \fBl\fP, \fBm\fP, \fBm1\fP, \fBm2\fP, \fBm3\fP, \fBm4\fP,
+\fBm5\fP, respectively) separated by a vertical bar (\(or).
+Similarly, the \fIcontext\fP is any combination of
+\fBwindow\fP,
+\fBtitle\fP,
+\fBicon\fP,
+\fBroot\fP,
+\fBframe\fP,
+\fBiconmgr\fP, their first letters (\fBiconmgr\fP abbreviation is \fBm\fP),
+or \fBall\fP,
+separated by a vertical bar. The \fIfunction\fP is any of the \fBf.\fP
+keywords described below. For example, the default startup
+file contains the following bindings:
+.EX 0
+Button1 = : root : f.menu "TwmWindows"
+Button1 = m : window | icon : f.function "move-or-lower"
+Button2 = m : window | icon : f.iconify
+Button3 = m : window | icon : f.function "move-or-raise"
+Button1 = : title : f.function "move-or-raise"
+Button2 = : title : f.raiselower
+Button1 = : icon : f.function "move-or-iconify"
+Button2 = : icon : f.iconify
+Button1 = : iconmgr : f.iconify
+Button2 = : iconmgr : f.iconify
+.EE
+A user who wanted to be able to manipulate windows from the keyboard could
+use the following bindings:
+.EX 0
+"F1" = : all : f.iconify
+"F2" = : all : f.raiselower
+"F3" = : all : f.warpring "next"
+"F4" = : all : f.warpto "xmh"
+"F5" = : all : f.warpto "emacs"
+"F6" = : all : f.colormap "next"
+"F7" = : all : f.colormap "default"
+"F20" = : all : f.warptoscreen "next"
+"Left" = m : all : f.backiconmgr
+"Right" = m | s : all : f.forwiconmgr
+"Up" = m : all : f.upiconmgr
+"Down" = m | s : all : f.downiconmgr
+.EE
+\fITwm\fP provides many more window manipulation primitives than can be
+conveniently stored in a titlebar, menu, or set of key bindings. Although
+a small set of defaults are supplied (unless the \fBNoDefaults\fP is
+specified), most users will want to have their most common operations
+bound to key and button strokes. To do this, \fItwm\fP associates names
+with each of the primitives and provides \fIuser-defined functions\fP for
+building higher level primitives and \fImenus\fP for interactively selecting
+among groups of functions.
+.PP
+User-defined functions contain the name by which they are referenced in
+calls to \fBf.function\fP and a list of other functions to execute. For
+example:
+.EX 0
+Function "move-or-lower" { f.move f.deltastop f.lower }
+Function "move-or-raise" { f.move f.deltastop f.raise }
+Function "move-or-iconify" { f.move f.deltastop f.iconify }
+Function "restore-colormap" { f.colormap "default" f.lower }
+.EE
+The function name must be used in \fBf.function\fP exactly as it appears in
+the function specification.
+.PP
+In the descriptions below, if the function is said to operate on the selected
+window, but is invoked from a root menu, the cursor will be changed to
+the \fBSelect\fP cursor and the next window to receive a button press will
+be chosen:
+.IP "\fB!\fP \fIstring\fP" 8
+This is an abbreviation for \fBf.exec\fP \fIstring\fP.
+.\"OBSOLETE - use a clipboard client
+.\".IP "\fB^\fP \fIstring\fP" 8
+.\"This is an abbreviation for \fBf.cut\fP \fIstring\fP.
+.IP "\fBf.autoraise\fP" 8
+This function toggles whether or not the selected window is raised whenever
+entered by the pointer. See the description of the variable \fBAutoRaise\fP.
+.IP "\fBf.backiconmgr\fI" 8
+This function warps the pointer to the previous column in the
+current icon manager, wrapping back to the previous row if necessary.
+.IP "\fBf.beep\fP" 8
+This function sounds the keyboard bell.
+.IP "\fBf.bottomzoom\fP" 8
+This function is similar to the \fBf.fullzoom\fP function, but
+resizes the window to fill only the bottom half of the screen.
+.IP "\fBf.circledown\fP" 8
+This function lowers the top-most window that occludes another window.
+.IP "\fBf.circleup\fP" 8
+This function raises the bottom-most window that is occluded by another window.
+.IP "\fBf.colormap\fP \fIstring\fP" 8
+This function rotates the colormaps (obtained from the WM_COLORMAP_WINDOWS
+property on the window) that \fItwm\fP will display when the pointer
+is in this window. The argument \fIstring\fP may have one of the following
+values: \fB"next"\fP, \fB"prev"\fP, and \fB"default"\fP. It should be noted
+here that in general, the installed colormap is determined by keyboard focus.
+A pointer driven keyboard focus will install a private colormap upon entry
+of the window owning the colormap. Using the click to type model, private
+colormaps will not be installed until the user presses a mouse button on
+the target window.
+.\"OBSOLETE - should go away and use a clipboard.
+.\".IP "\fBf.cut\fP \fIstring\fP" 8
+.\"This function places the specified \fIstring\fP (followed by a newline
+.\"character) into the root window property CUT_BUFFER0.
+.\".IP "\fBf.cutfile\fP" 8
+.\"This function reads the file indicated by the contents of the CUT_BUFFER0
+.\"window property and replaces the cut buffer.
+.IP "\fBf.deiconify\fP" 8
+This function deiconifies the selected window. If the window is not an icon,
+this function does nothing.
+.IP "\fBf.delete\fP" 8
+This function sends the WM_DELETE_WINDOW message to the selected window if
+the client application has requested it through the WM_PROTOCOLS window
+property. The application is supposed to respond to the message by removing
+the indicated window. If the window has not requested
+WM_DELETE_WINDOW messages, the keyboard bell will be rung indicating that
+the user should choose an alternative method. Note this is very different
+from f.destroy. The intent here is to delete a single window, not
+necessarily the entire application.
+.IP "\fBf.deltastop\fP" 8
+This function allows a user-defined function to be aborted if the pointer has
+been moved more than \fIMoveDelta\fP pixels. See the example definition
+given for \fBFunction "move-or-raise"\fP at the beginning of the section.
+.IP "\fBf.destroy\fP" 8
+This function instructs the X server to close the display connection of the
+client that created the selected window. This should only be used as a last
+resort for shutting down runaway clients. See also f.delete.
+.IP "\fBf.downiconmgr\fI" 8
+This function warps the pointer to the next row in the current icon manger,
+wrapping to the beginning of the next column if necessary.
+.IP "\fBf.exec\fP \fIstring\fP" 8
+This function passes the argument \fIstring\fP to /bin/sh for execution.
+In multiscreen mode, if \fIstring\fP starts a new X client without
+giving a display argument, the client will appear on the screen from
+which this function was invoked.
+.\".IP "\fBf.file\fP \fIstring\fP" 8
+.\"This function assumes \fIstring\fP is a file name. This file is read into
+.\"the window server's cut buffer.
+.IP "\fBf.focus\fP" 8
+This function toggles the keyboard focus of the server to the
+selected window, changing the focus rule from pointer-driven if necessary.
+If the selected window already was focused, this function executes an
+\fBf.unfocus\fP.
+.IP "\fBf.forcemove\fP" 8
+This function is like \fBf.move\fP except that it ignores the \fBDontMoveOff\fP
+variable.
+.IP "\fBf.forwiconmgr\fI" 8
+This function warps the pointer to the next column in the current icon
+manager, wrapping to the beginning of the next row if necessary.
+.IP "\fBf.fullzoom\fP" 8
+This function resizes the selected window to the full size of the display or
+else restores the original size if the window was already zoomed.
+.IP "\fBf.function\fP \fIstring\fP" 8
+This function executes the user-defined function whose name is specified
+by the argument \fIstring\fP.
+.IP "\fBf.hbzoom\fP" 8
+This function is a synonym for \fBf.bottomzoom\fP.
+.IP "\fBf.hideiconmgr\fP" 8
+This function unmaps the current icon manager.
+.IP "\fBf.horizoom\fP" 8
+This variable is similar to the \fBf.zoom\fP function except that the
+selected window is resized to the full width of the display.
+.IP "\fBf.htzoom\fP" 8
+This function is a synonym for \fBf.topzoom\fP.
+.IP "\fBf.hzoom\fP" 8
+This function is a synonym for \fBf.horizoom\fP.
+.IP "\fBf.iconify\fP" 8
+This function iconifies or deiconifies the selected window or icon,
+respectively.
+.IP "\fBf.identify\fP" 8
+This function displays a summary of the name and geometry of the
+selected window. If the server supports the SYNC extension, the priority
+of the client owning the window is also displayed.
+Clicking the pointer or pressing a key in the window
+will dismiss it.
+.IP "\fBf.lefticonmgr\fI" 8
+This function similar to \fBf.backiconmgr\fP except that wrapping does not
+change rows.
+.IP "\fBf.leftzoom\fP" 8
+This variable is similar to the \fBf.bottomzoom\fP function but causes
+the selected window is only resized to the left half of the display.
+.IP "\fBf.lower\fP" 8
+This function lowers the selected window.
+.IP "\fBf.menu\fP \fIstring\fP" 8
+This function invokes the menu specified by the argument \fIstring\fP.
+Cascaded menus may be built by nesting calls to \fBf.menu\fP.
+.IP "\fBf.move\fP" 8
+This function drags an outline of the selected window (or the window itself
+if the \fBOpaqueMove\fP variable is set) until the invoking pointer button
+is released. Double clicking within the number of milliseconds given by
+\fBConstrainedMoveTime\fP warps
+the pointer to the center of the window and
+constrains the move to be either horizontal or vertical depending on which
+grid line is crossed.
+To abort a move, press another button before releasing the
+first button.
+.IP "\fBf.nexticonmgr\fI" 8
+This function warps the pointer to the next icon manager containing any windows
+on the current or any succeeding screen.
+.IP "\fBf.nop\fP" 8
+This function does nothing and is typically used with the \fBDefaultFunction\fP
+or \fBWindowFunction\fP variables or to introduce blank lines in menus.
+.IP "\fBf.previconmgr\fI" 8
+This function warps the pointer to the previous icon manager containing any
+windows on the current or preceding screens.
+.IP "\fBf.priority\fP \fIstring\fP" 8
+This function sets the priority of the client owning the selected window to
+the numeric value of the argument \fIstring\fP, which should be a signed
+integer in double quotes (e.g. "999" ). This function has an effect only
+if the server supports the SYNC extension.
+.IP "\fBf.quit\fP" 8
+This function causes \fItwm\fP to restore the window's borders and exit. If
+\fItwm\fP is the first client invoked from \fIxdm\fP, this will result in a
+server reset.
+.IP "\fBf.raise\fP" 8
+This function raises the selected window.
+.IP "\fBf.raiselower\fP" 8
+This function raises the selected window to the top of the stacking order if
+it is occluded by any windows, otherwise the window will be lowered.
+.IP "\fBf.refresh\fP" 8
+This function causes all windows to be refreshed.
+.IP "\fBf.resize\fP" 8
+This function displays an outline of the selected window. Crossing a border
+(or setting \fBAutoRelativeResize\fP) will cause the outline to begin to
+rubber band until the invoking button is released. To abort a resize,
+press another button before releasing the first button.
+.IP "\fBf.restart\fP" 8
+
+This function kills and restarts \fItwm\fP.
+.IP "\fBf.righticonmgr\fI" 8
+This function is similar to \fBf.nexticonmgr\fP except that wrapping does
+not change rows.
+.IP "\fBf.rightzoom\fP" 8
+This variable is similar to the \fBf.bottomzoom\fP function except that
+the selected window is only resized to the right half of the display.
+.IP "\fBf.saveyourself\fP" 8
+This function sends a WM_SAVEYOURSELF message to the selected window if it
+has requested the message in its WM_PROTOCOLS window property. Clients that
+accept this message are supposed to checkpoint all state associated with the
+window and update the WM_COMMAND property as specified in the ICCCM. If
+the selected window has not selected for this message, the keyboard bell
+will be rung.
+.IP "\fBf.showiconmgr\fP" 8
+This function maps the current icon manager.
+.IP "\fBf.sorticonmgr\fP" 8
+This function sorts the entries in the current icon manager alphabetically.
+See the variable \fBSortIconManager\fP.
+.\".IP "\fBf.source\fP \fIstring\fP" 8
+.\"This function assumes \fIstring\fP is a file name. The file is read
+.\"and parsed as a \fItwm\fP startup file.
+.\"This
+.\"function is intended to be used only to re-build pull-down menus. None
+.\"of the \fItwm\fP variables are changed.
+.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.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.
+.\".IP "\fBf.twmrc\fP" 8
+.\"This function causes the startup customization file to be re-read. This
+.\"function is exactly like the \fBf.source\fP function without having to
+.\"specify the filename.
+.IP "\fBf.unfocus\fP" 8
+This function resets the focus back to pointer-driven. This should be used
+when a focused window is no longer desired.
+.IP "\fBf.upiconmgr\fI" 8
+This function warps the pointer to the previous row in the current icon
+manager, wrapping to the last row in the same column if necessary.
+.\".IP "\fBf.version\fI" 8
+.\"This function causes the \fItwm\fP version window to be displayed. This
+.\"window will be displayed until a pointer button is pressed or the
+.\"pointer is moved from one window to another.
+.IP "\fBf.vlzoom\fP" 8
+This function is a synonym for \fBf.leftzoom\fP.
+.IP "\fBf.vrzoom\fP" 8
+This function is a synonym for \fBf.rightzoom\fP.
+.IP "\fBf.warpring\fP \fIstring\fP" 8
+This function warps the pointer to the next or previous window (as indicated
+by the argument \fIstring\fP, which may be \fB"next"\fP or \fB"prev"\fP)
+specified in the \fBWindowRing\fP variable.
+.IP "\fBf.warpto\fP \fIstring\fP" 8
+This function warps the pointer to the window which has a name or class
+that matches \fIstring\fP. If the window is iconified, it will be deiconified
+if the variable \fBWarpUnmapped\fP is set or else ignored.
+.IP "\fBf.warptoiconmgr\fP \fIstring\fP" 8
+This function warps the pointer to the icon manager entry
+associated with the window containing the pointer in the icon manager
+specified by the argument \fIstring\fP. If \fIstring\fP is empty (i.e. ""),
+the current icon manager is chosen.
+.IP "\fBf.warptoscreen\fP \fIstring\fP" 8
+This function warps the pointer to the screen specified by the
+argument \fIstring\fP. \fIString\fP may be a number (e.g. \fB"0"\fP or
+\fB"1"\fP), the word \fB"next"\fP (indicating the current screen plus 1,
+skipping over any unmanaged screens),
+the word \fB"back"\fP (indicating the current screen minus 1, skipping over
+any unmanaged screens), or the word
+\fB"prev"\fP (indicating the last screen visited.
+.IP "\fBf.winrefresh\fP" 8
+This function is similar to the \fBf.refresh\fP function except that only the
+selected window is refreshed.
+.IP "\fBf.zoom\fP" 8
+This function is similar to the \fBf.fullzoom\fP function, except that
+the only the height of the selected window is changed.
+.SH MENUS
+.PP
+Functions may be grouped and interactively selected using pop-up
+(when bound to a pointer button) or pull-down (when associated
+with a titlebutton) menus. Each menu specification contains the name of the
+menu as it will be referred to by \fBf.menu\fP, optional default
+foreground and background colors, the list of item names and the functions
+they should invoke, and optional foreground and background colors for
+individual items:
+.EX 0
+\fBMenu\fP "\fImenuname\fP" [ ("\fIdeffore\fP":"\fIdefback\fP") ]
+{
+ \fIstring1\fP [ ("\fIfore1\fP":"\fIbackn\fP")] \fIfunction1\fP
+ \fIstring2\fP [ ("\fIfore2\fP":"\fIbackn\fP")] \fIfunction2\fP
+ .
+ .
+ .
+ \fIstringN\fP [ ("\fIforeN\fP":"\fIbackN\fP")] \fIfunctionN\fP
+}
+.EE
+.PP
+The \fImenuname\fP is case-sensitive.
+The optional \fIdeffore\fP and \fIdefback\fP arguments specify the foreground
+and background colors used on a color display
+to highlight menu entries.
+The \fIstring\fP portion
+of each menu entry will be the text which will appear in the menu.
+The optional \fIfore\fP and \fIback\fP arguments specify the foreground
+and background colors of the menu entry when the pointer is not in
+the entry. These colors will only be used on a color display. The
+default is to use the colors specified by the
+\fBMenuForeground\fP and \fBMenuBackground\fP variables.
+The \fIfunction\fP portion of the menu entry is one of the functions,
+including any user-defined functions, or additional menus.
+.PP
+There is a special menu named \fBTwmWindows\fP which contains the names of
+all of the client and \fItwm\fP-supplied windows. Selecting an entry will
+cause the
+\fBWindowFunction\fP to be executed on that window. If \fBWindowFunction\fP
+hasn't been set, the window will be deiconified and raised.
+.SH ICONS
+\fITwm\fP supports several different ways of manipulating iconified windows.
+The common pixmap-and-text style may be laid out by hand or automatically
+arranged as described by the \fBIconRegion\fP variable. In addition, a
+terse grid of icon names, called an icon manager, provides a more efficient
+use of screen space as well as the ability to navigate among windows from
+the keyboard.
+.PP
+An icon manager is a window that contains names of selected or all
+windows currently on the display. In addition to the window name,
+a small button using the default iconify symbol will be displayed to the
+left of the name when the window is iconified. By default, clicking on an
+entry in the icon manager performs \fBf.iconify\fP.
+To change the actions taken in the icon manager, use the
+the \fBiconmgr\fP context when specifying button and keyboard bindings.
+.PP
+Moving the pointer into the icon manager also directs keyboard focus to
+the indicated window (setting the focus explicitly or else sending synthetic
+events \fBNoTitleFocus\fP is set).
+Using the \fBf.upiconmgr\fP, \fBf.downiconmgr\fP
+\fBf.lefticonmgr\fP, and
+\fBf.righticonmgr\fP functions,
+the input focus can be changed between windows directly from the keyboard.
+.SH BUGS
+The resource manager should have been used instead of all of the window
+lists.
+.PP
+The \fBIconRegion\fP variable should take a list.
+.PP
+Double clicking very fast to get the constrained move function will sometimes
+cause the window to move, even though the pointer is not moved.
+.PP
+If \fBIconifyByUnmapping\fP is on and windows are listed in
+\fBIconManagerDontShow\fP but not in \fBDontIconifyByUnmapping\fP,
+they may be lost if they are iconified and no bindings to
+\fBf.menu "TwmWindows"\fP or \fBf.warpto\fP are setup.
+.SH FILES
+.PP
+.nf
+ $HOME/.twmrc.<screen number>
+ $HOME/.twmrc
+ <XRoot>/lib/X11/twm/system.twmrc
+.fi
+.SH "ENVIRONMENT VARIABLES"
+.IP "DISPLAY" 8
+This variable is used to determine which X server to use. It is also set
+during \fBf.exec\fP so that programs come up on the proper screen.
+.IP "HOME" 8
+This variable is used as the prefix for files that begin with a tilde and
+for locating the \fItwm\fP startup file.
+.SH "SEE ALSO"
+.PP
+X(1), Xserver(1), xdm(1), xrdb(1)
+.SH AUTHORS
+Tom LaStrange, Solbourne Computer; Jim Fulton, MIT X Consortium;
+Steve Pitschke, Stardent Computer; Keith Packard, MIT X Consortium;
+Dave Sternlicht, MIT X Consortium; Dave Payne, Apple Computer.
diff --git a/sample-twmrc/jim.twmrc b/sample-twmrc/jim.twmrc
new file mode 100644
index 0000000..210d118
--- /dev/null
+++ b/sample-twmrc/jim.twmrc
@@ -0,0 +1,250 @@
+#**********************************************************************
+#
+# .twmrc
+#
+#**********************************************************************
+
+#IconDirectory "/users/jim/icons" # use *bitmapFilePath instead.
+
+#
+# Use the SHAPE extension to make titles use as little space as possible. The
+# location of the titles is specified as a fraction of the distance from the
+# left (numerator positive) or right edge (numerator negative). A denominator
+# of 0 indicates that the numerator is measured in pixels. The title is then
+# justified over the indicated spot (note special cases are made for center on
+# 0/0 and right on 0/0 to indicate the center and right edge of the titlebar).
+#
+SqueezeTitle # also sets default to Squeeze all Titles
+{
+# name justify num denom
+ "oclock" center 0 0 # centered over middle of title
+ "XTerm" left 0 0 # left edge of title
+ "xlogo" right 0 0 # for kicks
+ "emacs" right 0 0 # left side emacs with center tab
+ "xmh" center 0 0
+}
+DontSqueezeTitle
+{
+ "XLogout" # make it stand out when mapped
+}
+NoDefaults # turn off iconify and resize button
+LeftTitleButton "menu12" = f.menu "windowmenu" # add a menu to each window
+TitleButtonBorderWidth 0 # don't want to see box around button
+ButtonIndent 0 # button doesn't have to be smaller
+
+UsePPosition "on" # use program-specified size hints accepted
+NoHighlight # do not flash borders on enter events
+OpaqueMove # actually move window instead of outline
+AutoRelativeResize # don't require resize to cross border to start
+RestartPreviousState # reiconify iconified things on startup
+ClientBorderWidth # use the application border width on frame
+BorderWidth 2 # width of top level windows created by twm
+NoGrabServer # don't grab server during menus, etc.
+NoRaiseOnMove # allow moving under other windows
+NoRaiseOnResize # allow resizing under other windows
+NoTitleFocus # avoid keystrokes in wrong window cause of lag
+DecorateTransients # put titlebars on transients
+TitleFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*"
+MenuFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*"
+IconFont "-adobe-helvetica-bold-r-normal--*-100-*-*-*-*-*-*"
+IconManagerFont "-adobe-helvetica-bold-r-normal--*-100-*-*-*"
+ResizeFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*"
+NoSaveUnders # faster to just repaint then save
+XORvalue 1 # tend to use visually distinct adjacent colors
+ConstrainedMoveTime 0 # turn off horizontal/vertical only moving
+NoCaseSensitive # turn off case-sensitivity in sorting icons
+WarpUnmapped # allow warping to unmapped windows
+
+###############################################################################
+# #
+# Declare some nice colors #
+# #
+###############################################################################
+
+Pixmaps
+{
+# TitleHighlight "solid4x4" # make it stand out
+}
+
+Color
+{
+ DefaultBackground "maroon"
+ DefaultForeground "gray85"
+ BorderColor "gray70"
+ TitleBackground "maroon"
+ TitleForeground "gray85"
+ MenuBackground "maroon"
+ MenuForeground "gray85"
+ MenuTitleBackground "gray70"
+ MenuTitleForeground "maroon"
+ IconBackground "maroon"
+ IconForeground "gray85"
+ IconBorderColor "gray85"
+ IconManagerBackground "maroon"
+ IconManagerForeground "gray85"
+}
+
+Monochrome
+{
+ IconManagerHighlight "white"
+ BorderColor "black"
+}
+
+
+###############################################################################
+# #
+# Define key bindings #
+# #
+###############################################################################
+
+MoveDelta 3 # need to move this much before takes effect
+Function "move-or-raise" # simulate uwm action
+{
+ f.move
+ f.deltastop
+ f.raise
+}
+
+DefaultFunction f.nop # ignore extraneous events
+
+Button1 = : root : f.menu "twmops"
+Button2 = : root : f.menu "windowops"
+Button3 = : root : f.menu "TwmWindows"
+Button1 = : title : f.function "move-or-raise"
+Button1 = : icon : f.iconify
+Button1 = : iconmgr : f.iconify
+Button1 = m : window|icon|frame|title : f.lower
+Button2 = m : window : f.resize
+Button3 = m : window|icon|frame|title : f.function "move-or-raise"
+Button1 = c|m|s : all : f.menu "twmops"
+#Button1 = c|m|s : root : f.refresh
+#"F20" = : all : f.warptoscreen "next"
+
+"F21" = : all : f.warpring "next"
+"F22" = : all : f.warptoiconmgr ""
+"F23" = : all : f.raiselower
+"Num_Lock" = : all : f.iconify
+"F24" = : all : f.warpto "xmh"
+"F25" = : all : f.warpto "[expo]"
+"F26" = : all : f.warpto "emacs"
+"KP_Subtract" = mod5 : all : f.colormap "prev"
+"KP_Add" = mod5 : all : f.colormap "next"
+"KP_Enter" = mod5 : all : f.colormap "default"
+"Left" = m : all : f.backiconmgr
+"Right" = m : all : f.forwiconmgr
+"Up" = m : all : f.upiconmgr
+"Down" = m : all : f.downiconmgr
+"Left" = mod5 : all : f.warpring "prev"
+"Right" = mod5 : all : f.warpring "next"
+
+###############################################################################
+# #
+# Display an icon manager across the top of the screen. Don't manage #
+# the windows for which you don't show a title. #
+# #
+###############################################################################
+
+SortIconManager # keep them in alphabetic order
+ShowIconManager # start with iconmgr up
+IconManagerGeometry "700x50+246+2" 14 # strip across top
+IconRegion "200x300+950+2" North East 50 50
+IconifyByUnmapping # just use icon manager
+IconManagerDontShow # but ignore these windows
+{
+ "xclock"
+ "xbiff"
+ "xload"
+ "oclock"
+ "xcutsel"
+ "XLogout"
+}
+DontIconifyByUnmapping # don't lose them (still in TwmWindows menu)
+{
+ "xclock"
+ "xbiff"
+ "xload"
+ "oclock"
+ "xcutsel"
+ "Untitled"
+}
+NoTitle # little programs that look like icons
+{
+ "xclock"
+ "xbiff"
+ "xload"
+ "TWM Icon Manager"
+ "xcutsel"
+}
+
+NoStackMode # prevent hostile clients from hosing display
+{
+ "saber"
+}
+
+WindowRing # f.warpring acts along these windows
+{
+ "XTerm"
+ "emacs"
+ "Xmh"
+}
+
+
+###############################################################################
+# #
+# Define some useful menus. #
+# #
+###############################################################################
+
+menu "twmops"
+{
+"System" f.title
+"Restart Twm" f.restart
+"Exit Twm" f.quit
+"" f.nop
+"xterm" !"xterm &"
+"xterm -e /bin/sh" !"xterm -e /bin/sh &"
+"xhost +" !"xhost + >/dev/null"
+"xhost -" !"xhost - >/dev/null"
+"" f.nop
+"Kill" f.menu "kill"
+"" f.nop
+"Logout" f.warpto "xlogout"
+}
+
+menu "windowops"
+{
+"Windows" f.title
+"Kill" f.menu "kill"
+"Save" f.saveyourself
+"Refresh" f.refresh
+"" f.nop
+"Iconify" f.iconify
+"Resize" f.resize
+"Move" f.move
+"Raise" f.raise
+"Lower" f.lower
+"Info" f.identify
+"Focus" f.focus
+"Unfocus" f.unfocus
+"" f.nop
+"Show Iconmgr" f.showiconmgr
+"Hide Iconmgr" f.hideiconmgr
+"Prev Iconmgr" f.previconmgr
+"Next Iconmgr" f.nexticonmgr
+}
+
+menu "windowmenu"
+{
+"Iconify" f.iconify
+"RaiseLower" f.raiselower
+"Refresh" f.winrefresh
+"Focus" f.focus
+"" f.nop
+"Kill" f.menu "kill"
+}
+
+menu "kill"
+{
+ "Send Delete" f.delete
+ "Kill Window" f.destroy
+}
diff --git a/sample-twmrc/keith.twmrc b/sample-twmrc/keith.twmrc
new file mode 100644
index 0000000..b85340b
--- /dev/null
+++ b/sample-twmrc/keith.twmrc
@@ -0,0 +1,223 @@
+#**********************************************************************
+#
+# .twmrc
+#
+#**********************************************************************
+
+IconDirectory "/users/keith/misc/bitmaps"
+
+#NoDefaults
+NoVersion
+NoGrabServer
+NoRaiseOnMove
+NoRaiseOnResize
+#NoMenuShadows
+NoTitleHighlight
+NoHighlight
+NoTitleFocus
+NoSaveUnders
+SqueezeTitle
+ConstrainedMoveTime 0
+DecorateTransients
+#TitleButtonBorderWidth 0
+#ButtonIndent 0
+#LeftTitleButton "iconify.bm" = f.iconify
+#RightTitleButton "resize.bm" = f.resize
+OpaqueMove
+#ClientBorderWidth
+BorderWidth 1
+RandomPlacement
+#IconRegion "1024x250+0+600" NORTH WEST 1024 25
+IconRegion "600x200-200+0" NORTH EAST 75 25
+#IconRegion "200x100-0+200" WEST NORTH 25 50
+TitleFont "-*-helvetica-bold-o-normal--*-140-*-*-*-*-iso8859-1"
+MenuFont "-*-helvetica-bold-r-normal--*-140-*-*-*-*-iso8859-1"
+IconFont "-*-helvetica-bold-r-normal--*-140-*-*-*-*-iso8859-1"
+ResizeFont "-*-helvetica-bold-r-normal--*-120-*-*-*-*-iso8859-1"
+IconManagerFont "-*-helvetica-bold-r-normal--*-120-*-*-*-*-iso8859-1"
+#ShowIconManager
+SortIconManager
+IconManagerGeometry "=100x100-200+0"
+
+# nice colors: background of wheat, foreground of #d36
+
+Cursors
+{
+ Button "left_ptr"
+ Menu "left_ptr"
+ Title "left_ptr"
+ Frame "left_ptr"
+ Icon "left_ptr"
+}
+
+Color
+{
+ BorderColor "black"
+ TitleBackground "CadetBlue"
+ TitleForeground "#fffff0"
+ MenuBackground "#fffff0"
+ MenuForeground "black"
+ MenuTitleBackground "CadetBlue"
+ MenuTitleForeground "#fffff0"
+ IconBackground "#fffff0"
+ IconForeground "black"
+ IconBorderColor "black"
+}
+
+Monochrome
+{
+ IconManagerHighlight "white"
+}
+
+# define key bindings
+
+MoveDelta 3
+
+Function "move-or-raise"
+{
+ f.move
+ f.deltastop
+ f.raise
+}
+
+Function "move-or-raiselower"
+{
+ f.move
+ f.deltastop
+ f.raiselower
+}
+
+Function "move-or-iconify"
+{
+ f.move
+ f.deltastop
+ f.iconify
+}
+
+Function "next-window"
+{
+}
+
+Function "previous-window"
+{
+}
+
+DefaultFunction f.nop
+
+Button1 = : title : f.function "move-or-raiselower"
+Button2 = : title : f.menu "Title Menu"
+Button3 = : title : f.resize
+Button1 = m : window|icon : f.iconify
+Button2 = m : window|icon : f.function "move-or-raiselower"
+Button3 = m : window|icon : f.resize
+Button3 = c m : title : f.destroy
+Button1 = : root : f.menu "Hosts"
+Button2 = : root : f.menu "Toys"
+Button3 = : root : f.menu "System"
+Button1 = : icon : f.function "move-or-iconify"
+
+#ForceIcons
+
+Icons
+{
+ "Xmh" "mail-up.bm" # from IconDirectory
+ "XTerm" "xterm.bm" # from IconDirectory
+}
+
+#UnknownIcon "icon"
+
+NoTitle
+{
+ "clock"
+ "oclock"
+ "xclock"
+ "xbiff"
+ "xeyes"
+ "xload"
+}
+
+IconManagerDontShow {
+ "clock"
+ "oclock"
+ "xclock"
+ "xbiff"
+ "xeyes"
+ "xload"
+}
+
+menu "Hosts"
+{
+"Hosts" f.title
+"xenon" !"xenon &"
+"expo" !"expo &"
+"kanga" !"kanga &"
+"exile" !"exile &"
+"expire" !"expire &"
+"excalibur" !"excalibur &"
+"hpx" !"hpx &"
+"expo bugs" !"expo -l bugs &"
+"extort" !"extort &"
+"apx" !"apx &"
+"mfb" !"mfb &"
+"sushi" !"sushi &"
+"tempura" !"tempora &"
+}
+
+menu "Toys"
+{
+"Toys" f.title
+"Jove" !"xjove &"
+"Mail" !"xmh &"
+"Manual" !"xman &"
+"Troff Viewer" !"xditview &"
+"Calculator" !"xcalc &"
+"Mille Bornes" !"xmille `path -n .mille` &"
+"Notepad" !"xclipboard &"
+"Eyes" !"xeyes &"
+"Lens" !"xmag &"
+"expo jove" !"expo xjove&"
+"expo mail" !"expo xmh &"
+}
+
+menu "System"
+{
+ "System" f.title
+ "Window ops" f.menu "Window Ops"
+ "Windows" f.menu "TwmWindows"
+ "" f.nop
+ "Refresh" f.refresh
+ "Unfocus" f.unfocus
+ "Show Icon Box" f.showiconmgr
+ "Hide Icon Box" f.hideiconmgr
+ "Version" f.version
+ "" f.nop
+ "Restart" f.restart
+ "Logout" f.quit
+}
+
+menu "Window Ops"
+{
+ "Window Ops" f.title
+ "Lower" f.lower
+ "Raise" f.raise
+ "Resize" f.resize
+ "Move" f.move
+ "Deiconify" f.deiconify
+ "Iconify" f.iconify
+ "Identify" f.identify
+ "Focus" f.focus
+ "Kill" f.destroy
+}
+
+menu "Title Menu"
+{
+ "Lower" f.lower
+ "Raise" f.raise
+ "Resize" f.resize
+ "Move" f.move
+ "Iconify" f.iconify
+ "Identify" f.identify
+ "Focus" f.focus
+ "Kill" f.destroy
+ "Dismiss" f.delete
+}
diff --git a/sample-twmrc/lemke.twmrc b/sample-twmrc/lemke.twmrc
new file mode 100644
index 0000000..f0a12af
--- /dev/null
+++ b/sample-twmrc/lemke.twmrc
@@ -0,0 +1,255 @@
+#
+# Dave Lemke's .twmrc
+#
+
+IconDirectory "/u/lemke/lib/icons"
+
+#AutoRelativeResize
+BorderWidth 3
+ButtonIndent 0
+ClientBorderWidth
+#DefaultFunction f.nop
+#DontMoveOff
+IconifyByUnmapping
+IconFont "-adobe-helvetica-bold-r-normal--14-100-100-100-p-82-iso8859-1"
+IconManagerFont "-adobe-helvetica-bold-r-normal--14-100-100-100-p-82-iso8859-1"
+IconManagerGeometry "=98x5-2+50"
+#LeftTitleButton "menu12.xbm" = f.menu "window-ops"
+MenuFont "-adobe-helvetica-bold-r-normal--14-100-100-100-p-82-iso8859-1"
+MoveDelta 5
+#NoBackingStore
+NoDefaults
+NoGrabServer
+NoMenuShadows
+#NoRaiseOnDeiconify
+NoRaiseOnMove
+#NoRaiseOnResize
+#NoSaveUnder
+#NoTitleFocus
+#NoVersion
+#OpaqueMove
+ResizeFont "10x20"
+RestartPreviousState
+#ReverseVideo
+ShowIconManager
+SortIconManager
+
+SqueezeTitle
+{
+ "XTerm" center 0 0
+ "Xsol" center 0 0
+ "Spider" center 0 0
+}
+
+TitleFont "-adobe-helvetica-bold-r-normal--14-100-100-100-p-82-iso8859-1"
+TitleButtonBorderWidth 1
+UnknownIcon "ncdlogo64.xbm"
+#WarpCursor
+XORValue 1
+#Zoom
+
+DefaultFunction f.nop
+
+Function "move-or-raise"
+{
+ f.move
+ f.deltastop
+ f.raise
+}
+
+AutoRaise
+{
+ "xtrek"
+ "TWM Icon Manager"
+ "xclock"
+ "xbiff"
+ "xeyes"
+}
+
+Cursors
+{
+ Menu "right_ptr"
+}
+
+DontIconifyByUnmapping
+{
+ "xclock"
+ "xbiff"
+ "twmOutput"
+ "xload"
+ "oclock"
+ "xeyes"
+}
+
+IconManagerDontShow
+{
+ "xclock"
+ "xbiff"
+ "twmOutput"
+ "xload"
+ "oclock"
+ "xeyes"
+}
+
+Monochrome
+{
+ DefaultForeground "black"
+ DefaultBackground "white"
+ BorderColor "black"
+ TitleForeground "black"
+ TitleBackground "white"
+ MenuForeground "black"
+ MenuBackground "white"
+}
+
+NoTitle
+{
+ "xclock"
+ "xbiff"
+ "xload"
+ "TWM Icon Manager"
+ "FrameMaker"
+ "FrameWriter"
+ "oclock"
+ "twmOutput"
+ "xeyes"
+}
+
+#
+# buttons
+#
+
+Button1 = : root : f.menu "button1"
+Button2 = : root : f.menu "Util_menu"
+Button3 = : root : f.menu "Hosts_menu"
+Button1 = : m : f.iconify
+Button2 = : m : f.lower
+Button1 = : t : f.function "move-or-raise"
+Button2 = : t : f.lower
+Button3 = : t : f.menu "window-ops"
+Button1 = : i : f.iconify
+Button2 = : i : f.function "move-or-raise"
+
+"F1" = : w|t|i : f.iconify
+"F2" = : all : f.refresh
+"F3" = : w|t|i : f.raise
+"F4" = : w|t|i : f.lower
+
+"F5" = : w|t|i : f.zoom
+
+
+
+menu "button1"
+{
+"Applications" f.title
+#"FrameWriter" !"rsh indian -n /usr/local/xframewriter $DISPLAY& "
+#"Q Calc " !"rsh indian -n /usr/bin/X11/xterm -display $DISPLAY -T Qcalc -e /pmax/u/demo/qsp/bin/qcalc &"
+#"Notepad" !"/usr/bin/dxnotepad -display $DISPLAY&"
+#"Calculator" !"xcalc -display $DISPLAY&"
+"Mail Box" !"/usr/bin/X11/xbiff -display $DISPLAY&"
+"Clock" !"oclock -display $DISPLAY &"
+"Xterm" !"/usr/bin/X11/xterm -ls -display $DISPLAY &"
+"Big Xterm" !"/usr/bin/X11/xterm -ls -fn 9x15 -display $DISPLAY &"
+"xsol" !"$HOME/games/bin/`arch`/xsol &"
+"Spider" !"$HOME/games/bin/`arch`/spider &"
+"Utility" f.title
+#"Focus" f.focus
+#"UnFocus" f.unfocus
+#"More.." f.title
+"..Hosts" f.menu "Hosts_menu"
+"..Applications" f.menu "Apps_menu"
+"..Utility" f.menu "Util_menu"
+"" f.title
+"Exit" f.quit
+}
+
+menu "Hosts_menu"
+{
+"Host Connections" f.title
+"Almanor" !"rsh -n almanor exec /usr/bin/X11/xterm -ls -display $DISPLAY -T Almanor&"
+"Hamilton" !"rsh -n hamilton exec /usr/bin/X11/xterm -ls -display $DISPLAY -T Hamilton&"
+"Homer" !"rsh -n Homer exec /usr/bin/X11/xterm -ls -display $DISPLAY -T Homer&"
+"Lupine" !"TERM=xterms xterm -fn 10x20 -T lupine -e rlogin lupine&"
+"Ramona" !"rsh -n ramona exec /usr/bin/X11/xterm -ls -display $DISPLAY -T Ramona&"
+"Pagemill" !"rsh pagemill -n /usr/bin/X11/xterm -display $DISPLAY -T Pagemill -e /bin/ksh&"
+"Sheridan" !"rsh -n sheridan exec /usr/bin/X11/xterm -ls -display $DISPLAY -T Sheridan&"
+}
+
+menu "Apps_menu"
+{
+"Applications" f.title
+"Man Pages" !"/usr/bin/X11/xman -display $DISPLAY&"
+#"Notepad" !"/usr/bin/dxnotepad -display $DISPLAY&"
+#"FrameMaker" !"rsh indian -n /usr/local/xframemaker $DISPLAY& "
+#"Calendar" !"/usr/bin/dxcalendar -display $DISPLAY &"
+"Clock" !"/usr/bin/X11/xclock -display $DISPLAY &"
+#"Rolodex" !"/usr/bin/dxcardfiler -display $DISPLAY &"
+#"Paint" !"/usr/bin/dxpaint -display $DISPLAY &"
+"Lock Screen" !"/usr/bin/X11/xlock & "
+"Preferences" !"/usr/bin/X11/xpref -display $DISPLAY&"
+"Xterm" !"/usr/bin/X11/xterm -ls -display $DISPLAY &"
+}
+
+menu "Util_menu"
+{
+"Utilities" f.title
+"Refresh" f.refresh
+"twm Version" f.version
+"Source .twmrc" f.twmrc
+"Restart twm" f.restart
+#"Hide IconManager" f.hideiconmgr
+#"Show IconManager" f.showiconmgr
+#"Destroy All Window" !"xkill -a&"
+"Preferences" f.menu "Pref_menu"
+"TwmWindows" f.menu "TwmWindows"
+"Exit twm" f.quit
+"Window Ops" f.title
+"Refresh Window" f.winrefresh
+"Move Window" f.move
+"Resize Window" f.resize
+"Lower Window" f.lower
+"Raise Window" f.raise
+"Iconify" f.iconify
+"Window Info" f.identify
+"Destroy Window" f.destroy
+"Focus on Window" f.focus
+"Focus on Root" f.unfocus
+}
+
+menu "Pref_menu"
+{
+"Preferences" f.title
+"Bell Loud" !"xset b 75&"
+"Bell Normal" !"xset b 50&"
+"Bell Quiet" !"xset b 25&"
+"Bell Off" !"xset b off&"
+"Mouse Fast" !"xset m 5 1&"
+"Mouse Normal" !"xset m 3 1&"
+"Mouse Slow" !"xset m 1 1&"
+"Screen Saver" f.menu "SSaver"
+}
+
+
+menu "SSaver"
+{
+"Screen Saver" f.title
+"Blank" !"/usr/bin/X11/xset s blank -display $DISPLAY &"
+"No Blank" !"/usr/bin/X11/xset s noblank -display $DISPLAY &"
+"Saver 2 Sec." !"/usr/bin/X11/xset s 2 2 -display $DISPLAY &"
+"Saver 2 Min." !"/usr/bin/X11/xset s 120 120 -display $DISPLAY &"
+"Saver 10 Min." !"/usr/bin/X11/xset s 600 600 -display $DISPLAY &"
+}
+
+menu "window-ops"
+{
+"Window Ops" f.title
+"Iconify" f.iconify
+"Refresh Window" f.winrefresh
+"Move Window" f.move
+"Resize Window" f.resize
+"Hide Window" f.lower
+"Expose Window" f.raise
+"Destroy Window" f.destroy
+"Delete Window" f.delete
+"Save" f.saveyourself
+}
diff --git a/src/add_window.c b/src/add_window.c
new file mode 100644
index 0000000..8a2059a
--- /dev/null
+++ b/src/add_window.c
@@ -0,0 +1,1629 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989,1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/**********************************************************************
+ *
+ * $Xorg: add_window.c,v 1.5 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Add a new window, put the titlbar and other stuff around
+ * the window
+ *
+ * 31-Mar-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include <X11/Xatom.h>
+#include "add_window.h"
+#include "util.h"
+#include "resize.h"
+#include "parse.h"
+#include "list.h"
+#include "events.h"
+#include "menus.h"
+#include "screen.h"
+#include "iconmgr.h"
+
+#define gray_width 2
+#define gray_height 2
+static char gray_bits[] = {
+ 0x02, 0x01};
+
+int AddingX;
+int AddingY;
+int AddingW;
+int AddingH;
+
+static int PlaceX = 50;
+static int PlaceY = 50;
+static void CreateWindowTitlebarButtons();
+
+char NoName[] = "Untitled"; /* name if no name is specified */
+
+
+/************************************************************************
+ *
+ * Procedure:
+ * GetGravityOffsets - map gravity to (x,y) offset signs for adding
+ * to x and y when window is mapped to get proper placement.
+ *
+ ************************************************************************
+ */
+
+GetGravityOffsets (tmp, xp, yp)
+ TwmWindow *tmp; /* window from which to get gravity */
+ int *xp, *yp; /* return values */
+{
+ static struct _gravity_offset {
+ int x, y;
+ } gravity_offsets[11] = {
+ { 0, 0 }, /* ForgetGravity */
+ { -1, -1 }, /* NorthWestGravity */
+ { 0, -1 }, /* NorthGravity */
+ { 1, -1 }, /* NorthEastGravity */
+ { -1, 0 }, /* WestGravity */
+ { 0, 0 }, /* CenterGravity */
+ { 1, 0 }, /* EastGravity */
+ { -1, 1 }, /* SouthWestGravity */
+ { 0, 1 }, /* SouthGravity */
+ { 1, 1 }, /* SouthEastGravity */
+ { 0, 0 }, /* StaticGravity */
+ };
+ register int g = ((tmp->hints.flags & PWinGravity)
+ ? tmp->hints.win_gravity : NorthWestGravity);
+
+ if (g < ForgetGravity || g > StaticGravity) {
+ *xp = *yp = 0;
+ } else {
+ *xp = gravity_offsets[g].x;
+ *yp = gravity_offsets[g].y;
+ }
+}
+
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddWindow - add a new window to the twm list
+ *
+ * Returned Value:
+ * (TwmWindow *) - pointer to the TwmWindow structure
+ *
+ * Inputs:
+ * w - the window id of the window to add
+ * iconm - flag to tell if this is an icon manager window
+ * iconp - pointer to icon manager struct
+ *
+ ***********************************************************************
+ */
+
+TwmWindow *
+AddWindow(w, iconm, iconp)
+Window w;
+int iconm;
+IconMgr *iconp;
+{
+ TwmWindow *tmp_win; /* new twm window structure */
+ int stat;
+ XEvent event;
+ unsigned long valuemask; /* mask for create windows */
+ XSetWindowAttributes attributes; /* attributes for create windows */
+ int width, height; /* tmp variable */
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytesafter;
+ int ask_user; /* don't know where to put the window */
+ int gravx, gravy; /* gravity signs for positioning */
+ int namelen;
+ int bw2;
+ short saved_x, saved_y, restore_icon_x, restore_icon_y;
+ unsigned short saved_width, saved_height;
+ Bool restore_iconified = 0;
+ Bool restore_icon_info_present = 0;
+ int restoredFromPrevSession;
+ Bool width_ever_changed_by_user;
+ Bool height_ever_changed_by_user;
+
+#ifdef DEBUG
+ fprintf(stderr, "AddWindow: w = 0x%x\n", w);
+#endif
+
+ /* allocate space for the twm window */
+ tmp_win = (TwmWindow *)calloc(1, sizeof(TwmWindow));
+ if (tmp_win == 0)
+ {
+ fprintf (stderr, "%s: Unable to allocate memory to manage window ID %lx.\n",
+ ProgramName, w);
+ return NULL;
+ }
+ tmp_win->w = w;
+ tmp_win->zoomed = ZOOM_NONE;
+ tmp_win->iconmgr = iconm;
+ tmp_win->iconmgrp = iconp;
+ tmp_win->cmaps.number_cwins = 0;
+
+ XSelectInput(dpy, tmp_win->w, PropertyChangeMask);
+
+ XGetWindowAttributes(dpy, tmp_win->w, &tmp_win->attr);
+
+ XFetchName(dpy, tmp_win->w, &tmp_win->name);
+ tmp_win->class = NoClass;
+ XGetClassHint(dpy, tmp_win->w, &tmp_win->class);
+ FetchWmProtocols (tmp_win);
+ FetchWmColormapWindows (tmp_win);
+
+ if (GetWindowConfig (tmp_win,
+ &saved_x, &saved_y, &saved_width, &saved_height,
+ &restore_iconified, &restore_icon_info_present,
+ &restore_icon_x, &restore_icon_y,
+ &width_ever_changed_by_user, &height_ever_changed_by_user))
+ {
+ tmp_win->attr.x = saved_x;
+ tmp_win->attr.y = saved_y;
+
+ tmp_win->widthEverChangedByUser = width_ever_changed_by_user;
+ tmp_win->heightEverChangedByUser = height_ever_changed_by_user;
+
+ if (width_ever_changed_by_user)
+ tmp_win->attr.width = saved_width;
+
+ if (height_ever_changed_by_user)
+ tmp_win->attr.height = saved_height;
+
+ restoredFromPrevSession = 1;
+ }
+ else
+ {
+ tmp_win->widthEverChangedByUser = False;
+ tmp_win->heightEverChangedByUser = False;
+
+ restoredFromPrevSession = 0;
+ }
+
+
+ /*
+ * do initial clip; should look at window gravity
+ */
+ if (tmp_win->attr.width > Scr->MaxWindowWidth)
+ tmp_win->attr.width = Scr->MaxWindowWidth;
+ if (tmp_win->attr.height > Scr->MaxWindowHeight)
+ tmp_win->attr.height = Scr->MaxWindowHeight;
+
+ tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w);
+
+ if (tmp_win->wmhints)
+ {
+ if (restore_iconified)
+ {
+ tmp_win->wmhints->initial_state = IconicState;
+ tmp_win->wmhints->flags |= StateHint;
+ }
+
+ if (restore_icon_info_present)
+ {
+ tmp_win->wmhints->icon_x = restore_icon_x;
+ tmp_win->wmhints->icon_y = restore_icon_y;
+ tmp_win->wmhints->flags |= IconPositionHint;
+ }
+ }
+
+ if (tmp_win->wmhints && (tmp_win->wmhints->flags & WindowGroupHint))
+ tmp_win->group = tmp_win->wmhints->window_group;
+ else
+ tmp_win->group = tmp_win->w/* NULL */;
+
+ /*
+ * The July 27, 1988 draft of the ICCCM ignores the size and position
+ * fields in the WM_NORMAL_HINTS property.
+ */
+
+ tmp_win->transient = Transient(tmp_win->w, &tmp_win->transientfor);
+
+ tmp_win->nameChanged = 0;
+ if (tmp_win->name == NULL)
+ tmp_win->name = NoName;
+ if (tmp_win->class.res_name == NULL)
+ tmp_win->class.res_name = NoName;
+ if (tmp_win->class.res_class == NULL)
+ tmp_win->class.res_class = NoName;
+
+ tmp_win->full_name = tmp_win->name;
+ namelen = strlen (tmp_win->name);
+
+ tmp_win->highlight = Scr->Highlight &&
+ (!(short)(int) LookInList(Scr->NoHighlight, tmp_win->full_name,
+ &tmp_win->class));
+
+ tmp_win->stackmode = Scr->StackMode &&
+ (!(short)(int) LookInList(Scr->NoStackModeL, tmp_win->full_name,
+ &tmp_win->class));
+
+ tmp_win->titlehighlight = Scr->TitleHighlight &&
+ (!(short)(int) LookInList(Scr->NoTitleHighlight, tmp_win->full_name,
+ &tmp_win->class));
+
+ tmp_win->auto_raise = (short)(int) LookInList(Scr->AutoRaise,
+ tmp_win->full_name,
+ &tmp_win->class);
+ if (tmp_win->auto_raise) Scr->NumAutoRaises++;
+ tmp_win->iconify_by_unmapping = Scr->IconifyByUnmapping;
+ if (Scr->IconifyByUnmapping)
+ {
+ tmp_win->iconify_by_unmapping = iconm ? FALSE :
+ !(short)(int) LookInList(Scr->DontIconify, tmp_win->full_name,
+ &tmp_win->class);
+ }
+ tmp_win->iconify_by_unmapping |=
+ (short)(int) LookInList(Scr->IconifyByUn, tmp_win->full_name,
+ &tmp_win->class);
+
+ if (LookInList(Scr->WindowRingL, tmp_win->full_name, &tmp_win->class)) {
+ if (Scr->Ring) {
+ tmp_win->ring.next = Scr->Ring->ring.next;
+ if (Scr->Ring->ring.next->ring.prev)
+ Scr->Ring->ring.next->ring.prev = tmp_win;
+ Scr->Ring->ring.next = tmp_win;
+ tmp_win->ring.prev = Scr->Ring;
+ } else {
+ tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win;
+ }
+ } else
+ tmp_win->ring.next = tmp_win->ring.prev = NULL;
+ tmp_win->ring.cursor_valid = False;
+
+ tmp_win->squeeze_info = NULL;
+ /*
+ * get the squeeze information; note that this does not have to be freed
+ * since it is coming from the screen list
+ */
+ if (HasShape) {
+ if (!LookInList (Scr->DontSqueezeTitleL, tmp_win->full_name,
+ &tmp_win->class)) {
+ tmp_win->squeeze_info = (SqueezeInfo *)
+ LookInList (Scr->SqueezeTitleL, tmp_win->full_name,
+ &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;
+ }
+ }
+ }
+
+ tmp_win->old_bw = tmp_win->attr.border_width;
+
+ if (Scr->ClientBorderWidth) {
+ tmp_win->frame_bw = tmp_win->old_bw;
+ } else {
+ tmp_win->frame_bw = Scr->BorderWidth;
+ }
+ bw2 = tmp_win->frame_bw * 2;
+
+ tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw;
+ if (Scr->NoTitlebar)
+ tmp_win->title_height = 0;
+ if (LookInList(Scr->MakeTitle, tmp_win->full_name, &tmp_win->class))
+ tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw;
+ if (LookInList(Scr->NoTitle, tmp_win->full_name, &tmp_win->class))
+ tmp_win->title_height = 0;
+
+ /* if it is a transient window, don't put a title on it */
+ if (tmp_win->transient && !Scr->DecorateTransients)
+ tmp_win->title_height = 0;
+
+ if (LookInList(Scr->StartIconified, tmp_win->full_name, &tmp_win->class))
+ {
+ if (!tmp_win->wmhints)
+ {
+ tmp_win->wmhints = (XWMHints *)malloc(sizeof(XWMHints));
+ tmp_win->wmhints->flags = 0;
+ }
+ tmp_win->wmhints->initial_state = IconicState;
+ tmp_win->wmhints->flags |= StateHint;
+ }
+
+ GetWindowSizeHints (tmp_win);
+
+ if (restoredFromPrevSession)
+ {
+ /*
+ * When restoring window positions from the previous session,
+ * we always use NorthWest gravity.
+ */
+
+ gravx = gravy = -1;
+ }
+ else
+ {
+ GetGravityOffsets (tmp_win, &gravx, &gravy);
+ }
+
+ /*
+ * Don't bother user if:
+ *
+ * o the window is a transient, or
+ *
+ * o a USPosition was requested, or
+ *
+ * o a PPosition was requested and UsePPosition is ON or
+ * NON_ZERO if the window is at other than (0,0)
+ */
+ ask_user = TRUE;
+ if (tmp_win->transient ||
+ (tmp_win->hints.flags & USPosition) ||
+ ((tmp_win->hints.flags & PPosition) && Scr->UsePPosition &&
+ (Scr->UsePPosition == PPOS_ON ||
+ tmp_win->attr.x != 0 || tmp_win->attr.y != 0)))
+ ask_user = FALSE;
+
+ /*
+ * do any prompting for position
+ */
+ if (HandlingEvents && ask_user && !restoredFromPrevSession) {
+ if (Scr->RandomPlacement) { /* just stick it somewhere */
+ if ((PlaceX + tmp_win->attr.width) > Scr->MyDisplayWidth)
+ PlaceX = 50;
+ if ((PlaceY + tmp_win->attr.height) > Scr->MyDisplayHeight)
+ PlaceY = 50;
+
+ tmp_win->attr.x = PlaceX;
+ tmp_win->attr.y = PlaceY;
+ PlaceX += 30;
+ PlaceY += 30;
+ } else { /* else prompt */
+ if (!(tmp_win->wmhints && tmp_win->wmhints->flags & StateHint &&
+ tmp_win->wmhints->initial_state == IconicState))
+ {
+ Bool firsttime = True;
+
+ /* better wait until all the mouse buttons have been
+ * released.
+ */
+ while (TRUE)
+ {
+ XUngrabServer(dpy);
+ XSync(dpy, 0);
+ XGrabServer(dpy);
+
+ JunkMask = 0;
+ if (!XQueryPointer (dpy, Scr->Root, &JunkRoot,
+ &JunkChild, &JunkX, &JunkY,
+ &AddingX, &AddingY, &JunkMask))
+ JunkMask = 0;
+
+ JunkMask &= (Button1Mask | Button2Mask | Button3Mask |
+ Button4Mask | Button5Mask);
+
+ /*
+ * watch out for changing screens
+ */
+ if (firsttime) {
+ if (JunkRoot != Scr->Root) {
+ register int scrnum;
+
+ for (scrnum = 0; scrnum < NumScreens; scrnum++) {
+ if (JunkRoot == RootWindow (dpy, scrnum)) break;
+ }
+
+ if (scrnum != NumScreens) PreviousScreen = scrnum;
+ }
+ firsttime = False;
+ }
+
+ /*
+ * wait for buttons to come up; yuck
+ */
+ if (JunkMask != 0) continue;
+
+ /*
+ * this will cause a warp to the indicated root
+ */
+ stat = XGrabPointer(dpy, Scr->Root, False,
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | PointerMotionHintMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, UpperLeftCursor, CurrentTime);
+
+ if (stat == GrabSuccess)
+ break;
+ }
+
+ width = (SIZE_HINDENT + XTextWidth (Scr->SizeFont.font,
+ tmp_win->name, namelen));
+ height = Scr->SizeFont.height + SIZE_VINDENT * 2;
+
+ XResizeWindow (dpy, Scr->SizeWindow, width + SIZE_HINDENT, height);
+ XMapRaised(dpy, Scr->SizeWindow);
+ InstallRootColormap();
+
+ FBF(Scr->DefaultC.fore, Scr->DefaultC.back,
+ Scr->SizeFont.font->fid);
+ XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC,
+ SIZE_HINDENT,
+ SIZE_VINDENT + Scr->SizeFont.font->ascent,
+ tmp_win->name, namelen);
+
+ AddingW = tmp_win->attr.width + bw2;
+ AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
+
+ if (Scr->DontMoveOff) {
+ /*
+ * Make sure the initial outline comes up on the screen.
+ */
+ if (AddingX < 0)
+ AddingX = 0;
+ if (AddingX > Scr->MyDisplayWidth - AddingW)
+ AddingX = Scr->MyDisplayWidth - AddingW;
+
+ if (AddingY < 0)
+ AddingY = 0;
+ if (AddingY > Scr->MyDisplayHeight - AddingH)
+ AddingY = Scr->MyDisplayHeight - AddingH;
+ }
+
+ MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
+ tmp_win->frame_bw, tmp_win->title_height);
+
+ while (TRUE)
+ {
+ XMaskEvent(dpy, ButtonPressMask | PointerMotionMask, &event);
+
+ if (Event.type == MotionNotify) {
+ /* discard any extra motion events before a release */
+ while(XCheckMaskEvent(dpy,
+ ButtonMotionMask | ButtonPressMask, &Event))
+ if (Event.type == ButtonPress)
+ break;
+ }
+
+ if (event.type == ButtonPress) {
+ AddingX = event.xbutton.x_root;
+ AddingY = event.xbutton.y_root;
+
+ /* DontMoveOff prohibits user form off-screen placement */
+ if (Scr->DontMoveOff)
+ {
+ int AddingR, AddingB;
+
+ AddingR = AddingX + AddingW;
+ AddingB = AddingY + AddingH;
+
+ if (AddingX < 0)
+ AddingX = 0;
+ if (AddingR > Scr->MyDisplayWidth)
+ AddingX = Scr->MyDisplayWidth - AddingW;
+
+ if (AddingY < 0)
+ AddingY = 0;
+ if (AddingB > Scr->MyDisplayHeight)
+ AddingY = Scr->MyDisplayHeight - AddingH;
+
+ }
+ break;
+ }
+
+ if (event.type != MotionNotify) {
+ continue;
+ }
+
+ XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
+ &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
+
+ if (Scr->DontMoveOff)
+ {
+ int AddingR, AddingB;
+
+ AddingR = AddingX + AddingW;
+ AddingB = AddingY + AddingH;
+
+ if (AddingX < 0)
+ AddingX = 0;
+ if (AddingR > Scr->MyDisplayWidth)
+ AddingX = Scr->MyDisplayWidth - AddingW;
+
+ if (AddingY < 0)
+ AddingY = 0;
+ if (AddingB > Scr->MyDisplayHeight)
+ AddingY = Scr->MyDisplayHeight - AddingH;
+ }
+
+ MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
+ tmp_win->frame_bw, tmp_win->title_height);
+
+ }
+
+ if (event.xbutton.button == Button2) {
+ int lastx, lasty;
+
+ Scr->SizeStringOffset = width +
+ XTextWidth(Scr->SizeFont.font, ": ", 2);
+ XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset +
+ Scr->SizeStringWidth, height);
+ XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC, width,
+ SIZE_VINDENT + Scr->SizeFont.font->ascent,
+ ": ", 2);
+ if (0/*Scr->AutoRelativeResize*/) {
+ int dx = (tmp_win->attr.width / 4);
+ int dy = (tmp_win->attr.height / 4);
+
+#define HALF_AVE_CURSOR_SIZE 8 /* so that it is visible */
+ 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
+ dx += (tmp_win->frame_bw + 1);
+ dy += (bw2 + tmp_win->title_height + 1);
+ if (AddingX + dx >= Scr->MyDisplayWidth)
+ dx = Scr->MyDisplayWidth - AddingX - 1;
+ if (AddingY + dy >= Scr->MyDisplayHeight)
+ dy = Scr->MyDisplayHeight - AddingY - 1;
+ if (dx > 0 && dy > 0)
+ XWarpPointer (dpy, None, None, 0, 0, 0, 0, dx, dy);
+ } else {
+ XWarpPointer (dpy, None, Scr->Root, 0, 0, 0, 0,
+ AddingX + AddingW/2, AddingY + AddingH/2);
+ }
+ AddStartResize(tmp_win, AddingX, AddingY, AddingW, AddingH);
+
+ lastx = -10000;
+ lasty = -10000;
+ while (TRUE)
+ {
+ XMaskEvent(dpy,
+ ButtonReleaseMask | ButtonMotionMask, &event);
+
+ if (Event.type == MotionNotify) {
+ /* discard any extra motion events before a release */
+ while(XCheckMaskEvent(dpy,
+ ButtonMotionMask | ButtonReleaseMask, &Event))
+ if (Event.type == ButtonRelease)
+ break;
+ }
+
+ if (event.type == ButtonRelease)
+ {
+ AddEndResize(tmp_win);
+ break;
+ }
+
+ if (event.type != MotionNotify) {
+ continue;
+ }
+
+ /*
+ * XXX - if we are going to do a loop, we ought to consider
+ * using multiple GXxor lines so that we don't need to
+ * grab the server.
+ */
+ XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
+ &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
+
+ if (lastx != AddingX || lasty != AddingY)
+ {
+ DoResize(AddingX, AddingY, tmp_win);
+
+ lastx = AddingX;
+ lasty = AddingY;
+ }
+
+ }
+ }
+ else if (event.xbutton.button == Button3)
+ {
+ int maxw = Scr->MyDisplayWidth - AddingX - bw2;
+ int maxh = Scr->MyDisplayHeight - AddingY - bw2;
+
+ /*
+ * Make window go to bottom of screen, and clip to right edge.
+ * This is useful when popping up large windows and fixed
+ * column text windows.
+ */
+ if (AddingW > maxw) AddingW = maxw;
+ AddingH = maxh;
+
+ ConstrainSize (tmp_win, &AddingW, &AddingH); /* w/o borders */
+ AddingW += bw2;
+ AddingH += bw2;
+ }
+ else
+ {
+ XMaskEvent(dpy, ButtonReleaseMask, &event);
+ }
+
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+ XUnmapWindow(dpy, Scr->SizeWindow);
+ UninstallRootColormap();
+ XUngrabPointer(dpy, CurrentTime);
+
+ tmp_win->attr.x = AddingX;
+ tmp_win->attr.y = AddingY + tmp_win->title_height;
+ tmp_win->attr.width = AddingW - bw2;
+ tmp_win->attr.height = AddingH - tmp_win->title_height - 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;
+ }
+
+
+#ifdef DEBUG
+ fprintf(stderr, " position window %d, %d %dx%d\n",
+ tmp_win->attr.x,
+ tmp_win->attr.y,
+ tmp_win->attr.width,
+ tmp_win->attr.height);
+#endif
+
+ if (!Scr->ClientBorderWidth) { /* need to adjust for twm borders */
+ int delta = tmp_win->attr.border_width - tmp_win->frame_bw;
+ tmp_win->attr.x += gravx * delta;
+ tmp_win->attr.y += gravy * delta;
+ }
+
+ tmp_win->title_width = tmp_win->attr.width;
+
+ if (tmp_win->old_bw) XSetWindowBorderWidth (dpy, tmp_win->w, 0);
+
+ tmp_win->name_width = XTextWidth(Scr->TitleBarFont.font, tmp_win->name,
+ namelen);
+
+ if (XGetWindowProperty (dpy, tmp_win->w, XA_WM_ICON_NAME, 0L, 200L, False,
+ XA_STRING, &actual_type, &actual_format, &nitems,
+ &bytesafter,(unsigned char **)&tmp_win->icon_name))
+ tmp_win->icon_name = tmp_win->name;
+
+ if (tmp_win->icon_name == NULL)
+ tmp_win->icon_name = tmp_win->name;
+
+ tmp_win->iconified = FALSE;
+ tmp_win->icon = FALSE;
+ tmp_win->icon_on = FALSE;
+
+ XGrabServer(dpy);
+
+ /*
+ * Make sure the client window still exists. We don't want to leave an
+ * orphan frame window if it doesn't. Since we now have the server
+ * grabbed, the window can't disappear later without having been
+ * reparented, so we'll get a DestroyNotify for it. We won't have
+ * gotten one for anything up to here, however.
+ */
+ if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY,
+ &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0)
+ {
+ free((char *)tmp_win);
+ XUngrabServer(dpy);
+ return(NULL);
+ }
+
+ /* add the window into the twm list */
+ tmp_win->next = Scr->TwmRoot.next;
+ if (Scr->TwmRoot.next != NULL)
+ Scr->TwmRoot.next->prev = tmp_win;
+ tmp_win->prev = &Scr->TwmRoot;
+ Scr->TwmRoot.next = tmp_win;
+
+ /* get all the colors for the window */
+
+ tmp_win->border = Scr->BorderColor;
+ tmp_win->icon_border = Scr->IconBorderColor;
+ tmp_win->border_tile.fore = Scr->BorderTileC.fore;
+ tmp_win->border_tile.back = Scr->BorderTileC.back;
+ tmp_win->title.fore = Scr->TitleC.fore;
+ tmp_win->title.back = Scr->TitleC.back;
+ tmp_win->iconc.fore = Scr->IconC.fore;
+ tmp_win->iconc.back = Scr->IconC.back;
+
+ GetColorFromList(Scr->BorderColorL, tmp_win->full_name, &tmp_win->class,
+ &tmp_win->border);
+ GetColorFromList(Scr->IconBorderColorL, tmp_win->full_name, &tmp_win->class,
+ &tmp_win->icon_border);
+ GetColorFromList(Scr->BorderTileForegroundL, tmp_win->full_name,
+ &tmp_win->class, &tmp_win->border_tile.fore);
+ GetColorFromList(Scr->BorderTileBackgroundL, tmp_win->full_name,
+ &tmp_win->class, &tmp_win->border_tile.back);
+ GetColorFromList(Scr->TitleForegroundL, tmp_win->full_name, &tmp_win->class,
+ &tmp_win->title.fore);
+ GetColorFromList(Scr->TitleBackgroundL, tmp_win->full_name, &tmp_win->class,
+ &tmp_win->title.back);
+ GetColorFromList(Scr->IconForegroundL, tmp_win->full_name, &tmp_win->class,
+ &tmp_win->iconc.fore);
+ GetColorFromList(Scr->IconBackgroundL, tmp_win->full_name, &tmp_win->class,
+ &tmp_win->iconc.back);
+
+
+ /* create windows */
+
+ 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_width = tmp_win->attr.width;
+ tmp_win->frame_height = tmp_win->attr.height + tmp_win->title_height;
+
+ valuemask = CWBackPixmap | CWBorderPixel | CWCursor | CWEventMask;
+ attributes.background_pixmap = None;
+ attributes.border_pixel = tmp_win->border;
+ attributes.cursor = Scr->FrameCursor;
+ attributes.event_mask = (SubstructureRedirectMask |
+ ButtonPressMask | ButtonReleaseMask |
+ EnterWindowMask | LeaveWindowMask);
+ if (tmp_win->attr.save_under) {
+ attributes.save_under = True;
+ valuemask |= CWSaveUnder;
+ }
+
+ tmp_win->frame = XCreateWindow (dpy, Scr->Root, tmp_win->frame_x,
+ tmp_win->frame_y,
+ (unsigned int) tmp_win->frame_width,
+ (unsigned int) tmp_win->frame_height,
+ (unsigned int) tmp_win->frame_bw,
+ Scr->d_depth,
+ (unsigned int) CopyFromParent,
+ Scr->d_visual, valuemask, &attributes);
+
+ if (tmp_win->title_height)
+ {
+ valuemask = (CWEventMask | CWBorderPixel | CWBackPixel);
+ attributes.event_mask = (KeyPressMask | ButtonPressMask |
+ ButtonReleaseMask | ExposureMask);
+ attributes.border_pixel = tmp_win->border;
+ attributes.background_pixel = tmp_win->title.back;
+ tmp_win->title_w = XCreateWindow (dpy, tmp_win->frame,
+ -tmp_win->frame_bw,
+ -tmp_win->frame_bw,
+ (unsigned int) tmp_win->attr.width,
+ (unsigned int) Scr->TitleHeight,
+ (unsigned int) tmp_win->frame_bw,
+ Scr->d_depth,
+ (unsigned int) CopyFromParent,
+ Scr->d_visual, valuemask,
+ &attributes);
+ }
+ else {
+ tmp_win->title_w = 0;
+ tmp_win->squeeze_info = NULL;
+ }
+
+ if (tmp_win->highlight)
+ {
+ tmp_win->gray = XCreatePixmapFromBitmapData(dpy, Scr->Root,
+ gray_bits, gray_width, gray_height,
+ tmp_win->border_tile.fore, tmp_win->border_tile.back,
+ Scr->d_depth);
+
+ SetBorder (tmp_win, False);
+ }
+ else
+ tmp_win->gray = None;
+
+
+ if (tmp_win->title_w) {
+ CreateWindowTitlebarButtons (tmp_win);
+ ComputeTitleLocation (tmp_win);
+ XMoveWindow (dpy, tmp_win->title_w,
+ tmp_win->title_x, tmp_win->title_y);
+ XDefineCursor(dpy, tmp_win->title_w, Scr->TitleCursor);
+ }
+
+ valuemask = (CWEventMask | CWDontPropagate);
+ attributes.event_mask = (StructureNotifyMask | PropertyChangeMask |
+ ColormapChangeMask | VisibilityChangeMask |
+ EnterWindowMask | LeaveWindowMask);
+ attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
+ XChangeWindowAttributes (dpy, tmp_win->w, valuemask, &attributes);
+
+ if (HasShape)
+ XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask);
+
+ if (tmp_win->title_w) {
+ XMapWindow (dpy, tmp_win->title_w);
+ }
+
+ if (HasShape) {
+ int xws, yws, xbs, ybs;
+ unsigned wws, hws, wbs, hbs;
+ int boundingShaped, clipShaped;
+
+ XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask);
+ XShapeQueryExtents (dpy, tmp_win->w,
+ &boundingShaped, &xws, &yws, &wws, &hws,
+ &clipShaped, &xbs, &ybs, &wbs, &hbs);
+ tmp_win->wShaped = boundingShaped;
+ }
+
+ if (!tmp_win->iconmgr)
+ XAddToSaveSet(dpy, tmp_win->w);
+
+ XReparentWindow(dpy, tmp_win->w, tmp_win->frame, 0, tmp_win->title_height);
+ /*
+ * Reparenting generates an UnmapNotify event, followed by a MapNotify.
+ * Set the map state to FALSE to prevent a transition back to
+ * WithdrawnState in HandleUnmapNotify. Map state gets set correctly
+ * again in HandleMapNotify.
+ */
+ tmp_win->mapped = FALSE;
+
+ SetupFrame (tmp_win, tmp_win->frame_x, tmp_win->frame_y,
+ tmp_win->frame_width, tmp_win->frame_height, -1, True);
+
+ /* wait until the window is iconified and the icon window is mapped
+ * before creating the icon window
+ */
+ tmp_win->icon_w = (Window) 0;
+
+ if (!tmp_win->iconmgr)
+ {
+ GrabButtons(tmp_win);
+ GrabKeys(tmp_win);
+ }
+
+ (void) AddIconManager(tmp_win);
+
+ XSaveContext(dpy, tmp_win->w, TwmContext, (caddr_t) tmp_win);
+ XSaveContext(dpy, tmp_win->w, ScreenContext, (caddr_t) Scr);
+ XSaveContext(dpy, tmp_win->frame, TwmContext, (caddr_t) tmp_win);
+ XSaveContext(dpy, tmp_win->frame, ScreenContext, (caddr_t) Scr);
+ if (tmp_win->title_height)
+ {
+ int i;
+ int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
+
+ XSaveContext(dpy, tmp_win->title_w, TwmContext, (caddr_t) tmp_win);
+ XSaveContext(dpy, tmp_win->title_w, ScreenContext, (caddr_t) Scr);
+ for (i = 0; i < nb; i++) {
+ XSaveContext(dpy, tmp_win->titlebuttons[i].window, TwmContext,
+ (caddr_t) tmp_win);
+ XSaveContext(dpy, tmp_win->titlebuttons[i].window, ScreenContext,
+ (caddr_t) Scr);
+ }
+ if (tmp_win->hilite_w)
+ {
+ XSaveContext(dpy, tmp_win->hilite_w, TwmContext, (caddr_t)tmp_win);
+ XSaveContext(dpy, tmp_win->hilite_w, ScreenContext, (caddr_t)Scr);
+ }
+ }
+
+ XUngrabServer(dpy);
+
+ /* if we were in the middle of a menu activated function, regrab
+ * the pointer
+ */
+ if (RootFunction)
+ ReGrab();
+
+ return (tmp_win);
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * MappedNotOverride - checks to see if we should really
+ * put a twm frame on the window
+ *
+ * Returned Value:
+ * TRUE - go ahead and frame the window
+ * FALSE - don't frame the window
+ *
+ * Inputs:
+ * w - the window to check
+ *
+ ***********************************************************************
+ */
+
+int
+MappedNotOverride(w)
+ Window w;
+{
+ XWindowAttributes wa;
+
+ XGetWindowAttributes(dpy, w, &wa);
+ return ((wa.map_state != IsUnmapped) && (wa.override_redirect != True));
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddDefaultBindings - attach default bindings so that naive users
+ * don't get messed up if they provide a minimal twmrc.
+ */
+static void do_add_binding (button, context, modifier, func)
+ int button, context, modifier;
+ int func;
+{
+ MouseButton *mb = &Scr->Mouse[button][context][modifier];
+
+ if (mb->func) return; /* already defined */
+
+ mb->func = func;
+ mb->item = NULL;
+}
+
+AddDefaultBindings ()
+{
+ /*
+ * The bindings are stored in Scr->Mouse, indexed by
+ * Mouse[button_number][C_context][modifier].
+ */
+
+#define NoModifierMask 0
+
+ do_add_binding (Button1, C_TITLE, NoModifierMask, F_MOVE);
+ do_add_binding (Button1, C_ICON, NoModifierMask, F_ICONIFY);
+ do_add_binding (Button1, C_ICONMGR, NoModifierMask, F_ICONIFY);
+
+ do_add_binding (Button2, C_TITLE, NoModifierMask, F_RAISELOWER);
+ do_add_binding (Button2, C_ICON, NoModifierMask, F_ICONIFY);
+ do_add_binding (Button2, C_ICONMGR, NoModifierMask, F_ICONIFY);
+
+#undef NoModifierMask
+}
+
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * GrabButtons - grab needed buttons for the window
+ *
+ * Inputs:
+ * tmp_win - the twm window structure to use
+ *
+ ***********************************************************************
+ */
+
+void
+GrabButtons(tmp_win)
+TwmWindow *tmp_win;
+{
+ int i, j;
+
+ for (i = 0; i < MAX_BUTTONS+1; i++)
+ {
+ for (j = 0; j < MOD_SIZE; j++)
+ {
+ if (Scr->Mouse[i][C_WINDOW][j].func != 0)
+ {
+ /* twm used to do this grab on the application main window,
+ * tmp_win->w . This was not ICCCM complient and was changed.
+ */
+ XGrabButton(dpy, i, j, tmp_win->frame,
+ True, ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync, None,
+ Scr->FrameCursor);
+ }
+ }
+ }
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * GrabKeys - grab needed keys for the window
+ *
+ * Inputs:
+ * tmp_win - the twm window structure to use
+ *
+ ***********************************************************************
+ */
+
+void
+GrabKeys(tmp_win)
+TwmWindow *tmp_win;
+{
+ FuncKey *tmp;
+ IconMgr *p;
+
+ for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
+ {
+ switch (tmp->cont)
+ {
+ case C_WINDOW:
+ XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w, True,
+ GrabModeAsync, GrabModeAsync);
+ break;
+
+ case C_ICON:
+ if (tmp_win->icon_w)
+ XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->icon_w, True,
+ GrabModeAsync, GrabModeAsync);
+
+ case C_TITLE:
+ if (tmp_win->title_w)
+ XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->title_w, True,
+ GrabModeAsync, GrabModeAsync);
+ break;
+
+ case C_NAME:
+ XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->w, True,
+ GrabModeAsync, GrabModeAsync);
+ if (tmp_win->icon_w)
+ XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->icon_w, True,
+ GrabModeAsync, GrabModeAsync);
+ if (tmp_win->title_w)
+ XGrabKey(dpy, tmp->keycode, tmp->mods, tmp_win->title_w, True,
+ GrabModeAsync, GrabModeAsync);
+ break;
+ /*
+ case C_ROOT:
+ XGrabKey(dpy, tmp->keycode, tmp->mods, Scr->Root, True,
+ GrabModeAsync, GrabModeAsync);
+ break;
+ */
+ }
+ }
+ for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
+ {
+ if (tmp->cont == C_ICONMGR && !Scr->NoIconManagers)
+ {
+ for (p = &Scr->iconmgr; p != NULL; p = p->next)
+ {
+ XUngrabKey(dpy, tmp->keycode, tmp->mods, p->twm_win->w);
+ }
+ }
+ }
+}
+
+static Window CreateHighlightWindow (tmp_win)
+ TwmWindow *tmp_win;
+{
+ XSetWindowAttributes attributes; /* attributes for create windows */
+ Pixmap pm = None;
+ GC gc;
+ XGCValues gcv;
+ unsigned long valuemask;
+ int h = (Scr->TitleHeight - 2 * Scr->FramePadding);
+ Window w;
+
+
+ /*
+ * If a special highlight pixmap was given, use that. Otherwise,
+ * use a nice, even gray pattern. The old horizontal lines look really
+ * awful on interlaced monitors (as well as resembling other looks a
+ * little bit too closely), but can be used by putting
+ *
+ * Pixmaps { TitleHighlight "hline2" }
+ *
+ * (or whatever the horizontal line bitmap is named) in the startup
+ * file. If all else fails, use the foreground color to look like a
+ * solid line.
+ */
+ if (!Scr->hilitePm) {
+ Scr->hilitePm = XCreateBitmapFromData (dpy, tmp_win->title_w,
+ gray_bits, gray_width,
+ gray_height);
+ Scr->hilite_pm_width = gray_width;
+ Scr->hilite_pm_height = gray_height;
+ }
+ if (Scr->hilitePm) {
+ pm = XCreatePixmap (dpy, tmp_win->title_w,
+ Scr->hilite_pm_width, Scr->hilite_pm_height,
+ Scr->d_depth);
+ gcv.foreground = tmp_win->title.fore;
+ gcv.background = tmp_win->title.back;
+ gcv.graphics_exposures = False;
+ gc = XCreateGC (dpy, pm,
+ (GCForeground|GCBackground|GCGraphicsExposures),
+ &gcv);
+ if (gc) {
+ XCopyPlane (dpy, Scr->hilitePm, pm, gc, 0, 0,
+ Scr->hilite_pm_width, Scr->hilite_pm_height,
+ 0, 0, 1);
+ XFreeGC (dpy, gc);
+ } else {
+ XFreePixmap (dpy, pm);
+ pm = None;
+ }
+ }
+ if (pm) {
+ valuemask = CWBackPixmap;
+ attributes.background_pixmap = pm;
+ } else {
+ valuemask = CWBackPixel;
+ attributes.background_pixel = tmp_win->title.fore;
+ }
+
+ 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);
+ if (pm) XFreePixmap (dpy, pm);
+ return w;
+}
+
+
+void ComputeCommonTitleOffsets ()
+{
+ int buttonwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
+
+ Scr->TBInfo.leftx = Scr->TBInfo.rightoff = Scr->FramePadding;
+ if (Scr->TBInfo.nleft > 0)
+ Scr->TBInfo.leftx += Scr->ButtonIndent;
+ Scr->TBInfo.titlex = (Scr->TBInfo.leftx +
+ (Scr->TBInfo.nleft * buttonwidth) - Scr->TBInfo.pad +
+ Scr->TitlePadding);
+ if (Scr->TBInfo.nright > 0)
+ Scr->TBInfo.rightoff += (Scr->ButtonIndent +
+ ((Scr->TBInfo.nright * buttonwidth) -
+ Scr->TBInfo.pad));
+ return;
+}
+
+void ComputeWindowTitleOffsets (tmp_win, width, squeeze)
+ TwmWindow *tmp_win;
+ Bool squeeze;
+{
+ tmp_win->highlightx = (Scr->TBInfo.titlex + tmp_win->name_width);
+ if (tmp_win->hilite_w || Scr->TBInfo.nright > 0)
+ tmp_win->highlightx += Scr->TitlePadding;
+ tmp_win->rightx = width - Scr->TBInfo.rightoff;
+ if (squeeze && tmp_win->squeeze_info) {
+ int rx = (tmp_win->highlightx +
+ (tmp_win->hilite_w
+ ? Scr->TBInfo.width * 2 : 0) +
+ (Scr->TBInfo.nright > 0 ? Scr->TitlePadding : 0) +
+ Scr->FramePadding);
+ if (rx < tmp_win->rightx) tmp_win->rightx = rx;
+ }
+ return;
+}
+
+
+/*
+ * ComputeTitleLocation - calculate the position of the title window; we need
+ * to take the frame_bw into account since we want (0,0) of the title window
+ * to line up with (0,0) of the frame window.
+ */
+void ComputeTitleLocation (tmp)
+ register TwmWindow *tmp;
+{
+ tmp->title_x = -tmp->frame_bw;
+ tmp->title_y = -tmp->frame_bw;
+
+ if (tmp->squeeze_info) {
+ register SqueezeInfo *si = tmp->squeeze_info;
+ int basex;
+ int maxwidth = tmp->frame_width;
+ int tw = tmp->title_width;
+
+ /*
+ * figure label base from squeeze info (justification fraction)
+ */
+ if (si->denom == 0) { /* num is pixel based */
+ if ((basex = si->num) == 0) { /* look for special cases */
+ switch (si->justify) {
+ case J_RIGHT:
+ basex = maxwidth;
+ break;
+ case J_CENTER:
+ basex = maxwidth / 2;
+ break;
+ }
+ }
+ } else { /* num/denom is fraction */
+ basex = ((si->num * maxwidth) / si->denom);
+ if (si->num < 0) basex += maxwidth;
+ }
+
+ /*
+ * adjust for left (nop), center, right justify and clip
+ */
+ switch (si->justify) {
+ case J_CENTER:
+ basex -= tw / 2;
+ break;
+ case J_RIGHT:
+ basex -= tw - 1;
+ break;
+ }
+ if (basex > maxwidth - tw + 1)
+ basex = maxwidth - tw + 1;
+ if (basex < 0) basex = 0;
+
+ tmp->title_x = basex - tmp->frame_bw;
+ }
+}
+
+
+static void CreateWindowTitlebarButtons (tmp_win)
+ TwmWindow *tmp_win;
+{
+ unsigned long valuemask; /* mask for create windows */
+ XSetWindowAttributes attributes; /* attributes for create windows */
+ int leftx, rightx, y;
+ TitleButton *tb;
+ int nb;
+
+ if (tmp_win->title_height == 0)
+ {
+ tmp_win->hilite_w = 0;
+ return;
+ }
+
+
+ /*
+ * 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);
+
+ leftx = y = Scr->TBInfo.leftx;
+ rightx = tmp_win->rightx;
+
+ attributes.win_gravity = NorthWestGravity;
+ attributes.background_pixel = tmp_win->title.back;
+ attributes.border_pixel = tmp_win->title.fore;
+ attributes.event_mask = (ButtonPressMask | ButtonReleaseMask |
+ ExposureMask);
+ attributes.cursor = Scr->ButtonCursor;
+ valuemask = (CWWinGravity | CWBackPixel | CWBorderPixel | CWEventMask |
+ CWCursor);
+
+ tmp_win->titlebuttons = NULL;
+ nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
+ if (nb > 0) {
+ tmp_win->titlebuttons = (TBWindow *) malloc (nb * sizeof(TBWindow));
+ if (!tmp_win->titlebuttons) {
+ fprintf (stderr, "%s: unable to allocate %d titlebuttons\n",
+ ProgramName, nb);
+ } else {
+ TBWindow *tbw;
+ int boxwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
+ unsigned int h = (Scr->TBInfo.width - Scr->TBInfo.border * 2);
+
+ for (tb = Scr->TBInfo.head, tbw = tmp_win->titlebuttons; tb;
+ tb = tb->next, tbw++) {
+ int x;
+ if (tb->rightside) {
+ x = rightx;
+ rightx += boxwidth;
+ 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,
+ (unsigned int) Scr->TBInfo.border,
+ 0, (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent,
+ valuemask, &attributes);
+ tbw->info = tb;
+ }
+ }
+ }
+
+ tmp_win->hilite_w = (tmp_win->titlehighlight
+ ? CreateHighlightWindow (tmp_win) : None);
+
+ XMapSubwindows(dpy, tmp_win->title_w);
+ if (tmp_win->hilite_w)
+ XUnmapWindow(dpy, tmp_win->hilite_w);
+ return;
+}
+
+
+SetHighlightPixmap (filename)
+ char *filename;
+{
+ Pixmap pm = GetBitmap (filename);
+
+ if (pm) {
+ if (Scr->hilitePm) {
+ XFreePixmap (dpy, Scr->hilitePm);
+ }
+ Scr->hilitePm = pm;
+ Scr->hilite_pm_width = JunkWidth;
+ Scr->hilite_pm_height = JunkHeight;
+ }
+}
+
+
+FetchWmProtocols (tmp)
+ TwmWindow *tmp;
+{
+ unsigned long flags = 0L;
+ Atom *protocols = NULL;
+ int n;
+
+ if (XGetWMProtocols (dpy, tmp->w, &protocols, &n)) {
+ register int i;
+ register Atom *ap;
+
+ for (i = 0, ap = protocols; i < n; i++, ap++) {
+ if (*ap == _XA_WM_TAKE_FOCUS) flags |= DoesWmTakeFocus;
+ if (*ap == _XA_WM_SAVE_YOURSELF) flags |= DoesWmSaveYourself;
+ if (*ap == _XA_WM_DELETE_WINDOW) flags |= DoesWmDeleteWindow;
+ }
+ if (protocols) XFree ((char *) protocols);
+ }
+ tmp->protocols = flags;
+}
+
+TwmColormap *
+CreateTwmColormap(c)
+ Colormap c;
+{
+ TwmColormap *cmap;
+ cmap = (TwmColormap *) malloc(sizeof(TwmColormap));
+ if (!cmap ||
+ XSaveContext(dpy, c, ColormapContext, (caddr_t) cmap)) {
+ if (cmap) free((char *) cmap);
+ return (NULL);
+ }
+ cmap->c = c;
+ cmap->state = 0;
+ cmap->install_req = 0;
+ cmap->w = None;
+ cmap->refcnt = 1;
+ return (cmap);
+}
+
+ColormapWindow *
+CreateColormapWindow(w, creating_parent, property_window)
+ Window w;
+ Bool creating_parent;
+ Bool property_window;
+{
+ ColormapWindow *cwin;
+ TwmColormap *cmap;
+ XWindowAttributes attributes;
+
+ cwin = (ColormapWindow *) malloc(sizeof(ColormapWindow));
+ if (cwin) {
+ if (!XGetWindowAttributes(dpy, w, &attributes) ||
+ XSaveContext(dpy, w, ColormapContext, (caddr_t) cwin)) {
+ free((char *) cwin);
+ return (NULL);
+ }
+
+ if (XFindContext(dpy, attributes.colormap, ColormapContext,
+ (caddr_t *)&cwin->colormap) == XCNOENT) {
+ cwin->colormap = cmap = CreateTwmColormap(attributes.colormap);
+ if (!cmap) {
+ XDeleteContext(dpy, w, ColormapContext);
+ free((char *) cwin);
+ return (NULL);
+ }
+ } else {
+ cwin->colormap->refcnt++;
+ }
+
+ cwin->w = w;
+ /*
+ * Assume that windows in colormap list are
+ * obscured if we are creating the parent window.
+ * Otherwise, we assume they are unobscured.
+ */
+ cwin->visibility = creating_parent ?
+ VisibilityPartiallyObscured : VisibilityUnobscured;
+ cwin->refcnt = 1;
+
+ /*
+ * If this is a ColormapWindow property window and we
+ * are not monitoring ColormapNotify or VisibilityNotify
+ * events, we need to.
+ */
+ if (property_window &&
+ (attributes.your_event_mask &
+ (ColormapChangeMask|VisibilityChangeMask)) !=
+ (ColormapChangeMask|VisibilityChangeMask)) {
+ XSelectInput(dpy, w, attributes.your_event_mask |
+ (ColormapChangeMask|VisibilityChangeMask));
+ }
+ }
+
+ return (cwin);
+}
+
+FetchWmColormapWindows (tmp)
+ TwmWindow *tmp;
+{
+ register int i, j;
+ Window *cmap_windows = NULL;
+ Bool can_free_cmap_windows = False;
+ int number_cmap_windows = 0;
+ ColormapWindow **cwins = NULL;
+ int previously_installed;
+ extern void free_cwins();
+
+ number_cmap_windows = 0;
+
+ if (/* SUPPRESS 560 */(previously_installed =
+ (Scr->cmapInfo.cmaps == &tmp->cmaps && tmp->cmaps.number_cwins))) {
+ cwins = tmp->cmaps.cwins;
+ for (i = 0; i < tmp->cmaps.number_cwins; i++)
+ cwins[i]->colormap->state = 0;
+ }
+
+ if (XGetWMColormapWindows (dpy, tmp->w, &cmap_windows,
+ &number_cmap_windows) &&
+ number_cmap_windows > 0) {
+
+ can_free_cmap_windows = False;
+ /*
+ * check if the top level is in the list, add to front if not
+ */
+ for (i = 0; i < number_cmap_windows; i++) {
+ if (cmap_windows[i] == tmp->w) break;
+ }
+ if (i == number_cmap_windows) { /* not in list */
+ Window *new_cmap_windows =
+ (Window *) malloc (sizeof(Window) * (number_cmap_windows + 1));
+
+ if (!new_cmap_windows) {
+ fprintf (stderr,
+ "%s: unable to allocate %d element colormap window array\n",
+ ProgramName, number_cmap_windows+1);
+ goto done;
+ }
+ new_cmap_windows[0] = tmp->w; /* add to front */
+ for (i = 0; i < number_cmap_windows; i++) { /* append rest */
+ new_cmap_windows[i+1] = cmap_windows[i];
+ }
+ XFree ((char *) cmap_windows);
+ can_free_cmap_windows = True; /* do not use XFree any more */
+ cmap_windows = new_cmap_windows;
+ number_cmap_windows++;
+ }
+
+ cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *) *
+ number_cmap_windows);
+ if (cwins) {
+ for (i = 0; i < number_cmap_windows; i++) {
+
+ /*
+ * Copy any existing entries into new list.
+ */
+ for (j = 0; j < tmp->cmaps.number_cwins; j++) {
+ if (tmp->cmaps.cwins[j]->w == cmap_windows[i]) {
+ cwins[i] = tmp->cmaps.cwins[j];
+ cwins[i]->refcnt++;
+ break;
+ }
+ }
+
+ /*
+ * If the colormap window is not being pointed by
+ * some other applications colormap window list,
+ * create a new entry.
+ */
+ if (j == tmp->cmaps.number_cwins) {
+ if (XFindContext(dpy, cmap_windows[i], ColormapContext,
+ (caddr_t *)&cwins[i]) == XCNOENT) {
+ if ((cwins[i] = CreateColormapWindow(cmap_windows[i],
+ (Bool) tmp->cmaps.number_cwins == 0,
+ True)) == NULL) {
+ int k;
+ for (k = i + 1; k < number_cmap_windows; k++)
+ cmap_windows[k-1] = cmap_windows[k];
+ i--;
+ number_cmap_windows--;
+ }
+ } else
+ cwins[i]->refcnt++;
+ }
+ }
+ }
+ }
+
+ /* No else here, in case we bailed out of clause above.
+ */
+ if (number_cmap_windows == 0) {
+
+ number_cmap_windows = 1;
+
+ cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *));
+ if (XFindContext(dpy, tmp->w, ColormapContext, (caddr_t *)&cwins[0]) ==
+ XCNOENT)
+ cwins[0] = CreateColormapWindow(tmp->w,
+ (Bool) tmp->cmaps.number_cwins == 0, False);
+ else
+ cwins[0]->refcnt++;
+ }
+
+ if (tmp->cmaps.number_cwins)
+ free_cwins(tmp);
+
+ tmp->cmaps.cwins = cwins;
+ tmp->cmaps.number_cwins = number_cmap_windows;
+ if (number_cmap_windows > 1)
+ tmp->cmaps.scoreboard =
+ (char *) calloc(1, ColormapsScoreboardLength(&tmp->cmaps));
+
+ if (previously_installed)
+ InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
+
+ done:
+ if (cmap_windows) {
+ if (can_free_cmap_windows)
+ free ((char *) cmap_windows);
+ else
+ XFree ((char *) cmap_windows);
+ }
+
+ return;
+}
+
+
+void GetWindowSizeHints (tmp)
+ TwmWindow *tmp;
+{
+ long supplied = 0;
+
+ if (!XGetWMNormalHints (dpy, tmp->w, &tmp->hints, &supplied))
+ tmp->hints.flags = 0;
+
+ if (tmp->hints.flags & PResizeInc) {
+ if (tmp->hints.width_inc == 0) tmp->hints.width_inc = 1;
+ if (tmp->hints.height_inc == 0) tmp->hints.height_inc = 1;
+ }
+
+ if (!(supplied & PWinGravity) && (tmp->hints.flags & USPosition)) {
+ static int gravs[] = { SouthEastGravity, SouthWestGravity,
+ NorthEastGravity, NorthWestGravity };
+ int right = tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw;
+ int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw;
+ tmp->hints.win_gravity =
+ gravs[((Scr->MyDisplayHeight - bottom < tmp->title_height) ? 0 : 2) |
+ ((Scr->MyDisplayWidth - right < tmp->title_height) ? 0 : 1)];
+ tmp->hints.flags |= PWinGravity;
+ }
+}
diff --git a/src/add_window.h b/src/add_window.h
new file mode 100644
index 0000000..36b4428
--- /dev/null
+++ b/src/add_window.h
@@ -0,0 +1,81 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/**********************************************************************
+ *
+ * $Xorg: add_window.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * AddWindow include file
+ *
+ * 31-Mar-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _ADD_WINDOW_
+#define _ADD_WINDOW_
+
+extern char NoName[];
+
+extern TwmWindow *AddWindow();
+extern int MappedNotOverride();
+extern void GrabButtons();
+extern void GrabKeys();
+extern void UngrabButtons();
+extern void UngrabKeys();
+extern void GetWindowSizeHints();
+extern int AddingX;
+extern int AddingY;
+extern int AddingW;
+extern int AddingH;
+
+#endif /* _ADD_WINDOW_ */
+
diff --git a/src/cursor.c b/src/cursor.c
new file mode 100644
index 0000000..713c236
--- /dev/null
+++ b/src/cursor.c
@@ -0,0 +1,175 @@
+/*
+ *
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ * */
+
+/***********************************************************************
+ *
+ * $Xorg: cursor.c,v 1.5 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * cursor creation code
+ *
+ * 05-Apr-89 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include <X11/Xos.h>
+#include "screen.h"
+#include "util.h"
+
+static struct _CursorName {
+ char *name;
+ unsigned int shape;
+ Cursor cursor;
+} cursor_names[] = {
+
+{"X_cursor", XC_X_cursor, None},
+{"arrow", XC_arrow, None},
+{"based_arrow_down", XC_based_arrow_down, None},
+{"based_arrow_up", XC_based_arrow_up, None},
+{"boat", XC_boat, None},
+{"bogosity", XC_bogosity, None},
+{"bottom_left_corner", XC_bottom_left_corner, None},
+{"bottom_right_corner", XC_bottom_right_corner, None},
+{"bottom_side", XC_bottom_side, None},
+{"bottom_tee", XC_bottom_tee, None},
+{"box_spiral", XC_box_spiral, None},
+{"center_ptr", XC_center_ptr, None},
+{"circle", XC_circle, None},
+{"clock", XC_clock, None},
+{"coffee_mug", XC_coffee_mug, None},
+{"cross", XC_cross, None},
+{"cross_reverse", XC_cross_reverse, None},
+{"crosshair", XC_crosshair, None},
+{"diamond_cross", XC_diamond_cross, None},
+{"dot", XC_dot, None},
+{"dotbox", XC_dotbox, None},
+{"double_arrow", XC_double_arrow, None},
+{"draft_large", XC_draft_large, None},
+{"draft_small", XC_draft_small, None},
+{"draped_box", XC_draped_box, None},
+{"exchange", XC_exchange, None},
+{"fleur", XC_fleur, None},
+{"gobbler", XC_gobbler, None},
+{"gumby", XC_gumby, None},
+{"hand1", XC_hand1, None},
+{"hand2", XC_hand2, None},
+{"heart", XC_heart, None},
+{"icon", XC_icon, None},
+{"iron_cross", XC_iron_cross, None},
+{"left_ptr", XC_left_ptr, None},
+{"left_side", XC_left_side, None},
+{"left_tee", XC_left_tee, None},
+{"leftbutton", XC_leftbutton, None},
+{"ll_angle", XC_ll_angle, None},
+{"lr_angle", XC_lr_angle, None},
+{"man", XC_man, None},
+{"middlebutton", XC_middlebutton, None},
+{"mouse", XC_mouse, None},
+{"pencil", XC_pencil, None},
+{"pirate", XC_pirate, None},
+{"plus", XC_plus, None},
+{"question_arrow", XC_question_arrow, None},
+{"right_ptr", XC_right_ptr, None},
+{"right_side", XC_right_side, None},
+{"right_tee", XC_right_tee, None},
+{"rightbutton", XC_rightbutton, None},
+{"rtl_logo", XC_rtl_logo, None},
+{"sailboat", XC_sailboat, None},
+{"sb_down_arrow", XC_sb_down_arrow, None},
+{"sb_h_double_arrow", XC_sb_h_double_arrow, None},
+{"sb_left_arrow", XC_sb_left_arrow, None},
+{"sb_right_arrow", XC_sb_right_arrow, None},
+{"sb_up_arrow", XC_sb_up_arrow, None},
+{"sb_v_double_arrow", XC_sb_v_double_arrow, None},
+{"shuttle", XC_shuttle, None},
+{"sizing", XC_sizing, None},
+{"spider", XC_spider, None},
+{"spraycan", XC_spraycan, None},
+{"star", XC_star, None},
+{"target", XC_target, None},
+{"tcross", XC_tcross, None},
+{"top_left_arrow", XC_top_left_arrow, None},
+{"top_left_corner", XC_top_left_corner, None},
+{"top_right_corner", XC_top_right_corner, None},
+{"top_side", XC_top_side, None},
+{"top_tee", XC_top_tee, None},
+{"trek", XC_trek, None},
+{"ul_angle", XC_ul_angle, None},
+{"umbrella", XC_umbrella, None},
+{"ur_angle", XC_ur_angle, None},
+{"watch", XC_watch, None},
+{"xterm", XC_xterm, None},
+};
+
+void NewFontCursor (cp, str)
+ Cursor *cp;
+ char *str;
+{
+ int i;
+
+ for (i = 0; i < sizeof(cursor_names)/sizeof(struct _CursorName); i++)
+ {
+ if (strcmp(str, cursor_names[i].name) == 0)
+ {
+ if (cursor_names[i].cursor == None)
+ cursor_names[i].cursor = XCreateFontCursor(dpy,
+ cursor_names[i].shape);
+ *cp = cursor_names[i].cursor;
+ return;
+ }
+ }
+ fprintf (stderr, "%s: unable to find font cursor \"%s\"\n",
+ ProgramName, str);
+}
+
+NewBitmapCursor(cp, source, mask)
+Cursor *cp;
+char *source, *mask;
+{
+ int hotx, hoty;
+ int sx, sy, mx, my;
+ unsigned int sw, sh, mw, mh;
+ Pixmap spm, mpm;
+
+ spm = GetBitmap(source);
+ if ((hotx = HotX) < 0) hotx = 0;
+ if ((hoty = HotY) < 0) hoty = 0;
+ mpm = GetBitmap(mask);
+
+ /* make sure they are the same size */
+
+ XGetGeometry(dpy, spm, &JunkRoot, &sx, &sy, &sw, &sh, &JunkBW,&JunkDepth);
+ XGetGeometry(dpy, mpm, &JunkRoot, &mx, &my, &mw, &mh, &JunkBW,&JunkDepth);
+ if (sw != mw || sh != mh)
+ {
+ fprintf (stderr,
+ "%s: cursor bitmaps \"%s\" and \"%s\" not the same size\n",
+ ProgramName, source, mask);
+ return;
+ }
+ *cp = XCreatePixmapCursor(dpy, spm, mpm, &Scr->PointerForeground,
+ &Scr->PointerBackground, hotx,hoty);
+}
diff --git a/src/events.c b/src/events.c
new file mode 100644
index 0000000..9b8c348
--- /dev/null
+++ b/src/events.c
@@ -0,0 +1,2817 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/***********************************************************************
+ *
+ * $Xorg: events.c,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * twm event handling
+ *
+ * 17-Nov-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include <X11/Xatom.h>
+#include "add_window.h"
+#include "menus.h"
+#include "events.h"
+#include "resize.h"
+#include "parse.h"
+#include "gram.h"
+#include "util.h"
+#include "screen.h"
+#include "iconmgr.h"
+#include "version.h"
+
+extern int iconifybox_width, iconifybox_height;
+extern unsigned int mods_used;
+extern int menuFromFrameOrWindowOrTitlebar;
+
+#define MAX_X_EVENT 256
+event_proc EventHandler[MAX_X_EVENT]; /* event handler jump table */
+char *Action;
+int Context = C_NO_CONTEXT; /* current button press context */
+TwmWindow *ButtonWindow; /* button press window structure */
+XEvent ButtonEvent; /* button press event */
+XEvent Event; /* the current event */
+TwmWindow *Tmp_win; /* the current twm window */
+
+/* Used in HandleEnterNotify to remove border highlight from a window
+ * that has not recieved a LeaveNotify event because of a pointer grab
+ */
+TwmWindow *UnHighLight_win = NULL;
+
+Window DragWindow; /* variables used in moving windows */
+int origDragX;
+int origDragY;
+int DragX;
+int DragY;
+int DragWidth;
+int DragHeight;
+int CurrentDragX;
+int CurrentDragY;
+
+/* Vars to tell if the resize has moved. */
+extern int ResizeOrigX;
+extern int ResizeOrigY;
+
+static int enter_flag;
+static int ColortableThrashing;
+static TwmWindow *enter_win, *raise_win;
+
+ScreenInfo *FindScreenInfo();
+int ButtonPressed = -1;
+int Cancel = FALSE;
+
+void HandleCreateNotify();
+
+void HandleShapeNotify ();
+extern int ShapeEventBase, ShapeErrorBase;
+
+void AutoRaiseWindow (tmp)
+ TwmWindow *tmp;
+{
+ XRaiseWindow (dpy, tmp->frame);
+ XSync (dpy, 0);
+ enter_win = NULL;
+ enter_flag = TRUE;
+ raise_win = tmp;
+}
+
+void SetRaiseWindow (tmp)
+ TwmWindow *tmp;
+{
+ enter_flag = TRUE;
+ enter_win = NULL;
+ raise_win = tmp;
+ XSync (dpy, 0);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * InitEvents - initialize the event jump table
+ *
+ ***********************************************************************
+ */
+
+void
+InitEvents()
+{
+ int i;
+
+
+ ResizeWindow = (Window) 0;
+ DragWindow = (Window) 0;
+ enter_flag = FALSE;
+ enter_win = raise_win = NULL;
+
+ for (i = 0; i < MAX_X_EVENT; i++)
+ EventHandler[i] = HandleUnknown;
+
+ EventHandler[Expose] = HandleExpose;
+ EventHandler[CreateNotify] = HandleCreateNotify;
+ EventHandler[DestroyNotify] = HandleDestroyNotify;
+ EventHandler[MapRequest] = HandleMapRequest;
+ EventHandler[MapNotify] = HandleMapNotify;
+ EventHandler[UnmapNotify] = HandleUnmapNotify;
+ EventHandler[MotionNotify] = HandleMotionNotify;
+ EventHandler[ButtonRelease] = HandleButtonRelease;
+ EventHandler[ButtonPress] = HandleButtonPress;
+ EventHandler[EnterNotify] = HandleEnterNotify;
+ EventHandler[LeaveNotify] = HandleLeaveNotify;
+ EventHandler[ConfigureRequest] = HandleConfigureRequest;
+ EventHandler[ClientMessage] = HandleClientMessage;
+ EventHandler[PropertyNotify] = HandlePropertyNotify;
+ EventHandler[KeyPress] = HandleKeyPress;
+ EventHandler[ColormapNotify] = HandleColormapNotify;
+ EventHandler[VisibilityNotify] = HandleVisibilityNotify;
+ if (HasShape)
+ EventHandler[ShapeEventBase+ShapeNotify] = HandleShapeNotify;
+}
+
+
+
+
+Time lastTimestamp = CurrentTime; /* until Xlib does this for us */
+
+Bool StashEventTime (ev)
+ register XEvent *ev;
+{
+ switch (ev->type) {
+ case KeyPress:
+ case KeyRelease:
+ lastTimestamp = ev->xkey.time;
+ return True;
+ case ButtonPress:
+ case ButtonRelease:
+ lastTimestamp = ev->xbutton.time;
+ return True;
+ case MotionNotify:
+ lastTimestamp = ev->xmotion.time;
+ return True;
+ case EnterNotify:
+ case LeaveNotify:
+ lastTimestamp = ev->xcrossing.time;
+ return True;
+ case PropertyNotify:
+ lastTimestamp = ev->xproperty.time;
+ return True;
+ case SelectionClear:
+ lastTimestamp = ev->xselectionclear.time;
+ return True;
+ case SelectionRequest:
+ lastTimestamp = ev->xselectionrequest.time;
+ return True;
+ case SelectionNotify:
+ lastTimestamp = ev->xselection.time;
+ return True;
+ }
+ return False;
+}
+
+
+
+/*
+ * WindowOfEvent - return the window about which this event is concerned; this
+ * window may not be the same as XEvent.xany.window (the first window listed
+ * in the structure).
+ */
+Window WindowOfEvent (e)
+ XEvent *e;
+{
+ /*
+ * Each window subfield is marked with whether or not it is the same as
+ * XEvent.xany.window or is different (which is the case for some of the
+ * notify events).
+ */
+ switch (e->type) {
+ case KeyPress:
+ case KeyRelease: return e->xkey.window; /* same */
+ case ButtonPress:
+ case ButtonRelease: return e->xbutton.window; /* same */
+ case MotionNotify: return e->xmotion.window; /* same */
+ case EnterNotify:
+ case LeaveNotify: return e->xcrossing.window; /* same */
+ case FocusIn:
+ case FocusOut: return e->xfocus.window; /* same */
+ case KeymapNotify: return e->xkeymap.window; /* same */
+ case Expose: return e->xexpose.window; /* same */
+ case GraphicsExpose: return e->xgraphicsexpose.drawable; /* same */
+ case NoExpose: return e->xnoexpose.drawable; /* same */
+ case VisibilityNotify: return e->xvisibility.window; /* same */
+ case CreateNotify: return e->xcreatewindow.window; /* DIFF */
+ case DestroyNotify: return e->xdestroywindow.window; /* DIFF */
+ case UnmapNotify: return e->xunmap.window; /* DIFF */
+ case MapNotify: return e->xmap.window; /* DIFF */
+ case MapRequest: return e->xmaprequest.window; /* DIFF */
+ case ReparentNotify: return e->xreparent.window; /* DIFF */
+ case ConfigureNotify: return e->xconfigure.window; /* DIFF */
+ case ConfigureRequest: return e->xconfigurerequest.window; /* DIFF */
+ case GravityNotify: return e->xgravity.window; /* DIFF */
+ case ResizeRequest: return e->xresizerequest.window; /* same */
+ case CirculateNotify: return e->xcirculate.window; /* DIFF */
+ case CirculateRequest: return e->xcirculaterequest.window; /* DIFF */
+ case PropertyNotify: return e->xproperty.window; /* same */
+ case SelectionClear: return e->xselectionclear.window; /* same */
+ case SelectionRequest: return e->xselectionrequest.requestor; /* DIFF */
+ case SelectionNotify: return e->xselection.requestor; /* same */
+ case ColormapNotify: return e->xcolormap.window; /* same */
+ case ClientMessage: return e->xclient.window; /* same */
+ case MappingNotify: return None;
+ }
+ return None;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * DispatchEvent2 -
+ * handle a single X event stored in global var Event
+ * this rouitine for is for a call during an f.move
+ *
+ ***********************************************************************
+ */
+Bool DispatchEvent2 ()
+{
+ Window w = Event.xany.window;
+ StashEventTime (&Event);
+
+ if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
+ Tmp_win = NULL;
+
+ if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) {
+ Scr = FindScreenInfo (WindowOfEvent (&Event));
+ }
+
+ if (!Scr) return False;
+
+ if (menuFromFrameOrWindowOrTitlebar && Event.type == Expose)
+ HandleExpose();
+
+ if (!menuFromFrameOrWindowOrTitlebar && Event.type>= 0 && Event.type < MAX_X_EVENT) {
+ (*EventHandler[Event.type])();
+ }
+
+ return True;
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * DispatchEvent - handle a single X event stored in global var Event
+ *
+ ***********************************************************************
+ */
+Bool DispatchEvent ()
+{
+ Window w = Event.xany.window;
+ StashEventTime (&Event);
+
+ if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
+ Tmp_win = NULL;
+
+ if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) {
+ Scr = FindScreenInfo (WindowOfEvent (&Event));
+ }
+
+ if (!Scr) return False;
+
+ if (Event.type>= 0 && Event.type < MAX_X_EVENT) {
+ (*EventHandler[Event.type])();
+ }
+
+ return True;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleEvents - handle X events
+ *
+ ***********************************************************************
+ */
+
+void
+HandleEvents()
+{
+ while (TRUE)
+ {
+ if (enter_flag && !QLength(dpy)) {
+ if (enter_win && enter_win != raise_win) {
+ AutoRaiseWindow (enter_win); /* sets enter_flag T */
+ } else {
+ enter_flag = FALSE;
+ }
+ }
+ if (ColortableThrashing && !QLength(dpy) && Scr) {
+ InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
+ }
+ WindowMoved = FALSE;
+ XtAppNextEvent(appContext, &Event);
+ if (Event.type>= 0 && Event.type < MAX_X_EVENT)
+ (void) DispatchEvent ();
+ else
+ XtDispatchEvent (&Event);
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleColormapNotify - colormap notify event handler
+ *
+ * This procedure handles both a client changing its own colormap, and
+ * a client explicitly installing its colormap itself (only the window
+ * manager should do that, so we must set it correctly).
+ *
+ ***********************************************************************
+ */
+
+void
+HandleColormapNotify()
+{
+ XColormapEvent *cevent = (XColormapEvent *) &Event;
+ ColormapWindow *cwin, **cwins;
+ TwmColormap *cmap;
+ int lost, won, n, number_cwins;
+ extern TwmColormap *CreateTwmColormap();
+
+ if (XFindContext(dpy, cevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
+ return;
+ cmap = cwin->colormap;
+
+ if (cevent->new)
+ {
+ if (XFindContext(dpy, cevent->colormap, ColormapContext,
+ (caddr_t *)&cwin->colormap) == XCNOENT)
+ cwin->colormap = CreateTwmColormap(cevent->colormap);
+ else
+ cwin->colormap->refcnt++;
+
+ cmap->refcnt--;
+
+ if (cevent->state == ColormapUninstalled)
+ cmap->state &= ~CM_INSTALLED;
+ else
+ cmap->state |= CM_INSTALLED;
+
+ if (cmap->state & CM_INSTALLABLE)
+ InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
+
+ if (cmap->refcnt == 0)
+ {
+ XDeleteContext(dpy, cmap->c, ColormapContext);
+ free((char *) cmap);
+ }
+
+ return;
+ }
+
+ if (cevent->state == ColormapUninstalled &&
+ (cmap->state & CM_INSTALLABLE))
+ {
+ if (!(cmap->state & CM_INSTALLED))
+ return;
+ cmap->state &= ~CM_INSTALLED;
+
+ if (!ColortableThrashing)
+ {
+ ColortableThrashing = TRUE;
+ XSync(dpy, 0);
+ }
+
+ if (cevent->serial >= Scr->cmapInfo.first_req)
+ {
+ number_cwins = Scr->cmapInfo.cmaps->number_cwins;
+
+ /*
+ * Find out which colortables collided.
+ */
+
+ cwins = Scr->cmapInfo.cmaps->cwins;
+ for (lost = won = -1, n = 0;
+ (lost == -1 || won == -1) && n < number_cwins;
+ n++)
+ {
+ if (lost == -1 && cwins[n] == cwin)
+ {
+ lost = n; /* This is the window which lost its colormap */
+ continue;
+ }
+
+ if (won == -1 &&
+ cwins[n]->colormap->install_req == cevent->serial)
+ {
+ won = n; /* This is the window whose colormap caused */
+ continue; /* the de-install of the previous colormap */
+ }
+ }
+
+ /*
+ ** Cases are:
+ ** Both the request and the window were found:
+ ** One of the installs made honoring the WM_COLORMAP
+ ** property caused another of the colormaps to be
+ ** de-installed, just mark the scoreboard.
+ **
+ ** Only the request was found:
+ ** One of the installs made honoring the WM_COLORMAP
+ ** property caused a window not in the WM_COLORMAP
+ ** list to lose its map. This happens when the map
+ ** it is losing is one which is trying to be installed,
+ ** but is getting getting de-installed by another map
+ ** in this case, we'll get a scoreable event later,
+ ** this one is meaningless.
+ **
+ ** Neither the request nor the window was found:
+ ** Somebody called installcolormap, but it doesn't
+ ** affect the WM_COLORMAP windows. This case will
+ ** probably never occur.
+ **
+ ** Only the window was found:
+ ** One of the WM_COLORMAP windows lost its colormap
+ ** but it wasn't one of the requests known. This is
+ ** probably because someone did an "InstallColormap".
+ ** The colormap policy is "enforced" by re-installing
+ ** the colormaps which are believed to be correct.
+ */
+
+ if (won != -1)
+ if (lost != -1)
+ {
+ /* lower diagonal index calculation */
+ if (lost > won)
+ n = lost*(lost-1)/2 + won;
+ else
+ n = won*(won-1)/2 + lost;
+ Scr->cmapInfo.cmaps->scoreboard[n] = 1;
+ } else
+ {
+ /*
+ ** One of the cwin installs caused one of the cwin
+ ** colormaps to be de-installed, so I'm sure to get an
+ ** UninstallNotify for the cwin I know about later.
+ ** I haven't got it yet, or the test of CM_INSTALLED
+ ** above would have failed. Turning the CM_INSTALLED
+ ** bit back on makes sure we get back here to score
+ ** the collision.
+ */
+ cmap->state |= CM_INSTALLED;
+ }
+ else if (lost != -1)
+ InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
+ }
+ }
+
+ else if (cevent->state == ColormapUninstalled)
+ cmap->state &= ~CM_INSTALLED;
+
+ else if (cevent->state == ColormapInstalled)
+ cmap->state |= CM_INSTALLED;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleVisibilityNotify - visibility notify event handler
+ *
+ * This routine keeps track of visibility events so that colormap
+ * installation can keep the maximum number of useful colormaps
+ * installed at one time.
+ *
+ ***********************************************************************
+ */
+
+void
+HandleVisibilityNotify()
+{
+ XVisibilityEvent *vevent = (XVisibilityEvent *) &Event;
+ ColormapWindow *cwin;
+ TwmColormap *cmap;
+
+ if (XFindContext(dpy, vevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
+ return;
+
+ /*
+ * when Saber complains about retreiving an <int> from an <unsigned int>
+ * just type "touch vevent->state" and "cont"
+ */
+ cmap = cwin->colormap;
+ if ((cmap->state & CM_INSTALLABLE) &&
+ vevent->state != cwin->visibility &&
+ (vevent->state == VisibilityFullyObscured ||
+ cwin->visibility == VisibilityFullyObscured) &&
+ cmap->w == cwin->w) {
+ cwin->visibility = vevent->state;
+ InstallWindowColormaps(VisibilityNotify, (TwmWindow *) NULL);
+ } else
+ cwin->visibility = vevent->state;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleKeyPress - key press event handler
+ *
+ ***********************************************************************
+ */
+
+int MovedFromKeyPress = False;
+
+void
+HandleKeyPress()
+{
+ KeySym ks;
+ FuncKey *key;
+ int len;
+ unsigned int modifier;
+
+ if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
+ Context = C_NO_CONTEXT;
+
+ if (Event.xany.window == Scr->Root)
+ Context = C_ROOT;
+ if (Tmp_win)
+ {
+ if (Event.xany.window == Tmp_win->title_w)
+ Context = C_TITLE;
+ if (Event.xany.window == Tmp_win->w)
+ Context = C_WINDOW;
+ if (Event.xany.window == Tmp_win->icon_w)
+ Context = C_ICON;
+ if (Event.xany.window == Tmp_win->frame)
+ Context = C_FRAME;
+ if (Tmp_win->list && Event.xany.window == Tmp_win->list->w)
+ Context = C_ICONMGR;
+ if (Tmp_win->list && Event.xany.window == Tmp_win->list->icon)
+ Context = C_ICONMGR;
+ }
+
+ modifier = (Event.xkey.state & mods_used);
+ ks = XLookupKeysym((XKeyEvent *) &Event, /* KeySyms index */ 0);
+ for (key = Scr->FuncKeyRoot.next; key != NULL; key = key->next)
+ {
+ if (key->keysym == ks &&
+ key->mods == modifier &&
+ (key->cont == Context || key->cont == C_NAME))
+ {
+ /* weed out the functions that don't make sense to execute
+ * from a key press
+ */
+ if (key->func == F_RESIZE)
+ return;
+ /* special case for F_MOVE/F_FORCEMOVE activated from a keypress */
+ if (key->func == F_MOVE || key->func == F_FORCEMOVE)
+ MovedFromKeyPress = True;
+
+ if (key->cont != C_NAME)
+ {
+ ExecuteFunction(key->func, key->action, Event.xany.window,
+ Tmp_win, &Event, Context, FALSE);
+ XUngrabPointer(dpy, CurrentTime);
+ return;
+ }
+ else
+ {
+ int matched = FALSE;
+ len = strlen(key->win_name);
+
+ /* try and match the name first */
+ for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
+ Tmp_win = Tmp_win->next)
+ {
+ if (!strncmp(key->win_name, Tmp_win->name, len))
+ {
+ matched = TRUE;
+ ExecuteFunction(key->func, key->action, Tmp_win->frame,
+ Tmp_win, &Event, C_FRAME, FALSE);
+ XUngrabPointer(dpy, CurrentTime);
+ }
+ }
+
+ /* now try the res_name */
+ if (!matched)
+ for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
+ Tmp_win = Tmp_win->next)
+ {
+ if (!strncmp(key->win_name, Tmp_win->class.res_name, len))
+ {
+ matched = TRUE;
+ ExecuteFunction(key->func, key->action, Tmp_win->frame,
+ Tmp_win, &Event, C_FRAME, FALSE);
+ XUngrabPointer(dpy, CurrentTime);
+ }
+ }
+
+ /* now try the res_class */
+ if (!matched)
+ for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
+ Tmp_win = Tmp_win->next)
+ {
+ if (!strncmp(key->win_name, Tmp_win->class.res_class, len))
+ {
+ matched = TRUE;
+ ExecuteFunction(key->func, key->action, Tmp_win->frame,
+ Tmp_win, &Event, C_FRAME, FALSE);
+ XUngrabPointer(dpy, CurrentTime);
+ }
+ }
+ if (matched)
+ return;
+ }
+ }
+ }
+
+ /* if we get here, no function key was bound to the key. Send it
+ * to the client if it was in a window we know about.
+ */
+ if (Tmp_win)
+ {
+ if (Event.xany.window == Tmp_win->icon_w ||
+ Event.xany.window == Tmp_win->frame ||
+ Event.xany.window == Tmp_win->title_w ||
+ (Tmp_win->list && (Event.xany.window == Tmp_win->list->w)))
+ {
+ Event.xkey.window = Tmp_win->w;
+ XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event);
+ }
+ }
+
+}
+
+
+
+static void free_window_names (tmp, nukefull, nukename, nukeicon)
+ TwmWindow *tmp;
+ Bool nukefull, nukename, nukeicon;
+{
+/*
+ * XXX - are we sure that nobody ever sets these to another constant (check
+ * twm windows)?
+ */
+ if (tmp->name == tmp->full_name) nukefull = False;
+ if (tmp->icon_name == tmp->name) nukename = False;
+
+#define isokay(v) ((v) && (v) != NoName)
+ if (nukefull && isokay(tmp->full_name)) XFree (tmp->full_name);
+ if (nukename && isokay(tmp->name)) XFree (tmp->name);
+ if (nukeicon && isokay(tmp->icon_name)) XFree (tmp->icon_name);
+#undef isokay
+ return;
+}
+
+
+
+void free_cwins (tmp)
+ TwmWindow *tmp;
+{
+ int i;
+ TwmColormap *cmap;
+
+ if (tmp->cmaps.number_cwins) {
+ for (i = 0; i < tmp->cmaps.number_cwins; i++) {
+ if (--tmp->cmaps.cwins[i]->refcnt == 0) {
+ cmap = tmp->cmaps.cwins[i]->colormap;
+ if (--cmap->refcnt == 0) {
+ XDeleteContext(dpy, cmap->c, ColormapContext);
+ free((char *) cmap);
+ }
+ XDeleteContext(dpy, tmp->cmaps.cwins[i]->w, ColormapContext);
+ free((char *) tmp->cmaps.cwins[i]);
+ }
+ }
+ free((char *) tmp->cmaps.cwins);
+ if (tmp->cmaps.number_cwins > 1) {
+ free(tmp->cmaps.scoreboard);
+ tmp->cmaps.scoreboard = NULL;
+ }
+ tmp->cmaps.number_cwins = 0;
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandlePropertyNotify - property notify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandlePropertyNotify()
+{
+ char *prop = NULL;
+ Atom actual = None;
+ int actual_format;
+ unsigned long nitems, bytesafter;
+ unsigned long valuemask; /* mask for create windows */
+ XSetWindowAttributes attributes; /* attributes for create windows */
+ Pixmap pm;
+
+ /* watch for standard colormap changes */
+ if (Event.xproperty.window == Scr->Root) {
+ XStandardColormap *maps = NULL;
+ int nmaps;
+
+ switch (Event.xproperty.state) {
+ case PropertyNewValue:
+ if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps,
+ Event.xproperty.atom)) {
+ /* if got one, then replace any existing entry */
+ InsertRGBColormap (Event.xproperty.atom, maps, nmaps, True);
+ }
+ return;
+
+ case PropertyDelete:
+ RemoveRGBColormap (Event.xproperty.atom);
+ return;
+ }
+ }
+
+ if (!Tmp_win) return; /* unknown window */
+
+#define MAX_NAME_LEN 200L /* truncate to this many */
+#define MAX_ICON_NAME_LEN 200L /* ditto */
+
+ switch (Event.xproperty.atom) {
+ case XA_WM_NAME:
+ if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0L,
+ MAX_NAME_LEN, False, XA_STRING, &actual,
+ &actual_format, &nitems, &bytesafter,
+ (unsigned char **) &prop) != Success ||
+ actual == None)
+ return;
+ if (!prop) prop = NoName;
+ free_window_names (Tmp_win, True, True, False);
+
+ Tmp_win->full_name = prop;
+ Tmp_win->name = prop;
+
+ Tmp_win->nameChanged = 1;
+
+ Tmp_win->name_width = XTextWidth (Scr->TitleBarFont.font,
+ Tmp_win->name,
+ strlen (Tmp_win->name));
+
+ SetupWindow (Tmp_win, Tmp_win->frame_x, Tmp_win->frame_y,
+ Tmp_win->frame_width, Tmp_win->frame_height, -1);
+
+ if (Tmp_win->title_w) XClearArea(dpy, Tmp_win->title_w, 0,0,0,0, True);
+
+ /*
+ * if the icon name is NoName, set the name of the icon to be
+ * the same as the window
+ */
+ if (Tmp_win->icon_name == NoName) {
+ Tmp_win->icon_name = Tmp_win->name;
+ RedoIconName();
+ }
+ break;
+
+ case XA_WM_ICON_NAME:
+ if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0,
+ MAX_ICON_NAME_LEN, False, XA_STRING, &actual,
+ &actual_format, &nitems, &bytesafter,
+ (unsigned char **) &prop) != Success ||
+ actual == None)
+ return;
+ if (!prop) prop = NoName;
+ free_window_names (Tmp_win, False, False, True);
+ Tmp_win->icon_name = prop;
+
+ RedoIconName();
+ break;
+
+ case XA_WM_HINTS:
+ if (Tmp_win->wmhints) XFree ((char *) Tmp_win->wmhints);
+ Tmp_win->wmhints = XGetWMHints(dpy, Event.xany.window);
+
+ if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & WindowGroupHint))
+ Tmp_win->group = Tmp_win->wmhints->window_group;
+
+ if (Tmp_win->icon_not_ours && Tmp_win->wmhints &&
+ !(Tmp_win->wmhints->flags & IconWindowHint)) {
+ /* IconWindowHint was formerly on, now off; revert
+ // to a default icon */
+ int icon_x = 0, icon_y = 0;
+ XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot,
+ &icon_x, &icon_y,
+ &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth);
+ XSelectInput (dpy, Tmp_win->icon_w, None);
+ XDeleteContext (dpy, Tmp_win->icon_w, TwmContext);
+ XDeleteContext (dpy, Tmp_win->icon_w, ScreenContext);
+ CreateIconWindow(Tmp_win, icon_x, icon_y);
+ break;
+ }
+
+ if (!Tmp_win->forced && Tmp_win->wmhints &&
+ Tmp_win->wmhints->flags & IconWindowHint) {
+ if (Tmp_win->icon_w) {
+ int icon_x, icon_y;
+
+ /*
+ * There's already an icon window.
+ * Try to find out where it is; if we succeed, move the new
+ * window to where the old one is.
+ */
+ if (XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot, &icon_x,
+ &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) {
+ /*
+ * Move the new icon window to where the old one was.
+ */
+ XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x,
+ icon_y);
+ }
+
+ /*
+ * If the window is iconic, map the new icon window.
+ */
+ if (Tmp_win->icon)
+ XMapWindow(dpy, Tmp_win->wmhints->icon_window);
+
+ /*
+ * Now, if the old window isn't ours, unmap it, otherwise
+ * just get rid of it completely.
+ */
+ if (Tmp_win->icon_not_ours) {
+ if (Tmp_win->icon_w != Tmp_win->wmhints->icon_window)
+ XUnmapWindow(dpy, Tmp_win->icon_w);
+ } else
+ XDestroyWindow(dpy, Tmp_win->icon_w);
+
+ XDeleteContext(dpy, Tmp_win->icon_w, TwmContext);
+ XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext);
+
+ /*
+ * The new icon window isn't our window, so note that fact
+ * so that we don't treat it as ours.
+ */
+ Tmp_win->icon_not_ours = TRUE;
+
+ /*
+ * Now make the new window the icon window for this window,
+ * and set it up to work as such (select for key presses
+ * and button presses/releases, set up the contexts for it,
+ * and define the cursor for it).
+ */
+ Tmp_win->icon_w = Tmp_win->wmhints->icon_window;
+ XSelectInput (dpy, Tmp_win->icon_w,
+ KeyPressMask | ButtonPressMask | ButtonReleaseMask);
+ XSaveContext(dpy, Tmp_win->icon_w, TwmContext, (caddr_t)Tmp_win);
+ XSaveContext(dpy, Tmp_win->icon_w, ScreenContext, (caddr_t)Scr);
+ XDefineCursor(dpy, Tmp_win->icon_w, Scr->IconCursor);
+ }
+ }
+
+ if (Tmp_win->icon_w && !Tmp_win->forced && Tmp_win->wmhints &&
+ (Tmp_win->wmhints->flags & IconPixmapHint)) {
+ if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot,
+ &JunkX, &JunkY, (unsigned int *)&Tmp_win->icon_width,
+ (unsigned int *)&Tmp_win->icon_height, &JunkBW, &JunkDepth)) {
+ return;
+ }
+
+ pm = XCreatePixmap (dpy, Scr->Root, Tmp_win->icon_width,
+ Tmp_win->icon_height, Scr->d_depth);
+
+ FB(Tmp_win->iconc.fore, Tmp_win->iconc.back);
+ XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm,
+ Scr->NormalGC,
+ 0,0, Tmp_win->icon_width, Tmp_win->icon_height, 0, 0, 1 );
+
+ valuemask = CWBackPixmap;
+ attributes.background_pixmap = pm;
+
+ if (Tmp_win->icon_bm_w)
+ XDestroyWindow(dpy, Tmp_win->icon_bm_w);
+
+ Tmp_win->icon_bm_w =
+ XCreateWindow (dpy, Tmp_win->icon_w, 0, 0,
+ (unsigned int) Tmp_win->icon_width,
+ (unsigned int) Tmp_win->icon_height,
+ (unsigned int) 0, Scr->d_depth,
+ (unsigned int) CopyFromParent, Scr->d_visual,
+ valuemask, &attributes);
+
+ XFreePixmap (dpy, pm);
+ RedoIconName();
+ }
+ break;
+
+ case XA_WM_NORMAL_HINTS:
+ GetWindowSizeHints (Tmp_win);
+ break;
+
+ default:
+ if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS) {
+ FetchWmColormapWindows (Tmp_win); /* frees old data */
+ break;
+ } else if (Event.xproperty.atom == _XA_WM_PROTOCOLS) {
+ FetchWmProtocols (Tmp_win);
+ break;
+ }
+ break;
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * RedoIconName - procedure to re-position the icon window and name
+ *
+ ***********************************************************************
+ */
+
+RedoIconName()
+{
+ int x, y;
+
+ if (Tmp_win->list)
+ {
+ /* let the expose event cause the repaint */
+ XClearArea(dpy, Tmp_win->list->w, 0,0,0,0, True);
+
+ if (Scr->SortIconMgr)
+ SortIconManager(Tmp_win->list->iconmgr);
+ }
+
+ if (Tmp_win->icon_w == (Window) 0)
+ return;
+
+ if (Tmp_win->icon_not_ours)
+ return;
+
+ Tmp_win->icon_w_width = XTextWidth(Scr->IconFont.font,
+ Tmp_win->icon_name, strlen(Tmp_win->icon_name));
+
+ Tmp_win->icon_w_width += 6;
+ if (Tmp_win->icon_w_width < Tmp_win->icon_width)
+ {
+ Tmp_win->icon_x = (Tmp_win->icon_width - Tmp_win->icon_w_width)/2;
+ Tmp_win->icon_x += 3;
+ Tmp_win->icon_w_width = Tmp_win->icon_width;
+ }
+ else
+ {
+ Tmp_win->icon_x = 3;
+ }
+
+ if (Tmp_win->icon_w_width == Tmp_win->icon_width)
+ x = 0;
+ else
+ x = (Tmp_win->icon_w_width - Tmp_win->icon_width)/2;
+
+ y = 0;
+
+ Tmp_win->icon_w_height = Tmp_win->icon_height + Scr->IconFont.height + 4;
+ Tmp_win->icon_y = Tmp_win->icon_height + Scr->IconFont.height;
+
+ XResizeWindow(dpy, Tmp_win->icon_w, Tmp_win->icon_w_width,
+ Tmp_win->icon_w_height);
+ if (Tmp_win->icon_bm_w)
+ {
+ XMoveWindow(dpy, Tmp_win->icon_bm_w, x, y);
+ XMapWindow(dpy, Tmp_win->icon_bm_w);
+ }
+ if (Tmp_win->icon)
+ {
+ XClearArea(dpy, Tmp_win->icon_w, 0, 0, 0, 0, True);
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleClientMessage - client message event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleClientMessage()
+{
+ if (Event.xclient.message_type == _XA_WM_CHANGE_STATE)
+ {
+ if (Tmp_win != NULL)
+ {
+ if (Event.xclient.data.l[0] == IconicState && !Tmp_win->icon)
+ {
+ XEvent button;
+
+ XQueryPointer( dpy, Scr->Root, &JunkRoot, &JunkChild,
+ &(button.xmotion.x_root),
+ &(button.xmotion.y_root),
+ &JunkX, &JunkY, &JunkMask);
+
+ ExecuteFunction(F_ICONIFY, NULLSTR, Event.xany.window,
+ Tmp_win, &button, FRAME, FALSE);
+ XUngrabPointer(dpy, CurrentTime);
+ }
+ }
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleExpose - expose event handler
+ *
+ ***********************************************************************
+ */
+
+static void flush_expose();
+
+void
+HandleExpose()
+{
+ MenuRoot *tmp;
+ if (XFindContext(dpy, Event.xany.window, MenuContext, (caddr_t *)&tmp) == 0)
+ {
+ PaintMenu(tmp, &Event);
+ return;
+ }
+
+ if (Event.xexpose.count != 0)
+ return;
+
+ if (Event.xany.window == Scr->InfoWindow && InfoLines)
+ {
+ int i;
+ int height;
+
+ FBF(Scr->DefaultC.fore, Scr->DefaultC.back,
+ Scr->DefaultFont.font->fid);
+
+ height = Scr->DefaultFont.height+2;
+ for (i = 0; i < InfoLines; i++)
+ {
+ XDrawString(dpy, Scr->InfoWindow, Scr->NormalGC,
+ 5, (i*height) + Scr->DefaultFont.y, Info[i], strlen(Info[i]));
+ }
+ flush_expose (Event.xany.window);
+ }
+ else if (Tmp_win != NULL)
+ {
+ if (Event.xany.window == Tmp_win->title_w)
+ {
+ FBF(Tmp_win->title.fore, Tmp_win->title.back,
+ Scr->TitleBarFont.font->fid);
+
+ XDrawString (dpy, Tmp_win->title_w, Scr->NormalGC,
+ Scr->TBInfo.titlex, Scr->TitleBarFont.y,
+ Tmp_win->name, strlen(Tmp_win->name));
+ flush_expose (Event.xany.window);
+ }
+ else if (Event.xany.window == Tmp_win->icon_w)
+ {
+ FBF(Tmp_win->iconc.fore, Tmp_win->iconc.back,
+ Scr->IconFont.font->fid);
+
+ XDrawString (dpy, Tmp_win->icon_w,
+ Scr->NormalGC,
+ Tmp_win->icon_x, Tmp_win->icon_y,
+ Tmp_win->icon_name, strlen(Tmp_win->icon_name));
+ flush_expose (Event.xany.window);
+ return;
+ } else if (Tmp_win->titlebuttons) {
+ int i;
+ Window w = Event.xany.window;
+ register TBWindow *tbw;
+ int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
+
+ for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
+ if (w == tbw->window) {
+ register TitleButton *tb = tbw->info;
+
+ FB(Tmp_win->title.fore, Tmp_win->title.back);
+ XCopyPlane (dpy, tb->bitmap, w, Scr->NormalGC,
+ tb->srcx, tb->srcy, tb->width, tb->height,
+ tb->dstx, tb->dsty, 1);
+ flush_expose (w);
+ return;
+ }
+ }
+ }
+ if (Tmp_win->list) {
+ if (Event.xany.window == Tmp_win->list->w)
+ {
+ FBF(Tmp_win->list->fore, Tmp_win->list->back,
+ Scr->IconManagerFont.font->fid);
+ XDrawString (dpy, Event.xany.window, Scr->NormalGC,
+ iconmgr_textx, Scr->IconManagerFont.y+4,
+ Tmp_win->icon_name, strlen(Tmp_win->icon_name));
+ DrawIconManagerBorder(Tmp_win->list);
+ flush_expose (Event.xany.window);
+ return;
+ }
+ if (Event.xany.window == Tmp_win->list->icon)
+ {
+ FB(Tmp_win->list->fore, Tmp_win->list->back);
+ XCopyPlane(dpy, Scr->siconifyPm, Tmp_win->list->icon,
+ Scr->NormalGC,
+ 0,0, iconifybox_width, iconifybox_height, 0, 0, 1);
+ flush_expose (Event.xany.window);
+ return;
+ }
+ }
+ }
+}
+
+
+
+static void remove_window_from_ring (tmp)
+ TwmWindow *tmp;
+{
+ TwmWindow *prev = tmp->ring.prev, *next = tmp->ring.next;
+
+ if (enter_win == tmp) {
+ enter_flag = FALSE;
+ enter_win = NULL;
+ }
+ if (raise_win == Tmp_win) raise_win = NULL;
+
+ /*
+ * 1. Unlink window
+ * 2. If window was only thing in ring, null out ring
+ * 3. If window was ring leader, set to next (or null)
+ */
+ if (prev) prev->ring.next = next;
+ if (next) next->ring.prev = prev;
+ if (Scr->Ring == tmp)
+ Scr->Ring = (next != tmp ? next : (TwmWindow *) NULL);
+
+ if (!Scr->Ring || Scr->RingLeader == tmp) Scr->RingLeader = Scr->Ring;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleDestroyNotify - DestroyNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleDestroyNotify()
+{
+ int i;
+
+ /*
+ * Warning, this is also called by HandleUnmapNotify; if it ever needs to
+ * look at the event, HandleUnmapNotify will have to mash the UnmapNotify
+ * into a DestroyNotify.
+ */
+
+ if (Tmp_win == NULL)
+ return;
+
+ if (Tmp_win == Scr->Focus)
+ {
+ FocusOnRoot();
+ }
+ XDeleteContext(dpy, Tmp_win->w, TwmContext);
+ XDeleteContext(dpy, Tmp_win->w, ScreenContext);
+ XDeleteContext(dpy, Tmp_win->frame, TwmContext);
+ XDeleteContext(dpy, Tmp_win->frame, ScreenContext);
+ if (Tmp_win->icon_w)
+ {
+ XDeleteContext(dpy, Tmp_win->icon_w, TwmContext);
+ XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext);
+ }
+ if (Tmp_win->title_height)
+ {
+ int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
+ XDeleteContext(dpy, Tmp_win->title_w, TwmContext);
+ XDeleteContext(dpy, Tmp_win->title_w, ScreenContext);
+ if (Tmp_win->hilite_w)
+ {
+ XDeleteContext(dpy, Tmp_win->hilite_w, TwmContext);
+ XDeleteContext(dpy, Tmp_win->hilite_w, ScreenContext);
+ }
+ if (Tmp_win->titlebuttons) {
+ for (i = 0; i < nb; i++) {
+ XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
+ TwmContext);
+ XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
+ ScreenContext);
+ }
+ }
+ }
+
+ if (Scr->cmapInfo.cmaps == &Tmp_win->cmaps)
+ InstallWindowColormaps(DestroyNotify, &Scr->TwmRoot);
+
+ /*
+ * TwmWindows contain the following pointers
+ *
+ * 1. full_name
+ * 2. name
+ * 3. icon_name
+ * 4. wmhints
+ * 5. class.res_name
+ * 6. class.res_class
+ * 7. list
+ * 8. iconmgrp
+ * 9. cwins
+ * 10. titlebuttons
+ * 11. window ring
+ */
+ if (Tmp_win->gray) XFreePixmap (dpy, Tmp_win->gray);
+
+ XDestroyWindow(dpy, Tmp_win->frame);
+ if (Tmp_win->icon_w && !Tmp_win->icon_not_ours) {
+ XDestroyWindow(dpy, Tmp_win->icon_w);
+ IconDown (Tmp_win);
+ }
+ RemoveIconManager(Tmp_win); /* 7 */
+ Tmp_win->prev->next = Tmp_win->next;
+ if (Tmp_win->next != NULL)
+ Tmp_win->next->prev = Tmp_win->prev;
+ if (Tmp_win->auto_raise) Scr->NumAutoRaises--;
+
+ free_window_names (Tmp_win, True, True, True); /* 1, 2, 3 */
+ if (Tmp_win->wmhints) /* 4 */
+ XFree ((char *)Tmp_win->wmhints);
+ if (Tmp_win->class.res_name && Tmp_win->class.res_name != NoName) /* 5 */
+ XFree ((char *)Tmp_win->class.res_name);
+ if (Tmp_win->class.res_class && Tmp_win->class.res_class != NoName) /* 6 */
+ XFree ((char *)Tmp_win->class.res_class);
+ free_cwins (Tmp_win); /* 9 */
+ if (Tmp_win->titlebuttons) /* 10 */
+ free ((char *) Tmp_win->titlebuttons);
+ remove_window_from_ring (Tmp_win); /* 11 */
+
+ if (UnHighLight_win == Tmp_win)
+ UnHighLight_win = NULL;
+
+ free((char *)Tmp_win);
+}
+
+
+
+void
+HandleCreateNotify()
+{
+#ifdef DEBUG_EVENTS
+ fprintf(stderr, "CreateNotify w = 0x%x\n", Event.xcreatewindow.window);
+ fflush(stderr);
+ Bell(XkbBI_Info,0,Event.xcreatewindow.window);
+ XSync(dpy, 0);
+#endif
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleMapRequest - MapRequest event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleMapRequest()
+{
+ int stat;
+ int zoom_save;
+
+ Event.xany.window = Event.xmaprequest.window;
+ stat = XFindContext(dpy, Event.xany.window, TwmContext, (caddr_t *)&Tmp_win);
+ if (stat == XCNOENT)
+ Tmp_win = NULL;
+
+ /* If the window has never been mapped before ... */
+ if (Tmp_win == NULL)
+ {
+ /* Add decorations. */
+ Tmp_win = AddWindow(Event.xany.window, FALSE, (IconMgr *) NULL);
+ if (Tmp_win == NULL)
+ return;
+ }
+ else
+ {
+ /*
+ * If the window has been unmapped by the client, it won't be listed
+ * in the icon manager. Add it again, if requested.
+ */
+ if (Tmp_win->list == NULL)
+ (void) AddIconManager (Tmp_win);
+ }
+
+ /* If it's not merely iconified, and we have hints, use them. */
+ if ((! Tmp_win->icon) &&
+ Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint))
+ {
+ int state;
+ Window icon;
+
+ /* use WM_STATE if enabled */
+ if (!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) &&
+ (state == NormalState || state == IconicState)))
+ state = Tmp_win->wmhints->initial_state;
+
+ switch (state)
+ {
+ case DontCareState:
+ case NormalState:
+ case ZoomState:
+ case InactiveState:
+ XMapWindow(dpy, Tmp_win->w);
+ XMapWindow(dpy, Tmp_win->frame);
+ SetMapStateProp(Tmp_win, NormalState);
+ SetRaiseWindow (Tmp_win);
+ break;
+
+ case IconicState:
+ zoom_save = Scr->DoZoom;
+ Scr->DoZoom = FALSE;
+ Iconify(Tmp_win, 0, 0);
+ Scr->DoZoom = zoom_save;
+ break;
+ }
+ }
+ /* If no hints, or currently an icon, just "deiconify" */
+ else
+ {
+ DeIconify(Tmp_win);
+ SetRaiseWindow (Tmp_win);
+ }
+}
+
+
+
+void SimulateMapRequest (w)
+ Window w;
+{
+ Event.xmaprequest.window = w;
+ HandleMapRequest ();
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleMapNotify - MapNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleMapNotify()
+{
+ if (Tmp_win == NULL)
+ return;
+
+ /*
+ * Need to do the grab to avoid race condition of having server send
+ * MapNotify to client before the frame gets mapped; this is bad because
+ * the client would think that the window has a chance of being viewable
+ * when it really isn't.
+ */
+ XGrabServer (dpy);
+ if (Tmp_win->icon_w)
+ XUnmapWindow(dpy, Tmp_win->icon_w);
+ if (Tmp_win->title_w)
+ XMapSubwindows(dpy, Tmp_win->title_w);
+ XMapSubwindows(dpy, Tmp_win->frame);
+ if (Scr->Focus != Tmp_win && Tmp_win->hilite_w)
+ XUnmapWindow(dpy, Tmp_win->hilite_w);
+
+ XMapWindow(dpy, Tmp_win->frame);
+ XUngrabServer (dpy);
+ XFlush (dpy);
+ Tmp_win->mapped = TRUE;
+ Tmp_win->icon = FALSE;
+ Tmp_win->icon_on = FALSE;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleUnmapNotify - UnmapNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleUnmapNotify()
+{
+ int dstx, dsty;
+ Window dumwin;
+
+ /*
+ * The July 27, 1988 ICCCM spec states that a client wishing to switch
+ * to WithdrawnState should send a synthetic UnmapNotify with the
+ * event field set to (pseudo-)root, in case the window is already
+ * unmapped (which is the case for twm for IconicState). Unfortunately,
+ * we looked for the TwmContext using that field, so try the window
+ * field also.
+ */
+ if (Tmp_win == NULL)
+ {
+ Event.xany.window = Event.xunmap.window;
+ if (XFindContext(dpy, Event.xany.window,
+ TwmContext, (caddr_t *)&Tmp_win) == XCNOENT)
+ Tmp_win = NULL;
+ }
+
+ if (Tmp_win == NULL || (!Tmp_win->mapped && !Tmp_win->icon))
+ return;
+
+ /*
+ * The program may have unmapped the client window, from either
+ * NormalState or IconicState. Handle the transition to WithdrawnState.
+ *
+ * We need to reparent the window back to the root (so that twm exiting
+ * won't cause it to get mapped) and then throw away all state (pretend
+ * that we've received a DestroyNotify).
+ */
+
+ XGrabServer (dpy);
+ if (XTranslateCoordinates (dpy, Event.xunmap.window, Tmp_win->attr.root,
+ 0, 0, &dstx, &dsty, &dumwin)) {
+ XEvent ev;
+ Bool reparented = XCheckTypedWindowEvent (dpy, Event.xunmap.window,
+ ReparentNotify, &ev);
+ SetMapStateProp (Tmp_win, WithdrawnState);
+ if (reparented) {
+ if (Tmp_win->old_bw) XSetWindowBorderWidth (dpy,
+ Event.xunmap.window,
+ Tmp_win->old_bw);
+ if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconWindowHint))
+ XUnmapWindow (dpy, Tmp_win->wmhints->icon_window);
+ } else {
+ XReparentWindow (dpy, Event.xunmap.window, Tmp_win->attr.root,
+ dstx, dsty);
+ RestoreWithdrawnLocation (Tmp_win);
+ }
+ XRemoveFromSaveSet (dpy, Event.xunmap.window);
+ XSelectInput (dpy, Event.xunmap.window, NoEventMask);
+ HandleDestroyNotify (); /* do not need to mash event before */
+ } /* else window no longer exists and we'll get a destroy notify */
+ XUngrabServer (dpy);
+ XFlush (dpy);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleMotionNotify - MotionNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleMotionNotify()
+{
+ if (ResizeWindow != (Window) 0)
+ {
+ XQueryPointer( dpy, Event.xany.window,
+ &(Event.xmotion.root), &JunkChild,
+ &(Event.xmotion.x_root), &(Event.xmotion.y_root),
+ &(Event.xmotion.x), &(Event.xmotion.y),
+ &JunkMask);
+
+ /* Set WindowMoved appropriately so that f.deltastop will
+ work with resize as well as move. */
+ if (abs (Event.xmotion.x - ResizeOrigX) >= Scr->MoveDelta
+ || abs (Event.xmotion.y - ResizeOrigY) >= Scr->MoveDelta)
+ WindowMoved = TRUE;
+
+ XFindContext(dpy, ResizeWindow, TwmContext, (caddr_t *)&Tmp_win);
+ DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win);
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleButtonRelease - ButtonRelease event handler
+ *
+ ***********************************************************************
+ */
+void
+HandleButtonRelease()
+{
+ int xl, xr, yt, yb, w, h;
+ unsigned mask;
+
+ if (InfoLines) /* delete info box on 2nd button release */
+ if (Context == C_IDENTIFY) {
+ XUnmapWindow(dpy, Scr->InfoWindow);
+ InfoLines = 0;
+ Context = C_NO_CONTEXT;
+ }
+
+ if (DragWindow != None)
+ {
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+
+ XFindContext(dpy, DragWindow, TwmContext, (caddr_t *)&Tmp_win);
+ if (DragWindow == Tmp_win->frame)
+ {
+ xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw;
+ yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw;
+ w = DragWidth + 2 * Tmp_win->frame_bw;
+ h = DragHeight + 2 * Tmp_win->frame_bw;
+ }
+ else
+ {
+ xl = Event.xbutton.x_root - DragX - Scr->IconBorderWidth;
+ yt = Event.xbutton.y_root - DragY - Scr->IconBorderWidth;
+ w = DragWidth + 2 * Scr->IconBorderWidth;
+ h = DragHeight + 2 * Scr->IconBorderWidth;
+ }
+
+ if (ConstMove)
+ {
+ if (ConstMoveDir == MOVE_HORIZ)
+ yt = ConstMoveY;
+
+ if (ConstMoveDir == MOVE_VERT)
+ xl = ConstMoveX;
+
+ if (ConstMoveDir == MOVE_NONE)
+ {
+ yt = ConstMoveY;
+ xl = ConstMoveX;
+ }
+ }
+
+ if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
+ {
+ xr = xl + w;
+ yb = yt + h;
+
+ if (xl < 0)
+ xl = 0;
+ if (xr > Scr->MyDisplayWidth)
+ xl = Scr->MyDisplayWidth - w;
+
+ if (yt < 0)
+ yt = 0;
+ if (yb > Scr->MyDisplayHeight)
+ yt = Scr->MyDisplayHeight - h;
+ }
+
+ CurrentDragX = xl;
+ CurrentDragY = yt;
+ if (DragWindow == Tmp_win->frame)
+ SetupWindow (Tmp_win, xl, yt,
+ Tmp_win->frame_width, Tmp_win->frame_height, -1);
+ else
+ XMoveWindow (dpy, DragWindow, xl, yt);
+
+ if (!Scr->NoRaiseMove && !Scr->OpaqueMove) /* opaque already did */
+ XRaiseWindow(dpy, DragWindow);
+
+ if (!Scr->OpaqueMove)
+ UninstallRootColormap();
+ else
+ XSync(dpy, 0);
+
+ if (Scr->NumAutoRaises) {
+ enter_flag = TRUE;
+ enter_win = NULL;
+ raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove)
+ ? Tmp_win : NULL);
+ }
+
+ DragWindow = (Window) 0;
+ ConstMove = FALSE;
+ }
+
+ if (ResizeWindow != (Window) 0)
+ {
+ EndResize();
+ }
+
+ if (ActiveMenu != NULL && RootFunction == 0)
+ {
+ if (ActiveItem != NULL)
+ {
+ int func = ActiveItem->func;
+ Action = ActiveItem->action;
+ switch (func) {
+ case F_MOVE:
+ case F_FORCEMOVE:
+ ButtonPressed = -1;
+ break;
+ case F_CIRCLEUP:
+ case F_CIRCLEDOWN:
+ case F_REFRESH:
+ case F_WARPTOSCREEN:
+ PopDownMenu();
+ break;
+ default:
+ break;
+ }
+ ExecuteFunction(func, Action,
+ ButtonWindow ? ButtonWindow->frame : None,
+ ButtonWindow, &Event/*&ButtonEvent*/, Context, TRUE);
+ Context = C_NO_CONTEXT;
+ ButtonWindow = NULL;
+
+ /* if we are not executing a defered command, then take down the
+ * menu
+ */
+ if (RootFunction == 0)
+ {
+ PopDownMenu();
+ }
+ }
+ else
+ PopDownMenu();
+ }
+
+ mask = (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
+ switch (Event.xbutton.button)
+ {
+ case Button1: mask &= ~Button1Mask; break;
+ case Button2: mask &= ~Button2Mask; break;
+ case Button3: mask &= ~Button3Mask; break;
+ case Button4: mask &= ~Button4Mask; break;
+ case Button5: mask &= ~Button5Mask; break;
+ }
+
+ if (RootFunction != 0 ||
+ ResizeWindow != None ||
+ DragWindow != None)
+ ButtonPressed = -1;
+
+ if (RootFunction == 0 &&
+ (Event.xbutton.state & mask) == 0 &&
+ DragWindow == None &&
+ ResizeWindow == None)
+ {
+ XUngrabPointer(dpy, CurrentTime);
+ XUngrabServer(dpy);
+ XFlush(dpy);
+ EventHandler[EnterNotify] = HandleEnterNotify;
+ EventHandler[LeaveNotify] = HandleLeaveNotify;
+ ButtonPressed = -1;
+ if (DownIconManager)
+ {
+ DownIconManager->down = FALSE;
+ if (Scr->Highlight) DrawIconManagerBorder(DownIconManager);
+ DownIconManager = NULL;
+ }
+ Cancel = FALSE;
+ }
+}
+
+
+
+static do_menu (menu, w)
+ MenuRoot *menu; /* menu to pop up */
+ Window w; /* invoking window or None */
+{
+ int x = Event.xbutton.x_root;
+ int y = Event.xbutton.y_root;
+ Bool center;
+
+ if (!Scr->NoGrabServer)
+ XGrabServer(dpy);
+ if (w) {
+ int h = Scr->TBInfo.width - Scr->TBInfo.border;
+ Window child;
+
+ (void) XTranslateCoordinates (dpy, w, Scr->Root, 0, h, &x, &y, &child);
+ center = False;
+ } else {
+ center = True;
+ }
+ if (PopUpMenu (menu, x, y, center)) {
+ UpdateMenu();
+ } else {
+ Bell(XkbBI_MinorError,0,w);
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleButtonPress - ButtonPress event handler
+ *
+ ***********************************************************************
+ */
+void
+HandleButtonPress()
+{
+ unsigned int modifier;
+ Cursor cur;
+
+ /* pop down the menu, if any */
+ if (ActiveMenu != NULL)
+ PopDownMenu();
+
+ XSync(dpy, 0); /* XXX - remove? */
+
+ if (ButtonPressed != -1 && !InfoLines) /* want menus if we have info box */
+ {
+ /* we got another butt press in addition to one still held
+ * down, we need to cancel the operation we were doing
+ */
+ Cancel = TRUE;
+ CurrentDragX = origDragX;
+ CurrentDragY = origDragY;
+ if (!menuFromFrameOrWindowOrTitlebar)
+ if (Scr->OpaqueMove && DragWindow != None) {
+ XMoveWindow (dpy, DragWindow, origDragX, origDragY);
+ } else {
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+ }
+ XUnmapWindow(dpy, Scr->SizeWindow);
+ if (!Scr->OpaqueMove)
+ UninstallRootColormap();
+ ResizeWindow = None;
+ DragWindow = None;
+ cur = LeftButt;
+ if (Event.xbutton.button == Button2)
+ cur = MiddleButt;
+ else if (Event.xbutton.button >= Button3)
+ cur = RightButt;
+
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonReleaseMask | ButtonPressMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, cur, CurrentTime);
+
+ return;
+ }
+ else
+ ButtonPressed = Event.xbutton.button;
+
+ if (ResizeWindow != None ||
+ DragWindow != None ||
+ ActiveMenu != NULL)
+ return;
+
+ /* check the title bar buttons */
+ if (Tmp_win && Tmp_win->title_height && Tmp_win->titlebuttons)
+ {
+ register int i;
+ register TBWindow *tbw;
+ int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
+
+ for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
+ if (Event.xany.window == tbw->window) {
+ if (tbw->info->func == F_MENU) {
+ Context = C_TITLE;
+ ButtonEvent = Event;
+ ButtonWindow = Tmp_win;
+ do_menu (tbw->info->menuroot, tbw->window);
+ } else {
+ ExecuteFunction (tbw->info->func, tbw->info->action,
+ Event.xany.window, Tmp_win, &Event,
+ C_TITLE, FALSE);
+ }
+ return;
+ }
+ }
+ }
+
+ Context = C_NO_CONTEXT;
+
+ if (Event.xany.window == Scr->InfoWindow)
+ Context = C_IDENTIFY;
+
+ if (Event.xany.window == Scr->Root)
+ Context = C_ROOT;
+ if (Tmp_win)
+ {
+ if (Tmp_win->list && RootFunction != 0 &&
+ (Event.xany.window == Tmp_win->list->w ||
+ Event.xany.window == Tmp_win->list->icon))
+ {
+ Tmp_win = Tmp_win->list->iconmgr->twm_win;
+ XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w,
+ Event.xbutton.x, Event.xbutton.y,
+ &JunkX, &JunkY, &JunkChild);
+
+ Event.xbutton.x = JunkX;
+ Event.xbutton.y = JunkY - Tmp_win->title_height;
+ Event.xany.window = Tmp_win->w;
+ Context = C_WINDOW;
+ }
+ else if (Event.xany.window == Tmp_win->title_w)
+ {
+ Context = C_TITLE;
+ }
+ else if (Event.xany.window == Tmp_win->w)
+ {
+ printf("ERROR! ERROR! ERROR! YOU SHOULD NOT BE HERE!!!\n");
+ Context = C_WINDOW;
+ }
+ else if (Event.xany.window == Tmp_win->icon_w)
+ {
+ Context = C_ICON;
+ }
+ else if (Event.xany.window == Tmp_win->frame)
+ {
+ /* since we now place a button grab on the frame instead
+ * of the window, (see GrabButtons() in add_window.c), we
+ * need to figure out where the pointer exactly is before
+ * assigning Context. If the pointer is on the application
+ * window we will change the event structure to look as if
+ * it came from the application window.
+ */
+ if (Event.xbutton.subwindow == Tmp_win->w) {
+ Event.xbutton.window = Tmp_win->w;
+ Event.xbutton.y -= Tmp_win->title_height;
+/*****
+ Event.xbutton.x -= Tmp_win->frame_bw;
+*****/
+ Context = C_WINDOW;
+ }
+ else Context = C_FRAME;
+ }
+ else if (Tmp_win->list &&
+ (Event.xany.window == Tmp_win->list->w ||
+ Event.xany.window == Tmp_win->list->icon))
+ {
+ Tmp_win->list->down = TRUE;
+ if (Scr->Highlight) DrawIconManagerBorder(Tmp_win->list);
+ DownIconManager = Tmp_win->list;
+ Context = C_ICONMGR;
+ }
+ }
+
+ /* this section of code checks to see if we were in the middle of
+ * a command executed from a menu
+ */
+ if (RootFunction != 0)
+ {
+ if (Event.xany.window == Scr->Root)
+ {
+ /* if the window was the Root, we don't know for sure it
+ * it was the root. We must check to see if it happened to be
+ * inside of a client that was getting button press events.
+ */
+ XTranslateCoordinates(dpy, Scr->Root, Scr->Root,
+ Event.xbutton.x,
+ Event.xbutton.y,
+ &JunkX, &JunkY, &Event.xany.window);
+
+ if (Event.xany.window == 0 ||
+ (XFindContext(dpy, Event.xany.window, TwmContext,
+ (caddr_t *)&Tmp_win) == XCNOENT))
+ {
+ RootFunction = 0;
+ Bell(XkbBI_MinorError,0,Event.xany.window);
+ return;
+ }
+
+ XTranslateCoordinates(dpy, Scr->Root, Event.xany.window,
+ Event.xbutton.x,
+ Event.xbutton.y,
+ &JunkX, &JunkY, &JunkChild);
+
+ Event.xbutton.x = JunkX;
+ Event.xbutton.y = JunkY;
+ Context = C_WINDOW;
+ }
+
+ /* make sure we are not trying to move an identify window */
+ if (Event.xany.window != Scr->InfoWindow)
+ ExecuteFunction(RootFunction, Action, Event.xany.window,
+ Tmp_win, &Event, Context, FALSE);
+
+ RootFunction = 0;
+ return;
+ }
+
+ ButtonEvent = Event;
+ ButtonWindow = Tmp_win;
+
+ /* if we get to here, we have to execute a function or pop up a
+ * menu
+ */
+ modifier = (Event.xbutton.state & mods_used);
+
+ if (Context == C_NO_CONTEXT)
+ return;
+
+ RootFunction = 0;
+ if (Scr->Mouse[Event.xbutton.button][Context][modifier].func == F_MENU)
+ {
+ do_menu (Scr->Mouse[Event.xbutton.button][Context][modifier].menu,
+ (Window) None);
+ }
+ else if (Scr->Mouse[Event.xbutton.button][Context][modifier].func != 0)
+ {
+ Action = Scr->Mouse[Event.xbutton.button][Context][modifier].item ?
+ Scr->Mouse[Event.xbutton.button][Context][modifier].item->action : NULL;
+ ExecuteFunction(Scr->Mouse[Event.xbutton.button][Context][modifier].func,
+ Action, Event.xany.window, Tmp_win, &Event, Context, FALSE);
+ }
+ else if (Scr->DefaultFunction.func != 0)
+ {
+ if (Scr->DefaultFunction.func == F_MENU)
+ {
+ do_menu (Scr->DefaultFunction.menu, (Window) None);
+ }
+ else
+ {
+ Action = Scr->DefaultFunction.item ?
+ Scr->DefaultFunction.item->action : NULL;
+ ExecuteFunction(Scr->DefaultFunction.func, Action,
+ Event.xany.window, Tmp_win, &Event, Context, FALSE);
+ }
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HENQueueScanner - EnterNotify event q scanner
+ *
+ * Looks at the queued events and determines if any matching
+ * LeaveNotify events or EnterEvents deriving from the
+ * termination of a grab are behind this event to allow
+ * skipping of unnecessary processing.
+ *
+ ***********************************************************************
+ */
+
+typedef struct HENScanArgs {
+ Window w; /* Window we are currently entering */
+ Bool leaves; /* Any LeaveNotifies found for this window */
+ Bool inferior; /* Was NotifyInferior the mode for LeaveNotify */
+ Bool enters; /* Any EnterNotify events with NotifyUngrab */
+} HENScanArgs;
+
+/* ARGSUSED*/
+static Bool
+HENQueueScanner(dpy, ev, args)
+ Display *dpy;
+ XEvent *ev;
+ char *args;
+{
+ if (ev->type == LeaveNotify) {
+ if (ev->xcrossing.window == ((HENScanArgs *) args)->w &&
+ ev->xcrossing.mode == NotifyNormal) {
+ ((HENScanArgs *) args)->leaves = True;
+ /*
+ * Only the last event found matters for the Inferior field.
+ */
+ ((HENScanArgs *) args)->inferior =
+ (ev->xcrossing.detail == NotifyInferior);
+ }
+ } else if (ev->type == EnterNotify) {
+ if (ev->xcrossing.mode == NotifyUngrab)
+ ((HENScanArgs *) args)->enters = True;
+ }
+
+ return (False);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleEnterNotify - EnterNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleEnterNotify()
+{
+ MenuRoot *mr;
+ XEnterWindowEvent *ewp = &Event.xcrossing;
+ HENScanArgs scanArgs;
+ XEvent dummy;
+
+ /*
+ * Save the id of the window entered. This will be used to remove
+ * border highlight on entering the next application window.
+ */
+ if (UnHighLight_win && ewp->window != UnHighLight_win->w) {
+ SetBorder (UnHighLight_win, False); /* application window */
+ if (UnHighLight_win->list) /* in the icon box */
+ NotActiveIconManager(UnHighLight_win->list);
+ }
+ if (ewp->window == Scr->Root)
+ UnHighLight_win = NULL;
+ else if (Tmp_win)
+ UnHighLight_win = Tmp_win;
+
+ /*
+ * if we aren't in the middle of menu processing
+ */
+ if (!ActiveMenu) {
+ /*
+ * We're not interested in pseudo Enter/Leave events generated
+ * from grab initiations.
+ */
+ if (ewp->mode == NotifyGrab)
+ return;
+
+ /*
+ * Scan for Leave and Enter Notify events to see if we can avoid some
+ * unnecessary processing.
+ */
+ scanArgs.w = ewp->window;
+ scanArgs.leaves = scanArgs.enters = False;
+ (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (char *) &scanArgs);
+
+ /*
+ * if entering root window, restore twm default colormap so that
+ * titlebars are legible
+ */
+ if (ewp->window == Scr->Root) {
+ if (!scanArgs.leaves && !scanArgs.enters)
+ InstallWindowColormaps(EnterNotify, &Scr->TwmRoot);
+ return;
+ }
+
+ /*
+ * if we have an event for a specific one of our windows
+ */
+ if (Tmp_win) {
+ /*
+ * If currently in PointerRoot mode (indicated by FocusRoot), then
+ * focus on this window
+ */
+ if (Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) {
+ if (Tmp_win->list) ActiveIconManager(Tmp_win->list);
+ if (Tmp_win->mapped) {
+ /*
+ * unhighlight old focus window
+ */
+ if (Scr->Focus &&
+ Scr->Focus != Tmp_win && Tmp_win->hilite_w)
+ XUnmapWindow(dpy, Scr->Focus->hilite_w);
+
+ /*
+ * If entering the frame or the icon manager, then do
+ * "window activation things":
+ *
+ * 1. turn on highlight window (if any)
+ * 2. install frame colormap
+ * 3. set frame and highlight window (if any) border
+ * 4. focus on client window to forward typing
+ * 4a. same as 4 but for icon mgr w/with NoTitlebar on.
+ * 5. send WM_TAKE_FOCUS if requested
+ */
+ if (ewp->window == Tmp_win->frame ||
+ (Tmp_win->list && ewp->window == Tmp_win->list->w)) {
+ if (Tmp_win->hilite_w) /* 1 */
+ XMapWindow (dpy, Tmp_win->hilite_w);
+ if (!scanArgs.leaves && !scanArgs.enters)
+ InstallWindowColormaps (EnterNotify, /* 2 */
+ &Scr->TwmRoot);
+ SetBorder (Tmp_win, True); /* 3 */
+ 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 */
+ Tmp_win->wmhints && Tmp_win->wmhints->input)
+ SetFocus (Tmp_win, ewp->time);
+ if (Tmp_win->protocols & DoesWmTakeFocus) /* 5 */
+ SendTakeFocusMessage (Tmp_win, ewp->time);
+ Scr->Focus = Tmp_win;
+ } else if (ewp->window == Tmp_win->w) {
+ /*
+ * If we are entering the application window, install
+ * its colormap(s).
+ */
+ if (!scanArgs.leaves || scanArgs.inferior)
+ InstallWindowColormaps(EnterNotify, Tmp_win);
+ }
+ } /* end if Tmp_win->mapped */
+ if (Tmp_win->wmhints != NULL &&
+ ewp->window == Tmp_win->wmhints->icon_window &&
+ (!scanArgs.leaves || scanArgs.inferior))
+ InstallWindowColormaps(EnterNotify, Tmp_win);
+ } /* end if FocusRoot */
+ /*
+ * If this window is to be autoraised, mark it so
+ */
+ if (Tmp_win->auto_raise) {
+ enter_win = Tmp_win;
+ if (enter_flag == FALSE) AutoRaiseWindow (Tmp_win);
+ } else if (enter_flag && raise_win == Tmp_win)
+ enter_win = Tmp_win;
+ /*
+ * set ring leader
+ */
+ if (Tmp_win->ring.next && (!enter_flag || raise_win == enter_win))
+ Scr->RingLeader = Tmp_win;
+ XSync (dpy, 0);
+ return;
+ } /* end if Tmp_win */
+ } /* end if !ActiveMenu */
+
+ /*
+ * Find the menu that we are dealing with now; punt if unknown
+ */
+ if (XFindContext (dpy, ewp->window, MenuContext, (caddr_t *)&mr) != XCSUCCESS) return;
+
+ mr->entered = TRUE;
+ if (ActiveMenu && mr == ActiveMenu->prev && RootFunction == 0) {
+ if (Scr->Shadow) XUnmapWindow (dpy, ActiveMenu->shadow);
+ XUnmapWindow (dpy, ActiveMenu->w);
+ ActiveMenu->mapped = UNMAPPED;
+ UninstallRootColormap ();
+ if (ActiveItem) {
+ ActiveItem->state = 0;
+ PaintEntry (ActiveMenu, ActiveItem, False);
+ }
+ ActiveItem = NULL;
+ ActiveMenu = mr;
+ MenuDepth--;
+ }
+ return;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HLNQueueScanner - LeaveNotify event q scanner
+ *
+ * Looks at the queued events and determines if any
+ * EnterNotify events are behind this event to allow
+ * skipping of unnecessary processing.
+ *
+ ***********************************************************************
+ */
+
+typedef struct HLNScanArgs {
+ Window w; /* The window getting the LeaveNotify */
+ Bool enters; /* Any EnterNotify event at all */
+ Bool matches; /* Any matching EnterNotify events */
+} HLNScanArgs;
+
+/* ARGSUSED*/
+static Bool
+HLNQueueScanner(dpy, ev, args)
+ Display *dpy;
+ XEvent *ev;
+ char *args;
+{
+ if (ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) {
+ ((HLNScanArgs *) args)->enters = True;
+ if (ev->xcrossing.window == ((HLNScanArgs *) args)->w)
+ ((HLNScanArgs *) args)->matches = True;
+ }
+
+ return (False);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleLeaveNotify - LeaveNotify event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleLeaveNotify()
+{
+ HLNScanArgs scanArgs;
+ XEvent dummy;
+
+ if (Tmp_win != NULL)
+ {
+ Bool inicon;
+
+ /*
+ * We're not interested in pseudo Enter/Leave events generated
+ * from grab initiations and terminations.
+ */
+ if (Event.xcrossing.mode != NotifyNormal)
+ return;
+
+ inicon = (Tmp_win->list &&
+ Tmp_win->list->w == Event.xcrossing.window);
+
+ if (Scr->RingLeader && Scr->RingLeader == Tmp_win &&
+ (Event.xcrossing.detail != NotifyInferior &&
+ Event.xcrossing.window != Tmp_win->w)) {
+ if (!inicon) {
+ if (Tmp_win->mapped) {
+ Tmp_win->ring.cursor_valid = False;
+ } else {
+ Tmp_win->ring.cursor_valid = True;
+ Tmp_win->ring.curs_x = (Event.xcrossing.x_root -
+ Tmp_win->frame_x);
+ Tmp_win->ring.curs_y = (Event.xcrossing.y_root -
+ Tmp_win->frame_y);
+ }
+ }
+ Scr->RingLeader = (TwmWindow *) NULL;
+ }
+ if (Scr->FocusRoot) {
+
+ if (Event.xcrossing.detail != NotifyInferior) {
+
+ /*
+ * Scan for EnterNotify events to see if we can avoid some
+ * unnecessary processing.
+ */
+ scanArgs.w = Event.xcrossing.window;
+ scanArgs.enters = scanArgs.matches = False;
+ (void) XCheckIfEvent(dpy, &dummy, HLNQueueScanner,
+ (char *) &scanArgs);
+
+ if ((Event.xcrossing.window == Tmp_win->frame &&
+ !scanArgs.matches) || inicon) {
+ if (Tmp_win->list) NotActiveIconManager(Tmp_win->list);
+ if (Tmp_win->hilite_w)
+ XUnmapWindow (dpy, Tmp_win->hilite_w);
+ SetBorder (Tmp_win, False);
+ if (Scr->TitleFocus ||
+ Tmp_win->protocols & DoesWmTakeFocus)
+ SetFocus ((TwmWindow *) NULL, Event.xcrossing.time);
+ Scr->Focus = NULL;
+ } else if (Event.xcrossing.window == Tmp_win->w &&
+ !scanArgs.enters) {
+ InstallWindowColormaps (LeaveNotify, &Scr->TwmRoot);
+ }
+ }
+ }
+ XSync (dpy, 0);
+ return;
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleConfigureRequest - ConfigureRequest event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleConfigureRequest()
+{
+ XWindowChanges xwc;
+ unsigned long xwcm;
+ int x, y, width, height, bw;
+ int gravx, gravy;
+ XConfigureRequestEvent *cre = &Event.xconfigurerequest;
+
+#ifdef DEBUG_EVENTS
+ fprintf(stderr, "ConfigureRequest\n");
+ if (cre->value_mask & CWX)
+ fprintf(stderr, " x = %d\n", cre->x);
+ if (cre->value_mask & CWY)
+ fprintf(stderr, " y = %d\n", cre->y);
+ if (cre->value_mask & CWWidth)
+ fprintf(stderr, " width = %d\n", cre->width);
+ if (cre->value_mask & CWHeight)
+ fprintf(stderr, " height = %d\n", cre->height);
+ if (cre->value_mask & CWSibling)
+ fprintf(stderr, " above = 0x%x\n", cre->above);
+ if (cre->value_mask & CWStackMode)
+ fprintf(stderr, " stack = %d\n", cre->detail);
+#endif
+
+ /*
+ * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will
+ * be wrong
+ */
+ Event.xany.window = cre->window; /* mash parent field */
+ if (XFindContext (dpy, cre->window, TwmContext, (caddr_t *) &Tmp_win) ==
+ XCNOENT)
+ Tmp_win = NULL;
+
+
+ /*
+ * According to the July 27, 1988 ICCCM draft, we should ignore size and
+ * position fields in the WM_NORMAL_HINTS property when we map a window.
+ * Instead, we'll read the current geometry. Therefore, we should respond
+ * to configuration requests for windows which have never been mapped.
+ */
+ if (!Tmp_win || Tmp_win->icon_w == cre->window) {
+ xwcm = cre->value_mask &
+ (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
+ xwc.x = cre->x;
+ xwc.y = cre->y;
+ xwc.width = cre->width;
+ xwc.height = cre->height;
+ xwc.border_width = cre->border_width;
+ XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc);
+ return;
+ }
+
+ if ((cre->value_mask & CWStackMode) && Tmp_win->stackmode) {
+ TwmWindow *otherwin;
+
+ xwc.sibling = (((cre->value_mask & CWSibling) &&
+ (XFindContext (dpy, cre->above, TwmContext,
+ (caddr_t *) &otherwin) == XCSUCCESS))
+ ? otherwin->frame : cre->above);
+ xwc.stack_mode = cre->detail;
+ XConfigureWindow (dpy, Tmp_win->frame,
+ cre->value_mask & (CWSibling | CWStackMode), &xwc);
+ }
+
+
+ /* Don't modify frame_XXX fields before calling SetupWindow! */
+ x = Tmp_win->frame_x;
+ y = Tmp_win->frame_y;
+ width = Tmp_win->frame_width;
+ height = Tmp_win->frame_height;
+ bw = Tmp_win->frame_bw;
+
+ /*
+ * Section 4.1.5 of the ICCCM states that the (x,y) coordinates in the
+ * configure request are for the upper-left outer corner of the window.
+ * This means that we need to adjust for the additional title height as
+ * well as for any border width changes that we decide to allow. The
+ * current window gravity is to be used in computing the adjustments, just
+ * as when initially locating the window. Note that if we do decide to
+ * allow border width changes, we will need to send the synthetic
+ * ConfigureNotify event.
+ */
+ GetGravityOffsets (Tmp_win, &gravx, &gravy);
+
+ if (cre->value_mask & CWBorderWidth) {
+ int bwdelta = cre->border_width - Tmp_win->old_bw; /* posit growth */
+ if (bwdelta && Scr->ClientBorderWidth) { /* if change allowed */
+ x += gravx * bwdelta; /* change default values only */
+ y += gravy * bwdelta; /* ditto */
+ bw = cre->border_width;
+ if (Tmp_win->title_height) height += bwdelta;
+ x += (gravx < 0) ? bwdelta : -bwdelta;
+ y += (gravy < 0) ? bwdelta : -bwdelta;
+ }
+ Tmp_win->old_bw = cre->border_width; /* for restoring */
+ }
+
+ if (cre->value_mask & CWX) { /* override even if border change */
+ x = cre->x - bw;
+ }
+ if (cre->value_mask & CWY) {
+ y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw;
+ }
+
+ if (cre->value_mask & CWWidth) {
+ width = cre->width;
+ }
+ if (cre->value_mask & CWHeight) {
+ height = cre->height + Tmp_win->title_height;
+ }
+
+ if (width != Tmp_win->frame_width || height != Tmp_win->frame_height)
+ Tmp_win->zoomed = ZOOM_NONE;
+
+ /*
+ * SetupWindow (x,y) are the location of the upper-left outer corner and
+ * are passed directly to XMoveResizeWindow (frame). The (width,height)
+ * are the inner size of the frame. The inner width is the same as the
+ * requested client window width; the inner height is the same as the
+ * requested client window height plus any title bar slop.
+ */
+ SetupWindow (Tmp_win, x, y, width, height, bw);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleShapeNotify - shape notification event handler
+ *
+ ***********************************************************************
+ */
+void
+HandleShapeNotify ()
+{
+ XShapeEvent *sev = (XShapeEvent *) &Event;
+
+ if (Tmp_win == NULL)
+ return;
+ if (sev->kind != ShapeBounding)
+ return;
+ if (!Tmp_win->wShaped && sev->shaped) {
+ XShapeCombineMask (dpy, Tmp_win->frame, ShapeClip, 0, 0, None,
+ ShapeSet);
+ }
+ Tmp_win->wShaped = sev->shaped;
+ SetFrameShape (Tmp_win);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * HandleUnknown - unknown event handler
+ *
+ ***********************************************************************
+ */
+
+void
+HandleUnknown()
+{
+#ifdef DEBUG_EVENTS
+ fprintf(stderr, "type = %d\n", Event.type);
+#endif
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * Transient - checks to see if the window is a transient
+ *
+ * Returned Value:
+ * TRUE - window is a transient
+ * FALSE - window is not a transient
+ *
+ * Inputs:
+ * w - the window to check
+ *
+ ***********************************************************************
+ */
+
+int
+Transient(w, propw)
+ Window w, *propw;
+{
+ return (XGetTransientForHint(dpy, w, propw));
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * FindScreenInfo - get ScreenInfo struct associated with a given window
+ *
+ * Returned Value:
+ * ScreenInfo struct
+ *
+ * Inputs:
+ * w - the window
+ *
+ ***********************************************************************
+ */
+
+ScreenInfo *
+FindScreenInfo(w)
+ Window w;
+{
+ XWindowAttributes attr;
+ int scrnum;
+
+ attr.screen = NULL;
+ if (XGetWindowAttributes(dpy, w, &attr)) {
+ for (scrnum = 0; scrnum < NumScreens; scrnum++) {
+ if (ScreenList[scrnum] != NULL &&
+ (ScreenOfDisplay(dpy, ScreenList[scrnum]->screen) ==
+ attr.screen))
+ return ScreenList[scrnum];
+ }
+ }
+
+ return NULL;
+}
+
+
+
+static void flush_expose (w)
+ Window w;
+{
+ XEvent dummy;
+
+ /* SUPPRESS 530 */
+ while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy)) ;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * InstallWindowColormaps - install the colormaps for one twm window
+ *
+ * Inputs:
+ * type - type of event that caused the installation
+ * tmp - for a subset of event types, the address of the
+ * window structure, whose colormaps are to be installed.
+ *
+ ***********************************************************************
+ */
+
+InstallWindowColormaps (type, tmp)
+ int type;
+ TwmWindow *tmp;
+{
+ int i, j, n, number_cwins, state;
+ ColormapWindow **cwins, *cwin, **maxcwin = NULL;
+ TwmColormap *cmap;
+ char *row, *scoreboard;
+
+ switch (type) {
+ case EnterNotify:
+ case LeaveNotify:
+ case DestroyNotify:
+ default:
+ /* Save the colormap to be loaded for when force loading of
+ * root colormap(s) ends.
+ */
+ Scr->cmapInfo.pushed_window = tmp;
+ /* Don't load any new colormap if root colormap(s) has been
+ * force loaded.
+ */
+ if (Scr->cmapInfo.root_pushes)
+ return;
+ /* Don't reload the currend window colormap list.
+ */
+ if (Scr->cmapInfo.cmaps == &tmp->cmaps)
+ return;
+ if (Scr->cmapInfo.cmaps)
+ for (i = Scr->cmapInfo.cmaps->number_cwins,
+ cwins = Scr->cmapInfo.cmaps->cwins; i-- > 0; cwins++)
+ (*cwins)->colormap->state &= ~CM_INSTALLABLE;
+ Scr->cmapInfo.cmaps = &tmp->cmaps;
+ break;
+
+ case PropertyNotify:
+ case VisibilityNotify:
+ case ColormapNotify:
+ break;
+ }
+
+ number_cwins = Scr->cmapInfo.cmaps->number_cwins;
+ cwins = Scr->cmapInfo.cmaps->cwins;
+ scoreboard = Scr->cmapInfo.cmaps->scoreboard;
+
+ ColortableThrashing = FALSE; /* in case installation aborted */
+
+ state = CM_INSTALLED;
+
+ for (i = n = 0; i < number_cwins; i++) {
+ cwin = cwins[i];
+ cmap = cwin->colormap;
+ cmap->state |= CM_INSTALLABLE;
+ cmap->state &= ~CM_INSTALL;
+ cmap->w = cwin->w;
+ }
+ for (i = n = 0; i < number_cwins; i++) {
+ cwin = cwins[i];
+ cmap = cwin->colormap;
+ if (cwin->visibility != VisibilityFullyObscured &&
+ n < Scr->cmapInfo.maxCmaps) {
+ row = scoreboard + (i*(i-1)/2);
+ for (j = 0; j < i; j++)
+ if (row[j] && (cwins[j]->colormap->state & CM_INSTALL))
+ break;
+ if (j != i)
+ continue;
+ n++;
+ maxcwin = &cwins[i];
+ state &= (cmap->state & CM_INSTALLED);
+ cmap->state |= CM_INSTALL;
+ }
+ }
+
+ Scr->cmapInfo.first_req = NextRequest(dpy);
+
+ for ( ; n > 0 && maxcwin >= cwins; maxcwin--) {
+ cmap = (*maxcwin)->colormap;
+ if (cmap->state & CM_INSTALL) {
+ cmap->state &= ~CM_INSTALL;
+ if (!(state & CM_INSTALLED)) {
+ cmap->install_req = NextRequest(dpy);
+ XInstallColormap(dpy, cmap->c);
+ }
+ cmap->state |= CM_INSTALLED;
+ n--;
+ }
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedures:
+ * <Uni/I>nstallRootColormap - Force (un)loads root colormap(s)
+ *
+ * These matching routines provide a mechanism to insure that
+ * the root colormap(s) is installed during operations like
+ * rubber banding or menu display that require colors from
+ * that colormap. Calls may be nested arbitrarily deeply,
+ * as long as there is one UninstallRootColormap call per
+ * InstallRootColormap call.
+ *
+ * The final UninstallRootColormap will cause the colormap list
+ * which would otherwise have be loaded to be loaded, unless
+ * Enter or Leave Notify events are queued, indicating some
+ * other colormap list would potentially be loaded anyway.
+ ***********************************************************************
+ */
+
+InstallRootColormap()
+{
+ TwmWindow *tmp;
+ if (Scr->cmapInfo.root_pushes == 0) {
+ /*
+ * The saving and restoring of cmapInfo.pushed_window here
+ * is a slimy way to remember the actual pushed list and
+ * not that of the root window.
+ */
+ tmp = Scr->cmapInfo.pushed_window;
+ InstallWindowColormaps(0, &Scr->TwmRoot);
+ Scr->cmapInfo.pushed_window = tmp;
+ }
+ Scr->cmapInfo.root_pushes++;
+}
+
+
+
+/* ARGSUSED*/
+static Bool
+UninstallRootColormapQScanner(dpy, ev, args)
+ Display *dpy;
+ XEvent *ev;
+ char *args;
+{
+ if (!*args)
+ if (ev->type == EnterNotify) {
+ if (ev->xcrossing.mode != NotifyGrab)
+ *args = 1;
+ } else if (ev->type == LeaveNotify) {
+ if (ev->xcrossing.mode == NotifyNormal)
+ *args = 1;
+ }
+
+ return (False);
+}
+
+
+
+UninstallRootColormap()
+{
+ char args;
+ XEvent dummy;
+
+ if (Scr->cmapInfo.root_pushes)
+ Scr->cmapInfo.root_pushes--;
+
+ if (!Scr->cmapInfo.root_pushes) {
+ /*
+ * If we have subsequent Enter or Leave Notify events,
+ * we can skip the reload of pushed colormaps.
+ */
+ XSync (dpy, 0);
+ args = 0;
+ (void) XCheckIfEvent(dpy, &dummy, UninstallRootColormapQScanner, &args);
+
+ if (!args)
+ InstallWindowColormaps(0, Scr->cmapInfo.pushed_window);
+ }
+}
+
+#ifdef TRACE
+dumpevent (e)
+ XEvent *e;
+{
+ char *name = NULL;
+
+ switch (e->type) {
+ case KeyPress: name = "KeyPress"; break;
+ case KeyRelease: name = "KeyRelease"; break;
+ case ButtonPress: name = "ButtonPress"; break;
+ case ButtonRelease: name = "ButtonRelease"; break;
+ case MotionNotify: name = "MotionNotify"; break;
+ case EnterNotify: name = "EnterNotify"; break;
+ case LeaveNotify: name = "LeaveNotify"; break;
+ case FocusIn: name = "FocusIn"; break;
+ case FocusOut: name = "FocusOut"; break;
+ case KeymapNotify: name = "KeymapNotify"; break;
+ case Expose: name = "Expose"; break;
+ case GraphicsExpose: name = "GraphicsExpose"; break;
+ case NoExpose: name = "NoExpose"; break;
+ case VisibilityNotify: name = "VisibilityNotify"; break;
+ case CreateNotify: name = "CreateNotify"; break;
+ case DestroyNotify: name = "DestroyNotify"; break;
+ case UnmapNotify: name = "UnmapNotify"; break;
+ case MapNotify: name = "MapNotify"; break;
+ case MapRequest: name = "MapRequest"; break;
+ case ReparentNotify: name = "ReparentNotify"; break;
+ case ConfigureNotify: name = "ConfigureNotify"; break;
+ case ConfigureRequest: name = "ConfigureRequest"; break;
+ case GravityNotify: name = "GravityNotify"; break;
+ case ResizeRequest: name = "ResizeRequest"; break;
+ case CirculateNotify: name = "CirculateNotify"; break;
+ case CirculateRequest: name = "CirculateRequest"; break;
+ case PropertyNotify: name = "PropertyNotify"; break;
+ case SelectionClear: name = "SelectionClear"; break;
+ case SelectionRequest: name = "SelectionRequest"; break;
+ case SelectionNotify: name = "SelectionNotify"; break;
+ case ColormapNotify: name = "ColormapNotify"; break;
+ case ClientMessage: name = "ClientMessage"; break;
+ case MappingNotify: name = "MappingNotify"; break;
+ }
+
+ if (name) {
+ printf ("event: %s, %d remaining\n", name, QLength(dpy));
+ } else {
+ printf ("unknown event %d, %d remaining\n", e->type, QLength(dpy));
+ }
+}
+#endif /* TRACE */
+
diff --git a/src/events.h b/src/events.h
new file mode 100644
index 0000000..adb15b5
--- /dev/null
+++ b/src/events.h
@@ -0,0 +1,111 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/***********************************************************************
+ *
+ * $Xorg: events.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * twm event handler include file
+ *
+ * 17-Nov-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#ifndef _EVENTS_
+#define _EVENTS_
+
+typedef void (*event_proc)();
+
+extern void InitEvents();
+extern Bool StashEventTime();
+extern Time lastTimestamp;
+extern void SimulateMapRequest();
+extern void AutoRaiseWindow();
+#define LastTimestamp() lastTimestamp
+extern Bool DispatchEvent();
+extern Bool DispatchEvent2();
+extern void HandleEvents();
+extern void HandleExpose();
+extern void HandleDestroyNotify();
+extern void HandleMapRequest();
+extern void HandleMapNotify();
+extern void HandleUnmapNotify();
+extern void HandleMotionNotify();
+extern void HandleButtonRelease();
+extern void HandleButtonPress();
+extern void HandleEnterNotify();
+extern void HandleLeaveNotify();
+extern void HandleConfigureRequest();
+extern void HandleClientMessage();
+extern void HandlePropertyNotify();
+extern void HandleKeyPress();
+extern void HandleColormapNotify();
+extern void HandleVisibilityNotify();
+extern void HandleUnknown();
+
+extern event_proc EventHandler[];
+extern Window DragWindow;
+extern int origDragX;
+extern int origDragY;
+extern int DragX;
+extern int DragY;
+extern int DragWidth;
+extern int DragHeight;
+extern int CurrentDragX;
+extern int CurrentDragY;
+
+extern int ButtonPressed;
+extern int Cancel;
+
+extern XEvent Event;
+
+#endif /* _EVENTS_ */
diff --git a/src/gc.c b/src/gc.c
new file mode 100644
index 0000000..2cdf838
--- /dev/null
+++ b/src/gc.c
@@ -0,0 +1,117 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/**********************************************************************
+ *
+ * $Xorg: gc.c,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Open the fonts and create the GCs
+ *
+ * 31-Mar-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include "util.h"
+#include "screen.h"
+
+/***********************************************************************
+ *
+ * Procedure:
+ * CreateGCs - open fonts and create all the needed GC's. I only
+ * want to do this once, hence the first_time flag.
+ *
+ ***********************************************************************
+ */
+
+void
+CreateGCs()
+{
+ static ScreenInfo *prevScr = NULL;
+ XGCValues gcv;
+ unsigned long gcm;
+
+ if (!Scr->FirstTime || prevScr == Scr)
+ return;
+
+ prevScr = Scr;
+
+ /* create GC's */
+
+ gcm = 0;
+ gcm |= GCFunction; gcv.function = GXxor;
+ gcm |= GCLineWidth; gcv.line_width = 0;
+ gcm |= GCForeground; gcv.foreground = Scr->XORvalue;
+ gcm |= GCSubwindowMode; gcv.subwindow_mode = IncludeInferiors;
+
+ Scr->DrawGC = XCreateGC(dpy, Scr->Root, gcm, &gcv);
+
+ gcm = 0;
+ gcm |= GCForeground; gcv.foreground = Scr->MenuC.fore;
+ gcm |= GCBackground; gcv.background = Scr->MenuC.back;
+ gcm |= GCFont; gcv.font = Scr->MenuFont.font->fid;
+
+ Scr->MenuGC = XCreateGC(dpy, Scr->Root, gcm, &gcv);
+
+ gcm = 0;
+ gcm |= GCPlaneMask; gcv.plane_mask = AllPlanes;
+ /*
+ * Prevent GraphicsExpose and NoExpose events. We'd only get NoExpose
+ * events anyway; they cause BadWindow errors from XGetWindowAttributes
+ * call in FindScreenInfo (events.c) (since drawable is a pixmap).
+ */
+ gcm |= GCGraphicsExposures; gcv.graphics_exposures = False;
+ gcm |= GCLineWidth; gcv.line_width = 0;
+
+ Scr->NormalGC = XCreateGC(dpy, Scr->Root, gcm, &gcv);
+}
diff --git a/src/gc.h b/src/gc.h
new file mode 100644
index 0000000..f8440ed
--- /dev/null
+++ b/src/gc.h
@@ -0,0 +1,68 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/**********************************************************************
+ *
+ * $Xorg: gc.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * GC related externs
+ *
+ * 8-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _GC_
+#define _GC_
+
+extern void CreateGCs();
+
+#endif /* _GC_ */
diff --git a/src/gram.y b/src/gram.y
new file mode 100644
index 0000000..8530b09
--- /dev/null
+++ b/src/gram.y
@@ -0,0 +1,883 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/***********************************************************************
+ *
+ * $Xorg: gram.y,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * .twmrc command grammer
+ *
+ * 07-Jan-86 Thomas E. LaStrange File created
+ * 11-Nov-90 Dave Sternlicht Adding SaveColors
+ * 10-Oct-90 David M. Sternlicht Storing saved colors on root
+ *
+ ***********************************************************************/
+
+%{
+#include <stdio.h>
+#include <ctype.h>
+#include "twm.h"
+#include "menus.h"
+#include "list.h"
+#include "util.h"
+#include "screen.h"
+#include "parse.h"
+#include <X11/Xos.h>
+#include <X11/Xmu/CharSet.h>
+
+static char *Action = "";
+static char *Name = "";
+static MenuRoot *root, *pull = NULL;
+
+static MenuRoot *GetRoot();
+
+static Bool CheckWarpScreenArg(), CheckWarpRingArg();
+static Bool CheckColormapArg();
+static void GotButton(), GotKey(), GotTitleButton();
+static char *ptr;
+static name_list **list;
+static int cont = 0;
+static int color;
+int mods = 0;
+unsigned int mods_used = (ShiftMask | ControlMask | Mod1Mask);
+
+extern int do_single_keyword(), do_string_keyword(), do_number_keyword();
+extern name_list **do_colorlist_keyword();
+extern int do_color_keyword(), do_string_savecolor();
+extern int yylineno;
+%}
+
+%union
+{
+ int num;
+ char *ptr;
+};
+
+%token <num> LB RB LP RP MENUS MENU BUTTON DEFAULT_FUNCTION PLUS MINUS
+%token <num> ALL OR CURSORS PIXMAPS ICONS COLOR SAVECOLOR MONOCHROME FUNCTION
+%token <num> ICONMGR_SHOW ICONMGR WINDOW_FUNCTION ZOOM ICONMGRS
+%token <num> ICONMGR_GEOMETRY ICONMGR_NOSHOW MAKE_TITLE GRAYSCALE
+%token <num> ICONIFY_BY_UNMAPPING DONT_ICONIFY_BY_UNMAPPING
+%token <num> NO_TITLE AUTO_RAISE NO_HILITE ICON_REGION
+%token <num> META SHIFT LOCK CONTROL WINDOW TITLE ICON ROOT FRAME
+%token <num> COLON EQUALS SQUEEZE_TITLE DONT_SQUEEZE_TITLE
+%token <num> START_ICONIFIED NO_TITLE_HILITE TITLE_HILITE
+%token <num> MOVE RESIZE WAIT SELECT KILL LEFT_TITLEBUTTON RIGHT_TITLEBUTTON
+%token <num> NUMBER KEYWORD NKEYWORD CKEYWORD CLKEYWORD FKEYWORD FSKEYWORD
+%token <num> SKEYWORD DKEYWORD JKEYWORD WINDOW_RING WARP_CURSOR ERRORTOKEN
+%token <num> NO_STACKMODE
+%token <ptr> STRING
+
+%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
+%type <num> action button number signed_number full fullkey
+
+%start twmrc
+
+%%
+twmrc : stmts
+ ;
+
+stmts : /* Empty */
+ | stmts stmt
+ ;
+
+stmt : error
+ | noarg
+ | sarg
+ | narg
+ | squeeze
+ | ICON_REGION string DKEYWORD DKEYWORD number number
+ { AddIconRegion($2, $3, $4, $5, $6); }
+ | ICONMGR_GEOMETRY string number { if (Scr->FirstTime)
+ {
+ Scr->iconmgr.geometry=$2;
+ Scr->iconmgr.columns=$3;
+ }
+ }
+ | ICONMGR_GEOMETRY string { if (Scr->FirstTime)
+ Scr->iconmgr.geometry = $2;
+ }
+ | ZOOM number { if (Scr->FirstTime)
+ {
+ Scr->DoZoom = TRUE;
+ Scr->ZoomCount = $2;
+ }
+ }
+ | ZOOM { if (Scr->FirstTime)
+ Scr->DoZoom = TRUE; }
+ | PIXMAPS pixmap_list {}
+ | CURSORS cursor_list {}
+ | ICONIFY_BY_UNMAPPING { list = &Scr->IconifyByUn; }
+ win_list
+ | ICONIFY_BY_UNMAPPING { if (Scr->FirstTime)
+ Scr->IconifyByUnmapping = TRUE; }
+ | LEFT_TITLEBUTTON string EQUALS action {
+ GotTitleButton ($2, $4, False);
+ }
+ | RIGHT_TITLEBUTTON string EQUALS action {
+ GotTitleButton ($2, $4, True);
+ }
+ | button string { root = GetRoot($2, NULLSTR, NULLSTR);
+ Scr->Mouse[$1][C_ROOT][0].func = F_MENU;
+ Scr->Mouse[$1][C_ROOT][0].menu = root;
+ }
+ | button action { Scr->Mouse[$1][C_ROOT][0].func = $2;
+ if ($2 == F_MENU)
+ {
+ pull->prev = NULL;
+ Scr->Mouse[$1][C_ROOT][0].menu = pull;
+ }
+ else
+ {
+ root = GetRoot(TWM_ROOT,NULLSTR,NULLSTR);
+ Scr->Mouse[$1][C_ROOT][0].item =
+ AddToMenu(root,"x",Action,
+ NULLSTR,$2,NULLSTR,NULLSTR);
+ }
+ Action = "";
+ pull = NULL;
+ }
+ | string fullkey { GotKey($1, $2); }
+ | button full { GotButton($1, $2); }
+ | DONT_ICONIFY_BY_UNMAPPING { list = &Scr->DontIconify; }
+ win_list
+ | ICONMGR_NOSHOW { list = &Scr->IconMgrNoShow; }
+ win_list
+ | ICONMGR_NOSHOW { Scr->IconManagerDontShow = TRUE; }
+ | ICONMGRS { list = &Scr->IconMgrs; }
+ iconm_list
+ | ICONMGR_SHOW { list = &Scr->IconMgrShow; }
+ win_list
+ | NO_TITLE_HILITE { list = &Scr->NoTitleHighlight; }
+ win_list
+ | NO_TITLE_HILITE { if (Scr->FirstTime)
+ Scr->TitleHighlight = FALSE; }
+ | NO_HILITE { list = &Scr->NoHighlight; }
+ win_list
+ | NO_HILITE { if (Scr->FirstTime)
+ Scr->Highlight = FALSE; }
+ | NO_STACKMODE { list = &Scr->NoStackModeL; }
+ win_list
+ | NO_STACKMODE { if (Scr->FirstTime)
+ Scr->StackMode = FALSE; }
+ | NO_TITLE { list = &Scr->NoTitle; }
+ win_list
+ | NO_TITLE { if (Scr->FirstTime)
+ Scr->NoTitlebar = TRUE; }
+ | MAKE_TITLE { list = &Scr->MakeTitle; }
+ win_list
+ | START_ICONIFIED { list = &Scr->StartIconified; }
+ win_list
+ | AUTO_RAISE { list = &Scr->AutoRaise; }
+ win_list
+ | MENU string LP string COLON string RP {
+ root = GetRoot($2, $4, $6); }
+ menu { root->real_menu = TRUE;}
+ | MENU string { root = GetRoot($2, NULLSTR, NULLSTR); }
+ menu { root->real_menu = TRUE; }
+ | FUNCTION string { root = GetRoot($2, NULLSTR, NULLSTR); }
+ function
+ | ICONS { list = &Scr->IconNames; }
+ icon_list
+ | COLOR { color = COLOR; }
+ color_list
+ | GRAYSCALE { color = GRAYSCALE; }
+ color_list
+ | SAVECOLOR
+ save_color_list
+ | MONOCHROME { color = MONOCHROME; }
+ color_list
+ | DEFAULT_FUNCTION action { Scr->DefaultFunction.func = $2;
+ if ($2 == F_MENU)
+ {
+ pull->prev = NULL;
+ Scr->DefaultFunction.menu = pull;
+ }
+ else
+ {
+ root = GetRoot(TWM_ROOT,NULLSTR,NULLSTR);
+ Scr->DefaultFunction.item =
+ AddToMenu(root,"x",Action,
+ NULLSTR,$2, NULLSTR, NULLSTR);
+ }
+ Action = "";
+ pull = NULL;
+ }
+ | WINDOW_FUNCTION action { Scr->WindowFunction.func = $2;
+ root = GetRoot(TWM_ROOT,NULLSTR,NULLSTR);
+ Scr->WindowFunction.item =
+ AddToMenu(root,"x",Action,
+ NULLSTR,$2, NULLSTR, NULLSTR);
+ Action = "";
+ pull = NULL;
+ }
+ | WARP_CURSOR { list = &Scr->WarpCursorL; }
+ win_list
+ | WARP_CURSOR { if (Scr->FirstTime)
+ Scr->WarpCursor = TRUE; }
+ | WINDOW_RING { list = &Scr->WindowRingL; }
+ win_list
+ ;
+
+
+noarg : KEYWORD { if (!do_single_keyword ($1)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unknown singleton keyword %d\n",
+ $1);
+ ParseError = 1;
+ }
+ }
+ ;
+
+sarg : SKEYWORD string { if (!do_string_keyword ($1, $2)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unknown string keyword %d (value \"%s\")\n",
+ $1, $2);
+ ParseError = 1;
+ }
+ }
+ ;
+
+narg : NKEYWORD number { if (!do_number_keyword ($1, $2)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unknown numeric keyword %d (value %d)\n",
+ $1, $2);
+ ParseError = 1;
+ }
+ }
+ ;
+
+
+
+full : EQUALS keys COLON contexts COLON action { $$ = $6; }
+ ;
+
+fullkey : EQUALS keys COLON contextkeys COLON action { $$ = $6; }
+ ;
+
+keys : /* Empty */
+ | keys key
+ ;
+
+key : META { mods |= Mod1Mask; }
+ | SHIFT { mods |= ShiftMask; }
+ | LOCK { mods |= LockMask; }
+ | CONTROL { mods |= ControlMask; }
+ | META number { if ($2 < 1 || $2 > 5) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "bad modifier number (%d), must be 1-5\n",
+ $2);
+ ParseError = 1;
+ } else {
+ mods |= (Mod1Mask << ($2 - 1));
+ }
+ }
+ | OR { }
+ ;
+
+contexts : /* Empty */
+ | contexts context
+ ;
+
+context : WINDOW { cont |= C_WINDOW_BIT; }
+ | TITLE { cont |= C_TITLE_BIT; }
+ | ICON { cont |= C_ICON_BIT; }
+ | ROOT { cont |= C_ROOT_BIT; }
+ | FRAME { cont |= C_FRAME_BIT; }
+ | ICONMGR { cont |= C_ICONMGR_BIT; }
+ | META { cont |= C_ICONMGR_BIT; }
+ | ALL { cont |= C_ALL_BITS; }
+ | OR { }
+ ;
+
+contextkeys : /* Empty */
+ | contextkeys contextkey
+ ;
+
+contextkey : WINDOW { cont |= C_WINDOW_BIT; }
+ | TITLE { cont |= C_TITLE_BIT; }
+ | ICON { cont |= C_ICON_BIT; }
+ | ROOT { cont |= C_ROOT_BIT; }
+ | FRAME { cont |= C_FRAME_BIT; }
+ | ICONMGR { cont |= C_ICONMGR_BIT; }
+ | META { cont |= C_ICONMGR_BIT; }
+ | ALL { cont |= C_ALL_BITS; }
+ | OR { }
+ | string { Name = $1; cont |= C_NAME_BIT; }
+ ;
+
+
+pixmap_list : LB pixmap_entries RB
+ ;
+
+pixmap_entries : /* Empty */
+ | pixmap_entries pixmap_entry
+ ;
+
+pixmap_entry : TITLE_HILITE string { SetHighlightPixmap ($2); }
+ ;
+
+
+cursor_list : LB cursor_entries RB
+ ;
+
+cursor_entries : /* Empty */
+ | cursor_entries cursor_entry
+ ;
+
+cursor_entry : FRAME string string {
+ NewBitmapCursor(&Scr->FrameCursor, $2, $3); }
+ | FRAME string {
+ NewFontCursor(&Scr->FrameCursor, $2); }
+ | TITLE string string {
+ NewBitmapCursor(&Scr->TitleCursor, $2, $3); }
+ | TITLE string {
+ NewFontCursor(&Scr->TitleCursor, $2); }
+ | ICON string string {
+ NewBitmapCursor(&Scr->IconCursor, $2, $3); }
+ | ICON string {
+ NewFontCursor(&Scr->IconCursor, $2); }
+ | ICONMGR string string {
+ NewBitmapCursor(&Scr->IconMgrCursor, $2, $3); }
+ | ICONMGR string {
+ NewFontCursor(&Scr->IconMgrCursor, $2); }
+ | BUTTON string string {
+ NewBitmapCursor(&Scr->ButtonCursor, $2, $3); }
+ | BUTTON string {
+ NewFontCursor(&Scr->ButtonCursor, $2); }
+ | MOVE string string {
+ NewBitmapCursor(&Scr->MoveCursor, $2, $3); }
+ | MOVE string {
+ NewFontCursor(&Scr->MoveCursor, $2); }
+ | RESIZE string string {
+ NewBitmapCursor(&Scr->ResizeCursor, $2, $3); }
+ | RESIZE string {
+ NewFontCursor(&Scr->ResizeCursor, $2); }
+ | WAIT string string {
+ NewBitmapCursor(&Scr->WaitCursor, $2, $3); }
+ | WAIT string {
+ NewFontCursor(&Scr->WaitCursor, $2); }
+ | MENU string string {
+ NewBitmapCursor(&Scr->MenuCursor, $2, $3); }
+ | MENU string {
+ NewFontCursor(&Scr->MenuCursor, $2); }
+ | SELECT string string {
+ NewBitmapCursor(&Scr->SelectCursor, $2, $3); }
+ | SELECT string {
+ NewFontCursor(&Scr->SelectCursor, $2); }
+ | KILL string string {
+ NewBitmapCursor(&Scr->DestroyCursor, $2, $3); }
+ | KILL string {
+ NewFontCursor(&Scr->DestroyCursor, $2); }
+ ;
+
+color_list : LB color_entries RB
+ ;
+
+
+color_entries : /* Empty */
+ | color_entries color_entry
+ ;
+
+color_entry : CLKEYWORD string { if (!do_colorlist_keyword ($1, color,
+ $2)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unhandled list color keyword %d (string \"%s\")\n",
+ $1, $2);
+ ParseError = 1;
+ }
+ }
+ | CLKEYWORD string { list = do_colorlist_keyword($1,color,
+ $2);
+ if (!list) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unhandled color list keyword %d (string \"%s\")\n",
+ $1, $2);
+ ParseError = 1;
+ }
+ }
+ win_color_list
+ | CKEYWORD string { if (!do_color_keyword ($1, color,
+ $2)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unhandled color keyword %d (string \"%s\")\n",
+ $1, $2);
+ ParseError = 1;
+ }
+ }
+ ;
+
+save_color_list : LB s_color_entries RB
+ ;
+
+s_color_entries : /* Empty */
+ | s_color_entries s_color_entry
+ ;
+
+s_color_entry : string { do_string_savecolor(color, $1); }
+ | CLKEYWORD { do_var_savecolor($1); }
+ ;
+
+win_color_list : LB win_color_entries RB
+ ;
+
+win_color_entries : /* Empty */
+ | win_color_entries win_color_entry
+ ;
+
+win_color_entry : string string { if (Scr->FirstTime &&
+ color == Scr->Monochrome)
+ AddToList(list, $1, $2); }
+ ;
+
+squeeze : SQUEEZE_TITLE {
+ if (HasShape) Scr->SqueezeTitle = TRUE;
+ }
+ | SQUEEZE_TITLE { list = &Scr->SqueezeTitleL;
+ if (HasShape && Scr->SqueezeTitle == -1)
+ Scr->SqueezeTitle = TRUE;
+ }
+ LB win_sqz_entries RB
+ | DONT_SQUEEZE_TITLE { Scr->SqueezeTitle = FALSE; }
+ | DONT_SQUEEZE_TITLE { list = &Scr->DontSqueezeTitleL; }
+ win_list
+ ;
+
+win_sqz_entries : /* Empty */
+ | win_sqz_entries string JKEYWORD signed_number number {
+ if (Scr->FirstTime) {
+ do_squeeze_entry (list, $2, $3, $4, $5);
+ }
+ }
+ ;
+
+
+iconm_list : LB iconm_entries RB
+ ;
+
+iconm_entries : /* Empty */
+ | iconm_entries iconm_entry
+ ;
+
+iconm_entry : string string number { if (Scr->FirstTime)
+ AddToList(list, $1, (char *)
+ AllocateIconManager($1, NULLSTR,
+ $2,$3));
+ }
+ | string string string number
+ { if (Scr->FirstTime)
+ AddToList(list, $1, (char *)
+ AllocateIconManager($1,$2,
+ $3, $4));
+ }
+ ;
+
+win_list : LB win_entries RB
+ ;
+
+win_entries : /* Empty */
+ | win_entries win_entry
+ ;
+
+win_entry : string { if (Scr->FirstTime)
+ AddToList(list, $1, 0);
+ }
+ ;
+
+icon_list : LB icon_entries RB
+ ;
+
+icon_entries : /* Empty */
+ | icon_entries icon_entry
+ ;
+
+icon_entry : string string { if (Scr->FirstTime) AddToList(list, $1, $2); }
+ ;
+
+function : LB function_entries RB
+ ;
+
+function_entries: /* Empty */
+ | function_entries function_entry
+ ;
+
+function_entry : action { AddToMenu(root, "", Action, NULLSTR, $1,
+ NULLSTR, NULLSTR);
+ Action = "";
+ }
+ ;
+
+menu : LB menu_entries RB
+ ;
+
+menu_entries : /* Empty */
+ | menu_entries menu_entry
+ ;
+
+menu_entry : string action { AddToMenu(root, $1, Action, pull, $2,
+ NULLSTR, NULLSTR);
+ Action = "";
+ pull = NULL;
+ }
+ | string LP string COLON string RP action {
+ AddToMenu(root, $1, Action, pull, $7,
+ $3, $5);
+ Action = "";
+ pull = NULL;
+ }
+ ;
+
+action : FKEYWORD { $$ = $1; }
+ | FSKEYWORD string {
+ $$ = $1;
+ Action = $2;
+ switch ($1) {
+ case F_MENU:
+ pull = GetRoot ($2, NULLSTR,NULLSTR);
+ pull->prev = root;
+ break;
+ case F_WARPRING:
+ if (!CheckWarpRingArg (Action)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring invalid f.warptoring argument \"%s\"\n",
+ Action);
+ $$ = F_NOP;
+ }
+ case F_WARPTOSCREEN:
+ if (!CheckWarpScreenArg (Action)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring invalid f.warptoscreen argument \"%s\"\n",
+ Action);
+ $$ = F_NOP;
+ }
+ break;
+ case F_COLORMAP:
+ if (CheckColormapArg (Action)) {
+ $$ = F_COLORMAP;
+ } else {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring invalid f.colormap argument \"%s\"\n",
+ Action);
+ $$ = F_NOP;
+ }
+ break;
+ } /* end switch */
+ }
+ ;
+
+
+signed_number : number { $$ = $1; }
+ | PLUS number { $$ = $2; }
+ | MINUS number { $$ = -($2); }
+ ;
+
+button : BUTTON number { $$ = $2;
+ if ($2 == 0)
+ yyerror("bad button 0");
+
+ if ($2 > MAX_BUTTONS)
+ {
+ $$ = 0;
+ yyerror("button number too large");
+ }
+ }
+ ;
+
+string : STRING { ptr = (char *)malloc(strlen($1)+1);
+ strcpy(ptr, $1);
+ RemoveDQuote(ptr);
+ $$ = ptr;
+ }
+number : NUMBER { $$ = $1; }
+ ;
+
+%%
+yyerror(s) char *s;
+{
+ twmrc_error_prefix();
+ fprintf (stderr, "error in input file: %s\n", s ? s : "");
+ ParseError = 1;
+}
+RemoveDQuote(str)
+char *str;
+{
+ register char *i, *o;
+ register n;
+ register count;
+
+ for (i=str+1, o=str; *i && *i != '\"'; o++)
+ {
+ if (*i == '\\')
+ {
+ switch (*++i)
+ {
+ case 'n':
+ *o = '\n';
+ i++;
+ break;
+ case 'b':
+ *o = '\b';
+ i++;
+ break;
+ case 'r':
+ *o = '\r';
+ i++;
+ break;
+ case 't':
+ *o = '\t';
+ i++;
+ break;
+ case 'f':
+ *o = '\f';
+ i++;
+ break;
+ case '0':
+ if (*++i == 'x')
+ goto hex;
+ else
+ --i;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ n = 0;
+ count = 0;
+ while (*i >= '0' && *i <= '7' && count < 3)
+ {
+ n = (n<<3) + (*i++ - '0');
+ count++;
+ }
+ *o = n;
+ break;
+ hex:
+ case 'x':
+ n = 0;
+ count = 0;
+ while (i++, count++ < 2)
+ {
+ if (*i >= '0' && *i <= '9')
+ n = (n<<4) + (*i - '0');
+ else if (*i >= 'a' && *i <= 'f')
+ n = (n<<4) + (*i - 'a') + 10;
+ else if (*i >= 'A' && *i <= 'F')
+ n = (n<<4) + (*i - 'A') + 10;
+ else
+ break;
+ }
+ *o = n;
+ break;
+ case '\n':
+ i++; /* punt */
+ o--; /* to account for o++ at end of loop */
+ break;
+ case '\"':
+ case '\'':
+ case '\\':
+ default:
+ *o = *i++;
+ break;
+ }
+ }
+ else
+ *o = *i++;
+ }
+ *o = '\0';
+}
+
+static MenuRoot *GetRoot(name, fore, back)
+char *name;
+char *fore, *back;
+{
+ MenuRoot *tmp;
+
+ tmp = FindMenuRoot(name);
+ if (tmp == NULL)
+ tmp = NewMenuRoot(name);
+
+ if (fore)
+ {
+ int save;
+
+ save = Scr->FirstTime;
+ Scr->FirstTime = TRUE;
+ GetColor(COLOR, &tmp->hi_fore, fore);
+ GetColor(COLOR, &tmp->hi_back, back);
+ Scr->FirstTime = save;
+ }
+
+ return tmp;
+}
+
+static void GotButton(butt, func)
+int butt, func;
+{
+ int i;
+
+ for (i = 0; i < NUM_CONTEXTS; i++)
+ {
+ if ((cont & (1 << i)) == 0)
+ continue;
+
+ Scr->Mouse[butt][i][mods].func = func;
+ if (func == F_MENU)
+ {
+ pull->prev = NULL;
+ Scr->Mouse[butt][i][mods].menu = pull;
+ }
+ else
+ {
+ root = GetRoot(TWM_ROOT, NULLSTR, NULLSTR);
+ Scr->Mouse[butt][i][mods].item = AddToMenu(root,"x",Action,
+ NULLSTR, func, NULLSTR, NULLSTR);
+ }
+ }
+ Action = "";
+ pull = NULL;
+ cont = 0;
+ mods_used |= mods;
+ mods = 0;
+}
+
+static void GotKey(key, func)
+char *key;
+int func;
+{
+ int i;
+
+ for (i = 0; i < NUM_CONTEXTS; i++)
+ {
+ if ((cont & (1 << i)) == 0)
+ continue;
+ if (!AddFuncKey(key, i, mods, func, Name, Action))
+ break;
+ }
+
+ Action = "";
+ pull = NULL;
+ cont = 0;
+ mods_used |= mods;
+ mods = 0;
+}
+
+
+static void GotTitleButton (bitmapname, func, rightside)
+ char *bitmapname;
+ int func;
+ Bool rightside;
+{
+ if (!CreateTitleButton (bitmapname, func, Action, pull, rightside, True)) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "unable to create %s titlebutton \"%s\"\n",
+ rightside ? "right" : "left", bitmapname);
+ }
+ Action = "";
+ pull = NULL;
+}
+
+static Bool CheckWarpScreenArg (s)
+ register char *s;
+{
+ XmuCopyISOLatin1Lowered (s, s);
+
+ if (strcmp (s, WARPSCREEN_NEXT) == 0 ||
+ strcmp (s, WARPSCREEN_PREV) == 0 ||
+ strcmp (s, WARPSCREEN_BACK) == 0)
+ return True;
+
+ for (; *s && isascii(*s) && isdigit(*s); s++) ; /* SUPPRESS 530 */
+ return (*s ? False : True);
+}
+
+
+static Bool CheckWarpRingArg (s)
+ register char *s;
+{
+ XmuCopyISOLatin1Lowered (s, s);
+
+ if (strcmp (s, WARPSCREEN_NEXT) == 0 ||
+ strcmp (s, WARPSCREEN_PREV) == 0)
+ return True;
+
+ return False;
+}
+
+
+static Bool CheckColormapArg (s)
+ register char *s;
+{
+ XmuCopyISOLatin1Lowered (s, s);
+
+ if (strcmp (s, COLORMAP_NEXT) == 0 ||
+ strcmp (s, COLORMAP_PREV) == 0 ||
+ strcmp (s, COLORMAP_DEFAULT) == 0)
+ return True;
+
+ return False;
+}
+
+
+twmrc_error_prefix ()
+{
+ fprintf (stderr, "%s: line %d: ", ProgramName, yylineno);
+}
diff --git a/src/iconmgr.c b/src/iconmgr.c
new file mode 100644
index 0000000..188495b
--- /dev/null
+++ b/src/iconmgr.c
@@ -0,0 +1,773 @@
+/*
+ *
+Copyright 1989,1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ * */
+
+/***********************************************************************
+ *
+ * $Xorg: iconmgr.c,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Icon Manager routines
+ *
+ * 09-Mar-89 Tom LaStrange File Created
+ *
+ ***********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include "util.h"
+#include "parse.h"
+#include "screen.h"
+#include "resize.h"
+#include "add_window.h"
+#include "siconify.bm"
+#include <X11/Xos.h>
+#include <X11/Xmu/CharSet.h>
+#ifdef macII
+int strcmp(); /* missing from string.h in AUX 2.0 */
+#endif
+
+int iconmgr_textx = siconify_width+11;
+WList *Active = NULL;
+WList *DownIconManager = NULL;
+int iconifybox_width = siconify_width;
+int iconifybox_height = siconify_height;
+
+/***********************************************************************
+ *
+ * Procedure:
+ * CreateIconManagers - creat all the icon manager windows
+ * for this screen.
+ *
+ * Returned Value:
+ * none
+ *
+ * Inputs:
+ * none
+ *
+ ***********************************************************************
+ */
+
+void CreateIconManagers()
+{
+ IconMgr *p;
+ int mask;
+ char str[100];
+ char str1[100];
+ Pixel background;
+ char *icon_name;
+
+ if (Scr->NoIconManagers)
+ return;
+
+ if (Scr->siconifyPm == None)
+ {
+ Scr->siconifyPm = XCreatePixmapFromBitmapData(dpy, Scr->Root,
+ (char *)siconify_bits, siconify_width, siconify_height, 1, 0, 1);
+ }
+
+ for (p = &Scr->iconmgr; p != NULL; p = p->next)
+ {
+ mask = XParseGeometry(p->geometry, &JunkX, &JunkY,
+ (unsigned int *) &p->width, (unsigned int *)&p->height);
+
+ if (mask & XNegative)
+ JunkX = Scr->MyDisplayWidth - p->width -
+ (2 * Scr->BorderWidth) + JunkX;
+
+ if (mask & YNegative)
+ JunkY = Scr->MyDisplayHeight - p->height -
+ (2 * Scr->BorderWidth) + JunkY;
+
+ background = Scr->IconManagerC.back;
+ GetColorFromList(Scr->IconManagerBL, p->name, (XClassHint *)NULL,
+ &background);
+
+ p->w = XCreateSimpleWindow(dpy, Scr->Root,
+ JunkX, JunkY, p->width, p->height, 1,
+ Scr->Black, background);
+
+ sprintf(str, "%s Icon Manager", p->name);
+ sprintf(str1, "%s Icons", p->name);
+ if (p->icon_name)
+ icon_name = p->icon_name;
+ else
+ icon_name = str1;
+
+ XSetStandardProperties(dpy, p->w, str, icon_name, None, NULL, 0, NULL);
+
+ p->twm_win = AddWindow(p->w, TRUE, p);
+ SetMapStateProp (p->twm_win, WithdrawnState);
+ }
+ for (p = &Scr->iconmgr; p != NULL; p = p->next)
+ {
+ GrabButtons(p->twm_win);
+ GrabKeys(p->twm_win);
+ }
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AllocateIconManager - allocate a new icon manager
+ *
+ * Inputs:
+ * name - the name of this icon manager
+ * icon_name - the name of the associated icon
+ * geom - a geometry string to eventually parse
+ * columns - the number of columns this icon manager has
+ *
+ ***********************************************************************
+ */
+
+IconMgr *AllocateIconManager(name, icon_name, geom, columns)
+ char *name;
+ char *geom;
+ char *icon_name;
+ int columns;
+{
+ IconMgr *p;
+
+#ifdef DEBUG_ICONMGR
+ fprintf(stderr, "AllocateIconManager\n");
+ fprintf(stderr, " name=\"%s\" icon_name=\"%s\", geom=\"%s\", col=%d\n",
+ name, icon_name, geom, columns);
+#endif
+
+ if (Scr->NoIconManagers)
+ return NULL;
+
+ p = (IconMgr *)malloc(sizeof(IconMgr));
+ p->name = name;
+ p->icon_name = icon_name;
+ p->geometry = geom;
+ p->columns = columns;
+ p->first = NULL;
+ p->last = NULL;
+ p->active = NULL;
+ p->scr = Scr;
+ p->count = 0;
+ p->x = 0;
+ p->y = 0;
+ p->width = 150;
+ p->height = 10;
+
+ Scr->iconmgr.lasti->next = p;
+ p->prev = Scr->iconmgr.lasti;
+ Scr->iconmgr.lasti = p;
+ p->next = NULL;
+
+ return(p);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * MoveIconManager - move the pointer around in an icon manager
+ *
+ * Inputs:
+ * dir - one of the following:
+ * F_FORWICONMGR - forward in the window list
+ * F_BACKICONMGR - backward in the window list
+ * F_UPICONMGR - up one row
+ * F_DOWNICONMGR - down one row
+ * F_LEFTICONMGR - left one column
+ * F_RIGHTICONMGR - right one column
+ *
+ * Special Considerations:
+ * none
+ *
+ ***********************************************************************
+ */
+
+void MoveIconManager(dir)
+ int dir;
+{
+ IconMgr *ip;
+ WList *tmp = NULL;
+ int cur_row, cur_col, new_row, new_col;
+ int row_inc, col_inc;
+ int got_it;
+
+ if (!Active) return;
+
+ cur_row = Active->row;
+ cur_col = Active->col;
+ ip = Active->iconmgr;
+
+ row_inc = 0;
+ col_inc = 0;
+ got_it = FALSE;
+
+ switch (dir)
+ {
+ case F_FORWICONMGR:
+ if ((tmp = Active->next) == NULL)
+ tmp = ip->first;
+ got_it = TRUE;
+ break;
+
+ case F_BACKICONMGR:
+ if ((tmp = Active->prev) == NULL)
+ tmp = ip->last;
+ got_it = TRUE;
+ break;
+
+ case F_UPICONMGR:
+ row_inc = -1;
+ break;
+
+ case F_DOWNICONMGR:
+ row_inc = 1;
+ break;
+
+ case F_LEFTICONMGR:
+ col_inc = -1;
+ break;
+
+ case F_RIGHTICONMGR:
+ col_inc = 1;
+ break;
+ }
+
+ /* If got_it is FALSE ast this point then we got a left, right,
+ * up, or down, command. We will enter this loop until we find
+ * a window to warp to.
+ */
+ new_row = cur_row;
+ new_col = cur_col;
+
+ while (!got_it)
+ {
+ new_row += row_inc;
+ new_col += col_inc;
+ if (new_row < 0)
+ new_row = ip->cur_rows - 1;
+ if (new_col < 0)
+ new_col = ip->cur_columns - 1;
+ if (new_row >= ip->cur_rows)
+ new_row = 0;
+ if (new_col >= ip->cur_columns)
+ new_col = 0;
+
+ /* Now let's go through the list to see if there is an entry with this
+ * new position
+ */
+ for (tmp = ip->first; tmp != NULL; tmp = tmp->next)
+ {
+ if (tmp->row == new_row && tmp->col == new_col)
+ {
+ got_it = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!got_it)
+ {
+ fprintf (stderr,
+ "%s: unable to find window (%d, %d) in icon manager\n",
+ ProgramName, new_row, new_col);
+ return;
+ }
+
+ if (tmp == NULL)
+ return;
+
+ /* raise the frame so the icon manager is visible */
+ if (ip->twm_win->mapped) {
+ XRaiseWindow(dpy, ip->twm_win->frame);
+ XWarpPointer(dpy, None, tmp->icon, 0,0,0,0, 5, 5);
+ } else {
+ if (tmp->twm->title_height) {
+ int tbx = Scr->TBInfo.titlex;
+ int x = tmp->twm->highlightx;
+ XWarpPointer (dpy, None, tmp->twm->title_w, 0, 0, 0, 0,
+ tbx + (x - tbx) / 2,
+ Scr->TitleHeight / 4);
+ } else {
+ XWarpPointer (dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5);
+ }
+ }
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * JumpIconManager - jump from one icon manager to another,
+ * possibly even on another screen
+ *
+ * Inputs:
+ * dir - one of the following:
+ * F_NEXTICONMGR - go to the next icon manager
+ * F_PREVICONMGR - go to the previous one
+ *
+ ***********************************************************************
+ */
+
+void JumpIconManager(dir)
+ register int dir;
+{
+ IconMgr *ip, *tmp_ip = NULL;
+ int got_it = FALSE;
+ ScreenInfo *sp;
+ int screen;
+
+ if (!Active) return;
+
+
+#define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev)
+#define IPOFSP(sp) (dir == F_NEXTICONMGR ? &(sp->iconmgr) : sp->iconmgr.lasti)
+#define TEST(ip) if ((ip)->count != 0 && (ip)->twm_win->mapped) \
+ { got_it = TRUE; break; }
+
+ ip = Active->iconmgr;
+ for (tmp_ip = ITER(ip); tmp_ip; tmp_ip = ITER(tmp_ip)) {
+ TEST (tmp_ip);
+ }
+
+ if (!got_it) {
+ int origscreen = ip->scr->screen;
+ int inc = (dir == F_NEXTICONMGR ? 1 : -1);
+
+ for (screen = origscreen + inc; ; screen += inc) {
+ if (screen >= NumScreens)
+ screen = 0;
+ else if (screen < 0)
+ screen = NumScreens - 1;
+
+ sp = ScreenList[screen];
+ if (sp) {
+ for (tmp_ip = IPOFSP (sp); tmp_ip; tmp_ip = ITER(tmp_ip)) {
+ TEST (tmp_ip);
+ }
+ }
+ if (got_it || screen == origscreen) break;
+ }
+ }
+
+#undef ITER
+#undef IPOFSP
+#undef TEST
+
+ if (!got_it) {
+ Bell(XkbBI_MinorError,0,None);
+ return;
+ }
+
+ /* raise the frame so it is visible */
+ XRaiseWindow(dpy, tmp_ip->twm_win->frame);
+ if (tmp_ip->active)
+ XWarpPointer(dpy, None, tmp_ip->active->icon, 0,0,0,0, 5, 5);
+ else
+ XWarpPointer(dpy, None, tmp_ip->w, 0,0,0,0, 5, 5);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddIconManager - add a window to an icon manager
+ *
+ * Inputs:
+ * tmp_win - the TwmWindow structure
+ *
+ ***********************************************************************
+ */
+
+WList *AddIconManager(tmp_win)
+ TwmWindow *tmp_win;
+{
+ WList *tmp;
+ int h;
+ unsigned long valuemask; /* mask for create windows */
+ XSetWindowAttributes attributes; /* attributes for create windows */
+ IconMgr *ip;
+
+ tmp_win->list = NULL;
+
+ if (tmp_win->iconmgr || tmp_win->transient || Scr->NoIconManagers)
+ return NULL;
+
+ if (LookInList(Scr->IconMgrNoShow, tmp_win->full_name, &tmp_win->class))
+ return NULL;
+ if (Scr->IconManagerDontShow &&
+ !LookInList(Scr->IconMgrShow, tmp_win->full_name, &tmp_win->class))
+ return NULL;
+ if ((ip = (IconMgr *)LookInList(Scr->IconMgrs, tmp_win->full_name,
+ &tmp_win->class)) == NULL)
+ ip = &Scr->iconmgr;
+
+ tmp = (WList *) malloc(sizeof(WList));
+ tmp->iconmgr = ip;
+ tmp->next = NULL;
+ tmp->active = FALSE;
+ tmp->down = FALSE;
+
+ InsertInIconManager(ip, tmp, tmp_win);
+
+ tmp->twm = tmp_win;
+
+ tmp->fore = Scr->IconManagerC.fore;
+ tmp->back = Scr->IconManagerC.back;
+ tmp->highlight = Scr->IconManagerHighlight;
+
+ GetColorFromList(Scr->IconManagerFL, tmp_win->full_name, &tmp_win->class,
+ &tmp->fore);
+ GetColorFromList(Scr->IconManagerBL, tmp_win->full_name, &tmp_win->class,
+ &tmp->back);
+ GetColorFromList(Scr->IconManagerHighlightL, tmp_win->full_name,
+ &tmp_win->class, &tmp->highlight);
+
+ h = Scr->IconManagerFont.height + 10;
+ if (h < (siconify_height + 4))
+ h = siconify_height + 4;
+
+ ip->height = h * ip->count;
+ tmp->me = ip->count;
+ tmp->x = -1;
+ tmp->y = -1;
+
+ valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
+ attributes.background_pixel = tmp->back;
+ attributes.border_pixel = tmp->back;
+ attributes.event_mask = (KeyPressMask | ButtonPressMask |
+ ButtonReleaseMask | ExposureMask |
+ EnterWindowMask | LeaveWindowMask);
+ attributes.cursor = Scr->IconMgrCursor;
+ tmp->w = XCreateWindow (dpy, ip->w, 0, 0, (unsigned int) 1,
+ (unsigned int) h, (unsigned int) 0,
+ CopyFromParent, (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent, valuemask, &attributes);
+
+
+ valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
+ attributes.background_pixel = tmp->back;
+ attributes.border_pixel = Scr->Black;
+ attributes.event_mask = (ButtonReleaseMask| ButtonPressMask |
+ ExposureMask);
+ attributes.cursor = Scr->ButtonCursor;
+ tmp->icon = XCreateWindow (dpy, tmp->w, 5, (int) (h - siconify_height)/2,
+ (unsigned int) siconify_width,
+ (unsigned int) siconify_height,
+ (unsigned int) 0, CopyFromParent,
+ (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent,
+ valuemask, &attributes);
+
+ ip->count += 1;
+ PackIconManager(ip);
+ XMapWindow(dpy, tmp->w);
+
+ XSaveContext(dpy, tmp->w, IconManagerContext, (caddr_t) tmp);
+ XSaveContext(dpy, tmp->w, TwmContext, (caddr_t) tmp_win);
+ XSaveContext(dpy, tmp->w, ScreenContext, (caddr_t) Scr);
+ XSaveContext(dpy, tmp->icon, TwmContext, (caddr_t) tmp_win);
+ XSaveContext(dpy, tmp->icon, ScreenContext, (caddr_t) Scr);
+ tmp_win->list = tmp;
+
+ if (!ip->twm_win->icon)
+ {
+ XMapWindow(dpy, ip->w);
+ XMapWindow(dpy, ip->twm_win->frame);
+ }
+
+ return (tmp);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * InsertInIconManager - put an allocated entry into an icon
+ * manager
+ *
+ * Inputs:
+ * ip - the icon manager pointer
+ * tmp - the entry to insert
+ *
+ ***********************************************************************
+ */
+
+void InsertInIconManager(ip, tmp, tmp_win)
+ IconMgr *ip;
+ WList *tmp;
+ TwmWindow *tmp_win;
+{
+ WList *tmp1;
+ int added;
+ int (*compar)() = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
+
+ added = FALSE;
+ if (ip->first == NULL)
+ {
+ ip->first = tmp;
+ tmp->prev = NULL;
+ ip->last = tmp;
+ added = TRUE;
+ }
+ else if (Scr->SortIconMgr)
+ {
+ for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next)
+ {
+ if ((*compar)(tmp_win->icon_name, tmp1->twm->icon_name) < 0)
+ {
+ tmp->next = tmp1;
+ tmp->prev = tmp1->prev;
+ tmp1->prev = tmp;
+ if (tmp->prev == NULL)
+ ip->first = tmp;
+ else
+ tmp->prev->next = tmp;
+ added = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!added)
+ {
+ ip->last->next = tmp;
+ tmp->prev = ip->last;
+ ip->last = tmp;
+ }
+}
+
+void RemoveFromIconManager(ip, tmp)
+ IconMgr *ip;
+ WList *tmp;
+{
+ if (tmp->prev == NULL)
+ ip->first = tmp->next;
+ else
+ tmp->prev->next = tmp->next;
+
+ if (tmp->next == NULL)
+ ip->last = tmp->prev;
+ else
+ tmp->next->prev = tmp->prev;
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * RemoveIconManager - remove a window from the icon manager
+ *
+ * Inputs:
+ * tmp_win - the TwmWindow structure
+ *
+ ***********************************************************************
+ */
+
+void RemoveIconManager(tmp_win)
+ TwmWindow *tmp_win;
+{
+ IconMgr *ip;
+ WList *tmp;
+
+ if (tmp_win->list == NULL)
+ return;
+
+ tmp = tmp_win->list;
+ tmp_win->list = NULL;
+ ip = tmp->iconmgr;
+
+ RemoveFromIconManager(ip, tmp);
+
+ XDeleteContext(dpy, tmp->icon, TwmContext);
+ XDeleteContext(dpy, tmp->icon, ScreenContext);
+ XDestroyWindow(dpy, tmp->icon);
+ XDeleteContext(dpy, tmp->w, IconManagerContext);
+ XDeleteContext(dpy, tmp->w, TwmContext);
+ XDeleteContext(dpy, tmp->w, ScreenContext);
+ XDestroyWindow(dpy, tmp->w);
+ ip->count -= 1;
+ free((char *) tmp);
+
+ PackIconManager(ip);
+
+ if (ip->count == 0)
+ {
+ XUnmapWindow(dpy, ip->twm_win->frame);
+ }
+
+}
+
+void ActiveIconManager(active)
+ WList *active;
+{
+ active->active = TRUE;
+ Active = active;
+ Active->iconmgr->active = active;
+ DrawIconManagerBorder(active);
+}
+
+void NotActiveIconManager(active)
+ WList *active;
+{
+ active->active = FALSE;
+ DrawIconManagerBorder(active);
+}
+
+void DrawIconManagerBorder(tmp)
+ WList *tmp;
+{
+ {
+ XSetForeground(dpy, Scr->NormalGC, tmp->fore);
+ XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 2, 2,
+ tmp->width-5, tmp->height-5);
+
+ if (tmp->active && Scr->Highlight)
+ XSetForeground(dpy, Scr->NormalGC, tmp->highlight);
+ else
+ XSetForeground(dpy, Scr->NormalGC, tmp->back);
+
+ XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 0, 0,
+ tmp->width-1, tmp->height-1);
+ XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 1, 1,
+ tmp->width-3, tmp->height-3);
+ }
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * SortIconManager - sort the dude
+ *
+ * Inputs:
+ * ip - a pointer to the icon manager struture
+ *
+ ***********************************************************************
+ */
+
+void SortIconManager(ip)
+ IconMgr *ip;
+{
+ WList *tmp1, *tmp2;
+ int done;
+ int (*compar)() = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
+
+ if (ip == NULL)
+ ip = Active->iconmgr;
+
+ done = FALSE;
+ do
+ {
+ for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next)
+ {
+ if ((tmp2 = tmp1->next) == NULL)
+ {
+ done = TRUE;
+ break;
+ }
+ if ((*compar)(tmp1->twm->icon_name, tmp2->twm->icon_name) > 0)
+ {
+ /* take it out and put it back in */
+ RemoveFromIconManager(ip, tmp2);
+ InsertInIconManager(ip, tmp2, tmp2->twm);
+ break;
+ }
+ }
+ }
+ while (!done);
+ PackIconManager(ip);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * PackIconManager - pack the icon manager windows following
+ * an addition or deletion
+ *
+ * Inputs:
+ * ip - a pointer to the icon manager struture
+ *
+ ***********************************************************************
+ */
+
+void PackIconManager(ip)
+ IconMgr *ip;
+{
+ int newwidth, i, row, col, maxcol, colinc, rowinc, wheight, wwidth;
+ int new_x, new_y;
+ int savewidth;
+ WList *tmp;
+
+ wheight = Scr->IconManagerFont.height + 10;
+ if (wheight < (siconify_height + 4))
+ wheight = siconify_height + 4;
+
+ wwidth = ip->width / ip->columns;
+
+ rowinc = wheight;
+ colinc = wwidth;
+
+ row = 0;
+ col = ip->columns;
+ maxcol = 0;
+ for (i = 0, tmp = ip->first; tmp != NULL; i++, tmp = tmp->next)
+ {
+ tmp->me = i;
+ if (++col >= ip->columns)
+ {
+ col = 0;
+ row += 1;
+ }
+ if (col > maxcol)
+ maxcol = col;
+
+ new_x = col * colinc;
+ new_y = (row-1) * rowinc;
+
+ /* if the position or size has not changed, don't touch it */
+ if (tmp->x != new_x || tmp->y != new_y ||
+ tmp->width != wwidth || tmp->height != wheight)
+ {
+ XMoveResizeWindow(dpy, tmp->w, new_x, new_y, wwidth, wheight);
+
+ tmp->row = row-1;
+ tmp->col = col;
+ tmp->x = new_x;
+ tmp->y = new_y;
+ tmp->width = wwidth;
+ tmp->height = wheight;
+ }
+ }
+ maxcol += 1;
+
+ ip->cur_rows = row;
+ ip->cur_columns = maxcol;
+ ip->height = row * rowinc;
+ if (ip->height == 0)
+ ip->height = rowinc;
+ newwidth = maxcol * colinc;
+ if (newwidth == 0)
+ newwidth = colinc;
+
+ XResizeWindow(dpy, ip->w, newwidth, ip->height);
+
+ savewidth = ip->width;
+ if (ip->twm_win)
+ SetupWindow (ip->twm_win,
+ ip->twm_win->frame_x, ip->twm_win->frame_y,
+ newwidth, ip->height + ip->twm_win->title_height, -1);
+ ip->width = savewidth;
+}
diff --git a/src/iconmgr.h b/src/iconmgr.h
new file mode 100644
index 0000000..90c7073
--- /dev/null
+++ b/src/iconmgr.h
@@ -0,0 +1,93 @@
+/*
+ *
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ * */
+
+/***********************************************************************
+ *
+ * $Xorg: iconmgr.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Icon Manager includes
+ *
+ * 09-Mar-89 Tom LaStrange File Created
+ *
+ ***********************************************************************/
+
+#ifndef _ICONMGR_
+#define _ICONMGR_
+
+typedef struct WList
+{
+ struct WList *next;
+ struct WList *prev;
+ struct TwmWindow *twm;
+ struct IconMgr *iconmgr;
+ Window w;
+ Window icon;
+ int x, y, width, height;
+ int row, col;
+ int me;
+ Pixel fore, back, highlight;
+ unsigned top, bottom;
+ short active;
+ short down;
+} WList;
+
+typedef struct IconMgr
+{
+ struct IconMgr *next; /* pointer to the next icon manager */
+ struct IconMgr *prev; /* pointer to the previous icon mgr */
+ struct IconMgr *lasti; /* pointer to the last icon mgr */
+ struct WList *first; /* first window in the list */
+ struct WList *last; /* last window in the list */
+ struct WList *active; /* the active entry */
+ TwmWindow *twm_win; /* back pointer to the new parent */
+ struct ScreenInfo *scr; /* the screen this thing is on */
+ Window w; /* this icon manager window */
+ char *geometry; /* geometry string */
+ char *name;
+ char *icon_name;
+ int x, y, width, height;
+ int columns, cur_rows, cur_columns;
+ int count;
+} IconMgr;
+
+extern int iconmgr_textx;
+extern WList *DownIconManager;
+
+extern void CreateIconManagers();
+extern IconMgr *AllocateIconManager();
+extern void MoveIconManager();
+extern void JumpIconManager();
+extern WList *AddIconManager();
+extern void InsertInIconManager();
+extern void RemoveFromIconManager();
+extern void RemoveIconManager();
+extern void ActiveIconManager();
+extern void NotActiveIconManager();
+extern void DrawIconManagerBorder();
+extern void SortIconManager();
+extern void PackIconManager();
+
+
+#endif /* _ICONMGR_ */
diff --git a/src/icons.c b/src/icons.c
new file mode 100644
index 0000000..32f0ce8
--- /dev/null
+++ b/src/icons.c
@@ -0,0 +1,588 @@
+/*
+ *
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ * */
+
+/**********************************************************************
+ *
+ * $Xorg: icons.c,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Icon releated routines
+ *
+ * 10-Apr-89 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include "screen.h"
+#include "icons.h"
+#include "gram.h"
+#include "parse.h"
+#include "util.h"
+
+#define iconWidth(w) (Scr->IconBorderWidth * 2 + w->icon_w_width)
+#define iconHeight(w) (Scr->IconBorderWidth * 2 + w->icon_w_height)
+
+static
+splitEntry (ie, grav1, grav2, w, h)
+ IconEntry *ie;
+ int grav1, grav2;
+ int w, h;
+{
+ IconEntry *new;
+
+ switch (grav1) {
+ case D_NORTH:
+ case D_SOUTH:
+ if (w != ie->w)
+ splitEntry (ie, grav2, grav1, w, ie->h);
+ if (h != ie->h) {
+ new = (IconEntry *)malloc (sizeof (IconEntry));
+ new->twm_win = 0;
+ new->used = 0;
+ new->next = ie->next;
+ ie->next = new;
+ new->x = ie->x;
+ new->h = (ie->h - h);
+ new->w = ie->w;
+ ie->h = h;
+ if (grav1 == D_SOUTH) {
+ new->y = ie->y;
+ ie->y = new->y + new->h;
+ } else
+ new->y = ie->y + ie->h;
+ }
+ break;
+ case D_EAST:
+ case D_WEST:
+ if (h != ie->h)
+ splitEntry (ie, grav2, grav1, ie->w, h);
+ if (w != ie->w) {
+ new = (IconEntry *)malloc (sizeof (IconEntry));
+ new->twm_win = 0;
+ new->used = 0;
+ new->next = ie->next;
+ ie->next = new;
+ new->y = ie->y;
+ new->w = (ie->w - w);
+ new->h = ie->h;
+ ie->w = w;
+ if (grav1 == D_EAST) {
+ new->x = ie->x;
+ ie->x = new->x + new->w;
+ } else
+ new->x = ie->x + ie->w;
+ }
+ break;
+ }
+}
+
+roundUp (v, multiple)
+{
+ return ((v + multiple - 1) / multiple) * multiple;
+}
+
+PlaceIcon(tmp_win, def_x, def_y, final_x, final_y)
+TwmWindow *tmp_win;
+int def_x, def_y;
+int *final_x, *final_y;
+{
+ IconRegion *ir;
+ IconEntry *ie;
+ int w = 0, h = 0;
+
+ ie = 0;
+ for (ir = Scr->FirstRegion; ir; ir = ir->next) {
+ w = roundUp (iconWidth (tmp_win), ir->stepx);
+ h = roundUp (iconHeight (tmp_win), ir->stepy);
+ for (ie = ir->entries; ie; ie=ie->next) {
+ if (ie->used)
+ continue;
+ if (ie->w >= w && ie->h >= h)
+ break;
+ }
+ if (ie)
+ break;
+ }
+ if (ie) {
+ splitEntry (ie, ir->grav1, ir->grav2, w, h);
+ ie->used = 1;
+ ie->twm_win = tmp_win;
+ *final_x = ie->x + (ie->w - iconWidth (tmp_win)) / 2;
+ *final_y = ie->y + (ie->h - iconHeight (tmp_win)) / 2;
+ } else {
+ *final_x = def_x;
+ *final_y = def_y;
+ }
+ return;
+}
+
+static IconEntry *
+FindIconEntry (tmp_win, irp)
+ TwmWindow *tmp_win;
+ IconRegion **irp;
+{
+ IconRegion *ir;
+ IconEntry *ie;
+
+ for (ir = Scr->FirstRegion; ir; ir = ir->next) {
+ for (ie = ir->entries; ie; ie=ie->next)
+ if (ie->twm_win == tmp_win) {
+ if (irp)
+ *irp = ir;
+ return ie;
+ }
+ }
+ return 0;
+}
+
+IconUp (tmp_win)
+ TwmWindow *tmp_win;
+{
+ int x, y;
+ int defx, defy;
+ struct IconRegion *ir;
+
+ /*
+ * If the client specified a particular location, let's use it (this might
+ * want to be an option at some point). Otherwise, try to fit within the
+ * icon region.
+ */
+ if (tmp_win->wmhints && (tmp_win->wmhints->flags & IconPositionHint))
+ return;
+
+ if (tmp_win->icon_moved) {
+ if (!XGetGeometry (dpy, tmp_win->icon_w, &JunkRoot, &defx, &defy,
+ &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth))
+ return;
+
+ x = defx + ((int) JunkWidth) / 2;
+ y = defy + ((int) JunkHeight) / 2;
+
+ for (ir = Scr->FirstRegion; ir; ir = ir->next) {
+ if (x >= ir->x && x < (ir->x + ir->w) &&
+ y >= ir->y && y < (ir->y + ir->h))
+ break;
+ }
+ if (!ir) return; /* outside icon regions, leave alone */
+ }
+
+ defx = -100;
+ defy = -100;
+ PlaceIcon(tmp_win, defx, defy, &x, &y);
+ if (x != defx || y != defy) {
+ XMoveWindow (dpy, tmp_win->icon_w, x, y);
+ tmp_win->icon_moved = FALSE; /* since we've restored it */
+ }
+}
+
+static IconEntry *
+prevIconEntry (ie, ir)
+ IconEntry *ie;
+ IconRegion *ir;
+{
+ IconEntry *ip;
+
+ if (ie == ir->entries)
+ return 0;
+ for (ip = ir->entries; ip->next != ie; ip=ip->next)
+ ;
+ return ip;
+}
+
+/* old is being freed; and is adjacent to ie. Merge
+ * regions together
+ */
+
+static
+mergeEntries (old, ie)
+ IconEntry *old, *ie;
+{
+ if (old->y == ie->y) {
+ ie->w = old->w + ie->w;
+ if (old->x < ie->x)
+ ie->x = old->x;
+ } else {
+ ie->h = old->h + ie->h;
+ if (old->y < ie->y)
+ ie->y = old->y;
+ }
+}
+
+IconDown (tmp_win)
+ TwmWindow *tmp_win;
+{
+ IconEntry *ie, *ip, *in;
+ IconRegion *ir;
+
+ ie = FindIconEntry (tmp_win, &ir);
+ if (ie) {
+ ie->twm_win = 0;
+ ie->used = 0;
+ ip = prevIconEntry (ie, ir);
+ in = ie->next;
+ for (;;) {
+ if (ip && ip->used == 0 &&
+ ((ip->x == ie->x && ip->w == ie->w) ||
+ (ip->y == ie->y && ip->h == ie->h)))
+ {
+ ip->next = ie->next;
+ mergeEntries (ie, ip);
+ free ((char *) ie);
+ ie = ip;
+ ip = prevIconEntry (ip, ir);
+ } else if (in && in->used == 0 &&
+ ((in->x == ie->x && in->w == ie->w) ||
+ (in->y == ie->y && in->h == ie->h)))
+ {
+ ie->next = in->next;
+ mergeEntries (in, ie);
+ free ((char *) in);
+ in = ie->next;
+ } else
+ break;
+ }
+ }
+}
+
+AddIconRegion(geom, grav1, grav2, stepx, stepy)
+char *geom;
+int grav1, grav2;
+{
+ IconRegion *ir;
+ int mask;
+
+ ir = (IconRegion *)malloc(sizeof(IconRegion));
+ ir->next = NULL;
+ if (Scr->LastRegion)
+ Scr->LastRegion->next = ir;
+ Scr->LastRegion = ir;
+ if (!Scr->FirstRegion)
+ Scr->FirstRegion = ir;
+
+ ir->entries = NULL;
+ ir->grav1 = grav1;
+ ir->grav2 = grav2;
+ if (stepx <= 0)
+ stepx = 1;
+ if (stepy <= 0)
+ stepy = 1;
+ ir->stepx = stepx;
+ ir->stepy = stepy;
+ ir->x = ir->y = ir->w = ir->h = 0;
+
+ mask = XParseGeometry(geom, &ir->x, &ir->y, (unsigned int *)&ir->w, (unsigned int *)&ir->h);
+
+ if (mask & XNegative)
+ ir->x += Scr->MyDisplayWidth - ir->w;
+
+ if (mask & YNegative)
+ ir->y += Scr->MyDisplayHeight - ir->h;
+ ir->entries = (IconEntry *)malloc(sizeof(IconEntry));
+ ir->entries->next = 0;
+ ir->entries->x = ir->x;
+ ir->entries->y = ir->y;
+ ir->entries->w = ir->w;
+ ir->entries->h = ir->h;
+ ir->entries->twm_win = 0;
+ ir->entries->used = 0;
+}
+
+#ifdef comment
+FreeIconEntries (ir)
+ IconRegion *ir;
+{
+ IconEntry *ie, *tmp;
+
+ for (ie = ir->entries; ie; ie=tmp)
+ {
+ tmp = ie->next;
+ free ((char *) ie);
+ }
+}
+FreeIconRegions()
+{
+ IconRegion *ir, *tmp;
+
+ for (ir = Scr->FirstRegion; ir != NULL;)
+ {
+ tmp = ir;
+ FreeIconEntries (ir);
+ ir = ir->next;
+ free((char *) tmp);
+ }
+ Scr->FirstRegion = NULL;
+ Scr->LastRegion = NULL;
+}
+#endif
+
+CreateIconWindow(tmp_win, def_x, def_y)
+TwmWindow *tmp_win;
+int def_x, def_y;
+{
+ unsigned long event_mask;
+ unsigned long valuemask; /* mask for create windows */
+ XSetWindowAttributes attributes; /* attributes for create windows */
+ Pixmap pm = None; /* tmp pixmap variable */
+ int final_x, final_y;
+ int x;
+
+
+ FB(tmp_win->iconc.fore, tmp_win->iconc.back);
+
+ tmp_win->forced = FALSE;
+ tmp_win->icon_not_ours = FALSE;
+
+ /* now go through the steps to get an icon window, if ForceIcon is
+ * set, then no matter what else is defined, the bitmap from the
+ * .twmrc file is used
+ */
+ if (Scr->ForceIcon)
+ {
+ char *icon_name;
+ Pixmap bm;
+
+ icon_name = LookInNameList(Scr->IconNames, tmp_win->full_name);
+ if (icon_name == NULL)
+ icon_name = LookInList(Scr->IconNames, tmp_win->full_name,
+ &tmp_win->class);
+
+ bm = None;
+ if (icon_name != NULL)
+ {
+ if ((bm = (Pixmap)LookInNameList(Scr->Icons, icon_name)) == None)
+ {
+ if ((bm = GetBitmap (icon_name)) != None)
+ AddToList(&Scr->Icons, icon_name, (char *)bm);
+ }
+ }
+
+ if (bm != None)
+ {
+ XGetGeometry(dpy, bm, &JunkRoot, &JunkX, &JunkY,
+ (unsigned int *) &tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height,
+ &JunkBW, &JunkDepth);
+
+ pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
+ tmp_win->icon_height, Scr->d_depth);
+
+ /* the copy plane works on color ! */
+ XCopyPlane(dpy, bm, pm, Scr->NormalGC,
+ 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
+
+ tmp_win->forced = TRUE;
+ }
+ }
+
+ /* if the pixmap is still NULL, we didn't get one from the above code,
+ * that could mean that ForceIcon was not set, or that the window
+ * was not in the Icons list, now check the WM hints for an icon
+ */
+ if (pm == None && tmp_win->wmhints &&
+ tmp_win->wmhints->flags & IconPixmapHint)
+ {
+
+ XGetGeometry(dpy, tmp_win->wmhints->icon_pixmap,
+ &JunkRoot, &JunkX, &JunkY,
+ (unsigned int *)&tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height, &JunkBW, &JunkDepth);
+
+ pm = XCreatePixmap(dpy, Scr->Root,
+ tmp_win->icon_width, tmp_win->icon_height,
+ Scr->d_depth);
+
+ XCopyPlane(dpy, tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
+ 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
+ }
+
+ /* if we still haven't got an icon, let's look in the Icon list
+ * if ForceIcon is not set
+ */
+ if (pm == None && !Scr->ForceIcon)
+ {
+ char *icon_name;
+ Pixmap bm;
+
+ icon_name = LookInNameList(Scr->IconNames, tmp_win->full_name);
+ if (icon_name == NULL)
+ icon_name = LookInList(Scr->IconNames, tmp_win->full_name,
+ &tmp_win->class);
+
+ bm = None;
+ if (icon_name != NULL)
+ {
+ if ((bm = (Pixmap)LookInNameList(Scr->Icons, icon_name)) == None)
+ {
+ if ((bm = GetBitmap (icon_name)) != None)
+ AddToList(&Scr->Icons, icon_name, (char *)bm);
+ }
+ }
+
+ if (bm != None)
+ {
+ XGetGeometry(dpy, bm, &JunkRoot, &JunkX, &JunkY,
+ (unsigned int *)&tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height,
+ &JunkBW, &JunkDepth);
+
+ pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
+ tmp_win->icon_height, Scr->d_depth);
+
+ /* the copy plane works on color ! */
+ XCopyPlane(dpy, bm, pm, Scr->NormalGC,
+ 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
+ }
+ }
+
+ /* if we still don't have an icon, assign the UnknownIcon */
+
+ if (pm == None && Scr->UnknownPm != None)
+ {
+ tmp_win->icon_width = Scr->UnknownWidth;
+ tmp_win->icon_height = Scr->UnknownHeight;
+
+ pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
+ tmp_win->icon_height, Scr->d_depth);
+
+ /* the copy plane works on color ! */
+ XCopyPlane(dpy, Scr->UnknownPm, pm, Scr->NormalGC,
+ 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
+ }
+
+ if (pm == None)
+ {
+ tmp_win->icon_height = 0;
+ tmp_win->icon_width = 0;
+ valuemask = 0;
+ }
+ else
+ {
+ valuemask = CWBackPixmap;
+ attributes.background_pixmap = pm;
+ }
+
+ tmp_win->icon_w_width = XTextWidth(Scr->IconFont.font,
+ tmp_win->icon_name, strlen(tmp_win->icon_name));
+
+ tmp_win->icon_w_width += 6;
+ if (tmp_win->icon_w_width < tmp_win->icon_width)
+ {
+ tmp_win->icon_x = (tmp_win->icon_width - tmp_win->icon_w_width)/2;
+ tmp_win->icon_x += 3;
+ tmp_win->icon_w_width = tmp_win->icon_width;
+ }
+ else
+ {
+ tmp_win->icon_x = 3;
+ }
+ tmp_win->icon_y = tmp_win->icon_height + Scr->IconFont.height;
+ tmp_win->icon_w_height = tmp_win->icon_height + Scr->IconFont.height + 4;
+
+ event_mask = 0;
+ if (tmp_win->wmhints && tmp_win->wmhints->flags & IconWindowHint)
+ {
+ tmp_win->icon_w = tmp_win->wmhints->icon_window;
+ if (tmp_win->forced ||
+ XGetGeometry(dpy, tmp_win->icon_w, &JunkRoot, &JunkX, &JunkY,
+ (unsigned int *)&tmp_win->icon_w_width, (unsigned int *)&tmp_win->icon_w_height,
+ &JunkBW, &JunkDepth) == 0)
+ {
+ tmp_win->icon_w = None;
+ tmp_win->wmhints->flags &= ~IconWindowHint;
+ }
+ else
+ {
+ tmp_win->icon_not_ours = TRUE;
+ event_mask = EnterWindowMask | LeaveWindowMask;
+ }
+ }
+ else
+ {
+ tmp_win->icon_w = None;
+ }
+
+ if (tmp_win->icon_w == None)
+ {
+ tmp_win->icon_w = XCreateSimpleWindow(dpy, Scr->Root,
+ 0,0,
+ tmp_win->icon_w_width, tmp_win->icon_w_height,
+ Scr->IconBorderWidth, tmp_win->icon_border, tmp_win->iconc.back);
+ event_mask = ExposureMask;
+ }
+
+ XSelectInput (dpy, tmp_win->icon_w,
+ KeyPressMask | ButtonPressMask | ButtonReleaseMask |
+ event_mask);
+
+ tmp_win->icon_bm_w = None;
+ if (pm != None &&
+ (! (tmp_win->wmhints && tmp_win->wmhints->flags & IconWindowHint)))
+ {
+ int y;
+
+ y = 0;
+ if (tmp_win->icon_w_width == tmp_win->icon_width)
+ x = 0;
+ else
+ x = (tmp_win->icon_w_width - tmp_win->icon_width)/2;
+
+ tmp_win->icon_bm_w = XCreateWindow (dpy, tmp_win->icon_w, x, y,
+ (unsigned int)tmp_win->icon_width,
+ (unsigned int)tmp_win->icon_height,
+ (unsigned int) 0, Scr->d_depth,
+ (unsigned int) CopyFromParent,
+ Scr->d_visual, valuemask,
+ &attributes);
+ }
+
+ /* I need to figure out where to put the icon window now, because
+ * getting here means that I am going to make the icon visible
+ */
+ if (tmp_win->wmhints &&
+ tmp_win->wmhints->flags & IconPositionHint)
+ {
+ final_x = tmp_win->wmhints->icon_x;
+ final_y = tmp_win->wmhints->icon_y;
+ }
+ else
+ {
+ PlaceIcon(tmp_win, def_x, def_y, &final_x, &final_y);
+ }
+
+ if (final_x > Scr->MyDisplayWidth)
+ final_x = Scr->MyDisplayWidth - tmp_win->icon_w_width -
+ (2 * Scr->IconBorderWidth);
+
+ if (final_y > Scr->MyDisplayHeight)
+ final_y = Scr->MyDisplayHeight - tmp_win->icon_height -
+ Scr->IconFont.height - 4 - (2 * Scr->IconBorderWidth);
+
+ XMoveWindow(dpy, tmp_win->icon_w, final_x, final_y);
+ tmp_win->iconified = TRUE;
+
+ XMapSubwindows(dpy, tmp_win->icon_w);
+ XSaveContext(dpy, tmp_win->icon_w, TwmContext, (caddr_t)tmp_win);
+ XSaveContext(dpy, tmp_win->icon_w, ScreenContext, (caddr_t)Scr);
+ XDefineCursor(dpy, tmp_win->icon_w, Scr->IconCursor);
+ if (pm) XFreePixmap (dpy, pm);
+ return;
+}
diff --git a/src/icons.h b/src/icons.h
new file mode 100644
index 0000000..43cbab9
--- /dev/null
+++ b/src/icons.h
@@ -0,0 +1,56 @@
+/*
+ *
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ * */
+
+/**********************************************************************
+ *
+ * $Xorg: icons.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * Icon releated definitions
+ *
+ * 10-Apr-89 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef ICONS_H
+#define ICONS_H
+
+typedef struct IconRegion
+{
+ struct IconRegion *next;
+ int x, y, w, h;
+ int grav1, grav2;
+ int stepx, stepy; /* allocation granularity */
+ struct IconEntry *entries;
+} IconRegion;
+
+typedef struct IconEntry
+{
+ struct IconEntry *next;
+ int x, y, w, h;
+ TwmWindow *twm_win;
+ short used;
+}IconEntry;
+
+#endif /* ICONS_H */
diff --git a/src/lex.l b/src/lex.l
new file mode 100644
index 0000000..1886f4b
--- /dev/null
+++ b/src/lex.l
@@ -0,0 +1,145 @@
+%{
+/*****************************************************************************/
+/*
+
+Copyright 1989,1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+/***********************************************************************
+ *
+ * $Xorg: lex.l,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * .twmrc lex file
+ *
+ * 12-Nov-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+/* #include <stdio.h> */ /* lex already includes stdio.h */
+#include "gram.h"
+#include "parse.h"
+extern char *ProgramName;
+
+extern int ParseError;
+#ifdef FLEX_SCANNER
+int yylineno;
+
+#undef YY_INPUT
+#define YY_INPUT(buf,result,size) ((result) = doinput((buf),(size)))
+doinput (buf, size)
+char *buf;
+{
+ int c;
+
+ if (size == 0)
+ return (0);
+
+ if ((c = (*twmInputFunc)()) <= 0)
+ return (0);
+
+ buf[0] = c;
+ return (1);
+}
+#endif
+
+%}
+
+string \"([^"]|\\.)*\"
+number [0-9]+
+%%
+"{" { return (LB); }
+"}" { return (RB); }
+"(" { return (LP); }
+")" { return (RP); }
+"=" { return (EQUALS); }
+":" { return (COLON); }
+"+" { return PLUS; }
+"-" { return MINUS; }
+"|" { return OR; }
+
+[a-zA-Z\.]+ { int token = parse_keyword (yytext,
+ &yylval.num);
+ if (token == ERRORTOKEN) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring unknown keyword: %s\n",
+ yytext);
+ ParseError = 1;
+ } else
+ return token;
+ }
+
+"!" { yylval.num = F_EXEC; return FSKEYWORD; }
+"^" { yylval.num = F_CUT; return FSKEYWORD; }
+
+{string} { yylval.ptr = (char *)yytext; return STRING; }
+{number} { (void)sscanf((char *)yytext, "%d", &yylval.num);
+ return (NUMBER);
+ }
+\#[^\n]*\n {;}
+[\n\t ] {;}
+. {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring character \"%s\"\n",
+ yytext);
+ ParseError = 1;
+ }
+%%
+#ifndef yywrap
+yywrap() { return(1);}
+#endif
+
+#undef unput
+#undef input
+#undef output
+#undef feof
+#define unput(c) twmUnput(c)
+#define input() (*twmInputFunc)()
+#define output(c) TwmOutput(c)
+#define feof() (1)
diff --git a/src/list.c b/src/list.c
new file mode 100644
index 0000000..e0f4774
--- /dev/null
+++ b/src/list.c
@@ -0,0 +1,258 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/**********************************************************************
+ *
+ * $Xorg: list.c,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * TWM code to deal with the name lists for the NoTitle list and
+ * the AutoRaise list
+ *
+ * 11-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include "screen.h"
+#include "gram.h"
+
+struct name_list_struct
+{
+ name_list *next; /* pointer to the next name */
+ char *name; /* the name of the window */
+ char *ptr; /* list dependent data */
+};
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddToList - add a window name to the appropriate list
+ *
+ * Inputs:
+ * list - the address of the pointer to the head of a list
+ * name - a pointer to the name of the window
+ * ptr - pointer to list dependent data
+ *
+ * Special Considerations
+ * If the list does not use the ptr value, a non-null value
+ * should be placed in it. LookInList returns this ptr value
+ * and procedures calling LookInList will check for a non-null
+ * return value as an indication of success.
+ *
+ ***********************************************************************
+ */
+
+void
+AddToList(list_head, name, ptr)
+name_list **list_head;
+char *name;
+char *ptr;
+{
+ name_list *nptr;
+
+ if (!list_head) return; /* ignore empty inserts */
+
+ nptr = (name_list *)malloc(sizeof(name_list));
+ if (nptr == NULL)
+ {
+ twmrc_error_prefix();
+ fprintf (stderr, "unable to allocate %d bytes for name_list\n",
+ sizeof(name_list));
+ Done();
+ }
+
+ nptr->next = *list_head;
+ nptr->name = name;
+ nptr->ptr = (ptr == NULL) ? (char *)TRUE : ptr;
+ *list_head = nptr;
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * LookInList - look through a list for a window name, or class
+ *
+ * Returned Value:
+ * the ptr field of the list structure or NULL if the name
+ * or class was not found in the list
+ *
+ * Inputs:
+ * list - a pointer to the head of a list
+ * name - a pointer to the name to look for
+ * class - a pointer to the class to look for
+ *
+ ***********************************************************************
+ */
+
+char *
+LookInList(list_head, name, class)
+name_list *list_head;
+char *name;
+XClassHint *class;
+{
+ name_list *nptr;
+
+ /* look for the name first */
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(name, nptr->name) == 0)
+ return (nptr->ptr);
+
+ if (class)
+ {
+ /* look for the res_name next */
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(class->res_name, nptr->name) == 0)
+ return (nptr->ptr);
+
+ /* finally look for the res_class */
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(class->res_class, nptr->name) == 0)
+ return (nptr->ptr);
+ }
+ return (NULL);
+}
+
+char *
+LookInNameList(list_head, name)
+name_list *list_head;
+char *name;
+{
+ return (LookInList(list_head, name, NULL));
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * GetColorFromList - look through a list for a window name, or class
+ *
+ * Returned Value:
+ * TRUE if the name was found
+ * FALSE if the name was not found
+ *
+ * Inputs:
+ * list - a pointer to the head of a list
+ * name - a pointer to the name to look for
+ * class - a pointer to the class to look for
+ *
+ * Outputs:
+ * ptr - fill in the list value if the name was found
+ *
+ ***********************************************************************
+ */
+
+int GetColorFromList(list_head, name, class, ptr)
+name_list *list_head;
+char *name;
+XClassHint *class;
+Pixel *ptr;
+{
+ int save;
+ name_list *nptr;
+
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(name, nptr->name) == 0)
+ {
+ save = Scr->FirstTime;
+ Scr->FirstTime = TRUE;
+ GetColor(Scr->Monochrome, ptr, nptr->ptr);
+ Scr->FirstTime = save;
+ return (TRUE);
+ }
+
+ if (class)
+ {
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(class->res_name, nptr->name) == 0)
+ {
+ save = Scr->FirstTime;
+ Scr->FirstTime = TRUE;
+ GetColor(Scr->Monochrome, ptr, nptr->ptr);
+ Scr->FirstTime = save;
+ return (TRUE);
+ }
+
+ for (nptr = list_head; nptr != NULL; nptr = nptr->next)
+ if (strcmp(class->res_class, nptr->name) == 0)
+ {
+ save = Scr->FirstTime;
+ Scr->FirstTime = TRUE;
+ GetColor(Scr->Monochrome, ptr, nptr->ptr);
+ Scr->FirstTime = save;
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * FreeList - free up a list
+ *
+ ***********************************************************************
+ */
+
+void FreeList(list)
+name_list **list;
+{
+ name_list *nptr;
+ name_list *tmp;
+
+ for (nptr = *list; nptr != NULL; )
+ {
+ tmp = nptr->next;
+ free((char *) nptr);
+ nptr = tmp;
+ }
+ *list = NULL;
+}
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..8b4cce3
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,75 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/**********************************************************************
+ *
+ * $Xorg: list.h,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * TWM list handling external definitions
+ *
+ * 11-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _LIST_
+#define _LIST_
+
+typedef struct name_list_struct name_list;
+
+extern void AddToList();
+extern char* LookInList();
+extern char* LookInNameList();
+extern int GetColorFromList();
+extern void FreeList();
+
+#endif /* _LIST_ */
+
diff --git a/src/menus.c b/src/menus.c
new file mode 100644
index 0000000..83fe792
--- /dev/null
+++ b/src/menus.c
@@ -0,0 +1,3035 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/***********************************************************************
+ *
+ * $Xorg: menus.c,v 1.6 2001/02/09 02:05:36 xorgcvs Exp $
+ *
+ * twm menu code
+ *
+ * 17-Nov-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#include <stdio.h>
+#include <X11/Xos.h>
+#include "twm.h"
+#include "gc.h"
+#include "menus.h"
+#include "resize.h"
+#include "events.h"
+#include "util.h"
+#include "parse.h"
+#include "gram.h"
+#include "screen.h"
+#include <X11/Xmu/CharSet.h>
+#include <X11/bitmaps/menu12>
+#include "version.h"
+#include <X11/extensions/sync.h>
+#include <X11/SM/SMlib.h>
+
+extern XEvent Event;
+
+int RootFunction = 0;
+MenuRoot *ActiveMenu = NULL; /* the active menu */
+MenuItem *ActiveItem = NULL; /* the active menu item */
+int MoveFunction; /* either F_MOVE or F_FORCEMOVE */
+int WindowMoved = FALSE;
+int menuFromFrameOrWindowOrTitlebar = FALSE;
+
+int ConstMove = FALSE; /* constrained move variables */
+int ConstMoveDir;
+int ConstMoveX;
+int ConstMoveY;
+int ConstMoveXL;
+int ConstMoveXR;
+int ConstMoveYT;
+int ConstMoveYB;
+
+/* Globals used to keep track of whether the mouse has moved during
+ a resize function. */
+int ResizeOrigX;
+int ResizeOrigY;
+
+int MenuDepth = 0; /* number of menus up */
+static struct {
+ int x;
+ int y;
+} MenuOrigins[MAXMENUDEPTH];
+static Cursor LastCursor;
+
+void WarpAlongRing(), WarpToWindow();
+
+extern char *Action;
+extern int Context;
+extern TwmWindow *ButtonWindow, *Tmp_win;
+extern XEvent Event, ButtonEvent;
+extern char *InitFile;
+static void Identify();
+
+#define SHADOWWIDTH 5 /* in pixels */
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * InitMenus - initialize menu roots
+ *
+ ***********************************************************************
+ */
+
+void
+InitMenus()
+{
+ int i, j, k;
+ FuncKey *key, *tmp;
+
+ for (i = 0; i < MAX_BUTTONS+1; i++)
+ for (j = 0; j < NUM_CONTEXTS; j++)
+ for (k = 0; k < MOD_SIZE; k++)
+ {
+ Scr->Mouse[i][j][k].func = 0;
+ Scr->Mouse[i][j][k].item = NULL;
+ }
+
+ Scr->DefaultFunction.func = 0;
+ Scr->WindowFunction.func = 0;
+
+ if (FirstScreen)
+ {
+ for (key = Scr->FuncKeyRoot.next; key != NULL;)
+ {
+ free(key->name);
+ tmp = key;
+ key = key->next;
+ free((char *) tmp);
+ }
+ Scr->FuncKeyRoot.next = NULL;
+ }
+
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddFuncKey - add a function key to the list
+ *
+ * Inputs:
+ * name - the name of the key
+ * cont - the context to look for the key press in
+ * mods - modifier keys that need to be pressed
+ * func - the function to perform
+ * win_name- the window name (if any)
+ * action - the action string associated with the function (if any)
+ *
+ ***********************************************************************
+ */
+
+Bool AddFuncKey (name, cont, mods, func, win_name, action)
+ char *name;
+ int cont, mods, func;
+ char *win_name;
+ char *action;
+{
+ FuncKey *tmp;
+ KeySym keysym;
+ KeyCode keycode;
+
+ /*
+ * Don't let a 0 keycode go through, since that means AnyKey to the
+ * XGrabKey call in GrabKeys().
+ */
+ if ((keysym = XStringToKeysym(name)) == NoSymbol ||
+ (keycode = XKeysymToKeycode(dpy, keysym)) == 0)
+ {
+ return False;
+ }
+
+ /* see if there already is a key defined for this context */
+ for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next)
+ {
+ if (tmp->keysym == keysym &&
+ tmp->cont == cont &&
+ tmp->mods == mods)
+ break;
+ }
+
+ if (tmp == NULL)
+ {
+ tmp = (FuncKey *) malloc(sizeof(FuncKey));
+ tmp->next = Scr->FuncKeyRoot.next;
+ Scr->FuncKeyRoot.next = tmp;
+ }
+
+ tmp->name = name;
+ tmp->keysym = keysym;
+ tmp->keycode = keycode;
+ tmp->cont = cont;
+ tmp->mods = mods;
+ tmp->func = func;
+ tmp->win_name = win_name;
+ tmp->action = action;
+
+ return True;
+}
+
+
+
+int CreateTitleButton (name, func, action, menuroot, rightside, append)
+ char *name;
+ int func;
+ char *action;
+ MenuRoot *menuroot;
+ Bool rightside;
+ Bool append;
+{
+ TitleButton *tb = (TitleButton *) malloc (sizeof(TitleButton));
+
+ if (!tb) {
+ fprintf (stderr,
+ "%s: unable to allocate %d bytes for title button\n",
+ ProgramName, sizeof(TitleButton));
+ return 0;
+ }
+
+ tb->next = NULL;
+ tb->name = name; /* note that we are not copying */
+ tb->bitmap = None; /* WARNING, values not set yet */
+ tb->width = 0; /* see InitTitlebarButtons */
+ tb->height = 0; /* ditto */
+ tb->func = func;
+ tb->action = action;
+ tb->menuroot = menuroot;
+ tb->rightside = rightside;
+ if (rightside) {
+ Scr->TBInfo.nright++;
+ } else {
+ Scr->TBInfo.nleft++;
+ }
+
+ /*
+ * Cases for list:
+ *
+ * 1. empty list, prepend left put at head of list
+ * 2. append left, prepend right put in between left and right
+ * 3. append right put at tail of list
+ *
+ * Do not refer to widths and heights yet since buttons not created
+ * (since fonts not loaded and heights not known).
+ */
+ if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) { /* 1 */
+ tb->next = Scr->TBInfo.head;
+ Scr->TBInfo.head = tb;
+ } else if (append && rightside) { /* 3 */
+ register TitleButton *t;
+ for /* SUPPRESS 530 */
+ (t = Scr->TBInfo.head; t->next; t = t->next);
+ t->next = tb;
+ tb->next = NULL;
+ } else { /* 2 */
+ register TitleButton *t, *prev = NULL;
+ for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) {
+ prev = t;
+ }
+ if (prev) {
+ tb->next = prev->next;
+ prev->next = tb;
+ } else {
+ tb->next = Scr->TBInfo.head;
+ Scr->TBInfo.head = tb;
+ }
+ }
+
+ return 1;
+}
+
+
+
+/*
+ * InitTitlebarButtons - Do all the necessary stuff to load in a titlebar
+ * button. If we can't find the button, then put in a question; if we can't
+ * find the question mark, something is wrong and we are probably going to be
+ * in trouble later on.
+ */
+void InitTitlebarButtons ()
+{
+ TitleButton *tb;
+ int h;
+
+ /*
+ * initialize dimensions
+ */
+ Scr->TBInfo.width = (Scr->TitleHeight -
+ 2 * (Scr->FramePadding + Scr->ButtonIndent));
+ Scr->TBInfo.pad = ((Scr->TitlePadding > 1)
+ ? ((Scr->TitlePadding + 1) / 2) : 1);
+ h = Scr->TBInfo.width - 2 * Scr->TBInfo.border;
+
+ /*
+ * add in some useful buttons and bindings so that novices can still
+ * use the system.
+ */
+ if (!Scr->NoDefaults) {
+ /* insert extra buttons */
+ if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL,
+ False, False)) {
+ fprintf (stderr, "%s: unable to add iconify button\n",
+ ProgramName);
+ }
+ if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL,
+ True, True)) {
+ fprintf (stderr, "%s: unable to add resize button\n",
+ ProgramName);
+ }
+ AddDefaultBindings ();
+ }
+ ComputeCommonTitleOffsets ();
+
+ /*
+ * load in images and do appropriate centering
+ */
+
+ for (tb = Scr->TBInfo.head; tb; tb = tb->next) {
+ tb->bitmap = FindBitmap (tb->name, &tb->width, &tb->height);
+ if (!tb->bitmap) {
+ tb->bitmap = FindBitmap (TBPM_QUESTION, &tb->width, &tb->height);
+ if (!tb->bitmap) { /* cannot happen (see util.c) */
+ fprintf (stderr,
+ "%s: unable to add titlebar button \"%s\"\n",
+ ProgramName, tb->name);
+ }
+ }
+
+ tb->dstx = (h - tb->width + 1) / 2;
+ if (tb->dstx < 0) { /* clip to minimize copying */
+ tb->srcx = -(tb->dstx);
+ tb->width = h;
+ tb->dstx = 0;
+ } else {
+ tb->srcx = 0;
+ }
+ tb->dsty = (h - tb->height + 1) / 2;
+ if (tb->dsty < 0) {
+ tb->srcy = -(tb->dsty);
+ tb->height = h;
+ tb->dsty = 0;
+ } else {
+ tb->srcy = 0;
+ }
+ }
+}
+
+
+
+PaintEntry(mr, mi, exposure)
+MenuRoot *mr;
+MenuItem *mi;
+int exposure;
+{
+ int y_offset;
+ int text_y;
+ GC gc;
+
+#ifdef DEBUG_MENUS
+ fprintf(stderr, "Paint entry\n");
+#endif
+ y_offset = mi->item_num * Scr->EntryHeight;
+ text_y = y_offset + Scr->MenuFont.y;
+
+ if (mi->func != F_TITLE)
+ {
+ int x, y;
+
+ if (mi->state)
+ {
+ XSetForeground(dpy, Scr->NormalGC, mi->hi_back);
+
+ XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
+ mr->width, Scr->EntryHeight);
+
+ FBF(mi->hi_fore, mi->hi_back, Scr->MenuFont.font->fid);
+
+ XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
+ text_y, mi->item, mi->strlen);
+
+ gc = Scr->NormalGC;
+ }
+ else
+ {
+ if (mi->user_colors || !exposure)
+ {
+ XSetForeground(dpy, Scr->NormalGC, mi->back);
+
+ XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
+ mr->width, Scr->EntryHeight);
+
+ FBF(mi->fore, mi->back, Scr->MenuFont.font->fid);
+ gc = Scr->NormalGC;
+ }
+ else
+ gc = Scr->MenuGC;
+
+ XDrawString(dpy, mr->w, gc, mi->x,
+ text_y, mi->item, mi->strlen);
+ }
+
+ if (mi->func == F_MENU)
+ {
+ /* create the pull right pixmap if needed */
+ if (Scr->pullPm == None)
+ {
+ Scr->pullPm = CreateMenuIcon (Scr->MenuFont.height,
+ &Scr->pullW, &Scr->pullH);
+ }
+ 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);
+ }
+ }
+ else
+ {
+ int y;
+
+ 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);
+
+ {
+ 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);
+ }
+
+ FBF(mi->fore, mi->back, Scr->MenuFont.font->fid);
+ /* finally render the title */
+ XDrawString(dpy, mr->w, Scr->NormalGC, mi->x,
+ text_y, mi->item, mi->strlen);
+ }
+}
+
+
+
+PaintMenu(mr, e)
+MenuRoot *mr;
+XEvent *e;
+{
+ MenuItem *mi;
+
+ for (mi = mr->first; mi != NULL; mi = mi->next)
+ {
+ int y_offset = mi->item_num * Scr->EntryHeight;
+
+ /* 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)
+ {
+ PaintEntry(mr, mi, True);
+ }
+ }
+ XSync(dpy, 0);
+}
+
+
+
+static Bool fromMenu;
+
+UpdateMenu()
+{
+ MenuItem *mi;
+ int i, x, y, x_root, y_root, entry;
+ int done;
+ MenuItem *badItem = NULL;
+
+ fromMenu = TRUE;
+
+ while (TRUE)
+ {
+ /* block until there is an event */
+ if (!menuFromFrameOrWindowOrTitlebar) {
+ XMaskEvent(dpy,
+ ButtonPressMask | ButtonReleaseMask |
+ EnterWindowMask | ExposureMask |
+ VisibilityChangeMask | LeaveWindowMask |
+ ButtonMotionMask, &Event);
+ }
+ if (Event.type == MotionNotify) {
+ /* discard any extra motion events before a release */
+ while(XCheckMaskEvent(dpy,
+ ButtonMotionMask | ButtonReleaseMask, &Event))
+ if (Event.type == ButtonRelease)
+ break;
+ }
+
+ if (!DispatchEvent ())
+ continue;
+
+ if (Event.type == ButtonRelease || Cancel) {
+ menuFromFrameOrWindowOrTitlebar = FALSE;
+ fromMenu = FALSE;
+ return;
+ }
+
+ if (Event.type != MotionNotify)
+ continue;
+
+ done = FALSE;
+ XQueryPointer( dpy, ActiveMenu->w, &JunkRoot, &JunkChild,
+ &x_root, &y_root, &x, &y, &JunkMask);
+
+ /* if we haven't recieved the enter notify yet, wait */
+ if (ActiveMenu && !ActiveMenu->entered)
+ continue;
+
+ XFindContext(dpy, ActiveMenu->w, ScreenContext, (caddr_t *)&Scr);
+
+ if (x < 0 || y < 0 ||
+ x >= ActiveMenu->width || y >= ActiveMenu->height)
+ {
+ if (ActiveItem && ActiveItem->func != F_TITLE)
+ {
+ ActiveItem->state = 0;
+ PaintEntry(ActiveMenu, ActiveItem, False);
+ }
+ ActiveItem = NULL;
+ continue;
+ }
+
+ /* look for the entry that the mouse is in */
+ entry = y / Scr->EntryHeight;
+ for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next)
+ {
+ if (i == entry)
+ break;
+ }
+
+ /* if there is an active item, we might have to turn it off */
+ if (ActiveItem)
+ {
+ /* is the active item the one we are on ? */
+ if (ActiveItem->item_num == entry && ActiveItem->state)
+ done = TRUE;
+
+ /* if we weren't on the active entry, let's turn the old
+ * active one off
+ */
+ if (!done && ActiveItem->func != F_TITLE)
+ {
+ ActiveItem->state = 0;
+ PaintEntry(ActiveMenu, ActiveItem, False);
+ }
+ }
+
+ /* if we weren't on the active item, change the active item and turn
+ * it on
+ */
+ if (!done)
+ {
+ ActiveItem = mi;
+ if (ActiveItem->func != F_TITLE && !ActiveItem->state)
+ {
+ ActiveItem->state = 1;
+ PaintEntry(ActiveMenu, ActiveItem, False);
+ }
+ }
+
+ /* now check to see if we were over the arrow of a pull right entry */
+ if (ActiveItem->func == F_MENU &&
+ ((ActiveMenu->width - x) < (ActiveMenu->width >> 1)))
+ {
+ MenuRoot *save = ActiveMenu;
+ int savex = MenuOrigins[MenuDepth - 1].x;
+ int savey = MenuOrigins[MenuDepth - 1].y;
+
+ if (MenuDepth < MAXMENUDEPTH) {
+ PopUpMenu (ActiveItem->sub,
+ (savex + (ActiveMenu->width >> 1)),
+ (savey + ActiveItem->item_num * Scr->EntryHeight)
+ /*(savey + ActiveItem->item_num * Scr->EntryHeight +
+ (Scr->EntryHeight >> 1))*/, False);
+ } else if (!badItem) {
+ Bell(XkbBI_MinorError,0,None);
+ badItem = ActiveItem;
+ }
+
+ /* if the menu did get popped up, unhighlight the active item */
+ if (save != ActiveMenu && ActiveItem->state)
+ {
+ ActiveItem->state = 0;
+ PaintEntry(save, ActiveItem, False);
+ ActiveItem = NULL;
+ }
+ }
+ if (badItem != ActiveItem) badItem = NULL;
+ XFlush(dpy);
+ }
+
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * NewMenuRoot - create a new menu root
+ *
+ * Returned Value:
+ * (MenuRoot *)
+ *
+ * Inputs:
+ * name - the name of the menu root
+ *
+ ***********************************************************************
+ */
+
+MenuRoot *
+NewMenuRoot(name)
+ char *name;
+{
+ MenuRoot *tmp;
+
+#define UNUSED_PIXEL ((unsigned long) (~0)) /* more than 24 bits */
+
+ tmp = (MenuRoot *) malloc(sizeof(MenuRoot));
+ tmp->hi_fore = UNUSED_PIXEL;
+ tmp->hi_back = UNUSED_PIXEL;
+ tmp->name = name;
+ tmp->prev = NULL;
+ tmp->first = NULL;
+ tmp->last = NULL;
+ tmp->items = 0;
+ tmp->width = 0;
+ tmp->mapped = NEVER_MAPPED;
+ tmp->pull = FALSE;
+ tmp->w = None;
+ tmp->shadow = None;
+ tmp->real_menu = FALSE;
+
+ if (Scr->MenuList == NULL)
+ {
+ Scr->MenuList = tmp;
+ Scr->MenuList->next = NULL;
+ }
+
+ if (Scr->LastMenu == NULL)
+ {
+ Scr->LastMenu = tmp;
+ Scr->LastMenu->next = NULL;
+ }
+ else
+ {
+ Scr->LastMenu->next = tmp;
+ Scr->LastMenu = tmp;
+ Scr->LastMenu->next = NULL;
+ }
+
+ if (strcmp(name, TWM_WINDOWS) == 0)
+ Scr->Windows = tmp;
+
+ return (tmp);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddToMenu - add an item to a root menu
+ *
+ * Returned Value:
+ * (MenuItem *)
+ *
+ * Inputs:
+ * menu - pointer to the root menu to add the item
+ * item - the text to appear in the menu
+ * action - the string to possibly execute
+ * sub - the menu root if it is a pull-right entry
+ * func - the numeric function
+ * fore - foreground color string
+ * back - background color string
+ *
+ ***********************************************************************
+ */
+
+MenuItem *
+AddToMenu(menu, item, action, sub, func, fore, back)
+ MenuRoot *menu;
+ char *item, *action;
+ MenuRoot *sub;
+ int func;
+ char *fore, *back;
+{
+ MenuItem *tmp;
+ int width;
+
+#ifdef DEBUG_MENUS
+ fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
+ item, action, sub, func);
+#endif
+
+ tmp = (MenuItem *) malloc(sizeof(MenuItem));
+ tmp->root = menu;
+
+ if (menu->first == NULL)
+ {
+ menu->first = tmp;
+ tmp->prev = NULL;
+ }
+ else
+ {
+ menu->last->next = tmp;
+ tmp->prev = menu->last;
+ }
+ menu->last = tmp;
+
+ tmp->item = item;
+ tmp->strlen = strlen(item);
+ tmp->action = action;
+ tmp->next = NULL;
+ tmp->sub = NULL;
+ tmp->state = 0;
+ tmp->func = func;
+
+ if (!Scr->HaveFonts) CreateFonts();
+ width = XTextWidth(Scr->MenuFont.font, item, tmp->strlen);
+ if (width <= 0)
+ width = 1;
+ if (width > menu->width)
+ menu->width = width;
+
+ tmp->user_colors = FALSE;
+ if (Scr->Monochrome == COLOR && fore != NULL)
+ {
+ int save;
+
+ save = Scr->FirstTime;
+ Scr->FirstTime = TRUE;
+ GetColor(COLOR, &tmp->fore, fore);
+ GetColor(COLOR, &tmp->back, back);
+ Scr->FirstTime = save;
+ tmp->user_colors = TRUE;
+ }
+ if (sub != NULL)
+ {
+ tmp->sub = sub;
+ menu->pull = TRUE;
+ }
+ tmp->item_num = menu->items++;
+
+ return (tmp);
+}
+
+
+
+MakeMenus()
+{
+ MenuRoot *mr;
+
+ for (mr = Scr->MenuList; mr != NULL; mr = mr->next)
+ {
+ if (mr->real_menu == FALSE)
+ continue;
+
+ MakeMenu(mr);
+ }
+}
+
+
+
+MakeMenu(mr)
+MenuRoot *mr;
+{
+ MenuItem *start, *end, *cur, *tmp;
+ XColor f1, f2, f3;
+ XColor b1, b2, b3;
+ XColor save_fore, save_back;
+ int num, i;
+ int fred, fgreen, fblue;
+ int bred, bgreen, bblue;
+ int width;
+ unsigned long valuemask;
+ XSetWindowAttributes attributes;
+ Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
+
+ Scr->EntryHeight = Scr->MenuFont.height + 4;
+
+ /* lets first size the window accordingly */
+ if (mr->mapped == NEVER_MAPPED)
+ {
+ if (mr->pull == TRUE)
+ {
+ mr->width += 16 + 10;
+ }
+
+ width = mr->width + 10;
+
+ for (cur = mr->first; cur != NULL; cur = cur->next)
+ {
+ if (cur->func != F_TITLE)
+ cur->x = 5;
+ else
+ {
+ cur->x = width - XTextWidth(Scr->MenuFont.font, cur->item,
+ cur->strlen);
+ cur->x /= 2;
+ }
+ }
+ mr->height = mr->items * Scr->EntryHeight;
+ mr->width += 10;
+
+ if (Scr->Shadow)
+ {
+ /*
+ * Make sure that you don't draw into the shadow window or else
+ * the background bits there will get saved
+ */
+ valuemask = (CWBackPixel | CWBorderPixel);
+ attributes.background_pixel = Scr->MenuShadowColor;
+ attributes.border_pixel = Scr->MenuShadowColor;
+ if (Scr->SaveUnder) {
+ valuemask |= CWSaveUnder;
+ attributes.save_under = True;
+ }
+ mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0,
+ (unsigned int) mr->width,
+ (unsigned int) mr->height,
+ (unsigned int)0,
+ CopyFromParent,
+ (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent,
+ valuemask, &attributes);
+ }
+
+ valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
+ attributes.background_pixel = Scr->MenuC.back;
+ attributes.border_pixel = Scr->MenuC.fore;
+ attributes.event_mask = (ExposureMask | EnterWindowMask);
+ if (Scr->SaveUnder) {
+ valuemask |= CWSaveUnder;
+ attributes.save_under = True;
+ }
+ if (Scr->BackingStore) {
+ valuemask |= CWBackingStore;
+ attributes.backing_store = Always;
+ }
+ mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width,
+ (unsigned int) mr->height, (unsigned int) 1,
+ CopyFromParent, (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent,
+ valuemask, &attributes);
+
+
+ XSaveContext(dpy, mr->w, MenuContext, (caddr_t)mr);
+ XSaveContext(dpy, mr->w, ScreenContext, (caddr_t)Scr);
+
+ mr->mapped = UNMAPPED;
+ }
+
+ /* get the default colors into the menus */
+ for (tmp = mr->first; tmp != NULL; tmp = tmp->next)
+ {
+ if (!tmp->user_colors) {
+ if (tmp->func != F_TITLE) {
+ tmp->fore = Scr->MenuC.fore;
+ tmp->back = Scr->MenuC.back;
+ } else {
+ tmp->fore = Scr->MenuTitleC.fore;
+ tmp->back = Scr->MenuTitleC.back;
+ }
+ }
+
+ if (mr->hi_fore != UNUSED_PIXEL)
+ {
+ tmp->hi_fore = mr->hi_fore;
+ tmp->hi_back = mr->hi_back;
+ }
+ else
+ {
+ tmp->hi_fore = tmp->back;
+ tmp->hi_back = tmp->fore;
+ }
+ }
+
+ if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors)
+ return;
+
+ start = mr->first;
+ while (TRUE)
+ {
+ for (; start != NULL; start = start->next)
+ {
+ if (start->user_colors)
+ break;
+ }
+ if (start == NULL)
+ break;
+
+ for (end = start->next; end != NULL; end = end->next)
+ {
+ if (end->user_colors)
+ break;
+ }
+ if (end == NULL)
+ break;
+
+ /* we have a start and end to interpolate between */
+ num = end->item_num - start->item_num;
+
+ f1.pixel = start->fore;
+ XQueryColor(dpy, cmap, &f1);
+ f2.pixel = end->fore;
+ XQueryColor(dpy, cmap, &f2);
+
+ b1.pixel = start->back;
+ XQueryColor(dpy, cmap, &b1);
+ b2.pixel = end->back;
+ XQueryColor(dpy, cmap, &b2);
+
+ fred = ((int)f2.red - (int)f1.red) / num;
+ fgreen = ((int)f2.green - (int)f1.green) / num;
+ fblue = ((int)f2.blue - (int)f1.blue) / num;
+
+ bred = ((int)b2.red - (int)b1.red) / num;
+ bgreen = ((int)b2.green - (int)b1.green) / num;
+ bblue = ((int)b2.blue - (int)b1.blue) / num;
+
+ f3 = f1;
+ f3.flags = DoRed | DoGreen | DoBlue;
+
+ b3 = b1;
+ b3.flags = DoRed | DoGreen | DoBlue;
+
+ num -= 1;
+ for (i = 0, cur = start->next; i < num; i++, cur = cur->next)
+ {
+ f3.red += fred;
+ f3.green += fgreen;
+ f3.blue += fblue;
+ save_fore = f3;
+
+ b3.red += bred;
+ b3.green += bgreen;
+ b3.blue += bblue;
+ save_back = b3;
+
+ XAllocColor(dpy, cmap, &f3);
+ XAllocColor(dpy, cmap, &b3);
+ cur->hi_back = cur->fore = f3.pixel;
+ cur->hi_fore = cur->back = b3.pixel;
+ cur->user_colors = True;
+
+ f3 = save_fore;
+ b3 = save_back;
+ }
+ start = end;
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * PopUpMenu - pop up a pull down menu
+ *
+ * Inputs:
+ * menu - the root pointer of the menu to pop up
+ * x, y - location of upper left of menu
+ * center - whether or not to center horizontally over position
+ *
+ ***********************************************************************
+ */
+
+Bool PopUpMenu (menu, x, y, center)
+ MenuRoot *menu;
+ int x, y;
+ Bool center;
+{
+ int WindowNameOffset, WindowNameCount;
+ TwmWindow **WindowNames;
+ TwmWindow *tmp_win2,*tmp_win3;
+ int i;
+ int (*compar)() =
+ (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
+
+ if (!menu) return False;
+
+ InstallRootColormap();
+
+ if (menu == Scr->Windows)
+ {
+ TwmWindow *tmp_win;
+
+ /* this is the twm windows menu, let's go ahead and build it */
+
+ DestroyMenu (menu);
+
+ menu->first = NULL;
+ menu->last = NULL;
+ menu->items = 0;
+ menu->width = 0;
+ menu->mapped = NEVER_MAPPED;
+ AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR);
+
+ WindowNameOffset=(char *)Scr->TwmRoot.next->name -
+ (char *)Scr->TwmRoot.next;
+ for(tmp_win = Scr->TwmRoot.next , WindowNameCount=0;
+ tmp_win != NULL;
+ tmp_win = tmp_win->next)
+ WindowNameCount++;
+ WindowNames =
+ (TwmWindow **)malloc(sizeof(TwmWindow *)*WindowNameCount);
+ WindowNames[0] = Scr->TwmRoot.next;
+ for(tmp_win = Scr->TwmRoot.next->next , WindowNameCount=1;
+ tmp_win != NULL;
+ tmp_win = tmp_win->next,WindowNameCount++)
+ {
+ tmp_win2 = tmp_win;
+ for (i=0;i<WindowNameCount;i++)
+ {
+ if ((*compar)(tmp_win2->name,WindowNames[i]->name) < 0)
+ {
+ tmp_win3 = tmp_win2;
+ tmp_win2 = WindowNames[i];
+ WindowNames[i] = tmp_win3;
+ }
+ }
+ WindowNames[WindowNameCount] = tmp_win2;
+ }
+ for (i=0; i<WindowNameCount; i++)
+ {
+ AddToMenu(menu, WindowNames[i]->name, (char *)WindowNames[i],
+ NULL, F_POPUP,NULL,NULL);
+ }
+ free(WindowNames);
+
+ MakeMenu(menu);
+ }
+
+ if (menu->w == None || menu->items == 0) return False;
+
+ /* Prevent recursively bringing up menus. */
+ if (menu->mapped == MAPPED) return False;
+
+ /*
+ * Dynamically set the parent; this allows pull-ups to also be main
+ * menus, or to be brought up from more than one place.
+ */
+ menu->prev = ActiveMenu;
+
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | PointerMotionHintMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->MenuCursor, CurrentTime);
+
+ ActiveMenu = menu;
+ menu->mapped = MAPPED;
+ menu->entered = FALSE;
+
+ if (center) {
+ x -= (menu->width / 2);
+ y -= (Scr->EntryHeight / 2); /* sticky menus would be nice here */
+ }
+
+ /*
+ * clip to screen
+ */
+ if (x + menu->width > Scr->MyDisplayWidth) {
+ x = Scr->MyDisplayWidth - menu->width;
+ }
+ if (x < 0) x = 0;
+ if (y + menu->height > Scr->MyDisplayHeight) {
+ y = Scr->MyDisplayHeight - menu->height;
+ }
+ if (y < 0) y = 0;
+
+ MenuOrigins[MenuDepth].x = x;
+ MenuOrigins[MenuDepth].y = y;
+ MenuDepth++;
+
+ XMoveWindow(dpy, menu->w, x, y);
+ if (Scr->Shadow) {
+ XMoveWindow (dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH);
+ }
+ if (Scr->Shadow) {
+ XRaiseWindow (dpy, menu->shadow);
+ }
+ XMapRaised(dpy, menu->w);
+ if (Scr->Shadow) {
+ XMapWindow (dpy, menu->shadow);
+ }
+ XSync(dpy, 0);
+ return True;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * PopDownMenu - unhighlight the current menu selection and
+ * take down the menus
+ *
+ ***********************************************************************
+ */
+
+PopDownMenu()
+{
+ MenuRoot *tmp;
+
+ if (ActiveMenu == NULL)
+ return;
+
+ if (ActiveItem)
+ {
+ ActiveItem->state = 0;
+ PaintEntry(ActiveMenu, ActiveItem, False);
+ }
+
+ for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev)
+ {
+ if (Scr->Shadow) {
+ XUnmapWindow (dpy, tmp->shadow);
+ }
+ XUnmapWindow(dpy, tmp->w);
+ tmp->mapped = UNMAPPED;
+ UninstallRootColormap();
+ }
+
+ XFlush(dpy);
+ ActiveMenu = NULL;
+ ActiveItem = NULL;
+ MenuDepth = 0;
+ if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE)
+ menuFromFrameOrWindowOrTitlebar = TRUE;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * FindMenuRoot - look for a menu root
+ *
+ * Returned Value:
+ * (MenuRoot *) - a pointer to the menu root structure
+ *
+ * Inputs:
+ * name - the name of the menu root
+ *
+ ***********************************************************************
+ */
+
+MenuRoot *
+FindMenuRoot(name)
+ char *name;
+{
+ MenuRoot *tmp;
+
+ for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next)
+ {
+ if (strcmp(name, tmp->name) == 0)
+ return (tmp);
+ }
+ return NULL;
+}
+
+
+
+static Bool belongs_to_twm_window (t, w)
+ register TwmWindow *t;
+ register Window w;
+{
+ if (!t) return False;
+
+ if (w == t->frame || w == t->title_w || w == t->hilite_w ||
+ w == t->icon_w || w == t->icon_bm_w) return True;
+
+ if (t && t->titlebuttons) {
+ register TBWindow *tbw;
+ register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
+ for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) {
+ if (tbw->window == w) return True;
+ }
+ }
+ return False;
+}
+
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * resizeFromCenter -
+ *
+ ***********************************************************************
+ */
+
+
+extern int AddingX;
+extern int AddingY;
+extern int AddingW;
+extern int AddingH;
+
+void resizeFromCenter(w, tmp_win)
+ Window w;
+ TwmWindow *tmp_win;
+{
+ int lastx, lasty, width, height, bw2;
+ int namelen;
+ XEvent event;
+
+ namelen = strlen (tmp_win->name);
+ bw2 = tmp_win->frame_bw * 2;
+ AddingW = tmp_win->attr.width + bw2;
+ AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
+ width = (SIZE_HINDENT + XTextWidth (Scr->SizeFont.font,
+ tmp_win->name, namelen));
+ height = Scr->SizeFont.height + SIZE_VINDENT * 2;
+ XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
+ (unsigned int *)&DragWidth, (unsigned int *)&DragHeight,
+ &JunkBW, &JunkDepth);
+ XWarpPointer(dpy, None, w,
+ 0, 0, 0, 0, DragWidth/2, DragHeight/2);
+ XQueryPointer (dpy, Scr->Root, &JunkRoot,
+ &JunkChild, &JunkX, &JunkY,
+ &AddingX, &AddingY, &JunkMask);
+/*****
+ Scr->SizeStringOffset = width +
+ XTextWidth(Scr->SizeFont.font, ": ", 2);
+ XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset +
+ Scr->SizeStringWidth, height);
+ XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC, width,
+ SIZE_VINDENT + Scr->SizeFont.font->ascent,
+ ": ", 2);
+*****/
+ lastx = -10000;
+ lasty = -10000;
+/*****
+ MoveOutline(Scr->Root,
+ origDragX - JunkBW, origDragY - JunkBW,
+ DragWidth * JunkBW, DragHeight * JunkBW,
+ tmp_win->frame_bw,
+ tmp_win->title_height);
+*****/
+ MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight);
+ while (TRUE)
+ {
+ XMaskEvent(dpy,
+ ButtonPressMask | PointerMotionMask, &event);
+
+ if (event.type == MotionNotify) {
+ /* discard any extra motion events before a release */
+ while(XCheckMaskEvent(dpy,
+ ButtonMotionMask | ButtonPressMask, &event))
+ if (event.type == ButtonPress)
+ break;
+ }
+
+ if (event.type == ButtonPress)
+ {
+ MenuEndResize(tmp_win);
+ XMoveResizeWindow(dpy, w, AddingX, AddingY, AddingW, AddingH);
+ break;
+ }
+
+/* if (!DispatchEvent ()) continue; */
+
+ if (event.type != MotionNotify) {
+ continue;
+ }
+
+ /*
+ * XXX - if we are going to do a loop, we ought to consider
+ * using multiple GXxor lines so that we don't need to
+ * grab the server.
+ */
+ XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
+ &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask);
+
+ if (lastx != AddingX || lasty != AddingY)
+ {
+ MenuDoResize(AddingX, AddingY, tmp_win);
+
+ lastx = AddingX;
+ lasty = AddingY;
+ }
+
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * ExecuteFunction - execute a twm root function
+ *
+ * Inputs:
+ * func - the function to execute
+ * action - the menu action to execute
+ * w - the window to execute this function on
+ * tmp_win - the twm window structure
+ * event - the event that caused the function
+ * context - the context in which the button was pressed
+ * pulldown- flag indicating execution from pull down menu
+ *
+ * Returns:
+ * TRUE if should continue with remaining actions else FALSE to abort
+ *
+ ***********************************************************************
+ */
+
+/* for F_WARPTO */
+#define true 1
+#define false 0
+int
+WarpThere(t)
+ TwmWindow* t;
+{
+ if (Scr->WarpUnmapped || t->mapped) {
+ if (!t->mapped) DeIconify (t);
+ if (!Scr->NoRaiseWarp) XRaiseWindow (dpy, t->frame);
+ WarpToWindow (t);
+ return true;
+ }
+ return false;
+}
+
+extern int MovedFromKeyPress;
+
+int
+ExecuteFunction(func, action, w, tmp_win, eventp, context, pulldown)
+ int func;
+ char *action;
+ Window w;
+ TwmWindow *tmp_win;
+ XEvent *eventp;
+ int context;
+ int pulldown;
+{
+ static Time last_time = 0;
+ char tmp[200];
+ char *ptr;
+ char buff[MAX_FILE_SIZE];
+ int count, fd;
+ Window rootw;
+ int origX, origY;
+ int do_next_action = TRUE;
+ int moving_icon = FALSE;
+ Bool fromtitlebar = False;
+ extern int ConstrainedMoveTime;
+
+ RootFunction = 0;
+ if (Cancel)
+ return TRUE; /* XXX should this be FALSE? */
+
+ switch (func)
+ {
+ case F_UPICONMGR:
+ case F_LEFTICONMGR:
+ case F_RIGHTICONMGR:
+ case F_DOWNICONMGR:
+ case F_FORWICONMGR:
+ case F_BACKICONMGR:
+ case F_NEXTICONMGR:
+ case F_PREVICONMGR:
+ case F_NOP:
+ case F_TITLE:
+ case F_DELTASTOP:
+ case F_RAISELOWER:
+ case F_WARPTOSCREEN:
+ case F_WARPTO:
+ case F_WARPRING:
+ case F_WARPTOICONMGR:
+ case F_COLORMAP:
+ break;
+ default:
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->WaitCursor, CurrentTime);
+ break;
+ }
+
+ switch (func)
+ {
+ case F_NOP:
+ case F_TITLE:
+ break;
+
+ case F_DELTASTOP:
+ if (WindowMoved) do_next_action = FALSE;
+ break;
+
+ case F_RESTART:
+ {
+ extern SmcConn smcConn;
+
+ XSync (dpy, 0);
+ Reborder (eventp->xbutton.time);
+ XSync (dpy, 0);
+ if (smcConn)
+ SmcCloseConnection (smcConn, 0, NULL);
+ execvp(*Argv, Argv);
+ fprintf (stderr, "%s: unable to restart: %s\n", ProgramName, *Argv);
+ break;
+ }
+
+ case F_UPICONMGR:
+ case F_DOWNICONMGR:
+ case F_LEFTICONMGR:
+ case F_RIGHTICONMGR:
+ case F_FORWICONMGR:
+ case F_BACKICONMGR:
+ MoveIconManager(func);
+ break;
+
+ case F_NEXTICONMGR:
+ case F_PREVICONMGR:
+ JumpIconManager(func);
+ break;
+
+ case F_SHOWLIST:
+ if (Scr->NoIconManagers)
+ break;
+ DeIconify(Scr->iconmgr.twm_win);
+ XRaiseWindow(dpy, Scr->iconmgr.twm_win->frame);
+ break;
+
+ case F_HIDELIST:
+ if (Scr->NoIconManagers)
+ break;
+ HideIconManager ();
+ break;
+
+ case F_SORTICONMGR:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ {
+ int save_sort;
+
+ save_sort = Scr->SortIconMgr;
+ Scr->SortIconMgr = TRUE;
+
+ if (context == C_ICONMGR)
+ SortIconManager((IconMgr *) NULL);
+ else if (tmp_win->iconmgr)
+ SortIconManager(tmp_win->iconmgrp);
+ else
+ Bell(XkbBI_Info,0,tmp_win->w);
+
+ Scr->SortIconMgr = save_sort;
+ }
+ break;
+
+ case F_IDENTIFY:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ Identify(tmp_win);
+ break;
+
+ case F_VERSION:
+ Identify ((TwmWindow *) NULL);
+ break;
+
+ case F_AUTORAISE:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ tmp_win->auto_raise = !tmp_win->auto_raise;
+ if (tmp_win->auto_raise) ++(Scr->NumAutoRaises);
+ else --(Scr->NumAutoRaises);
+ break;
+
+ case F_BEEP:
+ Bell(XkbBI_Info,0,None);
+ break;
+
+ case F_POPUP:
+ tmp_win = (TwmWindow *)action;
+ if (Scr->WindowFunction.func != 0)
+ {
+ ExecuteFunction(Scr->WindowFunction.func,
+ Scr->WindowFunction.item->action,
+ w, tmp_win, eventp, C_FRAME, FALSE);
+ }
+ else
+ {
+ DeIconify(tmp_win);
+ XRaiseWindow (dpy, tmp_win->frame);
+ }
+ break;
+
+ case F_RESIZE:
+ EventHandler[EnterNotify] = HandleUnknown;
+ EventHandler[LeaveNotify] = HandleUnknown;
+ if (DeferExecution(context, func, Scr->MoveCursor))
+ return TRUE;
+
+ PopDownMenu();
+
+ if (pulldown)
+ XWarpPointer(dpy, None, Scr->Root,
+ 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
+
+ if (w != tmp_win->icon_w) { /* can't resize icons */
+
+ if ((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE)
+ && fromMenu)
+ resizeFromCenter(w, tmp_win);
+ else {
+ /*
+ * see if this is being done from the titlebar
+ */
+ fromtitlebar =
+ belongs_to_twm_window (tmp_win, eventp->xbutton.window);
+
+ /* Save pointer position so we can tell if it was moved or
+ not during the resize. */
+ ResizeOrigX = eventp->xbutton.x_root;
+ ResizeOrigY = eventp->xbutton.y_root;
+
+ StartResize (eventp, tmp_win, fromtitlebar);
+
+ do {
+ XMaskEvent(dpy,
+ ButtonPressMask | ButtonReleaseMask |
+ EnterWindowMask | LeaveWindowMask |
+ ButtonMotionMask, &Event);
+
+ if (fromtitlebar && Event.type == ButtonPress) {
+ fromtitlebar = False;
+ continue;
+ }
+
+ if (Event.type == MotionNotify) {
+ /* discard any extra motion events before a release */
+ while
+ (XCheckMaskEvent
+ (dpy, ButtonMotionMask | ButtonReleaseMask, &Event))
+ if (Event.type == ButtonRelease)
+ break;
+ }
+
+ if (!DispatchEvent ()) continue;
+
+ } while (!(Event.type == ButtonRelease || Cancel));
+ return TRUE;
+ }
+ }
+ break;
+
+
+ case F_ZOOM:
+ case F_HORIZOOM:
+ case F_FULLZOOM:
+ case F_LEFTZOOM:
+ case F_RIGHTZOOM:
+ case F_TOPZOOM:
+ case F_BOTTOMZOOM:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+ fullzoom(tmp_win, func);
+ break;
+
+ case F_MOVE:
+ case F_FORCEMOVE:
+ if (DeferExecution(context, func, Scr->MoveCursor))
+ return TRUE;
+
+ PopDownMenu();
+ rootw = eventp->xbutton.root;
+ MoveFunction = func;
+
+ if (pulldown)
+ XWarpPointer(dpy, None, Scr->Root,
+ 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
+
+ EventHandler[EnterNotify] = HandleUnknown;
+ EventHandler[LeaveNotify] = HandleUnknown;
+
+ if (!Scr->NoGrabServer || !Scr->OpaqueMove) {
+ XGrabServer(dpy);
+ }
+ XGrabPointer(dpy, eventp->xbutton.root, True,
+ ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->MoveCursor, CurrentTime);
+
+ if (context == C_ICON && tmp_win->icon_w)
+ {
+ w = tmp_win->icon_w;
+ DragX = eventp->xbutton.x;
+ DragY = eventp->xbutton.y;
+ moving_icon = TRUE;
+ }
+
+ else if (w != tmp_win->icon_w)
+ {
+ XTranslateCoordinates(dpy, w, tmp_win->frame,
+ eventp->xbutton.x,
+ eventp->xbutton.y,
+ &DragX, &DragY, &JunkChild);
+
+ w = tmp_win->frame;
+ }
+
+ DragWindow = None;
+
+ XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
+ (unsigned int *)&DragWidth, (unsigned int *)&DragHeight, &JunkBW,
+ &JunkDepth);
+
+ origX = eventp->xbutton.x_root;
+ origY = eventp->xbutton.y_root;
+ CurrentDragX = origDragX;
+ CurrentDragY = origDragY;
+
+ /*
+ * only do the constrained move if timer is set; need to check it
+ * in case of stupid or wicked fast servers
+ */
+ if (ConstrainedMoveTime &&
+ (eventp->xbutton.time - last_time) < ConstrainedMoveTime)
+ {
+ int width, height;
+
+ ConstMove = TRUE;
+ ConstMoveDir = MOVE_NONE;
+ ConstMoveX = eventp->xbutton.x_root - DragX - JunkBW;
+ ConstMoveY = eventp->xbutton.y_root - DragY - JunkBW;
+ width = DragWidth + 2 * JunkBW;
+ height = DragHeight + 2 * JunkBW;
+ ConstMoveXL = ConstMoveX + width/3;
+ ConstMoveXR = ConstMoveX + 2*(width/3);
+ ConstMoveYT = ConstMoveY + height/3;
+ ConstMoveYB = ConstMoveY + 2*(height/3);
+
+ XWarpPointer(dpy, None, w,
+ 0, 0, 0, 0, DragWidth/2, DragHeight/2);
+
+ XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
+ &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
+ }
+ last_time = eventp->xbutton.time;
+
+ if (!Scr->OpaqueMove)
+ {
+ InstallRootColormap();
+ if (!Scr->MoveDelta)
+ {
+ /*
+ * Draw initial outline. This was previously done the
+ * first time though the outer loop by dropping out of
+ * the XCheckMaskEvent inner loop down to one of the
+ * MoveOutline's below.
+ */
+ MoveOutline(rootw,
+ origDragX - JunkBW, origDragY - JunkBW,
+ DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW,
+ tmp_win->frame_bw,
+ moving_icon ? 0 : tmp_win->title_height);
+ /*
+ * This next line causes HandleReleaseNotify to call
+ * XRaiseWindow(). This is solely to preserve the
+ * previous behaviour that raises a window being moved
+ * on button release even if you never actually moved
+ * any distance (unless you move less than MoveDelta or
+ * NoRaiseMove is set or OpaqueMove is set).
+ */
+ DragWindow = w;
+ }
+ }
+
+ /*
+ * see if this is being done from the titlebar
+ */
+ fromtitlebar = belongs_to_twm_window (tmp_win, eventp->xbutton.window);
+
+ if (menuFromFrameOrWindowOrTitlebar) {
+ /* warp the pointer to the middle of the window */
+ XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
+ origDragX + DragWidth / 2,
+ origDragY + DragHeight / 2);
+ XFlush(dpy);
+ }
+
+ while (TRUE)
+ {
+ long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
+ ButtonPress : ButtonRelease;
+ long movementMask = menuFromFrameOrWindowOrTitlebar ?
+ PointerMotionMask : ButtonMotionMask;
+
+ /* block until there is an interesting event */
+ XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
+ EnterWindowMask | LeaveWindowMask |
+ ExposureMask | movementMask |
+ VisibilityChangeMask, &Event);
+
+ /* throw away enter and leave events until release */
+ if (Event.xany.type == EnterNotify ||
+ Event.xany.type == LeaveNotify) continue;
+
+ if (Event.type == MotionNotify) {
+ /* discard any extra motion events before a logical release */
+ while(XCheckMaskEvent(dpy,
+ movementMask | releaseEvent, &Event))
+ if (Event.type == releaseEvent)
+ break;
+ }
+
+ /* test to see if we have a second button press to abort move */
+ if (!menuFromFrameOrWindowOrTitlebar && !MovedFromKeyPress) {
+ if (Event.type == ButtonPress && DragWindow != None) {
+ if (Scr->OpaqueMove)
+ XMoveWindow (dpy, DragWindow, origDragX, origDragY);
+ else
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+ DragWindow = None;
+ }
+ }
+ if (fromtitlebar && Event.type == ButtonPress) {
+ fromtitlebar = False;
+ CurrentDragX = origX = Event.xbutton.x_root;
+ CurrentDragY = origY = Event.xbutton.y_root;
+ XTranslateCoordinates (dpy, rootw, tmp_win->frame,
+ origX, origY,
+ &DragX, &DragY, &JunkChild);
+ continue;
+ }
+
+ if (!DispatchEvent2 ()) continue;
+
+ if (Cancel)
+ {
+ WindowMoved = FALSE;
+ if (!Scr->OpaqueMove)
+ UninstallRootColormap();
+ return TRUE; /* XXX should this be FALSE? */
+ }
+ if (Event.type == releaseEvent)
+ {
+ MoveOutline(rootw, 0, 0, 0, 0, 0, 0);
+ if (moving_icon &&
+ ((CurrentDragX != origDragX ||
+ CurrentDragY != origDragY)))
+ tmp_win->icon_moved = TRUE;
+ if (!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar)
+ XMoveWindow(dpy, DragWindow,
+ Event.xbutton.x_root - DragWidth / 2,
+ Event.xbutton.y_root - DragHeight / 2);
+ break;
+ }
+
+ /* something left to do only if the pointer moved */
+ if (Event.type != MotionNotify)
+ continue;
+
+ XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
+ &(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
+ &JunkX, &JunkY, &JunkMask);
+
+ if (DragWindow == None &&
+ abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
+ abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta)
+ continue;
+
+ WindowMoved = TRUE;
+ DragWindow = w;
+
+ if (!Scr->NoRaiseMove && Scr->OpaqueMove) /* can't restore... */
+ XRaiseWindow(dpy, DragWindow);
+
+ if (ConstMove)
+ {
+ switch (ConstMoveDir)
+ {
+ case MOVE_NONE:
+ if (eventp->xmotion.x_root < ConstMoveXL ||
+ eventp->xmotion.x_root > ConstMoveXR)
+ ConstMoveDir = MOVE_HORIZ;
+
+ if (eventp->xmotion.y_root < ConstMoveYT ||
+ eventp->xmotion.y_root > ConstMoveYB)
+ ConstMoveDir = MOVE_VERT;
+
+ XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild,
+ &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
+ break;
+
+ case MOVE_VERT:
+ ConstMoveY = eventp->xmotion.y_root - DragY - JunkBW;
+ break;
+
+ case MOVE_HORIZ:
+ ConstMoveX= eventp->xmotion.x_root - DragX - JunkBW;
+ break;
+ }
+
+ if (ConstMoveDir != MOVE_NONE)
+ {
+ int xl, yt, xr, yb, w, h;
+
+ xl = ConstMoveX;
+ yt = ConstMoveY;
+ w = DragWidth + 2 * JunkBW;
+ h = DragHeight + 2 * JunkBW;
+
+ if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
+ {
+ xr = xl + w;
+ yb = yt + h;
+
+ if (xl < 0)
+ xl = 0;
+ if (xr > Scr->MyDisplayWidth)
+ xl = Scr->MyDisplayWidth - w;
+
+ if (yt < 0)
+ yt = 0;
+ if (yb > Scr->MyDisplayHeight)
+ yt = Scr->MyDisplayHeight - h;
+ }
+ CurrentDragX = xl;
+ CurrentDragY = yt;
+ if (Scr->OpaqueMove)
+ XMoveWindow(dpy, DragWindow, xl, yt);
+ else
+ MoveOutline(eventp->xmotion.root, xl, yt, w, h,
+ tmp_win->frame_bw,
+ moving_icon ? 0 : tmp_win->title_height);
+ }
+ }
+ else if (DragWindow != None)
+ {
+ int xl, yt, xr, yb, w, h;
+ if (!menuFromFrameOrWindowOrTitlebar) {
+ xl = eventp->xmotion.x_root - DragX - JunkBW;
+ yt = eventp->xmotion.y_root - DragY - JunkBW;
+ }
+ else {
+ xl = eventp->xmotion.x_root - (DragWidth / 2);
+ yt = eventp->xmotion.y_root - (DragHeight / 2);
+ }
+ w = DragWidth + 2 * JunkBW;
+ h = DragHeight + 2 * JunkBW;
+
+ if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
+ {
+ xr = xl + w;
+ yb = yt + h;
+
+ if (xl < 0)
+ xl = 0;
+ if (xr > Scr->MyDisplayWidth)
+ xl = Scr->MyDisplayWidth - w;
+
+ if (yt < 0)
+ yt = 0;
+ if (yb > Scr->MyDisplayHeight)
+ yt = Scr->MyDisplayHeight - h;
+ }
+
+ CurrentDragX = xl;
+ CurrentDragY = yt;
+ if (Scr->OpaqueMove)
+ XMoveWindow(dpy, DragWindow, xl, yt);
+ else
+ MoveOutline(eventp->xmotion.root, xl, yt, w, h,
+ tmp_win->frame_bw,
+ moving_icon ? 0 : tmp_win->title_height);
+ }
+
+ }
+ MovedFromKeyPress = False;
+
+
+ if (!Scr->OpaqueMove && DragWindow == None)
+ UninstallRootColormap();
+
+ break;
+
+ case F_FUNCTION:
+ {
+ MenuRoot *mroot;
+ MenuItem *mitem;
+
+ if ((mroot = FindMenuRoot(action)) == NULL)
+ {
+ fprintf (stderr, "%s: couldn't find function \"%s\"\n",
+ ProgramName, action);
+ return TRUE;
+ }
+
+ if (NeedToDefer(mroot) && DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+ else
+ {
+ for (mitem = mroot->first; mitem != NULL; mitem = mitem->next)
+ {
+ if (!ExecuteFunction (mitem->func, mitem->action, w,
+ tmp_win, eventp, context, pulldown))
+ break;
+ }
+ }
+ }
+ break;
+
+ case F_DEICONIFY:
+ case F_ICONIFY:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (tmp_win->icon)
+ {
+ DeIconify(tmp_win);
+ }
+ else if (func == F_ICONIFY)
+ {
+ Iconify (tmp_win, eventp->xbutton.x_root - 5,
+ eventp->xbutton.y_root - 5);
+ }
+ break;
+
+ case F_RAISELOWER:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (!WindowMoved) {
+ XWindowChanges xwc;
+
+ xwc.stack_mode = Opposite;
+ if (w != tmp_win->icon_w)
+ w = tmp_win->frame;
+ XConfigureWindow (dpy, w, CWStackMode, &xwc);
+ }
+ break;
+
+ case F_RAISE:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ /* check to make sure raise is not from the WindowFunction */
+ if (w == tmp_win->icon_w && Context != C_ROOT)
+ XRaiseWindow(dpy, tmp_win->icon_w);
+ else
+ XRaiseWindow(dpy, tmp_win->frame);
+
+ break;
+
+ case F_LOWER:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (w == tmp_win->icon_w)
+ XLowerWindow(dpy, tmp_win->icon_w);
+ else
+ XLowerWindow(dpy, tmp_win->frame);
+
+ break;
+
+ case F_FOCUS:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (tmp_win->icon == FALSE)
+ {
+ if (!Scr->FocusRoot && Scr->Focus == tmp_win)
+ {
+ FocusOnRoot();
+ }
+ else
+ {
+ if (Scr->Focus != NULL) {
+ SetBorder (Scr->Focus, False);
+ if (Scr->Focus->hilite_w)
+ XUnmapWindow (dpy, Scr->Focus->hilite_w);
+ }
+
+ InstallWindowColormaps (0, tmp_win);
+ if (tmp_win->hilite_w) XMapWindow (dpy, tmp_win->hilite_w);
+ SetBorder (tmp_win, True);
+ SetFocus (tmp_win, eventp->xbutton.time);
+ Scr->FocusRoot = FALSE;
+ Scr->Focus = tmp_win;
+ }
+ }
+ break;
+
+ case F_DESTROY:
+ if (DeferExecution(context, func, Scr->DestroyCursor))
+ return TRUE;
+
+ if (tmp_win->iconmgr)
+ Bell(XkbBI_MinorError,0,tmp_win->w);
+ else
+ XKillClient(dpy, tmp_win->w);
+ break;
+
+ case F_DELETE:
+ if (DeferExecution(context, func, Scr->DestroyCursor))
+ return TRUE;
+
+ if (tmp_win->iconmgr) /* don't send ourself a message */
+ HideIconManager ();
+ else if (tmp_win->protocols & DoesWmDeleteWindow)
+ SendDeleteWindowMessage (tmp_win, LastTimestamp());
+ else
+ Bell(XkbBI_MinorError,0,tmp_win->w);
+ break;
+
+ case F_SAVEYOURSELF:
+ if (DeferExecution (context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (tmp_win->protocols & DoesWmSaveYourself)
+ SendSaveYourselfMessage (tmp_win, LastTimestamp());
+ else
+ Bell(XkbBI_MinorError,0,tmp_win->w);
+ break;
+
+ case F_CIRCLEUP:
+ XCirculateSubwindowsUp(dpy, Scr->Root);
+ break;
+
+ case F_CIRCLEDOWN:
+ XCirculateSubwindowsDown(dpy, Scr->Root);
+ break;
+
+ case F_EXEC:
+ PopDownMenu();
+ if (!Scr->NoGrabServer) {
+ XUngrabServer (dpy);
+ XSync (dpy, 0);
+ }
+ Execute(action);
+ break;
+
+ case F_UNFOCUS:
+ FocusOnRoot();
+ break;
+
+ case F_CUT:
+ strcpy(tmp, action);
+ strcat(tmp, "\n");
+ XStoreBytes(dpy, tmp, strlen(tmp));
+ break;
+
+ case F_CUTFILE:
+ ptr = XFetchBytes(dpy, &count);
+ if (ptr) {
+ if (sscanf (ptr, "%s", tmp) == 1) {
+ XFree (ptr);
+ ptr = ExpandFilename(tmp);
+ if (ptr) {
+ fd = open (ptr, 0);
+ if (fd >= 0) {
+ count = read (fd, buff, MAX_FILE_SIZE - 1);
+ if (count > 0) XStoreBytes (dpy, buff, count);
+ close(fd);
+ } else {
+ fprintf (stderr,
+ "%s: unable to open cut file \"%s\"\n",
+ ProgramName, tmp);
+ }
+ if (ptr != tmp) free (ptr);
+ }
+ } else {
+ XFree(ptr);
+ }
+ } else {
+ fprintf(stderr, "%s: cut buffer is empty\n", ProgramName);
+ }
+ break;
+
+ case F_WARPTOSCREEN:
+ {
+ if (strcmp (action, WARPSCREEN_NEXT) == 0) {
+ WarpToScreen (Scr->screen + 1, 1);
+ } else if (strcmp (action, WARPSCREEN_PREV) == 0) {
+ WarpToScreen (Scr->screen - 1, -1);
+ } else if (strcmp (action, WARPSCREEN_BACK) == 0) {
+ WarpToScreen (PreviousScreen, 0);
+ } else {
+ WarpToScreen (atoi (action), 0);
+ }
+ }
+ break;
+
+ case F_COLORMAP:
+ {
+ if (strcmp (action, COLORMAP_NEXT) == 0) {
+ BumpWindowColormap (tmp_win, 1);
+ } else if (strcmp (action, COLORMAP_PREV) == 0) {
+ BumpWindowColormap (tmp_win, -1);
+ } else {
+ BumpWindowColormap (tmp_win, 0);
+ }
+ }
+ break;
+
+ case F_WARPTO:
+ {
+ register TwmWindow *t;
+ int len;
+
+ len = strlen(action);
+
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
+ if (!strncmp(action, t->name, len))
+ if (WarpThere(t)) break;
+ }
+ if (!t) {
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
+ if (!strncmp(action, t->class.res_name, len))
+ if (WarpThere(t)) break;
+ }
+ if (!t) {
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
+ if (!strncmp(action, t->class.res_class, len))
+ if (WarpThere(t)) break;
+ }
+ }
+ }
+
+ if (!t)
+ Bell(XkbBI_MinorError,0,None);
+ }
+ break;
+
+ case F_WARPTOICONMGR:
+ {
+ TwmWindow *t;
+ int len;
+ Window raisewin = None, iconwin = None;
+
+ len = strlen(action);
+ if (len == 0) {
+ if (tmp_win && tmp_win->list) {
+ raisewin = tmp_win->list->iconmgr->twm_win->frame;
+ iconwin = tmp_win->list->icon;
+ } else if (Scr->iconmgr.active) {
+ raisewin = Scr->iconmgr.twm_win->frame;
+ iconwin = Scr->iconmgr.active->w;
+ }
+ } else {
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next) {
+ if (strncmp (action, t->icon_name, len) == 0) {
+ if (t->list && t->list->iconmgr->twm_win->mapped) {
+ raisewin = t->list->iconmgr->twm_win->frame;
+ iconwin = t->list->icon;
+ break;
+ }
+ }
+ }
+ }
+
+ if (raisewin) {
+ XRaiseWindow (dpy, raisewin);
+ XWarpPointer (dpy, None, iconwin, 0,0,0,0, 5, 5);
+ } else {
+ Bell(XkbBI_MinorError,0,None);
+ }
+ }
+ break;
+
+ case F_WARPRING:
+ switch (action[0]) {
+ case 'n':
+ WarpAlongRing (&eventp->xbutton, True);
+ break;
+ case 'p':
+ WarpAlongRing (&eventp->xbutton, False);
+ break;
+ default:
+ Bell(XkbBI_MinorError,0,None);
+ break;
+ }
+ break;
+
+ case F_FILE:
+ action = ExpandFilename(action);
+ fd = open(action, 0);
+ if (fd >= 0)
+ {
+ count = read(fd, buff, MAX_FILE_SIZE - 1);
+ if (count > 0)
+ XStoreBytes(dpy, buff, count);
+
+ close(fd);
+ }
+ else
+ {
+ fprintf (stderr, "%s: unable to open file \"%s\"\n",
+ ProgramName, action);
+ }
+ break;
+
+ case F_REFRESH:
+ {
+ XSetWindowAttributes attributes;
+ unsigned long valuemask;
+
+ valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder);
+ attributes.background_pixel = Scr->Black;
+ attributes.backing_store = NotUseful;
+ attributes.save_under = False;
+ w = XCreateWindow (dpy, Scr->Root, 0, 0,
+ (unsigned int) Scr->MyDisplayWidth,
+ (unsigned int) Scr->MyDisplayHeight,
+ (unsigned int) 0,
+ CopyFromParent, (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent, valuemask,
+ &attributes);
+ XMapWindow (dpy, w);
+ XDestroyWindow (dpy, w);
+ XFlush (dpy);
+ }
+ break;
+
+ case F_WINREFRESH:
+ if (DeferExecution(context, func, Scr->SelectCursor))
+ return TRUE;
+
+ if (context == C_ICON && tmp_win->icon_w)
+ w = XCreateSimpleWindow(dpy, tmp_win->icon_w,
+ 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
+ else
+ w = XCreateSimpleWindow(dpy, tmp_win->frame,
+ 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
+
+ XMapWindow(dpy, w);
+ XDestroyWindow(dpy, w);
+ XFlush(dpy);
+ break;
+
+ case F_QUIT:
+ Done();
+ break;
+
+ case F_PRIORITY:
+ if (HasSync)
+ {
+ if (DeferExecution (context, func, Scr->SelectCursor))
+ return TRUE;
+ (void)XSyncSetPriority(dpy, tmp_win->w, atoi(action));
+ }
+ break;
+ }
+
+ if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime);
+ return do_next_action;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * DeferExecution - defer the execution of a function to the
+ * next button press if the context is C_ROOT
+ *
+ * Inputs:
+ * context - the context in which the mouse button was pressed
+ * func - the function to defer
+ * cursor - the cursor to display while waiting
+ *
+ ***********************************************************************
+ */
+
+int
+DeferExecution(context, func, cursor)
+int context, func;
+Cursor cursor;
+{
+ if (context == C_ROOT)
+ {
+ LastCursor = cursor;
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, cursor, CurrentTime);
+
+ RootFunction = func;
+
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * ReGrab - regrab the pointer with the LastCursor;
+ *
+ ***********************************************************************
+ */
+
+ReGrab()
+{
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, LastCursor, CurrentTime);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * NeedToDefer - checks each function in the list to see if it
+ * is one that needs to be defered.
+ *
+ * Inputs:
+ * root - the menu root to check
+ *
+ ***********************************************************************
+ */
+
+NeedToDefer(root)
+MenuRoot *root;
+{
+ MenuItem *mitem;
+
+ for (mitem = root->first; mitem != NULL; mitem = mitem->next)
+ {
+ switch (mitem->func)
+ {
+ case F_IDENTIFY:
+ case F_RESIZE:
+ case F_MOVE:
+ case F_FORCEMOVE:
+ case F_DEICONIFY:
+ case F_ICONIFY:
+ case F_RAISELOWER:
+ case F_RAISE:
+ case F_LOWER:
+ case F_FOCUS:
+ case F_DESTROY:
+ case F_WINREFRESH:
+ case F_ZOOM:
+ case F_FULLZOOM:
+ case F_HORIZOOM:
+ case F_RIGHTZOOM:
+ case F_LEFTZOOM:
+ case F_TOPZOOM:
+ case F_BOTTOMZOOM:
+ case F_AUTORAISE:
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * Execute - execute the string by /bin/sh
+ *
+ * Inputs:
+ * s - the string containing the command
+ *
+ ***********************************************************************
+ */
+
+#if defined(sun) && defined(SVR4)
+static int System (s)
+ char *s;
+{
+ int pid, status;
+ if ((pid = fork ()) == 0) {
+ (void) setpgrp();
+ execl ("/bin/sh", "sh", "-c", s, 0);
+ } else
+ waitpid (pid, &status, 0);
+ return status;
+}
+#define system(s) System(s)
+#endif
+
+void
+Execute(s)
+ char *s;
+{
+ static char buf[256];
+ char *ds = DisplayString (dpy);
+ char *colon, *dot1;
+ char oldDisplay[256];
+ char *doisplay;
+ int restorevar = 0;
+
+ oldDisplay[0] = '\0';
+ doisplay=getenv("DISPLAY");
+ if (doisplay)
+ strcpy (oldDisplay, doisplay);
+
+ /*
+ * Build a display string using the current screen number, so that
+ * X programs which get fired up from a menu come up on the screen
+ * that they were invoked from, unless specifically overridden on
+ * their command line.
+ */
+ colon = strrchr (ds, ':');
+ if (colon) { /* if host[:]:dpy */
+ strcpy (buf, "DISPLAY=");
+ strcat (buf, ds);
+ colon = buf + 8 + (colon - ds); /* use version in buf */
+ dot1 = strchr (colon, '.'); /* first period after colon */
+ if (!dot1) dot1 = colon + strlen (colon); /* if not there, append */
+ (void) sprintf (dot1, ".%d", Scr->screen);
+ putenv (buf);
+ restorevar = 1;
+ }
+
+ (void) system (s);
+
+ if (restorevar) { /* why bother? */
+ (void) sprintf (buf, "DISPLAY=%s", oldDisplay);
+ putenv (buf);
+ }
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * FocusOnRoot - put input focus on the root window
+ *
+ ***********************************************************************
+ */
+
+void
+FocusOnRoot()
+{
+ SetFocus ((TwmWindow *) NULL, LastTimestamp());
+ if (Scr->Focus != NULL)
+ {
+ SetBorder (Scr->Focus, False);
+ if (Scr->Focus->hilite_w) XUnmapWindow (dpy, Scr->Focus->hilite_w);
+ }
+ InstallWindowColormaps(0, &Scr->TwmRoot);
+ Scr->Focus = NULL;
+ Scr->FocusRoot = TRUE;
+}
+
+DeIconify(tmp_win)
+TwmWindow *tmp_win;
+{
+ TwmWindow *t;
+
+ /* de-iconify the main window */
+ if (tmp_win->icon)
+ {
+ if (tmp_win->icon_on)
+ Zoom(tmp_win->icon_w, tmp_win->frame);
+ else if (tmp_win->group != (Window) 0)
+ {
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
+ {
+ if (tmp_win->group == t->w && t->icon_on)
+ {
+ Zoom(t->icon_w, tmp_win->frame);
+ break;
+ }
+ }
+ }
+ }
+
+ XMapWindow(dpy, tmp_win->w);
+ tmp_win->mapped = TRUE;
+ if (Scr->NoRaiseDeicon)
+ XMapWindow(dpy, tmp_win->frame);
+ else
+ XMapRaised(dpy, tmp_win->frame);
+ SetMapStateProp(tmp_win, NormalState);
+
+ if (tmp_win->icon_w) {
+ XUnmapWindow(dpy, tmp_win->icon_w);
+ IconDown (tmp_win);
+ }
+ if (tmp_win->list)
+ XUnmapWindow(dpy, tmp_win->list->icon);
+ if ((Scr->WarpCursor ||
+ LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class)) &&
+ tmp_win->icon)
+ WarpToWindow (tmp_win);
+ tmp_win->icon = FALSE;
+ tmp_win->icon_on = FALSE;
+
+
+ /* now de-iconify transients */
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
+ {
+ if (t->transient && t->transientfor == tmp_win->w)
+ {
+ if (t->icon_on)
+ Zoom(t->icon_w, t->frame);
+ else
+ Zoom(tmp_win->icon_w, t->frame);
+
+ XMapWindow(dpy, t->w);
+ t->mapped = TRUE;
+ if (Scr->NoRaiseDeicon)
+ XMapWindow(dpy, t->frame);
+ else
+ XMapRaised(dpy, t->frame);
+ SetMapStateProp(t, NormalState);
+
+ if (t->icon_w) {
+ XUnmapWindow(dpy, t->icon_w);
+ IconDown (t);
+ }
+ if (t->list) XUnmapWindow(dpy, t->list->icon);
+ t->icon = FALSE;
+ t->icon_on = FALSE;
+ }
+ }
+
+ XSync (dpy, 0);
+}
+
+
+
+Iconify(tmp_win, def_x, def_y)
+TwmWindow *tmp_win;
+int def_x, def_y;
+{
+ TwmWindow *t;
+ int iconify;
+ XWindowAttributes winattrs;
+ unsigned long eventMask;
+
+ iconify = ((!tmp_win->iconify_by_unmapping) || tmp_win->transient);
+ if (iconify)
+ {
+ if (tmp_win->icon_w == (Window) 0)
+ CreateIconWindow(tmp_win, def_x, def_y);
+ else
+ IconUp(tmp_win);
+ XMapRaised(dpy, tmp_win->icon_w);
+ }
+ if (tmp_win->list)
+ XMapWindow(dpy, tmp_win->list->icon);
+
+ XGetWindowAttributes(dpy, tmp_win->w, &winattrs);
+ eventMask = winattrs.your_event_mask;
+
+ /* iconify transients first */
+ for (t = Scr->TwmRoot.next; t != NULL; t = t->next)
+ {
+ if (t->transient && t->transientfor == tmp_win->w)
+ {
+ if (iconify)
+ {
+ if (t->icon_on)
+ Zoom(t->icon_w, tmp_win->icon_w);
+ else
+ Zoom(t->frame, tmp_win->icon_w);
+ }
+
+ /*
+ * Prevent the receipt of an UnmapNotify, since that would
+ * cause a transition to the Withdrawn state.
+ */
+ t->mapped = FALSE;
+ XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask);
+ XUnmapWindow(dpy, t->w);
+ XSelectInput(dpy, t->w, eventMask);
+ XUnmapWindow(dpy, t->frame);
+ if (t->icon_w)
+ XUnmapWindow(dpy, t->icon_w);
+ SetMapStateProp(t, IconicState);
+ SetBorder (t, False);
+ if (t == Scr->Focus)
+ {
+ SetFocus ((TwmWindow *) NULL, LastTimestamp());
+ Scr->Focus = NULL;
+ Scr->FocusRoot = TRUE;
+ }
+ if (t->list) XMapWindow(dpy, t->list->icon);
+ t->icon = TRUE;
+ t->icon_on = FALSE;
+ }
+ }
+
+ if (iconify)
+ Zoom(tmp_win->frame, tmp_win->icon_w);
+
+ /*
+ * Prevent the receipt of an UnmapNotify, since that would
+ * cause a transition to the Withdrawn state.
+ */
+ tmp_win->mapped = FALSE;
+ XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask);
+ XUnmapWindow(dpy, tmp_win->w);
+ XSelectInput(dpy, tmp_win->w, eventMask);
+ XUnmapWindow(dpy, tmp_win->frame);
+ SetMapStateProp(tmp_win, IconicState);
+
+ SetBorder (tmp_win, False);
+ if (tmp_win == Scr->Focus)
+ {
+ SetFocus ((TwmWindow *) NULL, LastTimestamp());
+ Scr->Focus = NULL;
+ Scr->FocusRoot = TRUE;
+ }
+ tmp_win->icon = TRUE;
+ if (iconify)
+ tmp_win->icon_on = TRUE;
+ else
+ tmp_win->icon_on = FALSE;
+ XSync (dpy, 0);
+}
+
+
+
+static void Identify (t)
+TwmWindow *t;
+{
+ int i, n, twidth, width, height;
+ int x, y;
+ unsigned int wwidth, wheight, bw, depth;
+ Window junk;
+ int px, py, dummy;
+ unsigned udummy;
+
+ n = 0;
+ (void) sprintf(Info[n++], "Twm version: %s", Version);
+ Info[n++][0] = '\0';
+
+ if (t) {
+ XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY,
+ &wwidth, &wheight, &bw, &depth);
+ (void) XTranslateCoordinates (dpy, t->w, Scr->Root, 0, 0,
+ &x, &y, &junk);
+ (void) sprintf(Info[n++], "Name = \"%s\"", t->full_name);
+ (void) sprintf(Info[n++], "Class.res_name = \"%s\"", t->class.res_name);
+ (void) sprintf(Info[n++], "Class.res_class = \"%s\"", t->class.res_class);
+ Info[n++][0] = '\0';
+ (void) sprintf(Info[n++], "Geometry/root = %dx%d+%d+%d", wwidth, wheight,
+ x, y);
+ (void) sprintf(Info[n++], "Border width = %d", bw);
+ (void) sprintf(Info[n++], "Depth = %d", depth);
+ if (HasSync)
+ {
+ int priority;
+ (void)XSyncGetPriority(dpy, t->w, &priority);
+ (void) sprintf(Info[n++], "Priority = %d", priority);
+ }
+ }
+
+ Info[n++][0] = '\0';
+ (void) sprintf(Info[n++], "Click to dismiss....");
+
+ /* figure out the width and height of the info window */
+ height = n * (Scr->DefaultFont.height+2);
+ width = 1;
+ for (i = 0; i < n; i++)
+ {
+ twidth = XTextWidth(Scr->DefaultFont.font, Info[i],
+ strlen(Info[i]));
+ if (twidth > width)
+ width = twidth;
+ }
+ if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
+
+ width += 10; /* some padding */
+ if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &px, &py,
+ &dummy, &dummy, &udummy)) {
+ px -= (width / 2);
+ py -= (height / 3);
+ if (px + width + BW2 >= Scr->MyDisplayWidth)
+ px = Scr->MyDisplayWidth - width - BW2;
+ if (py + height + BW2 >= Scr->MyDisplayHeight)
+ py = Scr->MyDisplayHeight - height - BW2;
+ if (px < 0) px = 0;
+ if (py < 0) py = 0;
+ } else {
+ px = py = 0;
+ }
+ XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height);
+ XMapRaised(dpy, Scr->InfoWindow);
+ InfoLines = n;
+}
+
+
+
+SetMapStateProp(tmp_win, state)
+TwmWindow *tmp_win;
+int state;
+{
+ unsigned long data[2]; /* "suggested" by ICCCM version 1 */
+
+ data[0] = (unsigned long) state;
+ data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None :
+ tmp_win->icon_w);
+
+ XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32,
+ PropModeReplace, (unsigned char *) data, 2);
+}
+
+
+
+Bool GetWMState (w, statep, iwp)
+ Window w;
+ int *statep;
+ Window *iwp;
+{
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytesafter;
+ unsigned long *datap = NULL;
+ Bool retval = False;
+
+ if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE,
+ &actual_type, &actual_format, &nitems, &bytesafter,
+ (unsigned char **) &datap) != Success || !datap)
+ return False;
+
+ if (nitems <= 2) { /* "suggested" by ICCCM version 1 */
+ *statep = (int) datap[0];
+ *iwp = (Window) datap[1];
+ retval = True;
+ }
+
+ XFree ((char *) datap);
+ return retval;
+}
+
+
+
+WarpToScreen (n, inc)
+ int n, inc;
+{
+ Window dumwin;
+ int x, y, dumint;
+ unsigned int dummask;
+ ScreenInfo *newscr = NULL;
+
+ while (!newscr) {
+ /* wrap around */
+ if (n < 0)
+ n = NumScreens - 1;
+ else if (n >= NumScreens)
+ n = 0;
+
+ newscr = ScreenList[n];
+ if (!newscr) { /* make sure screen is managed */
+ if (inc) { /* walk around the list */
+ n += inc;
+ continue;
+ }
+ fprintf (stderr, "%s: unable to warp to unmanaged screen %d\n",
+ ProgramName, n);
+ Bell(XkbBI_MinorError,0,None);
+ return;
+ }
+ }
+
+ if (Scr->screen == n) return; /* already on that screen */
+
+ PreviousScreen = Scr->screen;
+ XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
+ &dumint, &dumint, &dummask);
+
+ XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
+ return;
+}
+
+
+
+
+/*
+ * BumpWindowColormap - rotate our internal copy of WM_COLORMAP_WINDOWS
+ */
+
+BumpWindowColormap (tmp, inc)
+ TwmWindow *tmp;
+ int inc;
+{
+ int i, j, previously_installed;
+ ColormapWindow **cwins;
+
+ if (!tmp) return;
+
+ if (inc && tmp->cmaps.number_cwins > 0) {
+ cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)*
+ tmp->cmaps.number_cwins);
+ if (cwins) {
+ if ((previously_installed =
+ /* SUPPRESS 560 */(Scr->cmapInfo.cmaps == &tmp->cmaps &&
+ tmp->cmaps.number_cwins))) {
+ for (i = tmp->cmaps.number_cwins; i-- > 0; )
+ tmp->cmaps.cwins[i]->colormap->state = 0;
+ }
+
+ for (i = 0; i < tmp->cmaps.number_cwins; i++) {
+ j = i - inc;
+ if (j >= tmp->cmaps.number_cwins)
+ j -= tmp->cmaps.number_cwins;
+ else if (j < 0)
+ j += tmp->cmaps.number_cwins;
+ cwins[j] = tmp->cmaps.cwins[i];
+ }
+
+ free((char *) tmp->cmaps.cwins);
+
+ tmp->cmaps.cwins = cwins;
+
+ if (tmp->cmaps.number_cwins > 1)
+ bzero (tmp->cmaps.scoreboard,
+ ColormapsScoreboardLength(&tmp->cmaps));
+
+ if (previously_installed)
+ InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
+ }
+ } else
+ FetchWmColormapWindows (tmp);
+}
+
+
+
+HideIconManager ()
+{
+ SetMapStateProp (Scr->iconmgr.twm_win, WithdrawnState);
+ XUnmapWindow(dpy, Scr->iconmgr.twm_win->frame);
+ if (Scr->iconmgr.twm_win->icon_w)
+ XUnmapWindow (dpy, Scr->iconmgr.twm_win->icon_w);
+ Scr->iconmgr.twm_win->mapped = FALSE;
+ Scr->iconmgr.twm_win->icon = TRUE;
+}
+
+
+
+
+SetBorder (tmp, onoroff)
+ TwmWindow *tmp;
+ Bool onoroff;
+{
+ if (tmp->highlight) {
+ if (onoroff) {
+ XSetWindowBorder (dpy, tmp->frame, tmp->border);
+ if (tmp->title_w)
+ XSetWindowBorder (dpy, tmp->title_w, tmp->border);
+ } else {
+ XSetWindowBorderPixmap (dpy, tmp->frame, tmp->gray);
+ if (tmp->title_w)
+ XSetWindowBorderPixmap (dpy, tmp->title_w, tmp->gray);
+ }
+ }
+}
+
+
+
+DestroyMenu (menu)
+ MenuRoot *menu;
+{
+ MenuItem *item;
+
+ if (menu->w) {
+ XDeleteContext (dpy, menu->w, MenuContext);
+ XDeleteContext (dpy, menu->w, ScreenContext);
+ if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow);
+ XDestroyWindow(dpy, menu->w);
+ }
+
+ for (item = menu->first; item; ) {
+ MenuItem *tmp = item;
+ item = item->next;
+ free ((char *) tmp);
+ }
+}
+
+
+
+/*
+ * warping routines
+ */
+void WarpAlongRing (ev, forward)
+ XButtonEvent *ev;
+ Bool forward;
+{
+ TwmWindow *r, *head;
+
+ if (Scr->RingLeader)
+ head = Scr->RingLeader;
+ else if (!(head = Scr->Ring))
+ return;
+
+ if (forward) {
+ for (r = head->ring.next; r != head; r = r->ring.next) {
+ if (!r || r->mapped) break;
+ }
+ } else {
+ for (r = head->ring.prev; r != head; r = r->ring.prev) {
+ if (!r || r->mapped) break;
+ }
+ }
+
+ if (r && r != head) {
+ TwmWindow *p = Scr->RingLeader, *t;
+
+ Scr->RingLeader = r;
+ WarpToWindow (r);
+
+ if (p && p->mapped &&
+ XFindContext (dpy, ev->window, TwmContext, (caddr_t *)&t) == XCSUCCESS &&
+ p == t) {
+ 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;
+ 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;
+ }
+ }
+ }
+}
+
+
+
+void WarpToWindow (t)
+ TwmWindow *t;
+{
+ int x, y;
+
+ if (t->auto_raise || !Scr->NoRaiseWarp) AutoRaiseWindow (t);
+ if (t->ring.cursor_valid) {
+ x = t->ring.curs_x;
+ y = t->ring.curs_y;
+ } else {
+ x = t->frame_width / 2;
+ y = t->frame_height / 2;
+ }
+ XWarpPointer (dpy, None, t->frame, 0, 0, 0, 0, x, y);
+}
+
+
+
+
+/*
+ * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
+ * client messages will have the following form:
+ *
+ * event type ClientMessage
+ * message type _XA_WM_PROTOCOLS
+ * window tmp->w
+ * format 32
+ * data[0] message atom
+ * data[1] time stamp
+ */
+static void send_clientmessage (w, a, timestamp)
+ Window w;
+ Atom a;
+ Time timestamp;
+{
+ XClientMessageEvent ev;
+
+ ev.type = ClientMessage;
+ ev.window = w;
+ ev.message_type = _XA_WM_PROTOCOLS;
+ ev.format = 32;
+ ev.data.l[0] = a;
+ ev.data.l[1] = timestamp;
+ XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
+}
+
+SendDeleteWindowMessage (tmp, timestamp)
+ TwmWindow *tmp;
+ Time timestamp;
+{
+ send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp);
+}
+
+SendSaveYourselfMessage (tmp, timestamp)
+ TwmWindow *tmp;
+ Time timestamp;
+{
+ send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp);
+}
+
+
+SendTakeFocusMessage (tmp, timestamp)
+ TwmWindow *tmp;
+ Time timestamp;
+{
+ send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp);
+}
diff --git a/src/menus.h b/src/menus.h
new file mode 100644
index 0000000..f7729f9
--- /dev/null
+++ b/src/menus.h
@@ -0,0 +1,178 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989,1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/***********************************************************************
+ *
+ * $Xorg: menus.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * twm menus include file
+ *
+ * 17-Nov-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#ifndef _MENUS_
+#define _MENUS_
+
+#define TWM_ROOT "bLoB_GoOp" /* my private root menu */
+#define TWM_WINDOWS "TwmWindows" /* for f.menu "TwmWindows" */
+
+#define MAX_FILE_SIZE 4096 /* max chars to read from file for cut */
+
+typedef struct MenuItem
+{
+ struct MenuItem *next; /* next menu item */
+ struct MenuItem *prev; /* prev menu item */
+ struct MenuRoot *sub; /* MenuRoot of a pull right menu */
+ struct MenuRoot *root; /* back pointer to my MenuRoot */
+ char *item; /* the character string displayed */
+ char *action; /* action to be performed */
+ Pixel fore; /* foreground color */
+ Pixel back; /* background color */
+ Pixel hi_fore; /* highlight foreground */
+ Pixel hi_back; /* highlight background */
+ short item_num; /* item number of this menu */
+ short x; /* x coordinate for text */
+ short func; /* twm built in function */
+ short state; /* video state, 0 = normal, 1 = reversed */
+ short strlen; /* strlen(item) */
+ short user_colors; /* colors were specified */
+} MenuItem;
+
+typedef struct MenuRoot
+{
+ struct MenuItem *first; /* first item in menu */
+ struct MenuItem *last; /* last item in menu */
+ struct MenuRoot *prev; /* previous root menu if pull right */
+ struct MenuRoot *next; /* next in list of root menus */
+ char *name; /* name of root */
+ Window w; /* the window of the menu */
+ Window shadow; /* the shadow window */
+ Pixel hi_fore; /* highlight foreground */
+ Pixel hi_back; /* highlight background */
+ short mapped; /* NEVER_MAPPED, UNMAPPED, or MAPPED */
+ short height; /* height of the menu */
+ short width; /* width of the menu */
+ short items; /* number of items in the menu */
+ short pull; /* is there a pull right entry ? */
+ short entered; /* EnterNotify following pop up */
+ short real_menu; /* this is a real menu */
+} MenuRoot;
+
+#define NEVER_MAPPED 0 /* constants for mapped field of MenuRoot */
+#define UNMAPPED 1
+#define MAPPED 2
+
+
+typedef struct MouseButton
+{
+ int func; /* the function number */
+ int mask; /* modifier mask */
+ MenuRoot *menu; /* menu if func is F_MENU */
+ MenuItem *item; /* action to perform if func != F_MENU */
+} MouseButton;
+
+typedef struct FuncKey
+{
+ struct FuncKey *next; /* next in the list of function keys */
+ char *name; /* key name */
+ KeySym keysym; /* X keysym */
+ KeyCode keycode; /* X keycode */
+ int cont; /* context */
+ int mods; /* modifiers */
+ int func; /* function to perform */
+ char *win_name; /* window name (if any) */
+ char *action; /* action string (if any) */
+} FuncKey;
+
+extern int RootFunction;
+extern MenuRoot *ActiveMenu;
+extern MenuItem *ActiveItem;
+extern int MoveFunction;
+extern int WindowMoved;
+extern int ConstMove;
+extern int ConstMoveDir;
+extern int ConstMoveX;
+extern int ConstMoveY;
+extern int ConstMoveXL;
+extern int ConstMoveXR;
+extern int ConstMoveYT;
+extern int ConstMoveYB;
+
+#define MAXMENUDEPTH 10 /* max number of nested menus */
+extern int MenuDepth;
+
+#define MOVE_NONE 0 /* modes of constrained move */
+#define MOVE_VERT 1
+#define MOVE_HORIZ 2
+
+#define WARPSCREEN_NEXT "next"
+#define WARPSCREEN_PREV "prev"
+#define WARPSCREEN_BACK "back"
+
+#define COLORMAP_NEXT "next"
+#define COLORMAP_PREV "prev"
+#define COLORMAP_DEFAULT "default"
+
+extern void InitTitlebarButtons();
+extern void InitMenus();
+extern MenuRoot *NewMenuRoot();
+extern MenuItem *AddToMenu();
+extern Bool PopUpMenu();
+extern MenuRoot *FindMenuRoot();
+extern Bool AddFuncKey();
+extern int ExecuteFunction();
+extern int DeferExecution();
+extern void Execute();
+extern void FocusOnRoot();
+
+#endif /* _MENUS_ */
diff --git a/src/parse.c b/src/parse.c
new file mode 100644
index 0000000..7281d0b
--- /dev/null
+++ b/src/parse.c
@@ -0,0 +1,1149 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/***********************************************************************
+ *
+ * $Xorg: parse.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * parse the .twmrc file
+ *
+ * 17-Nov-87 Thomas E. LaStrange File created
+ * 10-Oct-90 David M. Sternlicht Storing saved colors on root
+ ***********************************************************************/
+
+#include <stdio.h>
+#include <X11/Xos.h>
+#include <X11/Xmu/CharSet.h>
+#include "twm.h"
+#include "screen.h"
+#include "menus.h"
+#include "util.h"
+#include "gram.h"
+#include "parse.h"
+#include <X11/Xatom.h>
+#include <X11/extensions/sync.h>
+
+#ifndef SYSTEM_INIT_FILE
+#define SYSTEM_INIT_FILE "/usr/lib/X11/twm/system.twmrc"
+#endif
+#define BUF_LEN 300
+
+static FILE *twmrc;
+static int ptr = 0;
+static int len = 0;
+static char buff[BUF_LEN+1];
+static char overflowbuff[20]; /* really only need one */
+static int overflowlen;
+static char **stringListSource, *currentString;
+static int ParseUsePPosition();
+
+extern int yylineno;
+extern int mods;
+
+int ConstrainedMoveTime = 400; /* milliseconds, event times */
+
+static int twmFileInput(), twmStringListInput();
+void twmUnput();
+int (*twmInputFunc)();
+
+extern char *defTwmrc[]; /* default bindings */
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * ParseTwmrc - parse the .twmrc file
+ *
+ * Inputs:
+ * filename - the filename to parse. A NULL indicates $HOME/.twmrc
+ *
+ ***********************************************************************
+ */
+
+static int doparse (ifunc, srctypename, srcname)
+ int (*ifunc)();
+ char *srctypename;
+ char *srcname;
+{
+ mods = 0;
+ ptr = 0;
+ len = 0;
+ yylineno = 1;
+ ParseError = FALSE;
+ twmInputFunc = ifunc;
+ overflowlen = 0;
+
+ yyparse();
+
+ if (Scr->PointerForeground.pixel != Scr->Black ||
+ Scr->PointerBackground.pixel != Scr->White)
+ {
+ XRecolorCursor(dpy, UpperLeftCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, RightButt,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, LeftButt,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, MiddleButt,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->FrameCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->TitleCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->IconCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->IconMgrCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->MoveCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->ResizeCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->MenuCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->ButtonCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->WaitCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->SelectCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ XRecolorCursor(dpy, Scr->DestroyCursor,
+ &Scr->PointerForeground, &Scr->PointerBackground);
+ }
+ if (ParseError) {
+ fprintf (stderr, "%s: errors found in twm %s",
+ ProgramName, srctypename);
+ if (srcname) fprintf (stderr, " \"%s\"", srcname);
+ fprintf (stderr, "\n");
+ }
+ return (ParseError ? 0 : 1);
+}
+
+
+int ParseTwmrc (filename)
+ char *filename;
+{
+ int i;
+ char *home = NULL;
+ int homelen = 0;
+ char *cp = NULL;
+ char tmpfilename[257];
+
+ /*
+ * If filename given, try it, else try ~/.twmrc.# then ~/.twmrc. Then
+ * try system.twmrc; finally using built-in defaults.
+ */
+ for (twmrc = NULL, i = 0; !twmrc && i < 4; i++) {
+ switch (i) {
+ case 0: /* -f filename */
+ cp = filename;
+ break;
+
+ case 1: /* ~/.twmrc.screennum */
+ if (!filename) {
+ home = getenv ("HOME");
+ if (home) {
+ homelen = strlen (home);
+ cp = tmpfilename;
+ (void) sprintf (tmpfilename, "%s/.twmrc.%d",
+ home, Scr->screen);
+ break;
+ }
+ }
+ continue;
+
+ case 2: /* ~/.twmrc */
+ if (home) {
+ tmpfilename[homelen + 7] = '\0';
+ }
+ break;
+
+ case 3: /* system.twmrc */
+ cp = SYSTEM_INIT_FILE;
+ break;
+ }
+
+ if (cp) twmrc = fopen (cp, "r");
+ }
+
+ if (twmrc) {
+ int status;
+
+ if (filename && cp != filename) {
+ fprintf (stderr,
+ "%s: unable to open twmrc file %s, using %s instead\n",
+ ProgramName, filename, cp);
+ }
+ status = doparse (twmFileInput, "file", cp);
+ fclose (twmrc);
+ return status;
+ } else {
+ if (filename) {
+ fprintf (stderr,
+ "%s: unable to open twmrc file %s, using built-in defaults instead\n",
+ ProgramName, filename);
+ }
+ return ParseStringList (defTwmrc);
+ }
+}
+
+int ParseStringList (sl)
+ char **sl;
+{
+ stringListSource = sl;
+ currentString = *sl;
+ return doparse (twmStringListInput, "string list", (char *)NULL);
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * twmFileInput - redefinition of the lex input routine for file input
+ *
+ * Returned Value:
+ * the next input character
+ *
+ ***********************************************************************
+ */
+
+static int twmFileInput()
+{
+ if (overflowlen) return (int) overflowbuff[--overflowlen];
+
+ while (ptr == len)
+ {
+ if (fgets(buff, BUF_LEN, twmrc) == NULL)
+ return 0;
+
+ yylineno++;
+
+ ptr = 0;
+ len = strlen(buff);
+ }
+ return ((int)buff[ptr++]);
+}
+
+static int twmStringListInput()
+{
+ if (overflowlen) return (int) overflowbuff[--overflowlen];
+
+ /*
+ * return the character currently pointed to
+ */
+ if (currentString) {
+ unsigned int c = (unsigned int) *currentString++;
+
+ if (c) return c; /* if non-nul char */
+ currentString = *++stringListSource; /* advance to next bol */
+ return '\n'; /* but say that we hit last eol */
+ }
+ return 0; /* eof */
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * twmUnput - redefinition of the lex unput routine
+ *
+ * Inputs:
+ * c - the character to push back onto the input stream
+ *
+ ***********************************************************************
+ */
+
+void twmUnput (c)
+ int c;
+{
+ if (overflowlen < sizeof overflowbuff) {
+ overflowbuff[overflowlen++] = (char) c;
+ } else {
+ twmrc_error_prefix ();
+ fprintf (stderr, "unable to unput character (%d)\n",
+ c);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * TwmOutput - redefinition of the lex output routine
+ *
+ * Inputs:
+ * c - the character to print
+ *
+ ***********************************************************************
+ */
+
+void
+TwmOutput(c)
+{
+ putchar(c);
+}
+
+
+/**********************************************************************
+ *
+ * Parsing table and routines
+ *
+ ***********************************************************************/
+
+typedef struct _TwmKeyword {
+ char *name;
+ int value;
+ int subnum;
+} TwmKeyword;
+
+#define kw0_NoDefaults 1
+#define kw0_AutoRelativeResize 2
+#define kw0_ForceIcons 3
+#define kw0_NoIconManagers 4
+#define kw0_OpaqueMove 5
+#define kw0_InterpolateMenuColors 6
+#define kw0_NoVersion 7
+#define kw0_SortIconManager 8
+#define kw0_NoGrabServer 9
+#define kw0_NoMenuShadows 10
+#define kw0_NoRaiseOnMove 11
+#define kw0_NoRaiseOnResize 12
+#define kw0_NoRaiseOnDeiconify 13
+#define kw0_DontMoveOff 14
+#define kw0_NoBackingStore 15
+#define kw0_NoSaveUnders 16
+#define kw0_RestartPreviousState 17
+#define kw0_ClientBorderWidth 18
+#define kw0_NoTitleFocus 19
+#define kw0_RandomPlacement 20
+#define kw0_DecorateTransients 21
+#define kw0_ShowIconManager 22
+#define kw0_NoCaseSensitive 23
+#define kw0_NoRaiseOnWarp 24
+#define kw0_WarpUnmapped 25
+
+#define kws_UsePPosition 1
+#define kws_IconFont 2
+#define kws_ResizeFont 3
+#define kws_MenuFont 4
+#define kws_TitleFont 5
+#define kws_IconManagerFont 6
+#define kws_UnknownIcon 7
+#define kws_IconDirectory 8
+#define kws_MaxWindowSize 9
+
+#define kwn_ConstrainedMoveTime 1
+#define kwn_MoveDelta 2
+#define kwn_XorValue 3
+#define kwn_FramePadding 4
+#define kwn_TitlePadding 5
+#define kwn_ButtonIndent 6
+#define kwn_BorderWidth 7
+#define kwn_IconBorderWidth 8
+#define kwn_TitleButtonBorderWidth 9
+#define kwn_Priority 10
+
+#define kwcl_BorderColor 1
+#define kwcl_IconManagerHighlight 2
+#define kwcl_BorderTileForeground 3
+#define kwcl_BorderTileBackground 4
+#define kwcl_TitleForeground 5
+#define kwcl_TitleBackground 6
+#define kwcl_IconForeground 7
+#define kwcl_IconBackground 8
+#define kwcl_IconBorderColor 9
+#define kwcl_IconManagerForeground 10
+#define kwcl_IconManagerBackground 11
+
+#define kwc_DefaultForeground 1
+#define kwc_DefaultBackground 2
+#define kwc_MenuForeground 3
+#define kwc_MenuBackground 4
+#define kwc_MenuTitleForeground 5
+#define kwc_MenuTitleBackground 6
+#define kwc_MenuShadowColor 7
+#define kwc_PointerForeground 8
+#define kwc_PointerBackground 9
+
+
+/*
+ * The following is sorted alphabetically according to name (which must be
+ * in lowercase and only contain the letters a-z). It is fed to a binary
+ * search to parse keywords.
+ */
+static TwmKeyword keytable[] = {
+ { "all", ALL, 0 },
+ { "autoraise", AUTO_RAISE, 0 },
+ { "autorelativeresize", KEYWORD, kw0_AutoRelativeResize },
+ { "bordercolor", CLKEYWORD, kwcl_BorderColor },
+ { "bordertilebackground", CLKEYWORD, kwcl_BorderTileBackground },
+ { "bordertileforeground", CLKEYWORD, kwcl_BorderTileForeground },
+ { "borderwidth", NKEYWORD, kwn_BorderWidth },
+ { "button", BUTTON, 0 },
+ { "buttonindent", NKEYWORD, kwn_ButtonIndent },
+ { "c", CONTROL, 0 },
+ { "center", JKEYWORD, J_CENTER },
+ { "clientborderwidth", KEYWORD, kw0_ClientBorderWidth },
+ { "color", COLOR, 0 },
+ { "constrainedmovetime", NKEYWORD, kwn_ConstrainedMoveTime },
+ { "control", CONTROL, 0 },
+ { "cursors", CURSORS, 0 },
+ { "decoratetransients", KEYWORD, kw0_DecorateTransients },
+ { "defaultbackground", CKEYWORD, kwc_DefaultBackground },
+ { "defaultforeground", CKEYWORD, kwc_DefaultForeground },
+ { "defaultfunction", DEFAULT_FUNCTION, 0 },
+ { "destroy", KILL, 0 },
+ { "donticonifybyunmapping", DONT_ICONIFY_BY_UNMAPPING, 0 },
+ { "dontmoveoff", KEYWORD, kw0_DontMoveOff },
+ { "dontsqueezetitle", DONT_SQUEEZE_TITLE, 0 },
+ { "east", DKEYWORD, D_EAST },
+ { "f", FRAME, 0 },
+ { "f.autoraise", FKEYWORD, F_AUTORAISE },
+ { "f.backiconmgr", FKEYWORD, F_BACKICONMGR },
+ { "f.beep", FKEYWORD, F_BEEP },
+ { "f.bottomzoom", FKEYWORD, F_BOTTOMZOOM },
+ { "f.circledown", FKEYWORD, F_CIRCLEDOWN },
+ { "f.circleup", FKEYWORD, F_CIRCLEUP },
+ { "f.colormap", FSKEYWORD, F_COLORMAP },
+ { "f.cut", FSKEYWORD, F_CUT },
+ { "f.cutfile", FKEYWORD, F_CUTFILE },
+ { "f.deiconify", FKEYWORD, F_DEICONIFY },
+ { "f.delete", FKEYWORD, F_DELETE },
+ { "f.deltastop", FKEYWORD, F_DELTASTOP },
+ { "f.destroy", FKEYWORD, F_DESTROY },
+ { "f.downiconmgr", FKEYWORD, F_DOWNICONMGR },
+ { "f.exec", FSKEYWORD, F_EXEC },
+ { "f.file", FSKEYWORD, F_FILE },
+ { "f.focus", FKEYWORD, F_FOCUS },
+ { "f.forcemove", FKEYWORD, F_FORCEMOVE },
+ { "f.forwiconmgr", FKEYWORD, F_FORWICONMGR },
+ { "f.fullzoom", FKEYWORD, F_FULLZOOM },
+ { "f.function", FSKEYWORD, F_FUNCTION },
+ { "f.hbzoom", FKEYWORD, F_BOTTOMZOOM },
+ { "f.hideiconmgr", FKEYWORD, F_HIDELIST },
+ { "f.horizoom", FKEYWORD, F_HORIZOOM },
+ { "f.htzoom", FKEYWORD, F_TOPZOOM },
+ { "f.hzoom", FKEYWORD, F_HORIZOOM },
+ { "f.iconify", FKEYWORD, F_ICONIFY },
+ { "f.identify", FKEYWORD, F_IDENTIFY },
+ { "f.lefticonmgr", FKEYWORD, F_LEFTICONMGR },
+ { "f.leftzoom", FKEYWORD, F_LEFTZOOM },
+ { "f.lower", FKEYWORD, F_LOWER },
+ { "f.menu", FSKEYWORD, F_MENU },
+ { "f.move", FKEYWORD, F_MOVE },
+ { "f.nexticonmgr", FKEYWORD, F_NEXTICONMGR },
+ { "f.nop", FKEYWORD, F_NOP },
+ { "f.previconmgr", FKEYWORD, F_PREVICONMGR },
+ { "f.priority", FSKEYWORD, F_PRIORITY },
+ { "f.quit", FKEYWORD, F_QUIT },
+ { "f.raise", FKEYWORD, F_RAISE },
+ { "f.raiselower", FKEYWORD, F_RAISELOWER },
+ { "f.refresh", FKEYWORD, F_REFRESH },
+ { "f.resize", FKEYWORD, F_RESIZE },
+ { "f.restart", FKEYWORD, F_RESTART },
+ { "f.righticonmgr", FKEYWORD, F_RIGHTICONMGR },
+ { "f.rightzoom", FKEYWORD, F_RIGHTZOOM },
+ { "f.saveyourself", FKEYWORD, F_SAVEYOURSELF },
+ { "f.showiconmgr", FKEYWORD, F_SHOWLIST },
+ { "f.sorticonmgr", FKEYWORD, F_SORTICONMGR },
+ { "f.source", FSKEYWORD, F_BEEP }, /* XXX - don't work */
+ { "f.title", FKEYWORD, F_TITLE },
+ { "f.topzoom", FKEYWORD, F_TOPZOOM },
+ { "f.twmrc", FKEYWORD, F_RESTART },
+ { "f.unfocus", FKEYWORD, F_UNFOCUS },
+ { "f.upiconmgr", FKEYWORD, F_UPICONMGR },
+ { "f.version", FKEYWORD, F_VERSION },
+ { "f.vlzoom", FKEYWORD, F_LEFTZOOM },
+ { "f.vrzoom", FKEYWORD, F_RIGHTZOOM },
+ { "f.warpring", FSKEYWORD, F_WARPRING },
+ { "f.warpto", FSKEYWORD, F_WARPTO },
+ { "f.warptoiconmgr", FSKEYWORD, F_WARPTOICONMGR },
+ { "f.warptoscreen", FSKEYWORD, F_WARPTOSCREEN },
+ { "f.winrefresh", FKEYWORD, F_WINREFRESH },
+ { "f.zoom", FKEYWORD, F_ZOOM },
+ { "forceicons", KEYWORD, kw0_ForceIcons },
+ { "frame", FRAME, 0 },
+ { "framepadding", NKEYWORD, kwn_FramePadding },
+ { "function", FUNCTION, 0 },
+ { "grayscale", GRAYSCALE, 0 },
+ { "greyscale", GRAYSCALE, 0 },
+ { "i", ICON, 0 },
+ { "icon", ICON, 0 },
+ { "iconbackground", CLKEYWORD, kwcl_IconBackground },
+ { "iconbordercolor", CLKEYWORD, kwcl_IconBorderColor },
+ { "iconborderwidth", NKEYWORD, kwn_IconBorderWidth },
+ { "icondirectory", SKEYWORD, kws_IconDirectory },
+ { "iconfont", SKEYWORD, kws_IconFont },
+ { "iconforeground", CLKEYWORD, kwcl_IconForeground },
+ { "iconifybyunmapping", ICONIFY_BY_UNMAPPING, 0 },
+ { "iconmanagerbackground", CLKEYWORD, kwcl_IconManagerBackground },
+ { "iconmanagerdontshow", ICONMGR_NOSHOW, 0 },
+ { "iconmanagerfont", SKEYWORD, kws_IconManagerFont },
+ { "iconmanagerforeground", CLKEYWORD, kwcl_IconManagerForeground },
+ { "iconmanagergeometry", ICONMGR_GEOMETRY, 0 },
+ { "iconmanagerhighlight", CLKEYWORD, kwcl_IconManagerHighlight },
+ { "iconmanagers", ICONMGRS, 0 },
+ { "iconmanagershow", ICONMGR_SHOW, 0 },
+ { "iconmgr", ICONMGR, 0 },
+ { "iconregion", ICON_REGION, 0 },
+ { "icons", ICONS, 0 },
+ { "interpolatemenucolors", KEYWORD, kw0_InterpolateMenuColors },
+ { "l", LOCK, 0 },
+ { "left", JKEYWORD, J_LEFT },
+ { "lefttitlebutton", LEFT_TITLEBUTTON, 0 },
+ { "lock", LOCK, 0 },
+ { "m", META, 0 },
+ { "maketitle", MAKE_TITLE, 0 },
+ { "maxwindowsize", SKEYWORD, kws_MaxWindowSize },
+ { "menu", MENU, 0 },
+ { "menubackground", CKEYWORD, kwc_MenuBackground },
+ { "menufont", SKEYWORD, kws_MenuFont },
+ { "menuforeground", CKEYWORD, kwc_MenuForeground },
+ { "menushadowcolor", CKEYWORD, kwc_MenuShadowColor },
+ { "menutitlebackground", CKEYWORD, kwc_MenuTitleBackground },
+ { "menutitleforeground", CKEYWORD, kwc_MenuTitleForeground },
+ { "meta", META, 0 },
+ { "mod", META, 0 }, /* fake it */
+ { "monochrome", MONOCHROME, 0 },
+ { "move", MOVE, 0 },
+ { "movedelta", NKEYWORD, kwn_MoveDelta },
+ { "nobackingstore", KEYWORD, kw0_NoBackingStore },
+ { "nocasesensitive", KEYWORD, kw0_NoCaseSensitive },
+ { "nodefaults", KEYWORD, kw0_NoDefaults },
+ { "nograbserver", KEYWORD, kw0_NoGrabServer },
+ { "nohighlight", NO_HILITE, 0 },
+ { "noiconmanagers", KEYWORD, kw0_NoIconManagers },
+ { "nomenushadows", KEYWORD, kw0_NoMenuShadows },
+ { "noraiseondeiconify", KEYWORD, kw0_NoRaiseOnDeiconify },
+ { "noraiseonmove", KEYWORD, kw0_NoRaiseOnMove },
+ { "noraiseonresize", KEYWORD, kw0_NoRaiseOnResize },
+ { "noraiseonwarp", KEYWORD, kw0_NoRaiseOnWarp },
+ { "north", DKEYWORD, D_NORTH },
+ { "nosaveunders", KEYWORD, kw0_NoSaveUnders },
+ { "nostackmode", NO_STACKMODE, 0 },
+ { "notitle", NO_TITLE, 0 },
+ { "notitlefocus", KEYWORD, kw0_NoTitleFocus },
+ { "notitlehighlight", NO_TITLE_HILITE, 0 },
+ { "noversion", KEYWORD, kw0_NoVersion },
+ { "opaquemove", KEYWORD, kw0_OpaqueMove },
+ { "pixmaps", PIXMAPS, 0 },
+ { "pointerbackground", CKEYWORD, kwc_PointerBackground },
+ { "pointerforeground", CKEYWORD, kwc_PointerForeground },
+ { "priority", NKEYWORD, kwn_Priority },
+ { "r", ROOT, 0 },
+ { "randomplacement", KEYWORD, kw0_RandomPlacement },
+ { "resize", RESIZE, 0 },
+ { "resizefont", SKEYWORD, kws_ResizeFont },
+ { "restartpreviousstate", KEYWORD, kw0_RestartPreviousState },
+ { "right", JKEYWORD, J_RIGHT },
+ { "righttitlebutton", RIGHT_TITLEBUTTON, 0 },
+ { "root", ROOT, 0 },
+ { "s", SHIFT, 0 },
+ { "savecolor", SAVECOLOR, 0},
+ { "select", SELECT, 0 },
+ { "shift", SHIFT, 0 },
+ { "showiconmanager", KEYWORD, kw0_ShowIconManager },
+ { "sorticonmanager", KEYWORD, kw0_SortIconManager },
+ { "south", DKEYWORD, D_SOUTH },
+ { "squeezetitle", SQUEEZE_TITLE, 0 },
+ { "starticonified", START_ICONIFIED, 0 },
+ { "t", TITLE, 0 },
+ { "title", TITLE, 0 },
+ { "titlebackground", CLKEYWORD, kwcl_TitleBackground },
+ { "titlebuttonborderwidth", NKEYWORD, kwn_TitleButtonBorderWidth },
+ { "titlefont", SKEYWORD, kws_TitleFont },
+ { "titleforeground", CLKEYWORD, kwcl_TitleForeground },
+ { "titlehighlight", TITLE_HILITE, 0 },
+ { "titlepadding", NKEYWORD, kwn_TitlePadding },
+ { "unknownicon", SKEYWORD, kws_UnknownIcon },
+ { "usepposition", SKEYWORD, kws_UsePPosition },
+ { "w", WINDOW, 0 },
+ { "wait", WAIT, 0 },
+ { "warpcursor", WARP_CURSOR, 0 },
+ { "warpunmapped", KEYWORD, kw0_WarpUnmapped },
+ { "west", DKEYWORD, D_WEST },
+ { "window", WINDOW, 0 },
+ { "windowfunction", WINDOW_FUNCTION, 0 },
+ { "windowring", WINDOW_RING, 0 },
+ { "xorvalue", NKEYWORD, kwn_XorValue },
+ { "zoom", ZOOM, 0 },
+};
+
+static int numkeywords = (sizeof(keytable)/sizeof(keytable[0]));
+
+int parse_keyword (s, nump)
+ char *s;
+ int *nump;
+{
+ register int lower = 0, upper = numkeywords - 1;
+
+ XmuCopyISOLatin1Lowered (s, s);
+ while (lower <= upper) {
+ int middle = (lower + upper) / 2;
+ TwmKeyword *p = &keytable[middle];
+ int res = strcmp (p->name, s);
+
+ if (res < 0) {
+ lower = middle + 1;
+ } else if (res == 0) {
+ *nump = p->subnum;
+ return p->value;
+ } else {
+ upper = middle - 1;
+ }
+ }
+ return ERRORTOKEN;
+}
+
+
+
+/*
+ * action routines called by grammar
+ */
+
+int do_single_keyword (keyword)
+ int keyword;
+{
+ switch (keyword) {
+ case kw0_NoDefaults:
+ Scr->NoDefaults = TRUE;
+ return 1;
+
+ case kw0_AutoRelativeResize:
+ Scr->AutoRelativeResize = TRUE;
+ return 1;
+
+ case kw0_ForceIcons:
+ if (Scr->FirstTime) Scr->ForceIcon = TRUE;
+ return 1;
+
+ case kw0_NoIconManagers:
+ Scr->NoIconManagers = TRUE;
+ return 1;
+
+ case kw0_OpaqueMove:
+ Scr->OpaqueMove = TRUE;
+ return 1;
+
+ case kw0_InterpolateMenuColors:
+ if (Scr->FirstTime) Scr->InterpolateMenuColors = TRUE;
+ return 1;
+
+ case kw0_NoVersion:
+ /* obsolete */
+ return 1;
+
+ case kw0_SortIconManager:
+ if (Scr->FirstTime) Scr->SortIconMgr = TRUE;
+ return 1;
+
+ case kw0_NoGrabServer:
+ Scr->NoGrabServer = TRUE;
+ return 1;
+
+ case kw0_NoMenuShadows:
+ if (Scr->FirstTime) Scr->Shadow = FALSE;
+ return 1;
+
+ case kw0_NoRaiseOnMove:
+ if (Scr->FirstTime) Scr->NoRaiseMove = TRUE;
+ return 1;
+
+ case kw0_NoRaiseOnResize:
+ if (Scr->FirstTime) Scr->NoRaiseResize = TRUE;
+ return 1;
+
+ case kw0_NoRaiseOnDeiconify:
+ if (Scr->FirstTime) Scr->NoRaiseDeicon = TRUE;
+ return 1;
+
+ case kw0_DontMoveOff:
+ Scr->DontMoveOff = TRUE;
+ return 1;
+
+ case kw0_NoBackingStore:
+ Scr->BackingStore = FALSE;
+ return 1;
+
+ case kw0_NoSaveUnders:
+ Scr->SaveUnder = FALSE;
+ return 1;
+
+ case kw0_RestartPreviousState:
+ RestartPreviousState = True;
+ return 1;
+
+ case kw0_ClientBorderWidth:
+ if (Scr->FirstTime) Scr->ClientBorderWidth = TRUE;
+ return 1;
+
+ case kw0_NoTitleFocus:
+ Scr->TitleFocus = FALSE;
+ return 1;
+
+ case kw0_RandomPlacement:
+ Scr->RandomPlacement = TRUE;
+ return 1;
+
+ case kw0_DecorateTransients:
+ Scr->DecorateTransients = TRUE;
+ return 1;
+
+ case kw0_ShowIconManager:
+ Scr->ShowIconManager = TRUE;
+ return 1;
+
+ case kw0_NoCaseSensitive:
+ Scr->CaseSensitive = FALSE;
+ return 1;
+
+ case kw0_NoRaiseOnWarp:
+ Scr->NoRaiseWarp = TRUE;
+ return 1;
+
+ case kw0_WarpUnmapped:
+ Scr->WarpUnmapped = TRUE;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int do_string_keyword (keyword, s)
+ int keyword;
+ char *s;
+{
+ switch (keyword) {
+ case kws_UsePPosition:
+ {
+ int ppos = ParseUsePPosition (s);
+ if (ppos < 0) {
+ twmrc_error_prefix();
+ fprintf (stderr,
+ "ignoring invalid UsePPosition argument \"%s\"\n", s);
+ } else {
+ Scr->UsePPosition = ppos;
+ }
+ return 1;
+ }
+
+ case kws_IconFont:
+ if (!Scr->HaveFonts) Scr->IconFont.name = s;
+ return 1;
+
+ case kws_ResizeFont:
+ if (!Scr->HaveFonts) Scr->SizeFont.name = s;
+ return 1;
+
+ case kws_MenuFont:
+ if (!Scr->HaveFonts) Scr->MenuFont.name = s;
+ return 1;
+
+ case kws_TitleFont:
+ if (!Scr->HaveFonts) Scr->TitleBarFont.name = s;
+ return 1;
+
+ case kws_IconManagerFont:
+ if (!Scr->HaveFonts) Scr->IconManagerFont.name = s;
+ return 1;
+
+ case kws_UnknownIcon:
+ if (Scr->FirstTime) GetUnknownIcon (s);
+ return 1;
+
+ case kws_IconDirectory:
+ if (Scr->FirstTime) Scr->IconDirectory = ExpandFilename (s);
+ return 1;
+
+ case kws_MaxWindowSize:
+ JunkMask = XParseGeometry (s, &JunkX, &JunkY, &JunkWidth, &JunkHeight);
+ if ((JunkMask & (WidthValue | HeightValue)) !=
+ (WidthValue | HeightValue)) {
+ twmrc_error_prefix();
+ fprintf (stderr, "bad MaxWindowSize \"%s\"\n", s);
+ return 0;
+ }
+ if (JunkWidth <= 0 || JunkHeight <= 0) {
+ twmrc_error_prefix();
+ fprintf (stderr, "MaxWindowSize \"%s\" must be positive\n", s);
+ return 0;
+ }
+ Scr->MaxWindowWidth = JunkWidth;
+ Scr->MaxWindowHeight = JunkHeight;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int do_number_keyword (keyword, num)
+ int keyword;
+ int num;
+{
+ switch (keyword) {
+ case kwn_ConstrainedMoveTime:
+ ConstrainedMoveTime = num;
+ return 1;
+
+ case kwn_MoveDelta:
+ Scr->MoveDelta = num;
+ return 1;
+
+ case kwn_XorValue:
+ if (Scr->FirstTime) Scr->XORvalue = num;
+ return 1;
+
+ case kwn_FramePadding:
+ if (Scr->FirstTime) Scr->FramePadding = num;
+ return 1;
+
+ case kwn_TitlePadding:
+ if (Scr->FirstTime) Scr->TitlePadding = num;
+ return 1;
+
+ case kwn_ButtonIndent:
+ if (Scr->FirstTime) Scr->ButtonIndent = num;
+ return 1;
+
+ case kwn_BorderWidth:
+ if (Scr->FirstTime) Scr->BorderWidth = num;
+ return 1;
+
+ case kwn_IconBorderWidth:
+ if (Scr->FirstTime) Scr->IconBorderWidth = num;
+ return 1;
+
+ case kwn_TitleButtonBorderWidth:
+ if (Scr->FirstTime) Scr->TBInfo.border = num;
+ return 1;
+
+ case kwn_Priority:
+ if (HasSync) XSyncSetPriority(dpy, /*self*/ None, num);
+ return 1;
+ }
+
+ return 0;
+}
+
+name_list **do_colorlist_keyword (keyword, colormode, s)
+ int keyword;
+ int colormode;
+ char *s;
+{
+ switch (keyword) {
+ case kwcl_BorderColor:
+ GetColor (colormode, &Scr->BorderColor, s);
+ return &Scr->BorderColorL;
+
+ case kwcl_IconManagerHighlight:
+ GetColor (colormode, &Scr->IconManagerHighlight, s);
+ return &Scr->IconManagerHighlightL;
+
+ case kwcl_BorderTileForeground:
+ GetColor (colormode, &Scr->BorderTileC.fore, s);
+ return &Scr->BorderTileForegroundL;
+
+ case kwcl_BorderTileBackground:
+ GetColor (colormode, &Scr->BorderTileC.back, s);
+ return &Scr->BorderTileBackgroundL;
+
+ case kwcl_TitleForeground:
+ GetColor (colormode, &Scr->TitleC.fore, s);
+ return &Scr->TitleForegroundL;
+
+ case kwcl_TitleBackground:
+ GetColor (colormode, &Scr->TitleC.back, s);
+ return &Scr->TitleBackgroundL;
+
+ case kwcl_IconForeground:
+ GetColor (colormode, &Scr->IconC.fore, s);
+ return &Scr->IconForegroundL;
+
+ case kwcl_IconBackground:
+ GetColor (colormode, &Scr->IconC.back, s);
+ return &Scr->IconBackgroundL;
+
+ case kwcl_IconBorderColor:
+ GetColor (colormode, &Scr->IconBorderColor, s);
+ return &Scr->IconBorderColorL;
+
+ case kwcl_IconManagerForeground:
+ GetColor (colormode, &Scr->IconManagerC.fore, s);
+ return &Scr->IconManagerFL;
+
+ case kwcl_IconManagerBackground:
+ GetColor (colormode, &Scr->IconManagerC.back, s);
+ return &Scr->IconManagerBL;
+ }
+ return NULL;
+}
+
+int do_color_keyword (keyword, colormode, s)
+ int keyword;
+ int colormode;
+ char *s;
+{
+ switch (keyword) {
+ case kwc_DefaultForeground:
+ GetColor (colormode, &Scr->DefaultC.fore, s);
+ return 1;
+
+ case kwc_DefaultBackground:
+ GetColor (colormode, &Scr->DefaultC.back, s);
+ return 1;
+
+ case kwc_MenuForeground:
+ GetColor (colormode, &Scr->MenuC.fore, s);
+ return 1;
+
+ case kwc_MenuBackground:
+ GetColor (colormode, &Scr->MenuC.back, s);
+ return 1;
+
+ case kwc_MenuTitleForeground:
+ GetColor (colormode, &Scr->MenuTitleC.fore, s);
+ return 1;
+
+ case kwc_MenuTitleBackground:
+ GetColor (colormode, &Scr->MenuTitleC.back, s);
+ return 1;
+
+ case kwc_MenuShadowColor:
+ GetColor (colormode, &Scr->MenuShadowColor, s);
+ return 1;
+
+ case kwc_PointerForeground:
+ GetColorValue (colormode, &Scr->PointerForeground, s);
+ return 1;
+
+ case kwc_PointerBackground:
+ GetColorValue (colormode, &Scr->PointerBackground, s);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * put_pixel_on_root() Save a pixel value in twm root window color property.
+ */
+put_pixel_on_root(pixel)
+ Pixel pixel;
+{
+ int i, addPixel = 1;
+ Atom pixelAtom, retAtom;
+ int retFormat;
+ unsigned long nPixels, retAfter;
+ Pixel *retProp;
+ pixelAtom = XInternAtom(dpy, "_MIT_PRIORITY_COLORS", True);
+ XGetWindowProperty(dpy, Scr->Root, pixelAtom, 0, 8192,
+ False, XA_CARDINAL, &retAtom,
+ &retFormat, &nPixels, &retAfter,
+ (unsigned char **)&retProp);
+
+ for (i=0; i< nPixels; i++)
+ if (pixel == retProp[i]) addPixel = 0;
+
+ if (addPixel)
+ XChangeProperty (dpy, Scr->Root, _XA_MIT_PRIORITY_COLORS,
+ XA_CARDINAL, 32, PropModeAppend,
+ (unsigned char *)&pixel, 1);
+}
+
+/*
+ * do_string_savecolor() save a color from a string in the twmrc file.
+ */
+do_string_savecolor(colormode, s)
+ int colormode;
+ char *s;
+{
+ Pixel p;
+ GetColor(colormode, &p, s);
+ put_pixel_on_root(p);
+}
+
+/*
+ * do_var_savecolor() save a color from a var in the twmrc file.
+ */
+typedef struct _cnode {int i; struct _cnode *next;} Cnode, *Cptr;
+Cptr chead = NULL;
+
+do_var_savecolor(key)
+int key;
+{
+ Cptr cptrav, cpnew;
+ if (!chead) {
+ chead = (Cptr)malloc(sizeof(Cnode));
+ chead->i = key; chead->next = NULL;
+ }
+ else {
+ cptrav = chead;
+ while (cptrav->next != NULL) { cptrav = cptrav->next; }
+ cpnew = (Cptr)malloc(sizeof(Cnode));
+ cpnew->i = key; cpnew->next = NULL; cptrav->next = cpnew;
+ }
+}
+
+/*
+ * assign_var_savecolor() traverse the var save color list placeing the pixels
+ * in the root window property.
+ */
+void assign_var_savecolor()
+{
+ Cptr cp = chead;
+ while (cp != NULL) {
+ switch (cp->i) {
+ case kwcl_BorderColor:
+ put_pixel_on_root(Scr->BorderColor);
+ break;
+ case kwcl_IconManagerHighlight:
+ put_pixel_on_root(Scr->IconManagerHighlight);
+ break;
+ case kwcl_BorderTileForeground:
+ put_pixel_on_root(Scr->BorderTileC.fore);
+ break;
+ case kwcl_BorderTileBackground:
+ put_pixel_on_root(Scr->BorderTileC.back);
+ break;
+ case kwcl_TitleForeground:
+ put_pixel_on_root(Scr->TitleC.fore);
+ break;
+ case kwcl_TitleBackground:
+ put_pixel_on_root(Scr->TitleC.back);
+ break;
+ case kwcl_IconForeground:
+ put_pixel_on_root(Scr->IconC.fore);
+ break;
+ case kwcl_IconBackground:
+ put_pixel_on_root(Scr->IconC.back);
+ break;
+ case kwcl_IconBorderColor:
+ put_pixel_on_root(Scr->IconBorderColor);
+ break;
+ case kwcl_IconManagerForeground:
+ put_pixel_on_root(Scr->IconManagerC.fore);
+ break;
+ case kwcl_IconManagerBackground:
+ put_pixel_on_root(Scr->IconManagerC.back);
+ break;
+ }
+ cp = cp->next;
+ }
+ if (chead) {
+ free(chead);
+ chead = NULL;
+ }
+}
+
+static int ParseUsePPosition (s)
+ register char *s;
+{
+ XmuCopyISOLatin1Lowered (s, s);
+
+ if (strcmp (s, "off") == 0) {
+ return PPOS_OFF;
+ } else if (strcmp (s, "on") == 0) {
+ return PPOS_ON;
+ } else if (strcmp (s, "non-zero") == 0 ||
+ strcmp (s, "nonzero") == 0) {
+ return PPOS_NON_ZERO;
+ }
+
+ return -1;
+}
+
+
+do_squeeze_entry (list, name, justify, num, denom)
+ name_list **list; /* squeeze or dont-squeeze list */
+ char *name; /* window name */
+ int justify; /* left, center, right */
+ int num; /* signed num */
+ int denom; /* 0 or indicates fraction denom */
+{
+ int absnum = (num < 0 ? -num : num);
+
+ if (denom < 0) {
+ twmrc_error_prefix();
+ fprintf (stderr, "negative SqueezeTitle denominator %d\n", denom);
+ return;
+ }
+ if (absnum > denom && denom != 0) {
+ twmrc_error_prefix();
+ fprintf (stderr, "SqueezeTitle fraction %d/%d outside window\n",
+ num, denom);
+ return;
+ }
+ if (denom == 1) {
+ twmrc_error_prefix();
+ fprintf (stderr, "useless SqueezeTitle faction %d/%d, assuming 0/0\n",
+ num, denom);
+ num = 0;
+ denom = 0;
+ }
+
+ if (HasShape) {
+ SqueezeInfo *sinfo;
+ sinfo = (SqueezeInfo *) malloc (sizeof(SqueezeInfo));
+
+ if (!sinfo) {
+ twmrc_error_prefix();
+ fprintf (stderr, "unable to allocate %d bytes for squeeze info\n",
+ sizeof(SqueezeInfo));
+ return;
+ }
+ sinfo->justify = justify;
+ sinfo->num = num;
+ sinfo->denom = denom;
+ AddToList (list, name, (char *) sinfo);
+ }
+}
diff --git a/src/parse.h b/src/parse.h
new file mode 100644
index 0000000..68443c4
--- /dev/null
+++ b/src/parse.h
@@ -0,0 +1,135 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/**********************************************************************
+ *
+ * $Xorg: parse.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * .twmrc parsing externs
+ *
+ * 8-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _PARSE_
+#define _PARSE_
+
+extern int ParseTwmrc(), ParseStringList();
+extern int (*twmInputFunc)();
+extern void twmUnput();
+extern void TwmOutput();
+
+#define F_NOP 0
+#define F_BEEP 1
+#define F_RESTART 2
+#define F_QUIT 3
+#define F_FOCUS 4
+#define F_REFRESH 5
+#define F_WINREFRESH 6
+#define F_DELTASTOP 7
+#define F_MOVE 8
+#define F_POPUP 9
+#define F_FORCEMOVE 10
+#define F_AUTORAISE 11
+#define F_IDENTIFY 12
+#define F_ICONIFY 13
+#define F_DEICONIFY 14
+#define F_UNFOCUS 15
+#define F_RESIZE 16
+#define F_ZOOM 17
+#define F_LEFTZOOM 18
+#define F_RIGHTZOOM 19
+#define F_TOPZOOM 20
+#define F_BOTTOMZOOM 21
+#define F_HORIZOOM 22
+#define F_FULLZOOM 23
+#define F_RAISE 24
+#define F_RAISELOWER 25
+#define F_LOWER 26
+#define F_DESTROY 27
+#define F_DELETE 28
+#define F_SAVEYOURSELF 29
+#define F_VERSION 30
+#define F_TITLE 31
+#define F_RIGHTICONMGR 32
+#define F_LEFTICONMGR 33
+#define F_UPICONMGR 34
+#define F_DOWNICONMGR 35
+#define F_FORWICONMGR 36
+#define F_BACKICONMGR 37
+#define F_NEXTICONMGR 38
+#define F_PREVICONMGR 39
+#define F_SORTICONMGR 40
+#define F_CIRCLEUP 41
+#define F_CIRCLEDOWN 42
+#define F_CUTFILE 43
+#define F_SHOWLIST 44
+#define F_HIDELIST 45
+
+#define F_MENU 101 /* string */
+#define F_WARPTO 102 /* string */
+#define F_WARPTOICONMGR 103 /* string */
+#define F_WARPRING 104 /* string */
+#define F_FILE 105 /* string */
+#define F_EXEC 106 /* string */
+#define F_CUT 107 /* string */
+#define F_FUNCTION 108 /* string */
+#define F_WARPTOSCREEN 109 /* string */
+#define F_COLORMAP 110 /* string */
+#define F_PRIORITY 111 /* string */
+
+#define D_NORTH 1
+#define D_SOUTH 2
+#define D_EAST 3
+#define D_WEST 4
+
+#endif /* _PARSE_ */
diff --git a/src/resize.c b/src/resize.c
new file mode 100644
index 0000000..5c07ce9
--- /dev/null
+++ b/src/resize.c
@@ -0,0 +1,1217 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/***********************************************************************
+ *
+ * $Xorg: resize.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * window resizing borrowed from the "wm" window manager
+ *
+ * 11-Dec-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#include <stdio.h>
+#include "twm.h"
+#include "parse.h"
+#include "util.h"
+#include "resize.h"
+#include "add_window.h"
+#include "screen.h"
+
+#define MINHEIGHT 0 /* had been 32 */
+#define MINWIDTH 0 /* had been 60 */
+
+static int dragx; /* all these variables are used */
+static int dragy; /* in resize operations */
+static int dragWidth;
+static int dragHeight;
+
+static int origx;
+static int origy;
+static int origWidth;
+static int origHeight;
+
+static int clampTop;
+static int clampBottom;
+static int clampLeft;
+static int clampRight;
+static int clampDX;
+static int clampDY;
+
+static int last_width;
+static int last_height;
+
+
+static void do_auto_clamp (tmp_win, evp)
+ TwmWindow *tmp_win;
+ XEvent *evp;
+{
+ Window junkRoot;
+ int x, y, h, v, junkbw;
+ unsigned int junkMask;
+
+ switch (evp->type) {
+ case ButtonPress:
+ x = evp->xbutton.x_root;
+ y = evp->xbutton.y_root;
+ break;
+ case KeyPress:
+ x = evp->xkey.x_root;
+ y = evp->xkey.y_root;
+ break;
+ default:
+ if (!XQueryPointer (dpy, Scr->Root, &junkRoot, &junkRoot,
+ &x, &y, &junkbw, &junkbw, &junkMask))
+ return;
+ }
+
+ h = ((x - dragx) / (dragWidth < 3 ? 1 : (dragWidth / 3)));
+ v = ((y - dragy - tmp_win->title_height) /
+ (dragHeight < 3 ? 1 : (dragHeight / 3)));
+
+ if (h <= 0) {
+ clampLeft = 1;
+ clampDX = (x - dragx);
+ } else if (h >= 2) {
+ clampRight = 1;
+ clampDX = (x - dragx - dragWidth);
+ }
+
+ if (v <= 0) {
+ clampTop = 1;
+ clampDY = (y - dragy);
+ } else if (v >= 2) {
+ clampBottom = 1;
+ clampDY = (y - dragy - dragHeight);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * StartResize - begin a window resize operation
+ *
+ * Inputs:
+ * ev - the event structure (button press)
+ * tmp_win - the TwmWindow pointer
+ * fromtitlebar - action invoked from titlebar button
+ *
+ ***********************************************************************
+ */
+
+void
+StartResize(evp, tmp_win, fromtitlebar)
+XEvent *evp;
+TwmWindow *tmp_win;
+Bool fromtitlebar;
+{
+ Window junkRoot;
+ unsigned int junkbw, junkDepth;
+
+ ResizeWindow = tmp_win->frame;
+ XGrabServer(dpy);
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | PointerMotionHintMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->ResizeCursor, CurrentTime);
+
+ XGetGeometry(dpy, (Drawable) tmp_win->frame, &junkRoot,
+ &dragx, &dragy, (unsigned int *)&dragWidth, (unsigned int *)&dragHeight, &junkbw,
+ &junkDepth);
+ dragx += tmp_win->frame_bw;
+ dragy += tmp_win->frame_bw;
+ origx = dragx;
+ origy = dragy;
+ origWidth = dragWidth;
+ origHeight = dragHeight;
+ clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
+
+ if (Scr->AutoRelativeResize && !fromtitlebar)
+ do_auto_clamp (tmp_win, evp);
+
+ Scr->SizeStringOffset = SIZE_HINDENT;
+ XResizeWindow (dpy, Scr->SizeWindow,
+ Scr->SizeStringWidth + SIZE_HINDENT * 2,
+ Scr->SizeFont.height + SIZE_VINDENT * 2);
+ XMapRaised(dpy, Scr->SizeWindow);
+ InstallRootColormap();
+ last_width = 0;
+ last_height = 0;
+ DisplaySize(tmp_win, origWidth, origHeight);
+ 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);
+}
+
+
+
+void
+MenuStartResize(tmp_win, x, y, w, h)
+TwmWindow *tmp_win;
+int x, y, w, h;
+{
+ XGrabServer(dpy);
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonPressMask | ButtonMotionMask | PointerMotionMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->ResizeCursor, CurrentTime);
+ dragx = x + tmp_win->frame_bw;
+ dragy = y + tmp_win->frame_bw;
+ origx = dragx;
+ origy = dragy;
+ dragWidth = origWidth = w; /* - 2 * tmp_win->frame_bw; */
+ dragHeight = origHeight = h; /* - 2 * tmp_win->frame_bw; */
+ clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
+ last_width = 0;
+ last_height = 0;
+ Scr->SizeStringOffset = SIZE_HINDENT;
+ XResizeWindow (dpy, Scr->SizeWindow,
+ Scr->SizeStringWidth + SIZE_HINDENT * 2,
+ Scr->SizeFont.height + SIZE_VINDENT * 2);
+ XMapRaised(dpy, Scr->SizeWindow);
+ DisplaySize(tmp_win, origWidth, origHeight);
+ 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);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddStartResize - begin a windorew resize operation from AddWindow
+ *
+ * Inputs:
+ * tmp_win - the TwmWindow pointer
+ *
+ ***********************************************************************
+ */
+
+void
+AddStartResize(tmp_win, x, y, w, h)
+TwmWindow *tmp_win;
+int x, y, w, h;
+{
+ XGrabServer(dpy);
+ XGrabPointer(dpy, Scr->Root, True,
+ ButtonReleaseMask | ButtonMotionMask | PointerMotionHintMask,
+ GrabModeAsync, GrabModeAsync,
+ Scr->Root, Scr->ResizeCursor, CurrentTime);
+
+ dragx = x + tmp_win->frame_bw;
+ dragy = y + tmp_win->frame_bw;
+ origx = dragx;
+ origy = dragy;
+ dragWidth = origWidth = w - 2 * tmp_win->frame_bw;
+ dragHeight = origHeight = h - 2 * tmp_win->frame_bw;
+ clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
+/*****
+ if (Scr->AutoRelativeResize) {
+ clampRight = clampBottom = 1;
+ }
+*****/
+ last_width = 0;
+ last_height = 0;
+ DisplaySize(tmp_win, origWidth, origHeight);
+}
+
+
+
+void
+MenuDoResize(x_root, y_root, tmp_win)
+int x_root;
+int y_root;
+TwmWindow *tmp_win;
+{
+ int action;
+
+ action = 0;
+
+ x_root -= clampDX;
+ y_root -= clampDY;
+
+ if (clampTop) {
+ int delta = y_root - dragy;
+ if (dragHeight - delta < MINHEIGHT) {
+ delta = dragHeight - MINHEIGHT;
+ clampTop = 0;
+ }
+ dragy += delta;
+ dragHeight -= delta;
+ action = 1;
+ }
+ else if (y_root <= dragy/* ||
+ y_root == findRootInfo(root)->rooty*/) {
+ dragy = y_root;
+ dragHeight = origy + origHeight -
+ y_root;
+ clampBottom = 0;
+ clampTop = 1;
+ clampDY = 0;
+ action = 1;
+ }
+ if (clampLeft) {
+ int delta = x_root - dragx;
+ if (dragWidth - delta < MINWIDTH) {
+ delta = dragWidth - MINWIDTH;
+ clampLeft = 0;
+ }
+ dragx += delta;
+ dragWidth -= delta;
+ action = 1;
+ }
+ else if (x_root <= dragx/* ||
+ x_root == findRootInfo(root)->rootx*/) {
+ dragx = x_root;
+ dragWidth = origx + origWidth -
+ x_root;
+ clampRight = 0;
+ clampLeft = 1;
+ clampDX = 0;
+ action = 1;
+ }
+ if (clampBottom) {
+ int delta = y_root - dragy - dragHeight;
+ if (dragHeight + delta < MINHEIGHT) {
+ delta = MINHEIGHT - dragHeight;
+ clampBottom = 0;
+ }
+ dragHeight += delta;
+ action = 1;
+ }
+ else if (y_root >= dragy + dragHeight) {
+ dragy = origy;
+ dragHeight = 1 + y_root - dragy;
+ clampTop = 0;
+ clampBottom = 1;
+ clampDY = 0;
+ action = 1;
+ }
+ if (clampRight) {
+ int delta = x_root - dragx - dragWidth;
+ if (dragWidth + delta < MINWIDTH) {
+ delta = MINWIDTH - dragWidth;
+ clampRight = 0;
+ }
+ dragWidth += delta;
+ action = 1;
+ }
+ else if (x_root >= dragx + dragWidth) {
+ dragx = origx;
+ dragWidth = 1 + x_root - origx;
+ clampLeft = 0;
+ clampRight = 1;
+ clampDX = 0;
+ action = 1;
+ }
+
+ if (action) {
+ ConstrainSize (tmp_win, &dragWidth, &dragHeight);
+ if (clampLeft)
+ dragx = origx + origWidth - dragWidth;
+ if (clampTop)
+ dragy = origy + origHeight - dragHeight;
+ 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);
+ }
+
+ DisplaySize(tmp_win, dragWidth, dragHeight);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * DoResize - move the rubberband around. This is called for
+ * each motion event when we are resizing
+ *
+ * Inputs:
+ * x_root - the X corrdinate in the root window
+ * y_root - the Y corrdinate in the root window
+ * tmp_win - the current twm window
+ *
+ ***********************************************************************
+ */
+
+void
+DoResize(x_root, y_root, tmp_win)
+int x_root;
+int y_root;
+TwmWindow *tmp_win;
+{
+ int action;
+
+ action = 0;
+
+ x_root -= clampDX;
+ y_root -= clampDY;
+
+ if (clampTop) {
+ int delta = y_root - dragy;
+ if (dragHeight - delta < MINHEIGHT) {
+ delta = dragHeight - MINHEIGHT;
+ clampTop = 0;
+ }
+ dragy += delta;
+ dragHeight -= delta;
+ action = 1;
+ }
+ else if (y_root <= dragy/* ||
+ y_root == findRootInfo(root)->rooty*/) {
+ dragy = y_root;
+ dragHeight = origy + origHeight -
+ y_root;
+ clampBottom = 0;
+ clampTop = 1;
+ clampDY = 0;
+ action = 1;
+ }
+ if (clampLeft) {
+ int delta = x_root - dragx;
+ if (dragWidth - delta < MINWIDTH) {
+ delta = dragWidth - MINWIDTH;
+ clampLeft = 0;
+ }
+ dragx += delta;
+ dragWidth -= delta;
+ action = 1;
+ }
+ else if (x_root <= dragx/* ||
+ x_root == findRootInfo(root)->rootx*/) {
+ dragx = x_root;
+ dragWidth = origx + origWidth -
+ x_root;
+ clampRight = 0;
+ clampLeft = 1;
+ clampDX = 0;
+ action = 1;
+ }
+ if (clampBottom) {
+ int delta = y_root - dragy - dragHeight;
+ if (dragHeight + delta < MINHEIGHT) {
+ delta = MINHEIGHT - dragHeight;
+ clampBottom = 0;
+ }
+ dragHeight += delta;
+ action = 1;
+ }
+ else if (y_root >= dragy + dragHeight - 1/* ||
+ y_root == findRootInfo(root)->rooty
+ + findRootInfo(root)->rootheight - 1*/) {
+ dragy = origy;
+ dragHeight = 1 + y_root - dragy;
+ clampTop = 0;
+ clampBottom = 1;
+ clampDY = 0;
+ action = 1;
+ }
+ if (clampRight) {
+ int delta = x_root - dragx - dragWidth;
+ if (dragWidth + delta < MINWIDTH) {
+ delta = MINWIDTH - dragWidth;
+ clampRight = 0;
+ }
+ dragWidth += delta;
+ action = 1;
+ }
+ else if (x_root >= dragx + dragWidth - 1/* ||
+ x_root == findRootInfo(root)->rootx +
+ findRootInfo(root)->rootwidth - 1*/) {
+ dragx = origx;
+ dragWidth = 1 + x_root - origx;
+ clampLeft = 0;
+ clampRight = 1;
+ clampDX = 0;
+ action = 1;
+ }
+
+ if (action) {
+ ConstrainSize (tmp_win, &dragWidth, &dragHeight);
+ if (clampLeft)
+ dragx = origx + origWidth - dragWidth;
+ if (clampTop)
+ dragy = origy + origHeight - dragHeight;
+ 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);
+ }
+
+ DisplaySize(tmp_win, dragWidth, dragHeight);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * DisplaySize - display the size in the dimensions window
+ *
+ * Inputs:
+ * tmp_win - the current twm window
+ * width - the width of the rubber band
+ * height - the height of the rubber band
+ *
+ ***********************************************************************
+ */
+
+void
+DisplaySize(tmp_win, width, height)
+TwmWindow *tmp_win;
+int width;
+int height;
+{
+ char str[100];
+ int dwidth;
+ int dheight;
+
+ if (last_width == width && last_height == height)
+ return;
+
+ last_width = width;
+ last_height = height;
+
+ dheight = height - tmp_win->title_height;
+ dwidth = width;
+
+ /*
+ * ICCCM says that PMinSize is the default is no PBaseSize is given,
+ * and vice-versa.
+ */
+ if (tmp_win->hints.flags&(PMinSize|PBaseSize) && tmp_win->hints.flags & PResizeInc)
+ {
+ if (tmp_win->hints.flags & PBaseSize) {
+ dwidth -= tmp_win->hints.base_width;
+ dheight -= tmp_win->hints.base_height;
+ } else {
+ dwidth -= tmp_win->hints.min_width;
+ dheight -= tmp_win->hints.min_height;
+ }
+ }
+
+ if (tmp_win->hints.flags & PResizeInc)
+ {
+ dwidth /= tmp_win->hints.width_inc;
+ dheight /= tmp_win->hints.height_inc;
+ }
+
+ (void) sprintf (str, " %4d x %-4d ", dwidth, dheight);
+ XRaiseWindow(dpy, Scr->SizeWindow);
+ FBF(Scr->DefaultC.fore, Scr->DefaultC.back, Scr->SizeFont.font->fid);
+ XDrawImageString (dpy, Scr->SizeWindow, Scr->NormalGC,
+ Scr->SizeStringOffset,
+ Scr->SizeFont.font->ascent + SIZE_VINDENT,
+ str, 13);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * EndResize - finish the resize operation
+ *
+ ***********************************************************************
+ */
+
+void
+EndResize()
+{
+ TwmWindow *tmp_win;
+
+#ifdef DEBUG
+ fprintf(stderr, "EndResize\n");
+#endif
+
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+ XUnmapWindow(dpy, Scr->SizeWindow);
+
+ XFindContext(dpy, ResizeWindow, TwmContext, (caddr_t *)&tmp_win);
+
+ ConstrainSize (tmp_win, &dragWidth, &dragHeight);
+
+ if (dragWidth != tmp_win->frame_width ||
+ dragHeight != tmp_win->frame_height)
+ tmp_win->zoomed = ZOOM_NONE;
+
+ SetupWindow (tmp_win, dragx - tmp_win->frame_bw, dragy - tmp_win->frame_bw,
+ dragWidth, dragHeight, -1);
+
+ if (tmp_win->iconmgr)
+ {
+ int ncols = tmp_win->iconmgrp->cur_columns;
+ if (ncols == 0) ncols = 1;
+
+ tmp_win->iconmgrp->width = (int) ((dragWidth *
+ (long) tmp_win->iconmgrp->columns)
+ / ncols);
+ PackIconManager(tmp_win->iconmgrp);
+ }
+
+ if (!Scr->NoRaiseResize)
+ XRaiseWindow(dpy, tmp_win->frame);
+
+ UninstallRootColormap();
+
+ ResizeWindow = None;
+}
+
+void
+MenuEndResize(tmp_win)
+TwmWindow *tmp_win;
+{
+ MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
+ XUnmapWindow(dpy, Scr->SizeWindow);
+ ConstrainSize (tmp_win, &dragWidth, &dragHeight);
+ AddingX = dragx;
+ AddingY = dragy;
+ AddingW = dragWidth + (2 * tmp_win->frame_bw);
+ AddingH = dragHeight + (2 * tmp_win->frame_bw);
+ SetupWindow (tmp_win, AddingX, AddingY, AddingW, AddingH, -1);
+}
+
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * AddEndResize - finish the resize operation for AddWindo<w
+ *
+ ***********************************************************************
+ */
+
+void
+AddEndResize(tmp_win)
+TwmWindow *tmp_win;
+{
+
+#ifdef DEBUG
+ fprintf(stderr, "AddEndResize\n");
+#endif
+
+ ConstrainSize (tmp_win, &dragWidth, &dragHeight);
+ AddingX = dragx;
+ AddingY = dragy;
+ AddingW = dragWidth + (2 * tmp_win->frame_bw);
+ AddingH = dragHeight + (2 * tmp_win->frame_bw);
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * ConstrainSize - adjust the given width and height to account for the
+ * constraints imposed by size hints
+ *
+ * The general algorithm, especially the aspect ratio stuff, is
+ * borrowed from uwm's CheckConsistency routine.
+ *
+ ***********************************************************************/
+
+ConstrainSize (tmp_win, widthp, heightp)
+ TwmWindow *tmp_win;
+ int *widthp, *heightp;
+{
+#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
+#define _min(a,b) (((a) < (b)) ? (a) : (b))
+
+ int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
+ int baseWidth, baseHeight;
+ int dwidth = *widthp, dheight = *heightp;
+
+
+ dheight -= tmp_win->title_height;
+
+ if (tmp_win->hints.flags & PMinSize) {
+ minWidth = tmp_win->hints.min_width;
+ minHeight = tmp_win->hints.min_height;
+ } else if (tmp_win->hints.flags & PBaseSize) {
+ minWidth = tmp_win->hints.base_width;
+ minHeight = tmp_win->hints.base_height;
+ } else
+ minWidth = minHeight = 1;
+
+ if (tmp_win->hints.flags & PBaseSize) {
+ baseWidth = tmp_win->hints.base_width;
+ baseHeight = tmp_win->hints.base_height;
+ } else if (tmp_win->hints.flags & PMinSize) {
+ baseWidth = tmp_win->hints.min_width;
+ baseHeight = tmp_win->hints.min_height;
+ } else
+ baseWidth = baseHeight = 0;
+
+
+ if (tmp_win->hints.flags & PMaxSize) {
+ maxWidth = _min (Scr->MaxWindowWidth, tmp_win->hints.max_width);
+ maxHeight = _min (Scr->MaxWindowHeight, tmp_win->hints.max_height);
+ } else {
+ maxWidth = Scr->MaxWindowWidth;
+ maxHeight = Scr->MaxWindowHeight;
+ }
+
+ if (tmp_win->hints.flags & PResizeInc) {
+ xinc = tmp_win->hints.width_inc;
+ yinc = tmp_win->hints.height_inc;
+ } else
+ xinc = yinc = 1;
+
+ /*
+ * First, clamp to min and max values
+ */
+ if (dwidth < minWidth) dwidth = minWidth;
+ if (dheight < minHeight) dheight = minHeight;
+
+ if (dwidth > maxWidth) dwidth = maxWidth;
+ if (dheight > maxHeight) dheight = maxHeight;
+
+
+ /*
+ * Second, fit to base + N * inc
+ */
+ dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
+ dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
+
+
+ /*
+ * Third, adjust for aspect ratio
+ */
+#define maxAspectX tmp_win->hints.max_aspect.x
+#define maxAspectY tmp_win->hints.max_aspect.y
+#define minAspectX tmp_win->hints.min_aspect.x
+#define minAspectY tmp_win->hints.min_aspect.y
+ /*
+ * The math looks like this:
+ *
+ * minAspectX dwidth maxAspectX
+ * ---------- <= ------- <= ----------
+ * minAspectY dheight maxAspectY
+ *
+ * If that is multiplied out, then the width and height are
+ * invalid in the following situations:
+ *
+ * minAspectX * dheight > minAspectY * dwidth
+ * maxAspectX * dheight < maxAspectY * dwidth
+ *
+ */
+
+ if (tmp_win->hints.flags & PAspect)
+ {
+ if (minAspectX * dheight > minAspectY * dwidth)
+ {
+ delta = makemult(minAspectX * dheight / minAspectY - dwidth,
+ xinc);
+ if (dwidth + delta <= maxWidth) dwidth += delta;
+ else
+ {
+ delta = makemult(dheight - dwidth*minAspectY/minAspectX,
+ yinc);
+ if (dheight - delta >= minHeight) dheight -= delta;
+ }
+ }
+
+ if (maxAspectX * dheight < maxAspectY * dwidth)
+ {
+ delta = makemult(dwidth * maxAspectY / maxAspectX - dheight,
+ yinc);
+ if (dheight + delta <= maxHeight) dheight += delta;
+ else
+ {
+ delta = makemult(dwidth - maxAspectX*dheight/maxAspectY,
+ xinc);
+ if (dwidth - delta >= minWidth) dwidth -= delta;
+ }
+ }
+ }
+
+
+ /*
+ * Fourth, account for border width and title height
+ */
+ *widthp = dwidth;
+ *heightp = dheight + tmp_win->title_height;
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * SetupWindow - set window sizes, this was called from either
+ * AddWindow, EndResize, or HandleConfigureNotify.
+ *
+ * Inputs:
+ * tmp_win - the TwmWindow pointer
+ * x - the x coordinate of the upper-left outer corner of the frame
+ * y - the y coordinate of the upper-left outer corner of the frame
+ * w - the width of the frame window w/o border
+ * h - the height of the frame window w/o border
+ * bw - the border width of the frame window or -1 not to change
+ *
+ * Special Considerations:
+ * This routine will check to make sure the window is not completely
+ * off the display, if it is, it'll bring some of it back on.
+ *
+ * The tmp_win->frame_XXX variables should NOT be updated with the
+ * values of x,y,w,h prior to calling this routine, since the new
+ * values are compared against the old to see whether a synthetic
+ * ConfigureNotify event should be sent. (It should be sent if the
+ * window was moved but not resized.)
+ *
+ ***********************************************************************
+ */
+
+void SetupWindow (tmp_win, x, y, w, h, bw)
+ TwmWindow *tmp_win;
+ int x, y, w, h, bw;
+{
+ SetupFrame (tmp_win, x, y, w, h, bw, False);
+}
+
+void SetupFrame (tmp_win, x, y, w, h, bw, sendEvent)
+ TwmWindow *tmp_win;
+ int x, y, w, h, bw;
+ Bool sendEvent; /* whether or not to force a send */
+{
+ XEvent client_event;
+ XWindowChanges frame_wc, xwc;
+ unsigned long frame_mask, xwcm;
+ int title_width, title_height;
+ int reShape;
+
+#ifdef DEBUG
+ fprintf (stderr, "SetupWindow: x=%d, y=%d, w=%d, h=%d, bw=%d\n",
+ x, y, w, h, bw);
+#endif
+
+ if (x >= Scr->MyDisplayWidth)
+ x = Scr->MyDisplayWidth - 16; /* one "average" cursor width */
+ if (y >= Scr->MyDisplayHeight)
+ y = Scr->MyDisplayHeight - 16; /* one "average" cursor width */
+ if (bw < 0)
+ 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;
+ }
+
+ /*
+ * According to the July 27, 1988 ICCCM draft, we should send a
+ * "synthetic" ConfigureNotify event to the client if the window
+ * was moved but not resized.
+ */
+ if (((x != tmp_win->frame_x || y != tmp_win->frame_y) &&
+ (w == tmp_win->frame_width && h == tmp_win->frame_height)) ||
+ (bw != tmp_win->frame_bw))
+ sendEvent = TRUE;
+
+ xwcm = CWWidth;
+ title_width = xwc.width = w;
+ title_height = Scr->TitleHeight + bw;
+
+ 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 (title_width < xwc.width)
+ {
+ 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 = xwc.width;
+ }
+ }
+
+ tmp_win->title_width = title_width;
+ if (tmp_win->title_height) tmp_win->title_height = title_height;
+
+ if (tmp_win->title_w) {
+ if (bw != tmp_win->frame_bw) {
+ xwc.border_width = bw;
+ tmp_win->title_x = xwc.x = -bw;
+ tmp_win->title_y = xwc.y = -bw;
+ xwcm |= (CWX | CWY | CWBorderWidth);
+ }
+
+ XConfigureWindow(dpy, tmp_win->title_w, xwcm, &xwc);
+ }
+
+ if (tmp_win->attr.width != w)
+ tmp_win->widthEverChangedByUser = True;
+
+ if (tmp_win->attr.height != (h - tmp_win->title_height))
+ tmp_win->heightEverChangedByUser = True;
+
+ tmp_win->attr.width = w;
+ tmp_win->attr.height = h - tmp_win->title_height;
+
+ XMoveResizeWindow (dpy, tmp_win->w, 0, tmp_win->title_height,
+ w, h - tmp_win->title_height);
+
+ /*
+ * fix up frame and assign size/location values in tmp_win
+ */
+ frame_mask = 0;
+ if (bw != tmp_win->frame_bw) {
+ frame_wc.border_width = tmp_win->frame_bw = bw;
+ frame_mask |= CWBorderWidth;
+ }
+ frame_wc.x = tmp_win->frame_x = x;
+ frame_wc.y = tmp_win->frame_y = y;
+ frame_wc.width = tmp_win->frame_width = w;
+ frame_wc.height = tmp_win->frame_height = h;
+ frame_mask |= (CWX | CWY | CWWidth | CWHeight);
+ XConfigureWindow (dpy, tmp_win->frame, frame_mask, &frame_wc);
+
+ /*
+ * fix up highlight window
+ */
+ if (tmp_win->title_height && tmp_win->hilite_w)
+ {
+ xwc.width = (tmp_win->rightx - tmp_win->highlightx);
+ if (Scr->TBInfo.nright > 0) xwc.width -= Scr->TitlePadding;
+ if (xwc.width <= 0) {
+ xwc.x = Scr->MyDisplayWidth; /* move offscreen */
+ xwc.width = 1;
+ } else {
+ xwc.x = tmp_win->highlightx;
+ }
+
+ xwcm = CWX | CWWidth;
+ XConfigureWindow(dpy, tmp_win->hilite_w, xwcm, &xwc);
+ }
+
+ if (HasShape && reShape) {
+ SetFrameShape (tmp_win);
+ }
+
+ if (sendEvent)
+ {
+ client_event.type = ConfigureNotify;
+ client_event.xconfigure.display = dpy;
+ client_event.xconfigure.event = tmp_win->w;
+ client_event.xconfigure.window = tmp_win->w;
+ 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;
+ 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 ????? */
+ client_event.xconfigure.above = tmp_win->frame;
+ client_event.xconfigure.override_redirect = False;
+ XSendEvent(dpy, tmp_win->w, False, StructureNotifyMask, &client_event);
+ }
+}
+
+
+/**********************************************************************
+ * Rutgers mod #1 - rocky.
+ * Procedure:
+ * fullzoom - zooms window to full height of screen or
+ * to full height and width of screen. (Toggles
+ * so that it can undo the zoom - even when switching
+ * between fullzoom and vertical zoom.)
+ *
+ * Inputs:
+ * tmp_win - the TwmWindow pointer
+ *
+ *
+ **********************************************************************
+ */
+
+void
+fullzoom(tmp_win,flag)
+TwmWindow *tmp_win;
+int flag;
+{
+ Window junkRoot;
+ unsigned int junkbw, junkDepth;
+ int basex, basey;
+ int frame_bw_times_2;
+
+ XGetGeometry(dpy, (Drawable) tmp_win->frame, &junkRoot,
+ &dragx, &dragy, (unsigned int *)&dragWidth, (unsigned int *)&dragHeight, &junkbw,
+ &junkDepth);
+
+ basex = 0;
+ basey = 0;
+
+ if (tmp_win->zoomed == flag)
+ {
+ dragHeight = tmp_win->save_frame_height;
+ dragWidth = tmp_win->save_frame_width;
+ dragx = tmp_win->save_frame_x;
+ dragy = tmp_win->save_frame_y;
+ tmp_win->zoomed = ZOOM_NONE;
+ }
+ else
+ {
+ if (tmp_win->zoomed == ZOOM_NONE)
+ {
+ tmp_win->save_frame_x = dragx;
+ tmp_win->save_frame_y = dragy;
+ tmp_win->save_frame_width = dragWidth;
+ tmp_win->save_frame_height = dragHeight;
+ tmp_win->zoomed = flag;
+ }
+ else
+ tmp_win->zoomed = flag;
+
+
+ frame_bw_times_2 = 2*tmp_win->frame_bw;
+
+ switch (flag)
+ {
+ case ZOOM_NONE:
+ break;
+ case F_ZOOM:
+ dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
+ dragy=basey;
+ break;
+ case F_HORIZOOM:
+ dragx = basex;
+ dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
+ break;
+ case F_FULLZOOM:
+ dragx = basex;
+ dragy = basey;
+ dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
+ dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
+ break;
+ case F_LEFTZOOM:
+ dragx = basex;
+ dragy = basey;
+ dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
+ dragWidth = Scr->MyDisplayWidth/2 - frame_bw_times_2;
+ break;
+ case F_RIGHTZOOM:
+ dragx = basex + Scr->MyDisplayWidth/2;
+ dragy = basey;
+ dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
+ dragWidth = Scr->MyDisplayWidth/2 - frame_bw_times_2;
+ break;
+ case F_TOPZOOM:
+ dragx = basex;
+ dragy = basey;
+ dragHeight = Scr->MyDisplayHeight/2 - frame_bw_times_2;
+ dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
+ break;
+ case F_BOTTOMZOOM:
+ dragx = basex;
+ dragy = basey + Scr->MyDisplayHeight/2;
+ dragHeight = Scr->MyDisplayHeight/2 - frame_bw_times_2;
+ dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
+ break;
+ }
+ }
+
+ if (!Scr->NoRaiseResize)
+ XRaiseWindow(dpy, tmp_win->frame);
+
+ ConstrainSize(tmp_win, &dragWidth, &dragHeight);
+
+ SetupWindow (tmp_win, dragx , dragy , dragWidth, dragHeight, -1);
+ XUngrabPointer (dpy, CurrentTime);
+ XUngrabServer (dpy);
+}
+
+SetFrameShape (tmp)
+ TwmWindow *tmp;
+{
+ /*
+ * see if the titlebar needs to move
+ */
+ if (tmp->title_w) {
+ int oldx = tmp->title_x, oldy = tmp->title_y;
+ ComputeTitleLocation (tmp);
+ if (oldx != tmp->title_x || oldy != tmp->title_y)
+ XMoveWindow (dpy, tmp->title_w, tmp->title_x, tmp->title_y);
+ }
+
+ /*
+ * The frame consists of the shape of the contents window offset by
+ * title_height or'ed with the shape of title_w (which is always
+ * rectangular).
+ */
+ if (tmp->wShaped) {
+ /*
+ * need to do general case
+ */
+ XShapeCombineShape (dpy, tmp->frame, ShapeBounding,
+ 0, tmp->title_height, 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 {
+ /*
+ * can optimize rectangular contents window
+ */
+ if (tmp->squeeze_info) {
+ XRectangle newBounding[2];
+ XRectangle newClip[2];
+ int fbw2 = 2 * tmp->frame_bw;
+
+ /*
+ * Build the border clipping rectangles; one around title, one
+ * around window. The title_[xy] field already have had frame_bw
+ * subtracted off them so that they line up properly in the frame.
+ *
+ * The frame_width and frame_height do *not* include borders.
+ */
+ /* border */
+ newBounding[0].x = tmp->title_x;
+ newBounding[0].y = tmp->title_y;
+ 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].width = tmp->attr.width + fbw2;
+ newBounding[1].height = tmp->attr.height + fbw2;
+ XShapeCombineRectangles (dpy, tmp->frame, ShapeBounding, 0, 0,
+ newBounding, 2, ShapeSet, YXBanded);
+ /* insides */
+ newClip[0].x = tmp->title_x + tmp->frame_bw;
+ newClip[0].y = 0;
+ newClip[0].width = tmp->title_width;
+ newClip[0].height = Scr->TitleHeight;
+ newClip[1].x = 0;
+ newClip[1].y = tmp->title_height;
+ newClip[1].width = tmp->attr.width;
+ newClip[1].height = tmp->attr.height;
+ XShapeCombineRectangles (dpy, tmp->frame, ShapeClip, 0, 0,
+ newClip, 2, ShapeSet, YXBanded);
+ } else {
+ (void) XShapeCombineMask (dpy, tmp->frame, ShapeBounding, 0, 0,
+ None, ShapeSet);
+ (void) XShapeCombineMask (dpy, tmp->frame, ShapeClip, 0, 0,
+ None, ShapeSet);
+ }
+ }
+}
+
+/*
+ * Squeezed Title:
+ *
+ * tmp->title_x
+ * 0 |
+ * tmp->title_y ........+--------------+......... -+,- tmp->frame_bw
+ * 0 : ......| +----------+ |....... : -++
+ * : : | | | | : : ||-Scr->TitleHeight
+ * : : | | | | : : ||
+ * +-------+ +----------+ +--------+ -+|-tmp->title_height
+ * | +---------------------------+ | --+
+ * | | | |
+ * | | | |
+ * | | | |
+ * | | | |
+ * | | | |
+ * | +---------------------------+ |
+ * +-------------------------------+
+ *
+ *
+ * Unsqueezed Title:
+ *
+ * tmp->title_x
+ * | 0
+ * tmp->title_y +-------------------------------+ -+,tmp->frame_bw
+ * 0 | +---------------------------+ | -+'
+ * | | | | |-Scr->TitleHeight
+ * | | | | |
+ * + +---------------------------+ + -+
+ * |-+---------------------------+-|
+ * | | | |
+ * | | | |
+ * | | | |
+ * | | | |
+ * | | | |
+ * | +---------------------------+ |
+ * +-------------------------------+
+ *
+ *
+ *
+ * Dimensions and Positions:
+ *
+ * frame orgin (0, 0)
+ * frame upper left border (-tmp->frame_bw, -tmp->frame_bw)
+ * frame size w/o border tmp->frame_width , tmp->frame_height
+ * frame/title border width tmp->frame_bw
+ * extra title height w/o bdr tmp->title_height = TitleHeight + frame_bw
+ * title window height Scr->TitleHeight
+ * title origin w/o border (tmp->title_x, tmp->title_y)
+ * client origin (0, Scr->TitleHeight + tmp->frame_bw)
+ * client size tmp->attr.width , tmp->attr.height
+ *
+ * When shaping, need to remember that the width and height of rectangles
+ * are really deltax and deltay to lower right handle corner, so they need
+ * to have -1 subtracted from would normally be the actual extents.
+ */
diff --git a/src/resize.h b/src/resize.h
new file mode 100644
index 0000000..742045e
--- /dev/null
+++ b/src/resize.h
@@ -0,0 +1,77 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/**********************************************************************
+ *
+ * $Xorg: resize.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * resize function externs
+ *
+ * 8-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _RESIZE_
+#define _RESIZE_
+
+extern void StartResize();
+extern void AddStartResize();
+extern void DoResize();
+extern void DisplaySize();
+extern void EndResize();
+extern void AddEndResize();
+extern void SetupWindow();
+extern void SetupFrame();
+
+#endif /* _RESIZE_ */
+
+extern void fullzoom();
diff --git a/src/screen.h b/src/screen.h
new file mode 100644
index 0000000..c47bc70
--- /dev/null
+++ b/src/screen.h
@@ -0,0 +1,267 @@
+/*
+ *
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ * */
+
+/***********************************************************************
+ *
+ * $Xorg: screen.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * twm per-screen data include file
+ *
+ * 11-3-88 Dave Payne, Apple Computer File created
+ *
+ ***********************************************************************/
+
+#ifndef _SCREEN_
+#define _SCREEN_
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include "list.h"
+#include "menus.h"
+#include "iconmgr.h"
+
+typedef struct _StdCmap {
+ struct _StdCmap *next; /* next link in chain */
+ Atom atom; /* property from which this came */
+ int nmaps; /* number of maps below */
+ XStandardColormap *maps; /* the actual maps */
+} StdCmap;
+
+#define SIZE_HINDENT 10
+#define SIZE_VINDENT 2
+
+typedef struct _TitlebarPixmaps {
+ Pixmap xlogo;
+ Pixmap resize;
+ Pixmap question;
+ Pixmap menu;
+ Pixmap delete;
+} TitlebarPixmaps;
+
+typedef struct ScreenInfo
+{
+ int screen; /* the default screen */
+ int d_depth; /* copy of DefaultDepth(dpy, screen) */
+ Visual *d_visual; /* copy of DefaultVisual(dpy, screen) */
+ int Monochrome; /* is the display monochrome ? */
+ int MyDisplayWidth; /* my copy of DisplayWidth(dpy, screen) */
+ int MyDisplayHeight; /* my copy of DisplayHeight(dpy, screen) */
+ int MaxWindowWidth; /* largest window to allow */
+ int MaxWindowHeight; /* ditto */
+
+ TwmWindow TwmRoot; /* the head of the twm window list */
+
+ Window Root; /* the root window */
+ Window SizeWindow; /* the resize dimensions window */
+ Window InfoWindow; /* the information window */
+
+ name_list *Icons; /* list of icon pixmaps */
+ TitlebarPixmaps tbpm; /* titlebar pixmaps */
+ Pixmap UnknownPm; /* the unknown icon pixmap */
+ Pixmap siconifyPm; /* the icon manager iconify pixmap */
+ Pixmap pullPm; /* pull right menu icon */
+ int pullW, pullH; /* size of pull right menu icon */
+ Pixmap hilitePm; /* focus highlight window background */
+ int hilite_pm_width, hilite_pm_height; /* cache the size */
+
+ MenuRoot *MenuList; /* head of the menu list */
+ MenuRoot *LastMenu; /* the last menu (mostly unused?) */
+ MenuRoot *Windows; /* the TwmWindows menu */
+
+ TwmWindow *Ring; /* one of the windows in window ring */
+ TwmWindow *RingLeader; /* current winodw in ring */
+
+ MouseButton Mouse[MAX_BUTTONS+1][NUM_CONTEXTS][MOD_SIZE];
+ MouseButton DefaultFunction;
+ MouseButton WindowFunction;
+
+ struct {
+ Colormaps *cmaps; /* current list of colormap windows */
+ int maxCmaps; /* maximum number of installed colormaps */
+ unsigned long first_req; /* seq # for first XInstallColormap() req in
+ pass thru loading a colortable list */
+ int root_pushes; /* current push level to install root
+ colormap windows */
+ TwmWindow *pushed_window; /* saved window to install when pushes drops
+ to zero */
+ } cmapInfo;
+
+ struct {
+ StdCmap *head, *tail; /* list of maps */
+ StdCmap *mru; /* most recently used in list */
+ int mruindex; /* index of mru in entry */
+ } StdCmapInfo;
+
+ struct {
+ int nleft, nright; /* numbers of buttons in list */
+ TitleButton *head; /* start of list */
+ int border; /* button border */
+ int pad; /* button-padding */
+ int width; /* width of single button & border */
+ int leftx; /* start of left buttons */
+ int titlex; /* start of title string */
+ int rightoff; /* offset back from right edge */
+ } TBInfo;
+ ColorPair BorderTileC; /* border tile colors */
+ ColorPair TitleC; /* titlebar colors */
+ ColorPair MenuC; /* menu colors */
+ ColorPair MenuTitleC; /* menu title colors */
+ ColorPair IconC; /* icon colors */
+ ColorPair IconManagerC; /* icon manager colors */
+ XColor PointerForeground; /* pointer foreground color */
+ XColor PointerBackground; /* pointer background color */
+ ColorPair DefaultC; /* default colors */
+ Pixel BorderColor; /* color of window borders */
+ Pixel MenuShadowColor; /* menu shadow color */
+ Pixel IconBorderColor; /* icon border color */
+ Pixel IconManagerHighlight; /* icon manager highlight */
+
+ Cursor TitleCursor; /* title bar cursor */
+ Cursor FrameCursor; /* frame cursor */
+ Cursor IconCursor; /* icon cursor */
+ Cursor IconMgrCursor; /* icon manager cursor */
+ Cursor ButtonCursor; /* title bar button cursor */
+ Cursor MoveCursor; /* move cursor */
+ Cursor ResizeCursor; /* resize cursor */
+ Cursor WaitCursor; /* wait a while cursor */
+ Cursor MenuCursor; /* menu cursor */
+ Cursor SelectCursor; /* dot cursor for f.move, etc. from menus */
+ Cursor DestroyCursor; /* skull and cross bones, f.destroy */
+
+ name_list *BorderColorL;
+ name_list *IconBorderColorL;
+ name_list *BorderTileForegroundL;
+ name_list *BorderTileBackgroundL;
+ name_list *TitleForegroundL;
+ name_list *TitleBackgroundL;
+ name_list *IconForegroundL;
+ name_list *IconBackgroundL;
+ name_list *IconManagerFL;
+ name_list *IconManagerBL;
+ name_list *IconMgrs;
+ name_list *NoTitle; /* list of window names with no title bar */
+ name_list *MakeTitle; /* list of window names with title bar */
+ name_list *AutoRaise; /* list of window names to auto-raise */
+ name_list *IconNames; /* list of window names and icon names */
+ name_list *NoHighlight; /* list of windows to not highlight */
+ name_list *NoStackModeL; /* windows to ignore stack mode requests */
+ name_list *NoTitleHighlight;/* list of windows to not highlight the TB*/
+ name_list *DontIconify; /* don't iconify by unmapping */
+ name_list *IconMgrNoShow; /* don't show in the icon manager */
+ name_list *IconMgrShow; /* show in the icon manager */
+ name_list *IconifyByUn; /* windows to iconify by unmapping */
+ name_list *StartIconified; /* windows to start iconic */
+ name_list *IconManagerHighlightL; /* icon manager highlight colors */
+ name_list *SqueezeTitleL; /* windows of which to squeeze title */
+ name_list *DontSqueezeTitleL; /* windows of which not to squeeze */
+ name_list *WindowRingL; /* windows in ring */
+ name_list *WarpCursorL; /* windows to warp cursor to on deiconify */
+
+ GC NormalGC; /* normal GC for everything */
+ GC MenuGC; /* gc for menus */
+ GC DrawGC; /* GC to draw lines for move and resize */
+
+ unsigned long Black;
+ unsigned long White;
+ unsigned long XORvalue; /* number to use when drawing xor'ed */
+ MyFont TitleBarFont; /* title bar font structure */
+ MyFont MenuFont; /* menu font structure */
+ MyFont IconFont; /* icon font structure */
+ MyFont SizeFont; /* resize font structure */
+ MyFont IconManagerFont; /* window list font structure */
+ MyFont DefaultFont;
+ IconMgr iconmgr; /* default icon manager */
+ struct IconRegion *FirstRegion; /* pointer to icon regions */
+ struct IconRegion *LastRegion; /* pointer to the last icon region */
+ char *IconDirectory; /* icon directory to search */
+ int SizeStringOffset; /* x offset in size window for drawing */
+ int SizeStringWidth; /* minimum width of size window */
+ int BorderWidth; /* border width of twm windows */
+ int IconBorderWidth; /* border width of icon windows */
+ int UnknownWidth; /* width of the unknown icon */
+ int UnknownHeight; /* height of the unknown icon */
+ int TitleHeight; /* height of the title bar window */
+ TwmWindow *Focus; /* the twm window that has focus */
+ int EntryHeight; /* menu entry height */
+ int FramePadding; /* distance between decorations and border */
+ int TitlePadding; /* distance between items in titlebar */
+ int ButtonIndent; /* amount to shrink buttons on each side */
+ int NumAutoRaises; /* number of autoraise windows on screen */
+ short NoDefaults; /* do not add in default UI stuff */
+ short UsePPosition; /* what do with PPosition, see values below */
+ 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 ForceIcon; /* force the icon to the user specified */
+ short NoGrabServer; /* don't do server grabs */
+ short NoRaiseMove; /* don't raise window following move */
+ short NoRaiseResize; /* don't raise window following resize */
+ short NoRaiseDeicon; /* don't raise window on deiconify */
+ short NoRaiseWarp; /* don't raise window on warp */
+ short DontMoveOff; /* don't allow windows to be moved off */
+ short DoZoom; /* zoom in and out of icons */
+ short TitleFocus; /* focus on window in title bar ? */
+ short NoTitlebar; /* put title bars on windows */
+ short DecorateTransients; /* put title bars on transients */
+ short IconifyByUnmapping; /* simply unmap windows when iconifying */
+ short ShowIconManager; /* display the window list */
+ short IconManagerDontShow; /* show nothing in the icon manager */
+ short BackingStore; /* use backing store for menus */
+ short SaveUnder; /* use save under's for menus */
+ short RandomPlacement; /* randomly place windows that no give hints */
+ short OpaqueMove; /* move the window rather than outline */
+ short Highlight; /* should we highlight the window borders */
+ short StackMode; /* should we honor stack mode requests */
+ short TitleHighlight; /* should we highlight the titlebar */
+ short MoveDelta; /* number of pixels before f.move starts */
+ short ZoomCount; /* zoom outline count */
+ short SortIconMgr; /* sort entries in the icon manager */
+ short Shadow; /* show the menu shadow */
+ short InterpolateMenuColors;/* make pretty menus */
+ short NoIconManagers; /* Don't create any icon managers */
+ short ClientBorderWidth; /* respect client window border width */
+ short SqueezeTitle; /* make title as small as possible */
+ short HaveFonts; /* set if fonts have been loaded */
+ short FirstTime; /* first time we've read .twmrc */
+ short CaseSensitive; /* be case-sensitive when sorting names */
+ short WarpUnmapped; /* allow warping to unmapped windows */
+
+ FuncKey FuncKeyRoot;
+} ScreenInfo;
+
+extern int MultiScreen;
+extern int NumScreens;
+extern ScreenInfo **ScreenList;
+extern ScreenInfo *Scr;
+extern int FirstScreen;
+
+#define PPOS_OFF 0
+#define PPOS_ON 1
+#define PPOS_NON_ZERO 2
+/* may eventually want an option for having the PPosition be the initial
+ location for the drag lines */
+
+#endif /* _SCREEN_ */
diff --git a/src/session.c b/src/session.c
new file mode 100644
index 0000000..992f8f2
--- /dev/null
+++ b/src/session.c
@@ -0,0 +1,1054 @@
+/* $Xorg: session.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $ */
+/******************************************************************************
+
+Copyright 1994, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+Author: Ralph Mor, X Consortium
+******************************************************************************/
+
+#include <X11/Xos.h>
+
+#ifndef X_NOT_POSIX
+#ifdef _POSIX_SOURCE
+#include <limits.h>
+#else
+#define _POSIX_SOURCE
+#include <limits.h>
+#undef _POSIX_SOURCE
+#endif
+#endif /* X_NOT_POSIX */
+#ifndef PATH_MAX
+#include <sys/param.h>
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+#endif /* PATH_MAX */
+
+#include <X11/Xlib.h>
+#include <X11/SM/SMlib.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include "twm.h"
+#include "screen.h"
+
+SmcConn smcConn = NULL;
+XtInputId iceInputId;
+char *twm_clientId;
+TWMWinConfigEntry *winConfigHead = NULL;
+Bool gotFirstSave = 0;
+Bool sent_save_done = 0;
+
+#define SAVEFILE_VERSION 2
+
+
+
+char *
+GetClientID (window)
+
+Window window;
+
+{
+ char *client_id = NULL;
+ Window client_leader;
+ XTextProperty tp;
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ unsigned char *prop = NULL;
+
+ if (XGetWindowProperty (dpy, window, _XA_WM_CLIENT_LEADER,
+ 0L, 1L, False, AnyPropertyType, &actual_type, &actual_format,
+ &nitems, &bytes_after, &prop) == Success)
+ {
+ if (actual_type == XA_WINDOW && actual_format == 32 &&
+ nitems == 1 && bytes_after == 0)
+ {
+ client_leader = *((Window *) prop);
+
+ if (XGetTextProperty (dpy, client_leader, &tp, _XA_SM_CLIENT_ID))
+ {
+ if (tp.encoding == XA_STRING &&
+ tp.format == 8 && tp.nitems != 0)
+ client_id = (char *) tp.value;
+ }
+ }
+
+ if (prop)
+ XFree (prop);
+ }
+
+ return client_id;
+}
+
+
+
+char *
+GetWindowRole (window)
+
+Window window;
+
+{
+ XTextProperty tp;
+
+ if (XGetTextProperty (dpy, window, &tp, _XA_WM_WINDOW_ROLE))
+ {
+ if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0)
+ return ((char *) tp.value);
+ }
+
+ return NULL;
+}
+
+
+
+int
+write_byte (file, b)
+
+FILE *file;
+unsigned char b;
+
+{
+ if (fwrite ((char *) &b, 1, 1, file) != 1)
+ return 0;
+ return 1;
+}
+
+
+int
+write_ushort (file, s)
+
+FILE *file;
+unsigned short s;
+
+{
+ unsigned char file_short[2];
+
+ file_short[0] = (s & (unsigned)0xff00) >> 8;
+ file_short[1] = s & 0xff;
+ if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
+ return 0;
+ return 1;
+}
+
+
+int
+write_short (file, s)
+
+FILE *file;
+short s;
+
+{
+ unsigned char file_short[2];
+
+ file_short[0] = (s & (unsigned)0xff00) >> 8;
+ file_short[1] = s & 0xff;
+ if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
+ return 0;
+ return 1;
+}
+
+
+int
+write_counted_string (file, string)
+
+FILE *file;
+char *string;
+
+{
+ if (string)
+ {
+ unsigned char count = strlen (string);
+
+ if (write_byte (file, count) == 0)
+ return 0;
+ if (fwrite (string, (int) sizeof (char), (int) count, file) != count)
+ return 0;
+ }
+ else
+ {
+ if (write_byte (file, 0) == 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+
+int
+read_byte (file, bp)
+
+FILE *file;
+unsigned char *bp;
+
+{
+ if (fread ((char *) bp, 1, 1, file) != 1)
+ return 0;
+ return 1;
+}
+
+
+int
+read_ushort (file, shortp)
+
+FILE *file;
+unsigned short *shortp;
+
+{
+ unsigned char file_short[2];
+
+ if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
+ return 0;
+ *shortp = file_short[0] * 256 + file_short[1];
+ return 1;
+}
+
+
+int
+read_short (file, shortp)
+
+FILE *file;
+short *shortp;
+
+{
+ unsigned char file_short[2];
+
+ if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
+ return 0;
+ *shortp = file_short[0] * 256 + file_short[1];
+ return 1;
+}
+
+
+int
+read_counted_string (file, stringp)
+
+FILE *file;
+char **stringp;
+
+{
+ unsigned char len;
+ char *data;
+
+ if (read_byte (file, &len) == 0)
+ return 0;
+ if (len == 0) {
+ data = 0;
+ } else {
+ data = malloc ((unsigned) len + 1);
+ if (!data)
+ return 0;
+ if (fread (data, (int) sizeof (char), (int) len, file) != len) {
+ free (data);
+ return 0;
+ }
+ data[len] = '\0';
+ }
+ *stringp = data;
+ return 1;
+}
+
+
+
+/*
+ * An entry in the saved window config file looks like this:
+ *
+ * FIELD BYTES
+ * ----- ----
+ * SM_CLIENT_ID ID len 1 (may be 0)
+ * SM_CLIENT_ID LIST of bytes (may be NULL)
+ *
+ * WM_WINDOW_ROLE length 1 (may be 0)
+ * WM_WINDOW_ROLE LIST of bytes (may be NULL)
+ *
+ * if no WM_WINDOW_ROLE (length = 0)
+ *
+ * WM_CLASS "res name" length 1
+ * WM_CLASS "res name" LIST of bytes
+ * WM_CLASS "res class" length 1
+ * WM_CLASS "res class" LIST of bytes
+ * WM_NAME length 1 (0 if name changed)
+ * WM_NAME LIST of bytes
+ * WM_COMMAND arg count 1 (0 if no SM_CLIENT_ID)
+ * For each arg in WM_COMMAND
+ * arg length 1
+ * arg LIST of bytes
+ *
+ * Iconified bool 1
+ * Icon info present bool 1
+ *
+ * if icon info present
+ * icon x 2
+ * icon y 2
+ *
+ * Geom x 2
+ * Geom y 2
+ * Geom width 2
+ * Geom height 2
+ *
+ * Width ever changed by user 1
+ * Height ever changed by user 1
+ */
+
+int
+WriteWinConfigEntry (configFile, theWindow, clientId, windowRole)
+
+FILE *configFile;
+TwmWindow *theWindow;
+char *clientId;
+char *windowRole;
+
+{
+ char **wm_command;
+ int wm_command_count, i;
+
+ if (!write_counted_string (configFile, clientId))
+ return 0;
+
+ if (!write_counted_string (configFile, windowRole))
+ return 0;
+
+ if (!windowRole)
+ {
+ if (!write_counted_string (configFile, theWindow->class.res_name))
+ return 0;
+ if (!write_counted_string (configFile, theWindow->class.res_class))
+ return 0;
+ if (theWindow->nameChanged)
+ {
+ /*
+ * If WM_NAME changed on this window, we can't use it as
+ * a criteria for looking up window configurations. See the
+ * longer explanation in the GetWindowConfig() function below.
+ */
+
+ if (!write_counted_string (configFile, NULL))
+ return 0;
+ }
+ else
+ {
+ if (!write_counted_string (configFile, theWindow->name))
+ return 0;
+ }
+
+ wm_command = NULL;
+ wm_command_count = 0;
+ XGetCommand (dpy, theWindow->w, &wm_command, &wm_command_count);
+
+ if (clientId || !wm_command || wm_command_count == 0)
+ {
+ if (!write_byte (configFile, 0))
+ return 0;
+ }
+ else
+ {
+ if (!write_byte (configFile, (char) wm_command_count))
+ return 0;
+ for (i = 0; i < wm_command_count; i++)
+ if (!write_counted_string (configFile, wm_command[i]))
+ return 0;
+ XFreeStringList (wm_command);
+ }
+ }
+
+ if (!write_byte (configFile, theWindow->icon ? 1 : 0)) /* iconified */
+ return 0;
+
+ if (!write_byte (configFile, theWindow->icon_w ? 1 : 0)) /* icon exists */
+ return 0;
+
+ if (theWindow->icon_w)
+ {
+ int icon_x, icon_y;
+
+ XGetGeometry (dpy, theWindow->icon_w, &JunkRoot, &icon_x,
+ &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth);
+
+ if (!write_short (configFile, (short) icon_x))
+ return 0;
+ if (!write_short (configFile, (short) icon_y))
+ return 0;
+ }
+
+ if (!write_short (configFile, (short) theWindow->frame_x))
+ return 0;
+ if (!write_short (configFile, (short) theWindow->frame_y))
+ return 0;
+ if (!write_ushort (configFile, (unsigned short) theWindow->attr.width))
+ return 0;
+ if (!write_ushort (configFile, (unsigned short) theWindow->attr.height))
+ return 0;
+
+ if (!write_byte (configFile, theWindow->widthEverChangedByUser ? 1 : 0))
+ return 0;
+
+ if (!write_byte (configFile, theWindow->heightEverChangedByUser ? 1 : 0))
+ return 0;
+
+ return 1;
+}
+
+
+int
+ReadWinConfigEntry (configFile, version, pentry)
+
+FILE *configFile;
+unsigned short version;
+TWMWinConfigEntry **pentry;
+
+{
+ TWMWinConfigEntry *entry;
+ unsigned char byte;
+ int i;
+
+ *pentry = entry = (TWMWinConfigEntry *) malloc (
+ sizeof (TWMWinConfigEntry));
+ if (!*pentry)
+ return 0;
+
+ entry->tag = 0;
+ entry->client_id = NULL;
+ entry->window_role = NULL;
+ entry->class.res_name = NULL;
+ entry->class.res_class = NULL;
+ entry->wm_name = NULL;
+ entry->wm_command = NULL;
+ entry->wm_command_count = 0;
+
+ if (!read_counted_string (configFile, &entry->client_id))
+ goto give_up;
+
+ if (!read_counted_string (configFile, &entry->window_role))
+ goto give_up;
+
+ if (!entry->window_role)
+ {
+ if (!read_counted_string (configFile, &entry->class.res_name))
+ goto give_up;
+ if (!read_counted_string (configFile, &entry->class.res_class))
+ goto give_up;
+ if (!read_counted_string (configFile, &entry->wm_name))
+ goto give_up;
+
+ if (!read_byte (configFile, &byte))
+ goto give_up;
+ entry->wm_command_count = byte;
+
+ if (entry->wm_command_count == 0)
+ entry->wm_command = NULL;
+ else
+ {
+ entry->wm_command = (char **) malloc (entry->wm_command_count *
+ sizeof (char *));
+
+ if (!entry->wm_command)
+ goto give_up;
+
+ for (i = 0; i < entry->wm_command_count; i++)
+ if (!read_counted_string (configFile, &entry->wm_command[i]))
+ goto give_up;
+ }
+ }
+
+ if (!read_byte (configFile, &byte))
+ goto give_up;
+ entry->iconified = byte;
+
+ if (!read_byte (configFile, &byte))
+ goto give_up;
+ entry->icon_info_present = byte;
+
+ if (entry->icon_info_present)
+ {
+ if (!read_short (configFile, (short *) &entry->icon_x))
+ goto give_up;
+ if (!read_short (configFile, (short *) &entry->icon_y))
+ goto give_up;
+ }
+
+ if (!read_short (configFile, (short *) &entry->x))
+ goto give_up;
+ if (!read_short (configFile, (short *) &entry->y))
+ goto give_up;
+ if (!read_ushort (configFile, &entry->width))
+ goto give_up;
+ if (!read_ushort (configFile, &entry->height))
+ goto give_up;
+
+ if (version > 1)
+ {
+ if (!read_byte (configFile, &byte))
+ goto give_up;
+ entry->width_ever_changed_by_user = byte;
+
+ if (!read_byte (configFile, &byte))
+ goto give_up;
+ entry->height_ever_changed_by_user = byte;
+ }
+ else
+ {
+ entry->width_ever_changed_by_user = False;
+ entry->height_ever_changed_by_user = False;
+ }
+
+ return 1;
+
+give_up:
+
+ if (entry->client_id)
+ free (entry->client_id);
+ if (entry->window_role)
+ free (entry->window_role);
+ if (entry->class.res_name)
+ free (entry->class.res_name);
+ if (entry->class.res_class)
+ free (entry->class.res_class);
+ if (entry->wm_name)
+ free (entry->wm_name);
+ if (entry->wm_command_count)
+ {
+ for (i = 0; i < entry->wm_command_count; i++)
+ if (entry->wm_command[i])
+ free (entry->wm_command[i]);
+ }
+ if (entry->wm_command)
+ free ((char *) entry->wm_command);
+
+ free ((char *) entry);
+ *pentry = NULL;
+
+ return 0;
+}
+
+
+void
+ReadWinConfigFile (filename)
+
+char *filename;
+
+{
+ FILE *configFile;
+ TWMWinConfigEntry *entry;
+ int done = 0;
+ unsigned short version;
+
+ configFile = fopen (filename, "rb");
+ if (!configFile)
+ return;
+
+ if (!read_ushort (configFile, &version) ||
+ version > SAVEFILE_VERSION)
+ {
+ done = 1;
+ }
+
+ while (!done)
+ {
+ if (ReadWinConfigEntry (configFile, version, &entry))
+ {
+ entry->next = winConfigHead;
+ winConfigHead = entry;
+ }
+ else
+ done = 1;
+ }
+
+ fclose (configFile);
+}
+
+
+
+int
+GetWindowConfig (theWindow, x, y, width, height,
+ iconified, icon_info_present, icon_x, icon_y,
+ width_ever_changed_by_user, height_ever_changed_by_user)
+
+TwmWindow *theWindow;
+short *x, *y;
+unsigned short *width, *height;
+Bool *iconified;
+Bool *icon_info_present;
+short *icon_x, *icon_y;
+Bool *width_ever_changed_by_user;
+Bool *height_ever_changed_by_user;
+
+{
+ char *clientId, *windowRole;
+ TWMWinConfigEntry *ptr;
+ int found = 0;
+
+ ptr = winConfigHead;
+
+ if (!ptr)
+ return 0;
+
+ clientId = GetClientID (theWindow->w);
+ windowRole = GetWindowRole (theWindow->w);
+
+ while (ptr && !found)
+ {
+ int client_id_match = (!clientId && !ptr->client_id) ||
+ (clientId && ptr->client_id &&
+ strcmp (clientId, ptr->client_id) == 0);
+
+ if (!ptr->tag && client_id_match)
+ {
+ if (windowRole || ptr->window_role)
+ {
+ found = (windowRole && ptr->window_role &&
+ strcmp (windowRole, ptr->window_role) == 0);
+ }
+ else
+ {
+ /*
+ * Compare WM_CLASS + only compare WM_NAME if the
+ * WM_NAME in the saved file is non-NULL. If the
+ * WM_NAME in the saved file is NULL, this means that
+ * the client changed the value of WM_NAME during the
+ * session, and we can not use it as a criteria for
+ * our search. For example, with xmh, at save time
+ * the window name might be "xmh: folderY". However,
+ * if xmh does not properly restore state when it is
+ * restarted, the initial window name might be
+ * "xmh: folderX". This would cause the window manager
+ * to fail in finding the saved window configuration.
+ * The best we can do is ignore WM_NAME if its value
+ * changed in the previous session.
+ */
+
+ if (strcmp (theWindow->class.res_name,
+ ptr->class.res_name) == 0 &&
+ strcmp (theWindow->class.res_class,
+ ptr->class.res_class) == 0 &&
+ (ptr->wm_name == NULL ||
+ strcmp (theWindow->name, ptr->wm_name) == 0))
+ {
+ if (clientId)
+ {
+ /*
+ * If a client ID was present, we should not check
+ * WM_COMMAND because Xt will put a -xtsessionID arg
+ * on the command line.
+ */
+
+ found = 1;
+ }
+ else
+ {
+ /*
+ * For non-XSMP clients, also check WM_COMMAND.
+ */
+
+ char **wm_command = NULL;
+ int wm_command_count = 0, i;
+
+ XGetCommand (dpy, theWindow->w,
+ &wm_command, &wm_command_count);
+
+ if (wm_command_count == ptr->wm_command_count)
+ {
+ for (i = 0; i < wm_command_count; i++)
+ if (strcmp (wm_command[i],
+ ptr->wm_command[i]) != 0)
+ break;
+
+ if (i == wm_command_count)
+ found = 1;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found)
+ ptr = ptr->next;
+ }
+
+ if (found)
+ {
+ *x = ptr->x;
+ *y = ptr->y;
+ *width = ptr->width;
+ *height = ptr->height;
+ *iconified = ptr->iconified;
+ *icon_info_present = ptr->icon_info_present;
+ *width_ever_changed_by_user = ptr->width_ever_changed_by_user;
+ *height_ever_changed_by_user = ptr->height_ever_changed_by_user;
+
+ if (*icon_info_present)
+ {
+ *icon_x = ptr->icon_x;
+ *icon_y = ptr->icon_y;
+ }
+ ptr->tag = 1;
+ }
+ else
+ *iconified = 0;
+
+ if (clientId)
+ XFree (clientId);
+
+ if (windowRole)
+ XFree (windowRole);
+
+ return found;
+}
+
+
+
+static char *
+unique_filename (path, prefix)
+
+char *path;
+char *prefix;
+
+{
+#ifndef X_NOT_POSIX
+ return ((char *) tempnam (path, prefix));
+#else
+ char tempFile[PATH_MAX];
+ char *tmp;
+
+ sprintf (tempFile, "%s/%sXXXXXX", path, prefix);
+ tmp = (char *) mktemp (tempFile);
+ if (tmp)
+ {
+ char *ptr = (char *) malloc (strlen (tmp) + 1);
+ strcpy (ptr, tmp);
+ return (ptr);
+ }
+ else
+ return (NULL);
+#endif
+}
+
+
+
+void
+SaveYourselfPhase2CB (smcConn, clientData)
+
+SmcConn smcConn;
+SmPointer clientData;
+
+{
+ int scrnum;
+ ScreenInfo *theScreen;
+ TwmWindow *theWindow;
+ char *clientId, *windowRole;
+ FILE *configFile = NULL;
+ char *path;
+ char *filename = NULL;
+ Bool success = False;
+ SmProp prop1, prop2, prop3, *props[3];
+ SmPropValue prop1val, prop2val, prop3val;
+ char discardCommand[80];
+ int numVals, i;
+ static int first_time = 1;
+
+ if (first_time)
+ {
+ char userId[20];
+ char hint = SmRestartIfRunning;
+
+ prop1.name = SmProgram;
+ prop1.type = SmARRAY8;
+ prop1.num_vals = 1;
+ prop1.vals = &prop1val;
+ prop1val.value = Argv[0];
+ prop1val.length = strlen (Argv[0]);
+
+ sprintf (userId, "%d", getuid());
+ prop2.name = SmUserID;
+ prop2.type = SmARRAY8;
+ prop2.num_vals = 1;
+ prop2.vals = &prop2val;
+ prop2val.value = (SmPointer) userId;
+ prop2val.length = strlen (userId);
+
+ prop3.name = SmRestartStyleHint;
+ prop3.type = SmCARD8;
+ prop3.num_vals = 1;
+ prop3.vals = &prop3val;
+ prop3val.value = (SmPointer) &hint;
+ prop3val.length = 1;
+
+ props[0] = &prop1;
+ props[1] = &prop2;
+ props[2] = &prop3;
+
+ SmcSetProperties (smcConn, 3, props);
+
+ first_time = 0;
+ }
+
+ path = getenv ("SM_SAVE_DIR");
+ if (!path)
+ {
+ path = getenv ("HOME");
+ if (!path)
+ path = ".";
+ }
+
+ if ((filename = unique_filename (path, ".twm")) == NULL)
+ goto bad;
+
+ if (!(configFile = fopen (filename, "wb")))
+ goto bad;
+
+ if (!write_ushort (configFile, SAVEFILE_VERSION))
+ goto bad;
+
+ success = True;
+
+ for (scrnum = 0; scrnum < NumScreens && success; scrnum++)
+ {
+ if (ScreenList[scrnum] != NULL)
+ {
+ theScreen = ScreenList[scrnum];
+ theWindow = theScreen->TwmRoot.next;
+
+ while (theWindow && success)
+ {
+ clientId = GetClientID (theWindow->w);
+ windowRole = GetWindowRole (theWindow->w);
+
+ if (!WriteWinConfigEntry (configFile, theWindow,
+ clientId, windowRole))
+ success = False;
+
+ if (clientId)
+ XFree (clientId);
+
+ if (windowRole)
+ XFree (windowRole);
+
+ theWindow = theWindow->next;
+ }
+ }
+ }
+
+ prop1.name = SmRestartCommand;
+ prop1.type = SmLISTofARRAY8;
+
+ prop1.vals = (SmPropValue *) malloc (
+ (Argc + 4) * sizeof (SmPropValue));
+
+ if (!prop1.vals)
+ {
+ success = False;
+ goto bad;
+ }
+
+ numVals = 0;
+
+ for (i = 0; i < Argc; i++)
+ {
+ if (strcmp (Argv[i], "-clientId") == 0 ||
+ strcmp (Argv[i], "-restore") == 0)
+ {
+ i++;
+ }
+ else
+ {
+ prop1.vals[numVals].value = (SmPointer) Argv[i];
+ prop1.vals[numVals++].length = strlen (Argv[i]);
+ }
+ }
+
+ prop1.vals[numVals].value = (SmPointer) "-clientId";
+ prop1.vals[numVals++].length = 9;
+
+ prop1.vals[numVals].value = (SmPointer) twm_clientId;
+ prop1.vals[numVals++].length = strlen (twm_clientId);
+
+ prop1.vals[numVals].value = (SmPointer) "-restore";
+ prop1.vals[numVals++].length = 8;
+
+ prop1.vals[numVals].value = (SmPointer) filename;
+ prop1.vals[numVals++].length = strlen (filename);
+
+ prop1.num_vals = numVals;
+
+ sprintf (discardCommand, "rm %s", filename);
+ prop2.name = SmDiscardCommand;
+ prop2.type = SmARRAY8;
+ prop2.num_vals = 1;
+ prop2.vals = &prop2val;
+ prop2val.value = (SmPointer) discardCommand;
+ prop2val.length = strlen (discardCommand);
+
+ props[0] = &prop1;
+ props[1] = &prop2;
+
+ SmcSetProperties (smcConn, 2, props);
+ free ((char *) prop1.vals);
+
+ bad:
+ SmcSaveYourselfDone (smcConn, success);
+ sent_save_done = 1;
+
+ if (configFile)
+ fclose (configFile);
+
+ if (filename)
+ free (filename);
+}
+
+
+
+void
+SaveYourselfCB (smcConn, clientData, saveType, shutdown, interactStyle, fast)
+
+SmcConn smcConn;
+SmPointer clientData;
+int saveType;
+Bool shutdown;
+int interactStyle;
+Bool fast;
+
+{
+ if (!SmcRequestSaveYourselfPhase2 (smcConn, SaveYourselfPhase2CB, NULL))
+ {
+ SmcSaveYourselfDone (smcConn, False);
+ sent_save_done = 1;
+ }
+ else
+ sent_save_done = 0;
+}
+
+
+
+void
+DieCB (smcConn, clientData)
+
+SmcConn smcConn;
+SmPointer clientData;
+
+{
+ SmcCloseConnection (smcConn, 0, NULL);
+ XtRemoveInput (iceInputId);
+ Done();
+}
+
+
+
+void
+SaveCompleteCB (smcConn, clientData)
+
+SmcConn smcConn;
+SmPointer clientData;
+
+{
+ ;
+}
+
+
+
+void
+ShutdownCancelledCB (smcConn, clientData)
+
+SmcConn smcConn;
+SmPointer clientData;
+
+{
+ if (!sent_save_done)
+ {
+ SmcSaveYourselfDone (smcConn, False);
+ sent_save_done = 1;
+ }
+}
+
+
+
+void
+ProcessIceMsgProc (client_data, source, id)
+
+XtPointer client_data;
+int *source;
+XtInputId *id;
+
+{
+ IceConn ice_conn = (IceConn) client_data;
+
+ IceProcessMessages (ice_conn, NULL, NULL);
+}
+
+
+
+void
+ConnectToSessionManager (previous_id)
+
+char *previous_id;
+
+{
+ char errorMsg[256];
+ unsigned long mask;
+ SmcCallbacks callbacks;
+ IceConn iceConn;
+
+ mask = SmcSaveYourselfProcMask | SmcDieProcMask |
+ SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
+
+ callbacks.save_yourself.callback = SaveYourselfCB;
+ callbacks.save_yourself.client_data = (SmPointer) NULL;
+
+ callbacks.die.callback = DieCB;
+ callbacks.die.client_data = (SmPointer) NULL;
+
+ callbacks.save_complete.callback = SaveCompleteCB;
+ callbacks.save_complete.client_data = (SmPointer) NULL;
+
+ callbacks.shutdown_cancelled.callback = ShutdownCancelledCB;
+ callbacks.shutdown_cancelled.client_data = (SmPointer) NULL;
+
+ smcConn = SmcOpenConnection (
+ NULL, /* use SESSION_MANAGER env */
+ (SmPointer) appContext,
+ SmProtoMajor,
+ SmProtoMinor,
+ mask,
+ &callbacks,
+ previous_id,
+ &twm_clientId,
+ 256, errorMsg);
+
+ if (smcConn == NULL)
+ return;
+
+ iceConn = SmcGetIceConnection (smcConn);
+
+ iceInputId = XtAppAddInput (
+ appContext,
+ IceConnectionNumber (iceConn),
+ (XtPointer) XtInputReadMask,
+ ProcessIceMsgProc,
+ (XtPointer) iceConn);
+}
+
+
+
diff --git a/src/siconify.bm b/src/siconify.bm
new file mode 100644
index 0000000..d6402b6
--- /dev/null
+++ b/src/siconify.bm
@@ -0,0 +1,5 @@
+#define siconify_width 11
+#define siconify_height 11
+static unsigned char siconify_bits[] = {
+ 0xff, 0x07, 0x01, 0x04, 0x0d, 0x05, 0x9d, 0x05, 0xb9, 0x04, 0x51, 0x04,
+ 0xe9, 0x04, 0xcd, 0x05, 0x85, 0x05, 0x01, 0x04, 0xff, 0x07};
diff --git a/src/system.twmrc b/src/system.twmrc
new file mode 100644
index 0000000..421f8d5
--- /dev/null
+++ b/src/system.twmrc
@@ -0,0 +1,89 @@
+#
+# $Xorg: system.twmrc,v 1.3 2000/08/17 19:54:08 cpqbld Exp $
+#
+# Default twm configuration file; needs to be kept small to conserve string
+# space in systems whose compilers don't handle medium-sized strings.
+#
+# Sites should tailor this file, providing any extra title buttons, menus, etc.
+# that may be appropriate for their environment. For example, if most of the
+# users were accustomed to uwm, the defaults could be set up not to decorate
+# any windows and to use meta-keys.
+#
+
+NoGrabServer
+RestartPreviousState
+DecorateTransients
+TitleFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*"
+ResizeFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*"
+MenuFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*"
+IconFont "-adobe-helvetica-bold-r-normal--*-100-*-*-*-*-*-*"
+IconManagerFont "-adobe-helvetica-bold-r-normal--*-100-*-*-*"
+#ClientBorderWidth
+
+Color
+{
+ BorderColor "slategrey"
+ DefaultBackground "rgb:2/a/9"
+ DefaultForeground "gray85"
+ TitleBackground "rgb:2/a/9"
+ TitleForeground "gray85"
+ MenuBackground "rgb:2/a/9"
+ MenuForeground "gray85"
+ MenuTitleBackground "gray70"
+ MenuTitleForeground "rgb:2/a/9"
+ IconBackground "rgb:2/a/9"
+ IconForeground "gray85"
+ IconBorderColor "gray85"
+ IconManagerBackground "rgb:2/a/9"
+ IconManagerForeground "gray85"
+}
+
+#
+# Define some useful functions for motion-based actions.
+#
+MoveDelta 3
+Function "move-or-lower" { f.move f.deltastop f.lower }
+Function "move-or-raise" { f.move f.deltastop f.raise }
+Function "move-or-iconify" { f.move f.deltastop f.iconify }
+
+#
+# Set some useful bindings. Sort of uwm-ish, sort of simple-button-ish
+#
+Button1 = : root : f.menu "defops"
+
+Button1 = m : window|icon : f.function "move-or-lower"
+Button2 = m : window|icon : f.iconify
+Button3 = m : window|icon : f.function "move-or-raise"
+
+Button1 = : title : f.function "move-or-raise"
+Button2 = : title : f.raiselower
+
+Button1 = : icon : f.function "move-or-iconify"
+Button2 = : icon : f.iconify
+
+Button1 = : iconmgr : f.iconify
+Button2 = : iconmgr : f.iconify
+
+#
+# And a menus with the usual things
+#
+menu "defops"
+{
+"Twm" f.title
+"Iconify" f.iconify
+"Resize" f.resize
+"Move" f.move
+"Raise" f.raise
+"Lower" f.lower
+"" f.nop
+"Focus" f.focus
+"Unfocus" f.unfocus
+"Show Iconmgr" f.showiconmgr
+"Hide Iconmgr" f.hideiconmgr
+"" f.nop
+"Kill" f.destroy
+"Delete" f.delete
+"" f.nop
+"Restart" f.restart
+"Exit" f.quit
+}
diff --git a/src/twm.c b/src/twm.c
new file mode 100644
index 0000000..900acc0
--- /dev/null
+++ b/src/twm.c
@@ -0,0 +1,898 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/***********************************************************************
+ *
+ * $Xorg: twm.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * twm - "Tom's Window Manager"
+ *
+ * 27-Oct-87 Thomas E. LaStrange File created
+ * 10-Oct-90 David M. Sternlicht Storing saved colors on root
+ ***********************************************************************/
+
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include "twm.h"
+#include "add_window.h"
+#include "gc.h"
+#include "parse.h"
+#include "version.h"
+#include "menus.h"
+#include "events.h"
+#include "util.h"
+#include "gram.h"
+#include "screen.h"
+#include "iconmgr.h"
+#include <X11/Xproto.h>
+#include <X11/Xatom.h>
+#include <X11/SM/SMlib.h>
+
+XtAppContext appContext; /* Xt application context */
+
+Display *dpy; /* which display are we talking to */
+Window ResizeWindow; /* the window we are resizing */
+
+int MultiScreen = TRUE; /* try for more than one screen? */
+int NumScreens; /* number of screens in ScreenList */
+int HasShape; /* server supports shape extension? */
+int ShapeEventBase, ShapeErrorBase;
+int HasSync; /* server supports SYNC extension? */
+int SyncEventBase, SyncErrorBase;
+ScreenInfo **ScreenList; /* structures for each screen */
+ScreenInfo *Scr = NULL; /* the cur and prev screens */
+int PreviousScreen; /* last screen that we were on */
+int FirstScreen; /* TRUE ==> first screen of display */
+Bool PrintErrorMessages = False; /* controls error messages */
+static int RedirectError; /* TRUE ==> another window manager running */
+static int CatchRedirectError(); /* for settting RedirectError */
+static int TwmErrorHandler(); /* for everything else */
+char Info[INFO_LINES][INFO_SIZE]; /* info strings to print */
+int InfoLines;
+char *InitFile = NULL;
+
+Cursor UpperLeftCursor; /* upper Left corner cursor */
+Cursor RightButt;
+Cursor MiddleButt;
+Cursor LeftButt;
+
+XContext TwmContext; /* context for twm windows */
+XContext MenuContext; /* context for all menu windows */
+XContext IconManagerContext; /* context for all window list windows */
+XContext ScreenContext; /* context to get screen data */
+XContext ColormapContext; /* context for colormap operations */
+
+XClassHint NoClass; /* for applications with no class */
+
+XGCValues Gcv;
+
+char *Home; /* the HOME environment variable */
+int HomeLen; /* length of Home */
+int ParseError; /* error parsing the .twmrc file */
+
+int HandlingEvents = FALSE; /* are we handling events yet? */
+
+Window JunkRoot; /* junk window */
+Window JunkChild; /* junk window */
+int JunkX; /* junk variable */
+int JunkY; /* junk variable */
+unsigned int JunkWidth, JunkHeight, JunkBW, JunkDepth, JunkMask;
+
+char *ProgramName;
+int Argc;
+char **Argv;
+char **Environ;
+
+Bool RestartPreviousState = False; /* try to restart in previous state */
+
+unsigned long black, white;
+
+extern void assign_var_savecolor();
+
+Atom TwmAtoms[11];
+
+/* don't change the order of these strings */
+static char* atom_names[11] = {
+ "_MIT_PRIORITY_COLORS",
+ "WM_CHANGE_STATE",
+ "WM_STATE",
+ "WM_COLORMAP_WINDOWS",
+ "WM_PROTOCOLS",
+ "WM_TAKE_FOCUS",
+ "WM_SAVE_YOURSELF",
+ "WM_DELETE_WINDOW",
+ "SM_CLIENT_ID",
+ "WM_CLIENT_LEADER",
+ "WM_WINDOW_ROLE"
+};
+
+/***********************************************************************
+ *
+ * Procedure:
+ * main - start of twm
+ *
+ ***********************************************************************
+ */
+
+main(argc, argv, environ)
+ int argc;
+ char **argv;
+ char **environ;
+{
+ Window root, parent, *children;
+ unsigned int nchildren;
+ int i, j;
+ char *display_name = NULL;
+ unsigned long valuemask; /* mask for create windows */
+ XSetWindowAttributes attributes; /* attributes for create windows */
+ int numManaged, firstscrn, lastscrn, scrnum;
+ extern ColormapWindow *CreateColormapWindow();
+ int zero = 0;
+ char *restore_filename = NULL;
+ char *client_id = NULL;
+
+ ProgramName = argv[0];
+ Argc = argc;
+ Argv = argv;
+ Environ = environ;
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ switch (argv[i][1]) {
+ case 'd': /* -display dpy */
+ if (++i >= argc) goto usage;
+ display_name = argv[i];
+ continue;
+ case 's': /* -single */
+ MultiScreen = FALSE;
+ continue;
+ case 'f': /* -file twmrcfilename */
+ if (++i >= argc) goto usage;
+ InitFile = argv[i];
+ continue;
+ case 'v': /* -verbose */
+ PrintErrorMessages = True;
+ continue;
+ case 'c': /* -clientId */
+ if (++i >= argc) goto usage;
+ client_id = argv[i];
+ continue;
+ case 'r': /* -restore */
+ if (++i >= argc) goto usage;
+ restore_filename = argv[i];
+ continue;
+ case 'q': /* -quiet */
+ PrintErrorMessages = False;
+ continue;
+ }
+ }
+ usage:
+ fprintf (stderr,
+ "usage: %s [-display dpy] [-f file] [-s] [-q] [-v] [-clientId id] [-restore file]\n",
+ ProgramName);
+ exit (1);
+ }
+
+#define newhandler(sig) \
+ if (signal (sig, SIG_IGN) != SIG_IGN) (void) signal (sig, Done)
+
+ newhandler (SIGINT);
+ newhandler (SIGHUP);
+ newhandler (SIGQUIT);
+ newhandler (SIGTERM);
+
+#undef newhandler
+
+ Home = getenv("HOME");
+ if (Home != NULL) {
+ char *temp_p;
+
+ /*
+ * Make a copy of Home because the string returned by getenv() can be
+ * overwritten by some POSIX.1 and ANSI-C implementations of getenv()
+ * when further calls to getenv() are made
+ */
+
+ temp_p = strdup(Home);
+ Home = temp_p;
+ }
+
+ if (Home == NULL)
+ Home = "./";
+
+ HomeLen = strlen(Home);
+
+ NoClass.res_name = NoName;
+ NoClass.res_class = NoName;
+
+ XtToolkitInitialize ();
+ appContext = XtCreateApplicationContext ();
+
+ if (!(dpy = XtOpenDisplay (appContext, display_name, "twm", "twm",
+ NULL, 0, &zero, NULL))) {
+ fprintf (stderr, "%s: unable to open display \"%s\"\n",
+ ProgramName, XDisplayName(display_name));
+ exit (1);
+ }
+
+ if (fcntl(ConnectionNumber(dpy), F_SETFD, 1) == -1) {
+ fprintf (stderr,
+ "%s: unable to mark display connection as close-on-exec\n",
+ ProgramName);
+ exit (1);
+ }
+
+ if (restore_filename)
+ ReadWinConfigFile (restore_filename);
+
+ HasShape = XShapeQueryExtension (dpy, &ShapeEventBase, &ShapeErrorBase);
+ HasSync = XSyncQueryExtension(dpy, &SyncEventBase, &SyncErrorBase);
+ TwmContext = XUniqueContext();
+ MenuContext = XUniqueContext();
+ IconManagerContext = XUniqueContext();
+ ScreenContext = XUniqueContext();
+ ColormapContext = XUniqueContext();
+
+ (void) XInternAtoms(dpy, atom_names, sizeof TwmAtoms / sizeof TwmAtoms[0],
+ False, TwmAtoms);
+
+ /* Set up the per-screen global information. */
+
+ NumScreens = ScreenCount(dpy);
+
+ if (MultiScreen)
+ {
+ firstscrn = 0;
+ lastscrn = NumScreens - 1;
+ }
+ else
+ {
+ firstscrn = lastscrn = DefaultScreen(dpy);
+ }
+
+ InfoLines = 0;
+
+ /* for simplicity, always allocate NumScreens ScreenInfo struct pointers */
+ ScreenList = (ScreenInfo **) calloc (NumScreens, sizeof (ScreenInfo *));
+ if (ScreenList == NULL)
+ {
+ fprintf (stderr, "%s: Unable to allocate memory for screen list, exiting.\n",
+ ProgramName);
+ exit (1);
+ }
+ numManaged = 0;
+ PreviousScreen = DefaultScreen(dpy);
+ FirstScreen = TRUE;
+ for (scrnum = firstscrn ; scrnum <= lastscrn; scrnum++)
+ {
+ /* Make sure property priority colors is empty */
+ XChangeProperty (dpy, RootWindow(dpy, scrnum), _XA_MIT_PRIORITY_COLORS,
+ XA_CARDINAL, 32, PropModeReplace, NULL, 0);
+ RedirectError = FALSE;
+ XSetErrorHandler(CatchRedirectError);
+ XSelectInput(dpy, RootWindow (dpy, scrnum),
+ ColormapChangeMask | EnterWindowMask | PropertyChangeMask |
+ SubstructureRedirectMask | KeyPressMask |
+ ButtonPressMask | ButtonReleaseMask);
+ XSync(dpy, 0);
+ XSetErrorHandler(TwmErrorHandler);
+
+ if (RedirectError)
+ {
+ fprintf (stderr, "%s: another window manager is already running",
+ ProgramName);
+ if (MultiScreen && NumScreens > 0)
+ fprintf(stderr, " on screen %d?\n", scrnum);
+ else
+ fprintf(stderr, "?\n");
+ continue;
+ }
+
+ numManaged ++;
+
+ /* Note: ScreenInfo struct is calloc'ed to initialize to zero. */
+ Scr = ScreenList[scrnum] =
+ (ScreenInfo *) calloc(1, sizeof(ScreenInfo));
+ if (Scr == NULL)
+ {
+ fprintf (stderr, "%s: unable to allocate memory for ScreenInfo structure for screen %d.\n",
+ ProgramName, scrnum);
+ continue;
+ }
+
+ /* initialize list pointers, remember to put an initialization
+ * in InitVariables also
+ */
+ Scr->BorderColorL = NULL;
+ Scr->IconBorderColorL = NULL;
+ Scr->BorderTileForegroundL = NULL;
+ Scr->BorderTileBackgroundL = NULL;
+ Scr->TitleForegroundL = NULL;
+ Scr->TitleBackgroundL = NULL;
+ Scr->IconForegroundL = NULL;
+ Scr->IconBackgroundL = NULL;
+ Scr->NoTitle = NULL;
+ Scr->MakeTitle = NULL;
+ Scr->AutoRaise = NULL;
+ Scr->IconNames = NULL;
+ Scr->NoHighlight = NULL;
+ Scr->NoStackModeL = NULL;
+ Scr->NoTitleHighlight = NULL;
+ Scr->DontIconify = NULL;
+ Scr->IconMgrNoShow = NULL;
+ Scr->IconMgrShow = NULL;
+ Scr->IconifyByUn = NULL;
+ Scr->IconManagerFL = NULL;
+ Scr->IconManagerBL = NULL;
+ Scr->IconMgrs = NULL;
+ Scr->StartIconified = NULL;
+ Scr->SqueezeTitleL = NULL;
+ Scr->DontSqueezeTitleL = NULL;
+ Scr->WindowRingL = NULL;
+ Scr->WarpCursorL = NULL;
+ /* remember to put an initialization in InitVariables also
+ */
+
+ Scr->screen = scrnum;
+ Scr->d_depth = DefaultDepth(dpy, scrnum);
+ Scr->d_visual = DefaultVisual(dpy, scrnum);
+ Scr->Root = RootWindow(dpy, scrnum);
+ XSaveContext (dpy, Scr->Root, ScreenContext, (caddr_t) Scr);
+
+ Scr->TwmRoot.cmaps.number_cwins = 1;
+ Scr->TwmRoot.cmaps.cwins =
+ (ColormapWindow **) malloc(sizeof(ColormapWindow *));
+ Scr->TwmRoot.cmaps.cwins[0] =
+ CreateColormapWindow(Scr->Root, True, False);
+ Scr->TwmRoot.cmaps.cwins[0]->visibility = VisibilityPartiallyObscured;
+
+ Scr->cmapInfo.cmaps = NULL;
+ Scr->cmapInfo.maxCmaps =
+ MaxCmapsOfScreen(ScreenOfDisplay(dpy, Scr->screen));
+ Scr->cmapInfo.root_pushes = 0;
+ InstallWindowColormaps(0, &Scr->TwmRoot);
+
+ Scr->StdCmapInfo.head = Scr->StdCmapInfo.tail =
+ Scr->StdCmapInfo.mru = NULL;
+ Scr->StdCmapInfo.mruindex = 0;
+ LocateStandardColormaps();
+
+ Scr->TBInfo.nleft = Scr->TBInfo.nright = 0;
+ Scr->TBInfo.head = NULL;
+ Scr->TBInfo.border = 1;
+ Scr->TBInfo.width = 0;
+ Scr->TBInfo.leftx = 0;
+ Scr->TBInfo.titlex = 0;
+
+ Scr->MyDisplayWidth = DisplayWidth(dpy, scrnum);
+ Scr->MyDisplayHeight = DisplayHeight(dpy, scrnum);
+ Scr->MaxWindowWidth = 32767 - Scr->MyDisplayWidth;
+ Scr->MaxWindowHeight = 32767 - Scr->MyDisplayHeight;
+
+ Scr->XORvalue = (((unsigned long) 1) << Scr->d_depth) - 1;
+
+ if (DisplayCells(dpy, scrnum) < 3)
+ Scr->Monochrome = MONOCHROME;
+ else if (DefaultVisual(dpy, scrnum)->class == GrayScale)
+ Scr->Monochrome = GRAYSCALE;
+ else
+ Scr->Monochrome = COLOR;
+
+ /* setup default colors */
+ Scr->FirstTime = TRUE;
+ GetColor(Scr->Monochrome, &black, "black");
+ Scr->Black = black;
+ GetColor(Scr->Monochrome, &white, "white");
+ Scr->White = white;
+
+ if (FirstScreen)
+ {
+ SetFocus ((TwmWindow *)NULL, CurrentTime);
+
+ /* define cursors */
+
+ NewFontCursor(&UpperLeftCursor, "top_left_corner");
+ NewFontCursor(&RightButt, "rightbutton");
+ NewFontCursor(&LeftButt, "leftbutton");
+ NewFontCursor(&MiddleButt, "middlebutton");
+ }
+
+ Scr->iconmgr.x = 0;
+ Scr->iconmgr.y = 0;
+ Scr->iconmgr.width = 150;
+ Scr->iconmgr.height = 5;
+ Scr->iconmgr.next = NULL;
+ Scr->iconmgr.prev = NULL;
+ Scr->iconmgr.lasti = &(Scr->iconmgr);
+ Scr->iconmgr.first = NULL;
+ Scr->iconmgr.last = NULL;
+ Scr->iconmgr.active = NULL;
+ Scr->iconmgr.scr = Scr;
+ Scr->iconmgr.columns = 1;
+ Scr->iconmgr.count = 0;
+ Scr->iconmgr.name = "TWM";
+ Scr->iconmgr.icon_name = "Icons";
+
+ Scr->IconDirectory = NULL;
+
+ Scr->siconifyPm = None;
+ Scr->pullPm = None;
+ Scr->hilitePm = None;
+ Scr->tbpm.xlogo = None;
+ Scr->tbpm.resize = None;
+ Scr->tbpm.question = None;
+ Scr->tbpm.menu = None;
+ Scr->tbpm.delete = None;
+
+ InitVariables();
+ InitMenus();
+
+ /* Parse it once for each screen. */
+ ParseTwmrc(InitFile);
+ assign_var_savecolor(); /* storeing pixels for twmrc "entities" */
+ if (Scr->SqueezeTitle == -1) Scr->SqueezeTitle = FALSE;
+ if (!Scr->HaveFonts) CreateFonts();
+ CreateGCs();
+ MakeMenus();
+
+ Scr->TitleBarFont.y += Scr->FramePadding;
+ Scr->TitleHeight = Scr->TitleBarFont.height + Scr->FramePadding * 2;
+ /* make title height be odd so buttons look nice and centered */
+ if (!(Scr->TitleHeight & 1)) Scr->TitleHeight++;
+
+ InitTitlebarButtons (); /* menus are now loaded! */
+
+ XGrabServer(dpy);
+ XSync(dpy, 0);
+
+ JunkX = 0;
+ JunkY = 0;
+
+ XQueryTree(dpy, Scr->Root, &root, &parent, &children, &nchildren);
+ CreateIconManagers();
+ if (!Scr->NoIconManagers)
+ Scr->iconmgr.twm_win->icon = TRUE;
+
+ /*
+ * weed out icon windows
+ */
+ for (i = 0; i < nchildren; i++) {
+ if (children[i]) {
+ XWMHints *wmhintsp = XGetWMHints (dpy, children[i]);
+
+ if (wmhintsp) {
+ if (wmhintsp->flags & IconWindowHint) {
+ for (j = 0; j < nchildren; j++) {
+ if (children[j] == wmhintsp->icon_window) {
+ children[j] = None;
+ break;
+ }
+ }
+ }
+ XFree ((char *) wmhintsp);
+ }
+ }
+ }
+
+ /*
+ * map all of the non-override windows
+ */
+ for (i = 0; i < nchildren; i++)
+ {
+ if (children[i] && MappedNotOverride(children[i]))
+ {
+ XUnmapWindow(dpy, children[i]);
+ SimulateMapRequest(children[i]);
+ }
+ }
+
+ if (Scr->ShowIconManager && !Scr->NoIconManagers)
+ {
+ Scr->iconmgr.twm_win->icon = FALSE;
+ if (Scr->iconmgr.count)
+ {
+ SetMapStateProp (Scr->iconmgr.twm_win, NormalState);
+ XMapWindow(dpy, Scr->iconmgr.w);
+ XMapWindow(dpy, Scr->iconmgr.twm_win->frame);
+ }
+ }
+
+
+ attributes.border_pixel = Scr->DefaultC.fore;
+ attributes.background_pixel = Scr->DefaultC.back;
+ attributes.event_mask = (ExposureMask | ButtonPressMask |
+ KeyPressMask | ButtonReleaseMask);
+ attributes.backing_store = NotUseful;
+ attributes.cursor = XCreateFontCursor (dpy, XC_hand2);
+ valuemask = (CWBorderPixel | CWBackPixel | CWEventMask |
+ CWBackingStore | CWCursor);
+ Scr->InfoWindow = XCreateWindow (dpy, Scr->Root, 0, 0,
+ (unsigned int) 5, (unsigned int) 5,
+ (unsigned int) BW, 0,
+ (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent,
+ valuemask, &attributes);
+
+ Scr->SizeStringWidth = XTextWidth (Scr->SizeFont.font,
+ " 8888 x 8888 ", 13);
+ valuemask = (CWBorderPixel | CWBackPixel | CWBitGravity);
+ attributes.bit_gravity = NorthWestGravity;
+ Scr->SizeWindow = XCreateWindow (dpy, Scr->Root, 0, 0,
+ (unsigned int) Scr->SizeStringWidth,
+ (unsigned int) (Scr->SizeFont.height +
+ SIZE_VINDENT*2),
+ (unsigned int) BW, 0,
+ (unsigned int) CopyFromParent,
+ (Visual *) CopyFromParent,
+ valuemask, &attributes);
+
+ XUngrabServer(dpy);
+
+ FirstScreen = FALSE;
+ Scr->FirstTime = FALSE;
+ } /* for */
+
+ if (numManaged == 0) {
+ if (MultiScreen && NumScreens > 0)
+ fprintf (stderr, "%s: unable to find any unmanaged screens\n",
+ ProgramName);
+ exit (1);
+ }
+
+ (void) ConnectToSessionManager (client_id);
+
+ RestartPreviousState = False;
+ HandlingEvents = TRUE;
+ InitEvents();
+ HandleEvents();
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * InitVariables - initialize twm variables
+ *
+ ***********************************************************************
+ */
+
+InitVariables()
+{
+ FreeList(&Scr->BorderColorL);
+ FreeList(&Scr->IconBorderColorL);
+ FreeList(&Scr->BorderTileForegroundL);
+ FreeList(&Scr->BorderTileBackgroundL);
+ FreeList(&Scr->TitleForegroundL);
+ FreeList(&Scr->TitleBackgroundL);
+ FreeList(&Scr->IconForegroundL);
+ FreeList(&Scr->IconBackgroundL);
+ FreeList(&Scr->IconManagerFL);
+ FreeList(&Scr->IconManagerBL);
+ FreeList(&Scr->IconMgrs);
+ FreeList(&Scr->NoTitle);
+ FreeList(&Scr->MakeTitle);
+ FreeList(&Scr->AutoRaise);
+ FreeList(&Scr->IconNames);
+ FreeList(&Scr->NoHighlight);
+ FreeList(&Scr->NoStackModeL);
+ FreeList(&Scr->NoTitleHighlight);
+ FreeList(&Scr->DontIconify);
+ FreeList(&Scr->IconMgrNoShow);
+ FreeList(&Scr->IconMgrShow);
+ FreeList(&Scr->IconifyByUn);
+ FreeList(&Scr->StartIconified);
+ FreeList(&Scr->IconManagerHighlightL);
+ FreeList(&Scr->SqueezeTitleL);
+ FreeList(&Scr->DontSqueezeTitleL);
+ FreeList(&Scr->WindowRingL);
+ FreeList(&Scr->WarpCursorL);
+
+ NewFontCursor(&Scr->FrameCursor, "top_left_arrow");
+ NewFontCursor(&Scr->TitleCursor, "top_left_arrow");
+ NewFontCursor(&Scr->IconCursor, "top_left_arrow");
+ NewFontCursor(&Scr->IconMgrCursor, "top_left_arrow");
+ NewFontCursor(&Scr->MoveCursor, "fleur");
+ NewFontCursor(&Scr->ResizeCursor, "fleur");
+ NewFontCursor(&Scr->MenuCursor, "sb_left_arrow");
+ NewFontCursor(&Scr->ButtonCursor, "hand2");
+ NewFontCursor(&Scr->WaitCursor, "watch");
+ NewFontCursor(&Scr->SelectCursor, "dot");
+ NewFontCursor(&Scr->DestroyCursor, "pirate");
+
+ Scr->Ring = NULL;
+ Scr->RingLeader = NULL;
+
+ Scr->DefaultC.fore = black;
+ Scr->DefaultC.back = white;
+ Scr->BorderColor = black;
+ Scr->BorderTileC.fore = black;
+ Scr->BorderTileC.back = white;
+ Scr->TitleC.fore = black;
+ Scr->TitleC.back = white;
+ Scr->MenuC.fore = black;
+ Scr->MenuC.back = white;
+ Scr->MenuTitleC.fore = black;
+ Scr->MenuTitleC.back = white;
+ Scr->MenuShadowColor = black;
+ Scr->IconC.fore = black;
+ Scr->IconC.back = white;
+ Scr->IconBorderColor = black;
+ Scr->PointerForeground.pixel = black;
+ XQueryColor(dpy, Scr->TwmRoot.cmaps.cwins[0]->colormap->c,
+ &Scr->PointerForeground);
+ Scr->PointerBackground.pixel = white;
+ XQueryColor(dpy, Scr->TwmRoot.cmaps.cwins[0]->colormap->c,
+ &Scr->PointerBackground);
+ Scr->IconManagerC.fore = black;
+ Scr->IconManagerC.back = white;
+ Scr->IconManagerHighlight = black;
+
+ Scr->FramePadding = 2; /* values that look "nice" on */
+ Scr->TitlePadding = 8; /* 75 and 100dpi displays */
+ Scr->ButtonIndent = 1;
+ Scr->SizeStringOffset = 0;
+ Scr->BorderWidth = BW;
+ Scr->IconBorderWidth = BW;
+ Scr->UnknownWidth = 0;
+ Scr->UnknownHeight = 0;
+ Scr->NumAutoRaises = 0;
+ Scr->NoDefaults = FALSE;
+ Scr->UsePPosition = PPOS_OFF;
+ Scr->FocusRoot = TRUE;
+ Scr->Focus = NULL;
+ Scr->WarpCursor = FALSE;
+ Scr->ForceIcon = FALSE;
+ Scr->NoGrabServer = FALSE;
+ Scr->NoRaiseMove = FALSE;
+ Scr->NoRaiseResize = FALSE;
+ Scr->NoRaiseDeicon = FALSE;
+ Scr->NoRaiseWarp = FALSE;
+ Scr->DontMoveOff = FALSE;
+ Scr->DoZoom = FALSE;
+ Scr->TitleFocus = TRUE;
+ Scr->NoTitlebar = FALSE;
+ Scr->DecorateTransients = FALSE;
+ Scr->IconifyByUnmapping = FALSE;
+ Scr->ShowIconManager = FALSE;
+ Scr->IconManagerDontShow =FALSE;
+ Scr->BackingStore = TRUE;
+ Scr->SaveUnder = TRUE;
+ Scr->RandomPlacement = FALSE;
+ Scr->OpaqueMove = FALSE;
+ Scr->Highlight = TRUE;
+ Scr->StackMode = TRUE;
+ Scr->TitleHighlight = TRUE;
+ Scr->MoveDelta = 1; /* so that f.deltastop will work */
+ Scr->ZoomCount = 8;
+ Scr->SortIconMgr = FALSE;
+ Scr->Shadow = TRUE;
+ Scr->InterpolateMenuColors = FALSE;
+ Scr->NoIconManagers = FALSE;
+ Scr->ClientBorderWidth = FALSE;
+ Scr->SqueezeTitle = -1;
+ Scr->FirstRegion = NULL;
+ Scr->LastRegion = NULL;
+ Scr->FirstTime = TRUE;
+ Scr->HaveFonts = FALSE; /* i.e. not loaded yet */
+ Scr->CaseSensitive = TRUE;
+ Scr->WarpUnmapped = FALSE;
+
+ /* setup default fonts; overridden by defaults from system.twmrc */
+#define DEFAULT_NICE_FONT "variable"
+#define DEFAULT_FAST_FONT "fixed"
+
+ Scr->TitleBarFont.font = NULL;
+ Scr->TitleBarFont.name = DEFAULT_NICE_FONT;
+ Scr->MenuFont.font = NULL;
+ Scr->MenuFont.name = DEFAULT_NICE_FONT;
+ Scr->IconFont.font = NULL;
+ Scr->IconFont.name = DEFAULT_NICE_FONT;
+ Scr->SizeFont.font = NULL;
+ Scr->SizeFont.name = DEFAULT_FAST_FONT;
+ Scr->IconManagerFont.font = NULL;
+ Scr->IconManagerFont.name = DEFAULT_NICE_FONT;
+ Scr->DefaultFont.font = NULL;
+ Scr->DefaultFont.name = DEFAULT_FAST_FONT;
+
+}
+
+
+CreateFonts ()
+{
+ GetFont(&Scr->TitleBarFont);
+ GetFont(&Scr->MenuFont);
+ GetFont(&Scr->IconFont);
+ GetFont(&Scr->SizeFont);
+ GetFont(&Scr->IconManagerFont);
+ GetFont(&Scr->DefaultFont);
+ Scr->HaveFonts = TRUE;
+}
+
+
+RestoreWithdrawnLocation (tmp)
+ TwmWindow *tmp;
+{
+ int gravx, gravy;
+ unsigned int bw, mask;
+ XWindowChanges xwc;
+
+ if (XGetGeometry (dpy, tmp->w, &JunkRoot, &xwc.x, &xwc.y,
+ &JunkWidth, &JunkHeight, &bw, &JunkDepth)) {
+
+ GetGravityOffsets (tmp, &gravx, &gravy);
+ if (gravy < 0) xwc.y -= tmp->title_height;
+
+ if (bw != tmp->old_bw) {
+ int xoff, yoff;
+
+ if (!Scr->ClientBorderWidth) {
+ xoff = gravx;
+ yoff = gravy;
+ } else {
+ xoff = 0;
+ yoff = 0;
+ }
+
+ xwc.x -= (xoff + 1) * tmp->old_bw;
+ xwc.y -= (yoff + 1) * tmp->old_bw;
+ }
+ if (!Scr->ClientBorderWidth) {
+ xwc.x += gravx * tmp->frame_bw;
+ xwc.y += gravy * tmp->frame_bw;
+ }
+
+ mask = (CWX | CWY);
+ if (bw != tmp->old_bw) {
+ xwc.border_width = tmp->old_bw;
+ mask |= CWBorderWidth;
+ }
+
+ XConfigureWindow (dpy, tmp->w, mask, &xwc);
+
+ if (tmp->wmhints && (tmp->wmhints->flags & IconWindowHint)) {
+ XUnmapWindow (dpy, tmp->wmhints->icon_window);
+ }
+
+ }
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * Done - cleanup and exit twm
+ *
+ * Returned Value:
+ * none
+ *
+ * Inputs:
+ * none
+ *
+ * Outputs:
+ * none
+ *
+ * Special Considerations:
+ * none
+ *
+ ***********************************************************************
+ */
+
+void Reborder (time)
+Time time;
+{
+ TwmWindow *tmp; /* temp twm window structure */
+ int scrnum;
+
+ /* put a border back around all windows */
+
+ XGrabServer (dpy);
+ for (scrnum = 0; scrnum < NumScreens; scrnum++)
+ {
+ if ((Scr = ScreenList[scrnum]) == NULL)
+ continue;
+
+ InstallWindowColormaps (0, &Scr->TwmRoot); /* force reinstall */
+ for (tmp = Scr->TwmRoot.next; tmp != NULL; tmp = tmp->next)
+ {
+ RestoreWithdrawnLocation (tmp);
+ XMapWindow (dpy, tmp->w);
+ }
+ }
+
+ XUngrabServer (dpy);
+ SetFocus ((TwmWindow*)NULL, time);
+}
+
+SIGNAL_T Done()
+{
+ Reborder (CurrentTime);
+ XCloseDisplay(dpy);
+ exit(0);
+ SIGNAL_RETURN;
+}
+
+
+/*
+ * Error Handlers. If a client dies, we'll get a BadWindow error (except for
+ * GetGeometry which returns BadDrawable) for most operations that we do before
+ * manipulating the client's window.
+ */
+
+Bool ErrorOccurred = False;
+XErrorEvent LastErrorEvent;
+
+static int TwmErrorHandler(dpy, event)
+ Display *dpy;
+ XErrorEvent *event;
+{
+ LastErrorEvent = *event;
+ ErrorOccurred = True;
+
+ if (PrintErrorMessages && /* don't be too obnoxious */
+ event->error_code != BadWindow && /* watch for dead puppies */
+ (event->request_code != X_GetGeometry && /* of all styles */
+ event->error_code != BadDrawable))
+ XmuPrintDefaultErrorMessage (dpy, event, stderr);
+ return 0;
+}
+
+
+/* ARGSUSED*/
+static int CatchRedirectError(dpy, event)
+ Display *dpy;
+ XErrorEvent *event;
+{
+ RedirectError = TRUE;
+ LastErrorEvent = *event;
+ ErrorOccurred = True;
+ return 0;
+}
diff --git a/src/twm.h b/src/twm.h
new file mode 100644
index 0000000..7fe187e
--- /dev/null
+++ b/src/twm.h
@@ -0,0 +1,426 @@
+/*****************************************************************************/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** names of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND AND DISCLAIMS ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES **/
+/** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+/*
+
+Portions Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+
+/***********************************************************************
+ *
+ * $Xorg: twm.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * twm include file
+ *
+ * 28-Oct-87 Thomas E. LaStrange File created
+ * 10-Oct-90 David M. Sternlicht Storeing saved colors on root
+ ***********************************************************************/
+
+#ifndef _TWM_
+#define _TWM_
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/extensions/shape.h>
+#include <X11/Xfuncs.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+
+#ifndef WithdrawnState
+#define WithdrawnState 0
+#endif
+
+#define PIXEL_ALREADY_TYPEDEFED /* for Xmu/Drawing.h */
+
+#ifdef SIGNALRETURNSINT
+#define SIGNAL_T int
+#define SIGNAL_RETURN return 0
+#else
+#define SIGNAL_T void
+#define SIGNAL_RETURN return
+#endif
+
+typedef SIGNAL_T (*SigProc)(); /* type of function returned by signal() */
+
+#define BW 2 /* border width */
+#define BW2 4 /* border width * 2 */
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define NULLSTR ((char *) NULL)
+
+#define MAX_BUTTONS 5 /* max mouse buttons supported */
+
+/* info stings defines */
+#define INFO_LINES 30
+#define INFO_SIZE 200
+
+/* contexts for button presses */
+#define C_NO_CONTEXT -1
+#define C_WINDOW 0
+#define C_TITLE 1
+#define C_ICON 2
+#define C_ROOT 3
+#define C_FRAME 4
+#define C_ICONMGR 5
+#define C_NAME 6
+#define C_IDENTIFY 7
+#define NUM_CONTEXTS 8
+
+#define C_WINDOW_BIT (1 << C_WINDOW)
+#define C_TITLE_BIT (1 << C_TITLE)
+#define C_ICON_BIT (1 << C_ICON)
+#define C_ROOT_BIT (1 << C_ROOT)
+#define C_FRAME_BIT (1 << C_FRAME)
+#define C_ICONMGR_BIT (1 << C_ICONMGR)
+#define C_NAME_BIT (1 << C_NAME)
+
+#define C_ALL_BITS (C_WINDOW_BIT | C_TITLE_BIT | C_ICON_BIT |\
+ C_ROOT_BIT | C_FRAME_BIT | C_ICONMGR_BIT)
+
+/* modifiers for button presses */
+#define MOD_SIZE ((ShiftMask | ControlMask | Mod1Mask \
+ | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) + 1)
+
+#define TITLE_BAR_SPACE 1 /* 2 pixel space bordering chars */
+#define TITLE_BAR_FONT_HEIGHT 15 /* max of 15 pixel high chars */
+#define TITLE_BAR_HEIGHT (TITLE_BAR_FONT_HEIGHT+(2*TITLE_BAR_SPACE))
+
+/* defines for zooming/unzooming */
+#define ZOOM_NONE 0
+
+#define FBF(fix_fore, fix_back, fix_font)\
+ Gcv.foreground = fix_fore;\
+ Gcv.background = fix_back;\
+ Gcv.font = fix_font;\
+ XChangeGC(dpy, Scr->NormalGC, GCFont|GCForeground|GCBackground,&Gcv)
+
+#define FB(fix_fore, fix_back)\
+ Gcv.foreground = fix_fore;\
+ Gcv.background = fix_back;\
+ XChangeGC(dpy, Scr->NormalGC, GCForeground|GCBackground,&Gcv)
+
+typedef struct MyFont
+{
+ char *name; /* name of the font */
+ XFontStruct *font; /* font structure */
+ int height; /* height of the font */
+ int y; /* Y coordinate to draw characters */
+} MyFont;
+
+typedef struct ColorPair
+{
+ Pixel fore, back;
+} ColorPair;
+
+typedef struct _TitleButton {
+ struct _TitleButton *next; /* next link in chain */
+ char *name; /* bitmap name in case of deferal */
+ Pixmap bitmap; /* image to display in button */
+ int srcx, srcy; /* from where to start copying */
+ unsigned int width, height; /* size of pixmap */
+ int dstx, dsty; /* to where to start copying */
+ int func; /* function to execute */
+ char *action; /* optional action arg */
+ struct MenuRoot *menuroot; /* menu to pop on F_MENU */
+ Bool rightside; /* t: on right, f: on left */
+} TitleButton;
+
+typedef struct _TBWindow {
+ Window window; /* which window in this frame */
+ TitleButton *info; /* description of this window */
+} TBWindow;
+
+typedef struct _SqueezeInfo {
+ int justify; /* left, center, right */
+ int num; /* signed pixel count or numerator */
+ int denom; /* 0 for pix count or denominator */
+} SqueezeInfo;
+
+#define J_LEFT 1
+#define J_CENTER 2
+#define J_RIGHT 3
+
+/* Colormap window entry for each window in WM_COLORMAP_WINDOWS
+ * ICCCM property.
+ */
+typedef struct TwmColormap
+{
+ Colormap c; /* Colormap id */
+ int state; /* install(ability) state */
+ unsigned long install_req; /* request number which installed it */
+ Window w; /* window causing load of color table */
+ int refcnt;
+} TwmColormap;
+
+#define CM_INSTALLABLE 1
+#define CM_INSTALLED 2
+#define CM_INSTALL 4
+
+typedef struct ColormapWindow
+{
+ Window w; /* Window id */
+ TwmColormap *colormap; /* Colormap for this window */
+ int visibility; /* Visibility of this window */
+ int refcnt;
+} ColormapWindow;
+
+typedef struct Colormaps
+{
+ ColormapWindow **cwins; /* current list of colormap windows */
+ int number_cwins; /* number of elements in current list */
+ char *scoreboard; /* conflicts between installable colortables */
+} Colormaps;
+
+#define ColormapsScoreboardLength(cm) ((cm)->number_cwins * \
+ ((cm)->number_cwins - 1) / 2)
+
+/* for each window that is on the display, one of these structures
+ * is allocated and linked into a list
+ */
+typedef struct TwmWindow
+{
+ struct TwmWindow *next; /* next twm window */
+ struct TwmWindow *prev; /* previous twm window */
+ Window w; /* the child window */
+ int old_bw; /* border width before reparenting */
+ Window frame; /* the frame window */
+ Window title_w; /* the title bar window */
+ Window hilite_w; /* the hilite window */
+ Pixmap gray;
+ Window icon_w; /* the icon window */
+ Window icon_bm_w; /* the icon bitmap window */
+ int frame_x; /* x position of frame */
+ int frame_y; /* y position of frame */
+ int frame_width; /* width of frame */
+ int frame_height; /* height of frame */
+ int frame_bw; /* borderwidth of frame */
+ int title_x;
+ int title_y;
+ int icon_x; /* icon text x coordinate */
+ int icon_y; /* icon text y coordiante */
+ int icon_w_width; /* width of the icon window */
+ int icon_w_height; /* height of the icon window */
+ int icon_width; /* width of the icon bitmap */
+ int icon_height; /* height of the icon bitmap */
+ int title_height; /* height of the title bar */
+ int title_width; /* width of the title bar */
+ char *full_name; /* full name of the window */
+ char *name; /* name of the window */
+ char *icon_name; /* name of the icon */
+ int name_width; /* width of name text */
+ int highlightx; /* start of highlight window */
+ int rightx; /* start of right buttons */
+ XWindowAttributes attr; /* the child window attributes */
+ XSizeHints hints; /* normal hints */
+ XWMHints *wmhints; /* WM hints */
+ Window group; /* group ID */
+ XClassHint class;
+ struct WList *list;
+ /***********************************************************************
+ * color definitions per window
+ **********************************************************************/
+ Pixel border; /* border color */
+ Pixel icon_border; /* border color */
+ ColorPair border_tile;
+ ColorPair title;
+ ColorPair iconc;
+ short iconified; /* has the window ever been iconified? */
+ short icon; /* is the window an icon now ? */
+ short icon_on; /* is the icon visible */
+ short mapped; /* is the window mapped ? */
+ short auto_raise; /* should we auto-raise this window ? */
+ short forced; /* has had an icon forced upon it */
+ short icon_not_ours; /* icon pixmap or window supplied to us */
+ short icon_moved; /* user explicitly moved the icon */
+ short highlight; /* should highlight this window */
+ short stackmode; /* honor stackmode requests */
+ short iconify_by_unmapping; /* unmap window to iconify it */
+ short iconmgr; /* this is an icon manager window */
+ short transient; /* this is a transient window */
+ Window transientfor; /* window contained in XA_XM_TRANSIENT_FOR */
+ short titlehighlight; /* should I highlight the title bar */
+ struct IconMgr *iconmgrp; /* pointer to it if this is an icon manager */
+ int save_frame_x; /* x position of frame */
+ int save_frame_y; /* y position of frame */
+ int save_frame_width; /* width of frame */
+ int save_frame_height; /* height of frame */
+ short zoomed; /* is the window zoomed? */
+ short wShaped; /* this window has a bounding shape */
+ unsigned long protocols; /* which protocols this window handles */
+ Colormaps cmaps; /* colormaps for this application */
+ TBWindow *titlebuttons;
+ SqueezeInfo *squeeze_info; /* should the title be squeezed? */
+ struct {
+ struct TwmWindow *next, *prev;
+ Bool cursor_valid;
+ int curs_x, curs_y;
+ } ring;
+
+ Bool nameChanged; /* did WM_NAME ever change? */
+
+ /* did the user ever change the width/height? {yes, no, or unknown} */
+
+ Bool widthEverChangedByUser;
+ Bool heightEverChangedByUser;
+
+} TwmWindow;
+
+
+typedef struct TWMWinConfigEntry
+{
+ struct TWMWinConfigEntry *next;
+ int tag;
+ char *client_id;
+ char *window_role;
+ XClassHint class;
+ char *wm_name;
+ int wm_command_count;
+ char **wm_command;
+ short x, y;
+ unsigned short width, height;
+ short icon_x, icon_y;
+ Bool iconified;
+ Bool icon_info_present;
+ Bool width_ever_changed_by_user;
+ Bool height_ever_changed_by_user;
+} TWMWinConfigEntry;
+
+
+#define DoesWmTakeFocus (1L << 0)
+#define DoesWmSaveYourself (1L << 1)
+#define DoesWmDeleteWindow (1L << 2)
+
+#define TBPM_DOT ":dot" /* name of titlebar pixmap for dot */
+#define TBPM_ICONIFY ":iconify" /* same image as dot */
+#define TBPM_RESIZE ":resize" /* name of titlebar pixmap for resize button */
+#define TBPM_XLOGO ":xlogo" /* name of titlebar pixmap for xlogo */
+#define TBPM_DELETE ":delete" /* same image as xlogo */
+#define TBPM_MENU ":menu" /* name of titlebar pixmap for menus */
+#define TBPM_QUESTION ":question" /* name of unknown titlebar pixmap */
+
+#include <X11/Xosdefs.h>
+#ifndef X_NOT_STDC_ENV
+#include <stdlib.h>
+#else
+extern char *malloc(), *calloc(), *realloc(), *getenv();
+extern void free();
+#endif
+extern void Reborder();
+extern SIGNAL_T Done();
+void ComputeCommonTitleOffsets();
+void ComputeWindowTitleOffsets(), ComputeTitleLocation();
+extern char *ProgramName;
+extern Display *dpy;
+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 PreviousScreen;
+
+extern Cursor UpperLeftCursor;
+extern Cursor RightButt;
+extern Cursor MiddleButt;
+extern Cursor LeftButt;
+
+extern XClassHint NoClass;
+
+extern XContext TwmContext;
+extern XContext MenuContext;
+extern XContext IconManagerContext;
+extern XContext ScreenContext;
+extern XContext ColormapContext;
+
+extern char *Home;
+extern int HomeLen;
+extern int ParseError;
+
+extern int HandlingEvents;
+
+extern Window JunkRoot;
+extern Window JunkChild;
+extern int JunkX;
+extern int JunkY;
+extern unsigned int JunkWidth, JunkHeight, JunkBW, JunkDepth, JunkMask;
+extern XGCValues Gcv;
+extern int InfoLines;
+extern char Info[][INFO_SIZE];
+extern int Argc;
+extern char **Argv;
+extern char **Environ;
+extern void NewFontCursor();
+extern Pixmap CreateMenuIcon();
+
+extern Bool ErrorOccurred;
+extern XErrorEvent LastErrorEvent;
+
+#define ResetError() (ErrorOccurred = False)
+
+extern Bool RestartPreviousState;
+extern Bool GetWMState();
+
+extern Atom TwmAtoms[];
+
+#define _XA_MIT_PRIORITY_COLORS TwmAtoms[0]
+#define _XA_WM_CHANGE_STATE TwmAtoms[1]
+#define _XA_WM_STATE TwmAtoms[2]
+#define _XA_WM_COLORMAP_WINDOWS TwmAtoms[3]
+#define _XA_WM_PROTOCOLS TwmAtoms[4]
+#define _XA_WM_TAKE_FOCUS TwmAtoms[5]
+#define _XA_WM_SAVE_YOURSELF TwmAtoms[6]
+#define _XA_WM_DELETE_WINDOW TwmAtoms[7]
+#define _XA_SM_CLIENT_ID TwmAtoms[8]
+#define _XA_WM_CLIENT_LEADER TwmAtoms[9]
+#define _XA_WM_WINDOW_ROLE TwmAtoms[10]
+
+#endif /* _TWM_ */
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..0082a4d
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,959 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/***********************************************************************
+ *
+ * $Xorg: util.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * utility routines for twm
+ *
+ * 28-Oct-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#include "twm.h"
+#include "util.h"
+#include "gram.h"
+#include "screen.h"
+#include <X11/Xos.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include <X11/Xmu/Drawing.h>
+#include <X11/Xmu/CharSet.h>
+
+static Pixmap CreateXLogoPixmap(), CreateResizePixmap();
+static Pixmap CreateQuestionPixmap(), CreateMenuPixmap();
+static Pixmap CreateDotPixmap();
+int HotX, HotY;
+
+/***********************************************************************
+ *
+ * Procedure:
+ * MoveOutline - move a window outline
+ *
+ * Inputs:
+ * root - the window we are outlining
+ * x - upper left x coordinate
+ * y - upper left y coordinate
+ * width - the width of the rectangle
+ * height - the height of the rectangle
+ * bw - the border width of the frame
+ * th - title height
+ *
+ ***********************************************************************
+ */
+
+/* ARGSUSED */
+void MoveOutline(root, x, y, width, height, bw, th)
+ Window root;
+ int x, y, width, height, bw, th;
+{
+ static int lastx = 0;
+ static int lasty = 0;
+ static int lastWidth = 0;
+ static int lastHeight = 0;
+ static int lastBW = 0;
+ static int lastTH = 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)
+ return;
+
+ r = outline;
+
+#define DRAWIT() \
+ if (lastWidth || lastHeight) \
+ { \
+ xl = lastx; \
+ xr = lastx + lastWidth - 1; \
+ yt = lasty; \
+ yb = lasty + lastHeight - 1; \
+ xinnerl = xl + lastBW; \
+ xinnerr = xr - lastBW; \
+ yinnert = yt + lastTH + lastBW; \
+ yinnerb = yb - lastBW; \
+ xthird = (xinnerr - xinnerl) / 3; \
+ ythird = (yinnerb - yinnert) / 3; \
+ \
+ r->x1 = xl; \
+ r->y1 = yt; \
+ r->x2 = xr; \
+ r->y2 = yt; \
+ r++; \
+ \
+ r->x1 = xl; \
+ r->y1 = yb; \
+ r->x2 = xr; \
+ r->y2 = yb; \
+ r++; \
+ \
+ r->x1 = xl; \
+ r->y1 = yt; \
+ r->x2 = xl; \
+ r->y2 = yb; \
+ r++; \
+ \
+ r->x1 = xr; \
+ r->y1 = yt; \
+ r->x2 = xr; \
+ r->y2 = yb; \
+ r++; \
+ \
+ r->x1 = xinnerl + xthird; \
+ r->y1 = yinnert; \
+ r->x2 = r->x1; \
+ r->y2 = yinnerb; \
+ r++; \
+ \
+ r->x1 = xinnerl + (2 * xthird); \
+ r->y1 = yinnert; \
+ r->x2 = r->x1; \
+ r->y2 = yinnerb; \
+ r++; \
+ \
+ r->x1 = xinnerl; \
+ r->y1 = yinnert + ythird; \
+ r->x2 = xinnerr; \
+ r->y2 = r->y1; \
+ r++; \
+ \
+ r->x1 = xinnerl; \
+ r->y1 = yinnert + (2 * ythird); \
+ r->x2 = xinnerr; \
+ r->y2 = r->y1; \
+ r++; \
+ \
+ if (lastTH != 0) { \
+ r->x1 = xl; \
+ r->y1 = yt + lastTH; \
+ r->x2 = xr; \
+ r->y2 = r->y1; \
+ r++; \
+ } \
+ }
+
+ /* undraw the old one, if any */
+ DRAWIT ();
+
+ lastx = x;
+ lasty = y;
+ lastWidth = width;
+ lastHeight = height;
+ lastBW = bw;
+ lastTH = th;
+
+ /* draw the new one, if any */
+ DRAWIT ();
+
+#undef DRAWIT
+
+
+ if (r != outline)
+ {
+ XDrawSegments(dpy, root, Scr->DrawGC, outline, r - outline);
+ }
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * Zoom - zoom in or out of an icon
+ *
+ * Inputs:
+ * wf - window to zoom from
+ * wt - window to zoom to
+ *
+ ***********************************************************************
+ */
+
+void
+Zoom(wf, wt)
+ Window wf, wt;
+{
+ int fx, fy, tx, ty; /* from, to */
+ unsigned int fw, fh, tw, th; /* from, to */
+ long dx, dy, dw, dh;
+ long z;
+ int j;
+
+ if (!Scr->DoZoom || Scr->ZoomCount < 1) return;
+
+ if (wf == None || wt == None) return;
+
+ XGetGeometry (dpy, wf, &JunkRoot, &fx, &fy, &fw, &fh, &JunkBW, &JunkDepth);
+ XGetGeometry (dpy, wt, &JunkRoot, &tx, &ty, &tw, &th, &JunkBW, &JunkDepth);
+
+ dx = ((long) (tx - fx)); /* going from -> to */
+ dy = ((long) (ty - fy)); /* going from -> to */
+ dw = ((long) (tw - fw)); /* going from -> to */
+ dh = ((long) (th - fh)); /* going from -> to */
+ z = (long) (Scr->ZoomCount + 1);
+
+ for (j = 0; j < 2; j++) {
+ long i;
+
+ XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, fx, fy, fw, fh);
+ for (i = 1; i < z; i++) {
+ int x = fx + (int) ((dx * i) / z);
+ int y = fy + (int) ((dy * i) / z);
+ unsigned width = (unsigned) (((long) fw) + (dw * i) / z);
+ unsigned height = (unsigned) (((long) fh) + (dh * i) / z);
+
+ XDrawRectangle (dpy, Scr->Root, Scr->DrawGC,
+ x, y, width, height);
+ }
+ XDrawRectangle (dpy, Scr->Root, Scr->DrawGC, tx, ty, tw, th);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * Procedure:
+ * ExpandFilename - expand the tilde character to HOME
+ * if it is the first character of the filename
+ *
+ * Returned Value:
+ * a pointer to the new name
+ *
+ * Inputs:
+ * name - the filename to expand
+ *
+ ***********************************************************************
+ */
+
+char *
+ExpandFilename(name)
+char *name;
+{
+ char *newname;
+
+ if (name[0] != '~') return name;
+
+ newname = (char *) malloc (HomeLen + strlen(name) + 2);
+ if (!newname) {
+ fprintf (stderr,
+ "%s: unable to allocate %d bytes to expand filename %s/%s\n",
+ ProgramName, HomeLen + strlen(name) + 2, Home, &name[1]);
+ } else {
+ (void) sprintf (newname, "%s/%s", Home, &name[1]);
+ }
+
+ return newname;
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * GetUnknownIcon - read in the bitmap file for the unknown icon
+ *
+ * Inputs:
+ * name - the filename to read
+ *
+ ***********************************************************************
+ */
+
+void
+GetUnknownIcon(name)
+char *name;
+{
+ if ((Scr->UnknownPm = GetBitmap(name)) != None)
+ {
+ XGetGeometry(dpy, Scr->UnknownPm, &JunkRoot, &JunkX, &JunkY,
+ (unsigned int *)&Scr->UnknownWidth, (unsigned int *)&Scr->UnknownHeight, &JunkBW, &JunkDepth);
+ }
+}
+
+/***********************************************************************
+ *
+ * Procedure:
+ * FindBitmap - read in a bitmap file and return size
+ *
+ * Returned Value:
+ * the pixmap associated with the bitmap
+ * widthp - pointer to width of bitmap
+ * heightp - pointer to height of bitmap
+ *
+ * Inputs:
+ * name - the filename to read
+ *
+ ***********************************************************************
+ */
+
+Pixmap FindBitmap (name, widthp, heightp)
+ char *name;
+ unsigned int *widthp, *heightp;
+{
+ char *bigname;
+ Pixmap pm;
+
+ if (!name) return None;
+
+ /*
+ * Names of the form :name refer to hardcoded images that are scaled to
+ * look nice in title buttons. Eventually, it would be nice to put in a
+ * menu symbol as well....
+ */
+ if (name[0] == ':') {
+ int i;
+ static struct {
+ char *name;
+ Pixmap (*proc)();
+ } pmtab[] = {
+ { TBPM_DOT, CreateDotPixmap },
+ { TBPM_ICONIFY, CreateDotPixmap },
+ { TBPM_RESIZE, CreateResizePixmap },
+ { TBPM_XLOGO, CreateXLogoPixmap },
+ { TBPM_DELETE, CreateXLogoPixmap },
+ { TBPM_MENU, CreateMenuPixmap },
+ { TBPM_QUESTION, CreateQuestionPixmap },
+ };
+
+ for (i = 0; i < (sizeof pmtab)/(sizeof pmtab[0]); i++) {
+ if (XmuCompareISOLatin1 (pmtab[i].name, name) == 0)
+ return (*pmtab[i].proc) (widthp, heightp);
+ }
+ fprintf (stderr, "%s: no such built-in bitmap \"%s\"\n",
+ ProgramName, name);
+ return None;
+ }
+
+ /*
+ * Generate a full pathname if any special prefix characters (such as ~)
+ * are used. If the bigname is different from name, bigname will need to
+ * be freed.
+ */
+ bigname = ExpandFilename (name);
+ if (!bigname) return None;
+
+ /*
+ * look along bitmapFilePath resource same as toolkit clients
+ */
+ pm = XmuLocateBitmapFile (ScreenOfDisplay(dpy, Scr->screen), bigname, NULL,
+ 0, (int *)widthp, (int *)heightp, &HotX, &HotY);
+ if (pm == None && Scr->IconDirectory && bigname[0] != '/') {
+ if (bigname != name) free (bigname);
+ /*
+ * Attempt to find icon in old IconDirectory (now obsolete)
+ */
+ bigname = (char *) malloc (strlen(name) + strlen(Scr->IconDirectory) +
+ 2);
+ if (!bigname) {
+ fprintf (stderr,
+ "%s: unable to allocate memory for \"%s/%s\"\n",
+ ProgramName, Scr->IconDirectory, name);
+ return None;
+ }
+ (void) sprintf (bigname, "%s/%s", Scr->IconDirectory, name);
+ if (XReadBitmapFile (dpy, Scr->Root, bigname, widthp, heightp, &pm,
+ &HotX, &HotY) != BitmapSuccess) {
+ pm = None;
+ }
+ }
+ if (bigname != name) free (bigname);
+ if (pm == None) {
+ fprintf (stderr, "%s: unable to find bitmap \"%s\"\n",
+ ProgramName, name);
+ }
+
+ return pm;
+}
+
+Pixmap GetBitmap (name)
+ char *name;
+{
+ return FindBitmap (name, &JunkWidth, &JunkHeight);
+}
+
+
+InsertRGBColormap (a, maps, nmaps, replace)
+ Atom a;
+ XStandardColormap *maps;
+ int nmaps;
+ Bool replace;
+{
+ StdCmap *sc = NULL;
+
+ if (replace) { /* locate existing entry */
+ for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
+ if (sc->atom == a) break;
+ }
+ }
+
+ if (!sc) { /* no existing, allocate new */
+ sc = (StdCmap *) malloc (sizeof (StdCmap));
+ if (!sc) {
+ fprintf (stderr, "%s: unable to allocate %d bytes for StdCmap\n",
+ ProgramName, sizeof (StdCmap));
+ return;
+ }
+ }
+
+ if (replace) { /* just update contents */
+ if (sc->maps) XFree ((char *) maps);
+ if (sc == Scr->StdCmapInfo.mru) Scr->StdCmapInfo.mru = NULL;
+ } else { /* else appending */
+ sc->next = NULL;
+ sc->atom = a;
+ if (Scr->StdCmapInfo.tail) {
+ Scr->StdCmapInfo.tail->next = sc;
+ } else {
+ Scr->StdCmapInfo.head = sc;
+ }
+ Scr->StdCmapInfo.tail = sc;
+ }
+ sc->nmaps = nmaps;
+ sc->maps = maps;
+
+ return;
+}
+
+RemoveRGBColormap (a)
+ Atom a;
+{
+ StdCmap *sc, *prev;
+
+ prev = NULL;
+ for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
+ if (sc->atom == a) break;
+ prev = sc;
+ }
+ if (sc) { /* found one */
+ if (sc->maps) XFree ((char *) sc->maps);
+ if (prev) prev->next = sc->next;
+ if (Scr->StdCmapInfo.head == sc) Scr->StdCmapInfo.head = sc->next;
+ if (Scr->StdCmapInfo.tail == sc) Scr->StdCmapInfo.tail = prev;
+ if (Scr->StdCmapInfo.mru == sc) Scr->StdCmapInfo.mru = NULL;
+ }
+ return;
+}
+
+LocateStandardColormaps()
+{
+ Atom *atoms;
+ int natoms;
+ int i;
+
+ atoms = XListProperties (dpy, Scr->Root, &natoms);
+ for (i = 0; i < natoms; i++) {
+ XStandardColormap *maps = NULL;
+ int nmaps;
+
+ if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, atoms[i])) {
+ /* if got one, then append to current list */
+ InsertRGBColormap (atoms[i], maps, nmaps, False);
+ }
+ }
+ if (atoms) XFree ((char *) atoms);
+ return;
+}
+
+GetColor(kind, what, name)
+int kind;
+Pixel *what;
+char *name;
+{
+ XColor color, junkcolor;
+ Status stat = 0;
+ Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
+
+#ifndef TOM
+ if (!Scr->FirstTime)
+ return;
+#endif
+
+ if (Scr->Monochrome != kind)
+ return;
+
+ if (!XAllocNamedColor (dpy, cmap, name, &color, &junkcolor))
+ {
+ /* if we could not allocate the color, let's see if this is a
+ * standard colormap
+ */
+ XStandardColormap *stdcmap = NULL;
+
+ /* parse the named color */
+ if (name[0] != '#')
+ stat = XParseColor (dpy, cmap, name, &color);
+ if (!stat)
+ {
+ fprintf (stderr, "%s: invalid color name \"%s\"\n",
+ ProgramName, name);
+ return;
+ }
+
+ /*
+ * look through the list of standard colormaps (check cache first)
+ */
+ if (Scr->StdCmapInfo.mru && Scr->StdCmapInfo.mru->maps &&
+ (Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex].colormap ==
+ cmap)) {
+ stdcmap = &(Scr->StdCmapInfo.mru->maps[Scr->StdCmapInfo.mruindex]);
+ } else {
+ StdCmap *sc;
+
+ for (sc = Scr->StdCmapInfo.head; sc; sc = sc->next) {
+ int i;
+
+ for (i = 0; i < sc->nmaps; i++) {
+ if (sc->maps[i].colormap == cmap) {
+ Scr->StdCmapInfo.mru = sc;
+ Scr->StdCmapInfo.mruindex = i;
+ stdcmap = &(sc->maps[i]);
+ goto gotit;
+ }
+ }
+ }
+ }
+
+ gotit:
+ if (stdcmap) {
+ color.pixel = (stdcmap->base_pixel +
+ ((Pixel)(((float)color.red / 65535.0) *
+ stdcmap->red_max + 0.5) *
+ stdcmap->red_mult) +
+ ((Pixel)(((float)color.green /65535.0) *
+ stdcmap->green_max + 0.5) *
+ stdcmap->green_mult) +
+ ((Pixel)(((float)color.blue / 65535.0) *
+ stdcmap->blue_max + 0.5) *
+ stdcmap->blue_mult));
+ } else {
+ fprintf (stderr, "%s: unable to allocate color \"%s\"\n",
+ ProgramName, name);
+ return;
+ }
+ }
+
+ *what = color.pixel;
+}
+
+GetColorValue(kind, what, name)
+int kind;
+XColor *what;
+char *name;
+{
+ XColor junkcolor;
+ Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c;
+
+#ifndef TOM
+ if (!Scr->FirstTime)
+ return;
+#endif
+
+ if (Scr->Monochrome != kind)
+ return;
+
+ if (!XLookupColor (dpy, cmap, name, what, &junkcolor))
+ {
+ fprintf (stderr, "%s: invalid color name \"%s\"\n",
+ ProgramName, name);
+ }
+ else
+ {
+ what->pixel = AllPlanes;
+ }
+}
+
+GetFont(font)
+MyFont *font;
+{
+ char *deffontname = "fixed";
+
+ if (font->font != NULL)
+ XFreeFont(dpy, font->font);
+
+ if ((font->font = XLoadQueryFont(dpy, font->name)) == NULL)
+ {
+ if (Scr->DefaultFont.name) {
+ deffontname = Scr->DefaultFont.name;
+ }
+ if ((font->font = XLoadQueryFont(dpy, deffontname)) == NULL)
+ {
+ fprintf (stderr, "%s: unable to open fonts \"%s\" or \"%s\"\n",
+ ProgramName, font->name, deffontname);
+ exit(1);
+ }
+
+ }
+ font->height = font->font->ascent + font->font->descent;
+ font->y = font->font->ascent;
+}
+
+
+/*
+ * SetFocus - separate routine to set focus to make things more understandable
+ * and easier to debug
+ */
+SetFocus (tmp_win, time)
+ TwmWindow *tmp_win;
+ Time time;
+{
+ Window w = (tmp_win ? tmp_win->w : PointerRoot);
+
+#ifdef TRACE
+ if (tmp_win) {
+ printf ("Focusing on window \"%s\"\n", tmp_win->full_name);
+ } else {
+ printf ("Unfocusing; Scr->Focus was \"%s\"\n",
+ Scr->Focus ? Scr->Focus->full_name : "(nil)");
+ }
+#endif
+
+ XSetInputFocus (dpy, w, RevertToPointerRoot, time);
+}
+
+
+#ifdef NOPUTENV
+/*
+ * define our own putenv() if the system doesn't have one.
+ * putenv(s): place s (a string of the form "NAME=value") in
+ * the environment; replacing any existing NAME. s is placed in
+ * environment, so if you change s, the environment changes (like
+ * putenv on a sun). Binding removed if you putenv something else
+ * called NAME.
+ */
+int
+putenv(s)
+ char *s;
+{
+ char *v;
+ int varlen, idx;
+ extern char **environ;
+ char **newenv;
+ static int virgin = 1; /* true while "environ" is a virgin */
+
+ v = index(s, '=');
+ if(v == 0)
+ return 0; /* punt if it's not of the right form */
+ varlen = (v + 1) - s;
+
+ for (idx = 0; environ[idx] != 0; idx++) {
+ if (strncmp(environ[idx], s, varlen) == 0) {
+ if(v[1] != 0) { /* true if there's a value */
+ environ[idx] = s;
+ return 0;
+ } else {
+ do {
+ environ[idx] = environ[idx+1];
+ } while(environ[++idx] != 0);
+ return 0;
+ }
+ }
+ }
+
+ /* add to environment (unless no value; then just return) */
+ if(v[1] == 0)
+ return 0;
+ if(virgin) {
+ register i;
+
+ newenv = (char **) malloc((unsigned) ((idx + 2) * sizeof(char*)));
+ if(newenv == 0)
+ return -1;
+ for(i = idx-1; i >= 0; --i)
+ newenv[i] = environ[i];
+ virgin = 0; /* you're not a virgin anymore, sweety */
+ } else {
+ newenv = (char **) realloc((char *) environ,
+ (unsigned) ((idx + 2) * sizeof(char*)));
+ if (newenv == 0)
+ return -1;
+ }
+
+ environ = newenv;
+ environ[idx] = s;
+ environ[idx+1] = 0;
+
+ return 0;
+}
+#endif /* NOPUTENV */
+
+
+static Pixmap CreateXLogoPixmap (widthp, heightp)
+ unsigned int *widthp, *heightp;
+{
+ int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
+ if (h < 0) h = 0;
+
+ *widthp = *heightp = (unsigned int) h;
+ if (Scr->tbpm.xlogo == None) {
+ GC gc, gcBack;
+
+ Scr->tbpm.xlogo = XCreatePixmap (dpy, Scr->Root, h, h, 1);
+ gc = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
+ XSetForeground (dpy, gc, 0);
+ XFillRectangle (dpy, Scr->tbpm.xlogo, gc, 0, 0, h, h);
+ XSetForeground (dpy, gc, 1);
+ gcBack = XCreateGC (dpy, Scr->tbpm.xlogo, 0L, NULL);
+ XSetForeground (dpy, gcBack, 0);
+
+ /*
+ * draw the logo large so that it gets as dense as possible; then white
+ * out the edges so that they look crisp
+ */
+ XmuDrawLogo (dpy, Scr->tbpm.xlogo, gc, gcBack, -1, -1, h + 2, h + 2);
+ XDrawRectangle (dpy, Scr->tbpm.xlogo, gcBack, 0, 0, h - 1, h - 1);
+
+ /*
+ * done drawing
+ */
+ XFreeGC (dpy, gc);
+ XFreeGC (dpy, gcBack);
+ }
+ return Scr->tbpm.xlogo;
+}
+
+
+static Pixmap CreateResizePixmap (widthp, heightp)
+ unsigned int *widthp, *heightp;
+{
+ int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
+ if (h < 1) h = 1;
+
+ *widthp = *heightp = (unsigned int) h;
+ if (Scr->tbpm.resize == None) {
+ XPoint points[3];
+ GC gc;
+ int w;
+ int lw;
+
+ /*
+ * create the pixmap
+ */
+ Scr->tbpm.resize = XCreatePixmap (dpy, Scr->Root, h, h, 1);
+ gc = XCreateGC (dpy, Scr->tbpm.resize, 0L, NULL);
+ XSetForeground (dpy, gc, 0);
+ XFillRectangle (dpy, Scr->tbpm.resize, gc, 0, 0, h, h);
+ XSetForeground (dpy, gc, 1);
+ lw = h / 16;
+ if (lw == 1)
+ lw = 0;
+ XSetLineAttributes (dpy, gc, lw, LineSolid, CapButt, JoinMiter);
+
+ /*
+ * draw the resize button,
+ */
+ w = (h * 2) / 3;
+ points[0].x = w;
+ points[0].y = 0;
+ points[1].x = w;
+ points[1].y = w;
+ points[2].x = 0;
+ points[2].y = w;
+ XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
+ w = w / 2;
+ points[0].x = w;
+ points[0].y = 0;
+ points[1].x = w;
+ points[1].y = w;
+ points[2].x = 0;
+ points[2].y = w;
+ XDrawLines (dpy, Scr->tbpm.resize, gc, points, 3, CoordModeOrigin);
+
+ /*
+ * done drawing
+ */
+ XFreeGC(dpy, gc);
+ }
+ return Scr->tbpm.resize;
+}
+
+
+static Pixmap CreateDotPixmap (widthp, heightp)
+ unsigned int *widthp, *heightp;
+{
+ int h = Scr->TBInfo.width - Scr->TBInfo.border * 2;
+
+ h = h * 3 / 4;
+ if (h < 1) h = 1;
+ if (!(h & 1))
+ h--;
+ *widthp = *heightp = (unsigned int) h;
+ if (Scr->tbpm.delete == None) {
+ GC gc;
+ Pixmap pix;
+
+ pix = Scr->tbpm.delete = XCreatePixmap (dpy, Scr->Root, h, h, 1);
+ gc = XCreateGC (dpy, pix, 0L, NULL);
+ XSetLineAttributes (dpy, gc, h, LineSolid, CapRound, JoinRound);
+ XSetForeground (dpy, gc, 0L);
+ XFillRectangle (dpy, pix, gc, 0, 0, h, h);
+ XSetForeground (dpy, gc, 1L);
+ XDrawLine (dpy, pix, gc, h/2, h/2, h/2, h/2);
+ XFreeGC (dpy, gc);
+ }
+ return Scr->tbpm.delete;
+}
+
+#define questionmark_width 8
+#define questionmark_height 8
+static char questionmark_bits[] = {
+ 0x38, 0x7c, 0x64, 0x30, 0x18, 0x00, 0x18, 0x18};
+
+static Pixmap CreateQuestionPixmap (widthp, heightp)
+ unsigned int *widthp, *heightp;
+{
+ *widthp = questionmark_width;
+ *heightp = questionmark_height;
+ if (Scr->tbpm.question == None) {
+ Scr->tbpm.question = XCreateBitmapFromData (dpy, Scr->Root,
+ questionmark_bits,
+ questionmark_width,
+ questionmark_height);
+ }
+ /*
+ * this must succeed or else we are in deep trouble elsewhere
+ */
+ return Scr->tbpm.question;
+}
+
+
+static Pixmap CreateMenuPixmap (widthp, heightp)
+ int *widthp, *heightp;
+{
+ return CreateMenuIcon (Scr->TBInfo.width - Scr->TBInfo.border * 2,
+ widthp,heightp);
+}
+
+Pixmap CreateMenuIcon (height, widthp, heightp)
+ int height;
+ int *widthp, *heightp;
+{
+ int h, w;
+ int ih, iw;
+ int ix, iy;
+ int mh, mw;
+ int tw, th;
+ int lw, lh;
+ int lx, ly;
+ int lines, dly;
+ int off;
+ int bw;
+
+ h = height;
+ w = h * 7 / 8;
+ if (h < 1)
+ h = 1;
+ if (w < 1)
+ w = 1;
+ *widthp = w;
+ *heightp = h;
+ if (Scr->tbpm.menu == None) {
+ Pixmap pix;
+ GC gc;
+
+ pix = Scr->tbpm.menu = XCreatePixmap (dpy, Scr->Root, w, h, 1);
+ gc = XCreateGC (dpy, pix, 0L, NULL);
+ XSetForeground (dpy, gc, 0L);
+ XFillRectangle (dpy, pix, gc, 0, 0, w, h);
+ XSetForeground (dpy, gc, 1L);
+ ix = 1;
+ iy = 1;
+ ih = h - iy * 2;
+ iw = w - ix * 2;
+ off = ih / 8;
+ mh = ih - off;
+ mw = iw - off;
+ bw = mh / 16;
+ if (bw == 0 && mw > 2)
+ bw = 1;
+ tw = mw - bw * 2;
+ th = mh - bw * 2;
+ XFillRectangle (dpy, pix, gc, ix, iy, mw, mh);
+ XFillRectangle (dpy, pix, gc, ix + iw - mw, iy + ih - mh, mw, mh);
+ XSetForeground (dpy, gc, 0L);
+ XFillRectangle (dpy, pix, gc, ix+bw, iy+bw, tw, th);
+ XSetForeground (dpy, gc, 1L);
+ lw = tw / 2;
+ if ((tw & 1) ^ (lw & 1))
+ lw++;
+ lx = ix + bw + (tw - lw) / 2;
+
+ lh = th / 2 - bw;
+ if ((lh & 1) ^ ((th - bw) & 1))
+ lh++;
+ ly = iy + bw + (th - bw - lh) / 2;
+
+ lines = 3;
+ if ((lh & 1) && lh < 6)
+ {
+ lines--;
+ }
+ dly = lh / (lines - 1);
+ while (lines--)
+ {
+ XFillRectangle (dpy, pix, gc, lx, ly, lw, bw);
+ ly += dly;
+ }
+ XFreeGC (dpy, gc);
+ }
+ return Scr->tbpm.menu;
+}
+
+void
+Bell(type,percent,win)
+ int type;
+ int percent;
+ Window win;
+{
+#ifdef XKB
+ XkbStdBell(dpy, win, percent, type);
+#else
+ XBell(dpy, percent);
+#endif
+ return;
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..bfeab2f
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,95 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+
+/***********************************************************************
+ *
+ * $Xorg: util.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * utility routines header file
+ *
+ * 28-Oct-87 Thomas E. LaStrange File created
+ *
+ ***********************************************************************/
+
+#ifndef _UTIL_
+#define _UTIL_
+
+extern void Zoom();
+extern void MoveOutline();
+extern Pixmap GetBitmap(), FindBitmap();
+extern void GetUnknownIcon();
+extern char *ExpandFilename();
+extern int GetColor();
+
+extern int HotX, HotY;
+
+#define WM_BELL 0
+#define MINOR_ERROR_BELL 1
+#define MAJOR_ERROR_BELL 2
+#define INFO_BELL 3
+#define NUM_BELLS 4
+
+#define QUIET_BELL -100
+#define MODERATE_BELL 0
+#define LOUD_BELL 100
+
+#ifdef XKB
+#include <X11/extensions/XKBbells.h>
+#else
+#define XkbBI_Info 0
+#define XkbBI_MinorError 1
+#define XkbBI_MajorError 2
+#endif
+
+extern void Bell();
+
+#endif /* _UTIL_ */
diff --git a/src/version.c b/src/version.c
new file mode 100644
index 0000000..9e3e70c
--- /dev/null
+++ b/src/version.c
@@ -0,0 +1,54 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+/* $Xorg: version.c,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $ */
+char *Version = "The Open Group, R6.3";
+
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 0000000..d232190
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/*
+
+Copyright 1989, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
+/** Salt Lake City, Utah **/
+/** Cambridge, Massachusetts **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** Permission to use, copy, modify, and distribute this software and **/
+/** its documentation for any purpose and without fee is hereby **/
+/** granted, provided that the above copyright notice appear in all **/
+/** copies and that both that copyright notice and this permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Evans & Sutherland not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/
+/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
+/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/
+/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
+/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
+/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
+/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
+/** OR PERFORMANCE OF THIS SOFTWARE. **/
+/*****************************************************************************/
+
+/**********************************************************************
+ *
+ * $Xorg: version.h,v 1.4 2001/02/09 02:05:37 xorgcvs Exp $
+ *
+ * TWM version externs
+ *
+ * 8-Apr-88 Tom LaStrange Initial Version.
+ *
+ **********************************************************************/
+
+#ifndef _VERSION_
+#define _VERSION_
+
+extern char *Version;
+
+#endif /* _VERSION_ */