summaryrefslogtreecommitdiff
path: root/lwlib
diff options
context:
space:
mode:
authorRichard M. Stallman <rms@gnu.org>1994-01-18 23:47:41 +0000
committerRichard M. Stallman <rms@gnu.org>1994-01-18 23:47:41 +0000
commit07bf635fc3142206f15500d33024886c4339e522 (patch)
treeb418c805c1cba62903cc9ea4928ccb3d48463087 /lwlib
parent87cd38d6effdfa2d06a5f6e17f4e2f701595ecdd (diff)
downloademacs-07bf635fc3142206f15500d33024886c4339e522.tar.gz
Initial revision
Diffstat (limited to 'lwlib')
-rw-r--r--lwlib/Makefile.in397
-rw-r--r--lwlib/dispatch.c275
-rw-r--r--lwlib/lwlib-Xlw.c178
-rw-r--r--lwlib/lwlib-Xlw.h29
-rw-r--r--lwlib/lwlib-Xm.c1495
-rw-r--r--lwlib/lwlib-Xm.h34
-rw-r--r--lwlib/lwlib-Xol.h29
-rw-r--r--lwlib/lwlib-int.h54
-rw-r--r--lwlib/lwlib-utils.c162
-rw-r--r--lwlib/lwlib-utils.h20
-rw-r--r--lwlib/lwlib.c1111
-rw-r--r--lwlib/lwlib.h103
-rw-r--r--lwlib/xlwmenu.c1265
-rw-r--r--lwlib/xlwmenu.h50
14 files changed, 5202 insertions, 0 deletions
diff --git a/lwlib/Makefile.in b/lwlib/Makefile.in
new file mode 100644
index 00000000000..5caa9310b99
--- /dev/null
+++ b/lwlib/Makefile.in
@@ -0,0 +1,397 @@
+# Makefile generated by imake - do not edit!
+# $XConsortium: imake.c,v 1.51 89/12/12 12:37:30 jim Exp $
+#
+# The cpp used on this machine replaces all newlines and multiple tabs and
+# spaces in a macro expansion with a single space. Imake tries to compensate
+# for this, but is not always successful.
+#
+
+###########################################################################
+# Makefile generated from "Imake.tmpl" and <Imakefile>
+# $XConsortium: Imake.tmpl,v 1.77 89/12/18 17:01:37 jim Exp $
+#
+# Platform-specific parameters may be set in the appropriate .cf
+# configuration files. Site-wide parameters may be set in the file
+# site.def. Full rebuilds are recommended if any parameters are changed.
+#
+# If your C preprocessor doesn't define any unique symbols, you'll need
+# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing
+# "make Makefile", "make Makefiles", or "make World").
+#
+# If you absolutely can't get imake to work, you'll need to set the
+# variables at the top of each Makefile as well as the dependencies at the
+# bottom (makedepend will do this automatically).
+#
+
+###########################################################################
+# platform-specific configuration parameters - edit sun.cf to change
+
+# platform: $XConsortium: sun.cf,v 1.38 89/12/23 16:10:10 jim Exp $
+# operating system: SunOS 4.0.3
+
+###########################################################################
+# site-specific configuration parameters - edit site.def to change
+
+# site: $XConsortium: site.def,v 1.21 89/12/06 11:46:50 jim Exp $
+
+ SHELL = /bin/sh
+
+ TOP = .
+ CURRENT_DIR = .
+
+ AR = ar cq
+ BOOTSTRAPCFLAGS =
+ CC = gcc -DNOSTDHDRS -fstrength-reduce -fpcc-struct-return -fwritable-strings -traditional
+
+ COMPRESS = compress
+ CPP = /lib/cpp $(STD_CPP_DEFINES)
+ PREPROCESSCMD = gcc -DNOSTDHDRS -fstrength-reduce -fpcc-struct-return -fwritable-strings -traditional -E $(STD_CPP_DEFINES)
+ INSTALL = install
+ LD = ld
+ LINT = lint
+ LINTLIBFLAG = -C
+ LINTOPTS = -axz
+ LN = ln -s
+ MAKE = make
+ MV = mv
+ CP = cp
+ RANLIB = ranlib
+ RANLIBINSTFLAGS =
+ RM = rm -f
+ STD_INCLUDES =
+ STD_CPP_DEFINES =
+ STD_DEFINES =
+ EXTRA_LOAD_FLAGS =
+ EXTRA_LIBRARIES =
+ TAGS = ctags
+
+ SHAREDCODEDEF = -DSHAREDCODE
+ SHLIBDEF = -DSUNSHLIB
+
+ PROTO_DEFINES =
+
+ INSTPGMFLAGS =
+
+ INSTBINFLAGS = -m 0755
+ INSTUIDFLAGS = -m 4755
+ INSTLIBFLAGS = -m 0664
+ INSTINCFLAGS = -m 0444
+ INSTMANFLAGS = -m 0444
+ INSTDATFLAGS = -m 0444
+ INSTKMEMFLAGS = -m 4755
+
+ DESTDIR =
+
+ TOP_INCLUDES = -I$(INCROOT)
+
+ CDEBUGFLAGS = -O
+ CCOPTIONS =
+ COMPATFLAGS =
+
+ ALLINCLUDES = $(STD_INCLUDES) $(TOP_INCLUDES) $(INCLUDES) $(EXTRA_INCLUDES)
+ ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(PROTO_DEFINES) $(DEFINES) $(COMPATFLAGS)
+ CFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(ALLDEFINES)
+ LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES)
+ LDLIBS = $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)
+ LDOPTIONS = $(CDEBUGFLAGS) $(CCOPTIONS)
+ LDCOMBINEFLAGS = -X -r
+
+ MACROFILE = sun.cf
+ RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut
+
+ IMAKE_DEFINES =
+
+ IRULESRC = $(CONFIGDIR)
+ IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES)
+
+ ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/Imake.rules \
+ $(IRULESRC)/Project.tmpl $(IRULESRC)/site.def \
+ $(IRULESRC)/$(MACROFILE) $(EXTRA_ICONFIGFILES)
+
+###########################################################################
+# X Window System Build Parameters
+# $XConsortium: Project.tmpl,v 1.63 89/12/18 16:46:44 jim Exp $
+
+###########################################################################
+# X Window System make variables; this need to be coordinated with rules
+# $XConsortium: Project.tmpl,v 1.63 89/12/18 16:46:44 jim Exp $
+
+ PATHSEP = /
+ USRLIBDIR = $(DESTDIR)/usr/lib
+ BINDIR = $(DESTDIR)/usr/bin/X11
+ INCROOT = $(DESTDIR)/usr/include
+ BUILDINCROOT = $(TOP)
+ BUILDINCDIR = $(BUILDINCROOT)/X11
+ BUILDINCTOP = ..
+ INCDIR = $(INCROOT)/X11
+ ADMDIR = $(DESTDIR)/usr/adm
+ LIBDIR = $(USRLIBDIR)/X11
+ CONFIGDIR = $(LIBDIR)/config
+ LINTLIBDIR = $(USRLIBDIR)/lint
+
+ FONTDIR = $(LIBDIR)/fonts
+ XINITDIR = $(LIBDIR)/xinit
+ XDMDIR = $(LIBDIR)/xdm
+ AWMDIR = $(LIBDIR)/awm
+ TWMDIR = $(LIBDIR)/twm
+ GWMDIR = $(LIBDIR)/gwm
+ MANPATH = $(DESTDIR)/usr/man
+ MANSOURCEPATH = $(MANPATH)/man
+ MANDIR = $(MANSOURCEPATH)n
+ LIBMANDIR = $(MANSOURCEPATH)3
+ XAPPLOADDIR = $(LIBDIR)/app-defaults
+
+ SOXLIBREV = 4.2
+ SOXTREV = 4.0
+ SOXAWREV = 4.0
+ SOOLDXREV = 4.0
+ SOXMUREV = 4.0
+ SOXEXTREV = 4.0
+
+ FONTCFLAGS = -t
+
+ INSTAPPFLAGS = $(INSTDATFLAGS)
+
+ IMAKE = imake
+ DEPEND = makedepend
+ RGB = rgb
+ FONTC = bdftosnf
+ MKFONTDIR = mkfontdir
+ MKDIRHIER = /bin/sh $(BINDIR)/mkdirhier
+
+ CONFIGSRC = $(TOP)/config
+ CLIENTSRC = $(TOP)/clients
+ DEMOSRC = $(TOP)/demos
+ LIBSRC = $(TOP)/lib
+ FONTSRC = $(TOP)/fonts
+ INCLUDESRC = $(TOP)/X11
+ SERVERSRC = $(TOP)/server
+ UTILSRC = $(TOP)/util
+ SCRIPTSRC = $(UTILSRC)/scripts
+ EXAMPLESRC = $(TOP)/examples
+ CONTRIBSRC = $(TOP)/../contrib
+ DOCSRC = $(TOP)/doc
+ RGBSRC = $(TOP)/rgb
+ DEPENDSRC = $(UTILSRC)/makedepend
+ IMAKESRC = $(CONFIGSRC)
+ XAUTHSRC = $(LIBSRC)/Xau
+ XLIBSRC = $(LIBSRC)/X
+ XMUSRC = $(LIBSRC)/Xmu
+ TOOLKITSRC = $(LIBSRC)/Xt
+ AWIDGETSRC = $(LIBSRC)/Xaw
+ OLDXLIBSRC = $(LIBSRC)/oldX
+ XDMCPLIBSRC = $(LIBSRC)/Xdmcp
+ BDFTOSNFSRC = $(FONTSRC)/bdftosnf
+ MKFONTDIRSRC = $(FONTSRC)/mkfontdir
+ EXTENSIONSRC = $(TOP)/extensions
+
+ DEPEXTENSIONLIB = $(USRLIBDIR)/libXext.a
+ EXTENSIONLIB = -lXext
+
+ DEPXLIB = $(DEPEXTENSIONLIB)
+ XLIB = $(EXTENSIONLIB) -lX11
+
+ DEPXAUTHLIB = $(USRLIBDIR)/libXau.a
+ XAUTHLIB = -lXau
+
+ DEPXMULIB =
+ XMULIB = -lXmu
+
+ DEPOLDXLIB =
+ OLDXLIB = -loldX
+
+ DEPXTOOLLIB =
+ XTOOLLIB = -lXt
+
+ DEPXAWLIB =
+ XAWLIB = -lXaw
+
+ LINTEXTENSIONLIB = $(USRLIBDIR)/llib-lXext.ln
+ LINTXLIB = $(USRLIBDIR)/llib-lX11.ln
+ LINTXMU = $(USRLIBDIR)/llib-lXmu.ln
+ LINTXTOOL = $(USRLIBDIR)/llib-lXt.ln
+ LINTXAW = $(USRLIBDIR)/llib-lXaw.ln
+
+ XWLIBSRC = $(CONTRIBSRC)/toolkits/Xw
+ DEPXWLIB = $(USRLIBDIR)/libXw.a
+ XWLIB = -lXw
+
+ DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB)
+
+ DEPLIBS1 = $(DEPLIBS)
+ DEPLIBS2 = $(DEPLIBS)
+ DEPLIBS3 = $(DEPLIBS)
+
+###########################################################################
+# Imake rules for building libraries, programs, scripts, and data files
+# rules: $XConsortium: Imake.rules,v 1.67 89/12/18 17:14:15 jim Exp $
+
+###########################################################################
+# start of Imakefile
+
+# Imakefile file for liblw.a, Copyright (c) 1992-1993 Lucid, Inc.
+
+ STD_DEFINES =
+ CDEBUGFLAGS = -O
+ EXT_DEFINES = -DTHIS_IS_X11R4
+ WHICH_X = x11r4
+
+ LUCID_SRCS = lwlib-Xlw.c xlwmenu.c
+ LUCID_OBJS = lwlib-Xlw.o xlwmenu.o
+ MOTIF_SRCS = lwlib-Xm.c
+ MOTIF_OBJS = lwlib-Xm.o
+ OLIT_SRCS = lwlib-Xol.c lwlib-Xol-mb.c
+ OLIT_OBJS = lwlib-Xol.o lwlib-Xol-mb.o
+
+TOOLKIT_DEFINES = -DUSE_LUCID
+ TOOLKIT_SRCS = $(LUCID_SRC)
+ TOOLKIT_OBJS = $(LUCID_OBJS)
+
+ SRCS = lwlib.c $(TOOLKIT_SRCS) lwlib-utils.c $(EXT_SRCS)
+ OBJS = lwlib.o $(TOOLKIT_OBJS) lwlib-utils.o $(EXT_OBJS) $(EZ_OBJS)
+ EXT_FLAGS = -I$(TOOLKITSRC) $(EXT_DEFINES)
+ LIBNAME = liblw.a
+
+.c.o:
+ $(RM) $@
+ $(CC) -c $(CFLAGS) $*.c
+
+all:: liblw.a
+
+liblw.a: $(OBJS)
+ $(RM) $@
+ $(AR) $@ $(OBJS)
+ $(RANLIB) $@
+
+Makefiles::
+ @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
+ for i in energize ;\
+ do \
+ echo "making Makefiles in $(CURRENT_DIR)/$$i..."; \
+ case "$$i" in \
+ ./?*/?*/?*/?*) newtop=../../../../ sub=subsubsubsub;; \
+ ./?*/?*/?*) newtop=../../../ sub=subsubsub;; \
+ ./?*/?*) newtop=../../ sub=subsub;; \
+ ./?*) newtop=../ sub=sub;; \
+ */?*/?*/?*) newtop=../../../../ sub=subsubsubsub;; \
+ */?*/?*) newtop=../../../ sub=subsubsub;; \
+ */?*) newtop=../../ sub=subsub;; \
+ *) newtop=../ sub=sub;; \
+ esac; \
+ case "$(TOP)" in \
+ /?*) newtop= upprefix= ;; \
+ *) upprefix=../ ;; \
+ esac; \
+ $(MAKE) $${sub}dirMakefiles UPPREFIX=$$upprefix NEWTOP=$$newtop \
+ MAKEFILE_SUBDIR=$$i NEW_CURRENT_DIR=$(CURRENT_DIR)/$$i;\
+ done
+
+subdirMakefiles:
+ $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak
+ -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \
+ echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \
+ $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \
+ else exit 0; fi
+ cd $(MAKEFILE_SUBDIR); $(IMAKE_CMD) -DTOPDIR=$(UPPREFIX)$(TOP) -DCURDIR=$(NEW_CURRENT_DIR); \
+ $(MAKE) $(MFLAGS) Makefiles
+
+subsubdirMakefiles:
+ $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak
+ -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \
+ echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \
+ $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \
+ else exit 0; fi
+ cd $(MAKEFILE_SUBDIR); $(IMAKE_CMD) -DTOPDIR=$(UPPREFIX)$(UPPREFIX)$(TOP) -DCURDIR=$(NEW_CURRENT_DIR); \
+ $(MAKE) $(MFLAGS) Makefiles
+
+subsubsubdirMakefiles:
+ $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak
+ -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \
+ echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \
+ $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \
+ else exit 0; fi
+ cd $(MAKEFILE_SUBDIR); $(IMAKE_CMD) -DTOPDIR=$(UPPREFIX)$(UPPREFIX)$(UPPREFIX)$(TOP) -DCURDIR=$(NEW_CURRENT_DIR); \
+ $(MAKE) $(MFLAGS) Makefiles
+
+subsubsubsubdirMakefiles:
+ $(RM) $(MAKEFILE_SUBDIR)/Makefile.bak
+ -@if [ -f $(MAKEFILE_SUBDIR)/Makefile ]; then \
+ echo " $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak"; \
+ $(MV) $(MAKEFILE_SUBDIR)/Makefile $(MAKEFILE_SUBDIR)/Makefile.bak; \
+ else exit 0; fi
+ cd $(MAKEFILE_SUBDIR); $(IMAKE_CMD) -DTOPDIR=$(UPPREFIX)$(UPPREFIX)$(UPPREFIX)$(UPPREFIX)$(TOP) -DCURDIR=$(NEW_CURRENT_DIR); \
+ $(MAKE) $(MFLAGS) Makefiles
+
+depend::
+ $(DEPEND) -s "# DO NOT DELETE" -- $(ALLDEFINES) -- $(SRCS)
+
+CPPDEFS=-DCPP_PROGRAM=\"/lib/cpp\"
+
+lwlib.o: lwlib.c
+ $(RM) $@
+ $(CC) -c $(CFLAGS) $(TOOLKIT_DEFINES) $*.c
+
+dispatch.o: dispatch.c
+ $(RM) $@
+ $(CC) -c $(CFLAGS) $(EXT_FLAGS) $*.c
+
+xrdb-cpp.o: xrdb-cpp.c
+ $(RM) $@
+ $(CC) -c $(CFLAGS) $(EXT_FLAGS) "$(CPPDEFS)" $*.c
+
+xrdb.o: xrdb.c
+ $(RM) $@
+ $(CC) -c $(CFLAGS) $(EXT_FLAGS) $*.c
+
+lwlib-Xm.o: lwlib-Xm.c
+ $(RM) $@
+ $(CC) -c $(CFLAGS) $(ENERGIZEP) $*.c
+
+lwlib-utils.o: lwlib-utils.h
+lwlib.o: lwlib.h lwlib-internal.h
+lwlib-Xlw.o: lwlib.h lwlib-internal.h
+lwlib-Xm.o: lwlib.h lwlib-internal.h lwlib-utils.h
+lwlib-Xol.o: lwlib.h lwlib-internal.h
+lwlib-Xol-mb.o: lwlib-Xol-mb.h lwlib-Xol-mbP.h
+
+###########################################################################
+# common rules for all Makefiles - do not edit
+
+emptyrule::
+
+clean::
+ $(RM_CMD) \#*
+
+Makefile::
+ -@if [ -f Makefile ]; then \
+ echo " $(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \
+ $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
+ else exit 0; fi
+ $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR)
+
+tags::
+ $(TAGS) -w *.[ch]
+ $(TAGS) -xw *.[ch] > TAGS
+
+saber:
+ #load $(ALLDEFINES) $(SRCS)
+
+osaber:
+ #load $(ALLDEFINES) $(OBJS)
+
+###########################################################################
+# empty rules for directories that do not have SUBDIRS - do not edit
+
+install::
+ @echo "install in $(CURRENT_DIR) done"
+
+install.man::
+ @echo "install.man in $(CURRENT_DIR) done"
+
+Makefiles::
+
+includes::
+
+###########################################################################
+# dependencies generated by makedepend
+
diff --git a/lwlib/dispatch.c b/lwlib/dispatch.c
new file mode 100644
index 00000000000..428512bc3d7
--- /dev/null
+++ b/lwlib/dispatch.c
@@ -0,0 +1,275 @@
+/* Defines a function to find the Widget that XtDispatchEvent() would use.
+ Copyright (C) 1992 Lucid, Inc.
+
+This file is part of the Lucid Widget Library.
+
+The Lucid Widget Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+The Lucid Widget Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * The function XtWidgetToDispatchTo(), given an XEvent, returns the
+ * widget that XtDispatchEvent() would send that event to if called now.
+ * This file copies much code from the X11r4 Xt source, and is thus a
+ * portability problem. It also requires data structures defined in
+ * IntrinsicI.h, which is a non-exported Xt header file, so you can't
+ * compile this file unless you have the Xt sources online.
+ */
+
+#include <IntrinsicI.h> /* Don't change this: see comments in Imakefile. */
+#include <X11/Xatom.h>
+#include "dispatch.h"
+
+#ifdef THIS_IS_X11R4
+
+#ifdef THIS_IS_X11R5
+ERROR!! only one of THIS_IS_X11R4 or THIS_IS_X11R5 must be defined.
+#endif
+
+#else /* ! THIS_IS_X11R4 */
+
+#ifndef THIS_IS_X11R5
+ERROR!! one of THIS_IS_X11R4 or THIS_IS_X11R5 must be defined.
+#endif
+
+#endif /* ! THIS_IS_X11R4 */
+
+
+/* ## All of the code on this page was copied from the X11R5 lib/Xt/Event.c,
+ ## but is compatible with X11R4; the code in Event.c is different, but
+ ## functionally equivalent for our purposes.
+ */
+
+#if __STDC__
+#define Const const
+#else
+#define Const /**/
+#endif
+
+#define NonMaskableMask ((EventMask)0x80000000L)
+
+#define COMP_EXPOSE (widget->core.widget_class->core_class.compress_exposure)
+#define COMP_EXPOSE_TYPE (COMP_EXPOSE & 0x0f)
+#define GRAPHICS_EXPOSE ((XtExposeGraphicsExpose & COMP_EXPOSE) || \
+ (XtExposeGraphicsExposeMerged & COMP_EXPOSE))
+#define NO_EXPOSE (XtExposeNoExpose & COMP_EXPOSE)
+
+
+/* -- lots of stuff we don't need to copy, omitted -- */
+
+
+static EventMask Const masks[] = {
+ 0, /* Error, should never see */
+ 0, /* Reply, should never see */
+ KeyPressMask, /* KeyPress */
+ KeyReleaseMask, /* KeyRelease */
+ ButtonPressMask, /* ButtonPress */
+ ButtonReleaseMask, /* ButtonRelease */
+ PointerMotionMask /* MotionNotify */
+ | ButtonMotionMask,
+ EnterWindowMask, /* EnterNotify */
+ LeaveWindowMask, /* LeaveNotify */
+ FocusChangeMask, /* FocusIn */
+ FocusChangeMask, /* FocusOut */
+ KeymapStateMask, /* KeymapNotify */
+ ExposureMask, /* Expose */
+ NonMaskableMask, /* GraphicsExpose, in GC */
+ NonMaskableMask, /* NoExpose, in GC */
+ VisibilityChangeMask, /* VisibilityNotify */
+ SubstructureNotifyMask, /* CreateNotify */
+ StructureNotifyMask /* DestroyNotify */
+ | SubstructureNotifyMask,
+ StructureNotifyMask /* UnmapNotify */
+ | SubstructureNotifyMask,
+ StructureNotifyMask /* MapNotify */
+ | SubstructureNotifyMask,
+ SubstructureRedirectMask, /* MapRequest */
+ StructureNotifyMask /* ReparentNotify */
+ | SubstructureNotifyMask,
+ StructureNotifyMask /* ConfigureNotify */
+ | SubstructureNotifyMask,
+ SubstructureRedirectMask, /* ConfigureRequest */
+ StructureNotifyMask /* GravityNotify */
+ | SubstructureNotifyMask,
+ ResizeRedirectMask, /* ResizeRequest */
+ StructureNotifyMask /* CirculateNotify */
+ | SubstructureNotifyMask,
+ SubstructureRedirectMask, /* CirculateRequest */
+ PropertyChangeMask, /* PropertyNotify */
+ NonMaskableMask, /* SelectionClear */
+ NonMaskableMask, /* SelectionRequest */
+ NonMaskableMask, /* SelectionNotify */
+ ColormapChangeMask, /* ColormapNotify */
+ NonMaskableMask, /* ClientMessage */
+ NonMaskableMask /* MappingNotify */
+};
+
+#ifdef THIS_IS_X11R4
+
+static /* in R5, this is not static, so we don't need to define it at all */
+EventMask _XtConvertTypeToMask (eventType)
+ int eventType;
+{
+ eventType &= 0x7f; /* Events sent with XSendEvent have high bit set. */
+ if (eventType < XtNumber(masks))
+ return masks[eventType];
+ else
+ return 0;
+}
+
+#endif /* R4 */
+
+/* -- _XtOnGrabList() omitted -- */
+
+
+static Widget LookupSpringLoaded(grabList)
+ XtGrabList grabList;
+{
+ XtGrabList gl;
+
+ for (gl = grabList; gl != NULL; gl = gl->next) {
+ if (gl->spring_loaded)
+ if (XtIsSensitive(gl->widget))
+ return gl->widget;
+ else
+ return NULL;
+ if (gl->exclusive) break;
+ }
+ return NULL;
+}
+
+
+
+/* This function is new. */
+
+static Boolean WouldDispatchEvent(event, widget, mask, pd)
+ register XEvent *event;
+ Widget widget;
+ EventMask mask;
+ XtPerDisplay pd;
+{
+ XtEventRec *p;
+ Boolean would_dispatched = False;
+
+ if ((mask == ExposureMask) ||
+ ((event->type == NoExpose) && NO_EXPOSE) ||
+ ((event->type == GraphicsExpose) && GRAPHICS_EXPOSE) )
+ if (widget->core.widget_class->core_class.expose != NULL )
+ return True;
+
+
+ if ((mask == VisibilityChangeMask) &&
+ XtClass(widget)->core_class.visible_interest)
+ return True;
+
+ for (p=widget->core.event_table; p != NULL; p = p->next)
+ if ((mask & p->mask) != 0
+#ifdef THIS_IS_X11R4
+ || (mask == 0 && p->non_filter)
+#endif
+ )
+ return True;
+
+ return False;
+}
+
+
+/* #### This function is mostly copied from DecideToDispatch().
+ */
+
+typedef enum _GrabType {pass, ignore, remap} GrabType;
+
+Widget
+XtWidgetToDispatchTo (XEvent* event)
+{
+ register Widget widget;
+ EventMask mask;
+ GrabType grabType;
+ Widget dspWidget;
+ Time time = 0;
+ XtPerDisplay pd;
+ XtPerDisplayInput pdi;
+ XtGrabList grabList;
+
+ widget = XtWindowToWidget (event->xany.display, event->xany.window);
+ pd = _XtGetPerDisplay(event->xany.display);
+ pdi = _XtGetPerDisplayInput(event->xany.display);
+ grabList = *_XtGetGrabList(pdi);
+
+ mask = _XtConvertTypeToMask(event->xany.type);
+ grabType = pass;
+ switch (event->xany.type & 0x7f) {
+ case KeyPress:
+ case KeyRelease: grabType = remap; break;
+ case ButtonPress:
+ case ButtonRelease: grabType = remap; break;
+ case MotionNotify: grabType = ignore;
+#define XKnownButtons (Button1MotionMask|Button2MotionMask|Button3MotionMask|\
+ Button4MotionMask|Button5MotionMask)
+ mask |= (event->xmotion.state & XKnownButtons);
+#undef XKnownButtons
+ break;
+ case EnterNotify: grabType = ignore; break;
+ }
+
+ if (widget == NULL) {
+ if (grabType != remap) return False;
+ /* event occurred in a non-widget window, but we've promised also
+ to dispatch it to the nearest accessible spring_loaded widget */
+ else if ((widget = LookupSpringLoaded(grabList)) != NULL)
+ return widget;
+ return False;
+ }
+
+ switch(grabType) {
+ case pass:
+ return widget;
+
+ case ignore:
+ if ((grabList == NULL || _XtOnGrabList(widget,grabList))
+ && XtIsSensitive(widget)) {
+ return widget;
+ }
+ return NULL;
+
+ case remap:
+
+ {
+ Widget was_dispatched_to= NULL;
+ extern Widget _XtFindRemapWidget();
+ extern void _XtUngrabBadGrabs();
+
+ dspWidget = _XtFindRemapWidget(event, widget, mask, pdi);
+
+ if ((grabList == NULL ||
+ _XtOnGrabList(dspWidget, grabList)) &&
+ XtIsSensitive(dspWidget)) {
+ if (WouldDispatchEvent (event, dspWidget, mask, pd))
+ was_dispatched_to = dspWidget;
+ }
+
+ /* Also dispatch to nearest accessible spring_loaded. */
+ /* Fetch this afterward to reflect modal list changes */
+ grabList = *_XtGetGrabList(pdi);
+ widget = LookupSpringLoaded(grabList);
+ if (widget != NULL && widget != dspWidget) {
+ if (!was_dispatched_to)
+ was_dispatched_to = widget;
+ }
+
+ return was_dispatched_to;
+ }
+ }
+ /* should never reach here */
+ return NULL;
+}
diff --git a/lwlib/lwlib-Xlw.c b/lwlib/lwlib-Xlw.c
new file mode 100644
index 00000000000..1c56b8eb3a3
--- /dev/null
+++ b/lwlib/lwlib-Xlw.c
@@ -0,0 +1,178 @@
+/* The lwlib interface to "xlwmenu" menus.
+ Copyright (C) 1992 Lucid, Inc.
+
+This file is part of the Lucid Widget Library.
+
+The Lucid Widget Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+The Lucid Widget Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "lwlib-Xlw.h"
+#include <X11/StringDefs.h>
+#include <X11/IntrinsicP.h>
+#include <X11/ObjectP.h>
+#include <X11/CompositeP.h>
+#include <X11/Shell.h>
+#include "xlwmenu.h"
+
+ /* Menu callbacks */
+static void
+pre_hook (Widget w, XtPointer client_data, XtPointer call_data)
+{
+ widget_instance* instance = (widget_instance*)client_data;
+ widget_value* val;
+
+ if (w->core.being_destroyed)
+ return;
+
+ val = lw_get_widget_value_for_widget (instance, w);
+ if (instance->info->pre_activate_cb)
+ instance->info->pre_activate_cb (w, instance->info->id,
+ val ? val->call_data : NULL);
+}
+
+static void
+pick_hook (Widget w, XtPointer client_data, XtPointer call_data)
+{
+ widget_instance* instance = (widget_instance*)client_data;
+ widget_value* contents_val = (widget_value*)call_data;
+ widget_value* widget_val;
+ XtPointer widget_arg;
+
+ if (w->core.being_destroyed)
+ return;
+
+ if (instance->info->selection_cb && contents_val && contents_val->enabled
+ && !contents_val->contents)
+ instance->info->selection_cb (w, instance->info->id,
+ contents_val->call_data);
+
+ widget_val = lw_get_widget_value_for_widget (instance, w);
+ widget_arg = widget_val ? widget_val->call_data : NULL;
+ if (instance->info->post_activate_cb)
+ instance->info->post_activate_cb (w, instance->info->id, widget_arg);
+
+}
+
+ /* creation functions */
+static Widget
+xlw_create_menubar (widget_instance* instance)
+{
+ Widget widget =
+ XtVaCreateWidget (instance->info->name, xlwMenuWidgetClass,
+ instance->parent,
+ XtNmenu, instance->info->val,
+ 0);
+ XtAddCallback (widget, XtNopen, pre_hook, (XtPointer)instance);
+ XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance);
+ return widget;
+}
+
+static Widget
+xlw_create_popup_menu (widget_instance* instance)
+{
+ Widget popup_shell =
+ XtCreatePopupShell (instance->info->name, overrideShellWidgetClass,
+ instance->parent, NULL, 0);
+
+ Widget widget =
+ XtVaCreateManagedWidget ("popup", xlwMenuWidgetClass,
+ popup_shell,
+ XtNmenu, instance->info->val,
+ XtNhorizontal, False,
+ 0);
+
+ XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance);
+
+ return popup_shell;
+}
+
+widget_creation_entry
+xlw_creation_table [] =
+{
+ {"menubar", xlw_create_menubar},
+ {"popup", xlw_create_popup_menu},
+ {NULL, NULL}
+};
+
+Boolean
+lw_lucid_widget_p (Widget widget)
+{
+ WidgetClass the_class = XtClass (widget);
+ if (the_class == xlwMenuWidgetClass)
+ return True;
+ if (the_class == overrideShellWidgetClass)
+ return
+ XtClass (((CompositeWidget)widget)->composite.children [0])
+ == xlwMenuWidgetClass;
+ return False;
+}
+
+void
+xlw_update_one_widget (widget_instance* instance, Widget widget,
+ widget_value* val, Boolean deep_p)
+{
+ XlwMenuWidget mw;
+
+ if (XtIsShell (widget))
+ mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0];
+ else
+ mw = (XlwMenuWidget)widget;
+ XtVaSetValues (widget, XtNmenu, val, 0);
+}
+
+void
+xlw_update_one_value (widget_instance* instance, Widget widget,
+ widget_value* val)
+{
+ return;
+}
+
+void
+xlw_pop_instance (widget_instance* instance, Boolean up)
+{
+}
+
+void
+xlw_popup_menu (Widget widget)
+{
+ XButtonPressedEvent dummy;
+ XlwMenuWidget mw;
+
+ if (!XtIsShell (widget))
+ return;
+
+ mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0];
+
+ dummy.type = ButtonPress;
+ dummy.serial = 0;
+ dummy.send_event = 0;
+ dummy.display = XtDisplay (widget);
+ dummy.window = XtWindow (XtParent (widget));
+ dummy.time = CurrentTime;
+ dummy.button = 0;
+ XQueryPointer (dummy.display, dummy.window, &dummy.root,
+ &dummy.subwindow, &dummy.x_root, &dummy.y_root,
+ &dummy.x, &dummy.y, &dummy.state);
+
+ pop_up_menu (mw, &dummy);
+}
+
+ /* Destruction of instances */
+void
+xlw_destroy_instance (widget_instance* instance)
+{
+ if (instance->widget)
+ XtDestroyWidget (instance->widget);
+}
+
diff --git a/lwlib/lwlib-Xlw.h b/lwlib/lwlib-Xlw.h
new file mode 100644
index 00000000000..33d83e88850
--- /dev/null
+++ b/lwlib/lwlib-Xlw.h
@@ -0,0 +1,29 @@
+#ifndef LWLIB_XLW_H
+#define LWLIB_XLW_H
+
+#include "lwlib-internal.h"
+
+extern widget_creation_entry xlw_creation_table [];
+extern widget_creation_function xlw_create_dialog;
+
+Boolean
+lw_lucid_widget_p (Widget widget);
+
+void
+xlw_update_one_widget (widget_instance* instance, Widget widget,
+ widget_value* val, Boolean deep_p);
+
+void
+xlw_update_one_value (widget_instance* instance, Widget widget,
+ widget_value* val);
+
+void
+xlw_destroy_instance (widget_instance* instance);
+
+void
+xlw_pop_instance (widget_instance* instance, Boolean up);
+
+void
+xlw_popup_menu (Widget widget);
+
+#endif /* LWLIB_XLW_H */
diff --git a/lwlib/lwlib-Xm.c b/lwlib/lwlib-Xm.c
new file mode 100644
index 00000000000..13d28862697
--- /dev/null
+++ b/lwlib/lwlib-Xm.c
@@ -0,0 +1,1495 @@
+/* The lwlib interface to Motif widgets.
+ Copyright (C) 1992 Lucid, Inc.
+
+This file is part of the Lucid Widget Library.
+
+The Lucid Widget Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+The Lucid Widget Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <X11/StringDefs.h>
+#include <X11/IntrinsicP.h>
+#include <X11/ObjectP.h>
+#include <X11/CoreP.h>
+#include <X11/CompositeP.h>
+
+#include "lwlib-Xm.h"
+#include "lwlib-utils.h"
+
+#include <Xm/BulletinB.h>
+#include <Xm/CascadeB.h>
+#include <Xm/DrawingA.h>
+#include <Xm/FileSB.h>
+#include <Xm/Label.h>
+#include <Xm/List.h>
+#include <Xm/MenuShell.h>
+#include <Xm/MessageB.h>
+#include <Xm/PushB.h>
+#include <Xm/PushBG.h>
+#include <Xm/ArrowB.h>
+#include <Xm/SelectioB.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+#include <Xm/ToggleB.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/RowColumn.h>
+#include <Xm/ScrolledW.h>
+#include <Xm/Separator.h>
+#include <Xm/DialogS.h>
+#include <Xm/Form.h>
+
+static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
+static void xm_internal_update_other_instances (Widget, XtPointer,
+ XtPointer);
+static void xm_generic_callback (Widget, XtPointer, XtPointer);
+static void xm_nosel_callback (Widget, XtPointer, XtPointer);
+static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
+
+static void
+xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
+ Boolean deep_p);
+
+ /* Structures to keep destroyed instances */
+typedef struct _destroyed_instance
+{
+ char* name;
+ char* type;
+ Widget widget;
+ Widget parent;
+ Boolean pop_up_p;
+ struct _destroyed_instance* next;
+} destroyed_instance;
+
+static destroyed_instance*
+all_destroyed_instances = NULL;
+
+static destroyed_instance*
+make_destroyed_instance (char* name, char* type, Widget widget, Widget parent,
+ Boolean pop_up_p)
+{
+ destroyed_instance* instance =
+ (destroyed_instance*)malloc (sizeof (destroyed_instance));
+ instance->name = strdup (name);
+ instance->type = strdup (type);
+ instance->widget = widget;
+ instance->parent = parent;
+ instance->pop_up_p = pop_up_p;
+ instance->next = NULL;
+ return instance;
+}
+
+static void
+free_destroyed_instance (destroyed_instance* instance)
+{
+ free (instance->name);
+ free (instance->type);
+ free (instance);
+}
+
+ /* motif utility functions */
+Widget
+first_child (Widget widget)
+{
+ return ((CompositeWidget)widget)->composite.children [0];
+}
+
+Boolean
+lw_motif_widget_p (Widget widget)
+{
+ return
+ XtClass (widget) == xmDialogShellWidgetClass
+ || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
+}
+
+static XmString
+resource_motif_string (Widget widget, char* name)
+{
+ XtResource resource;
+ XmString result = 0;
+
+ resource.resource_name = name;
+ resource.resource_class = XmCXmString;
+ resource.resource_type = XmRXmString;
+ resource.resource_size = sizeof (XmString);
+ resource.resource_offset = 0;
+ resource.default_type = XtRImmediate;
+ resource.default_addr = 0;
+
+ XtGetSubresources (widget, (XtPointer)&result, "dialogString",
+ "DialogString", &resource, 1, NULL, 0);
+ return result;
+}
+
+static void
+destroy_all_children (Widget widget)
+{
+ Widget* children;
+ unsigned int number;
+ int i;
+
+ children = XtCompositeChildren (widget, &number);
+ if (children)
+ {
+ /* Unmanage all children and destroy them. They will only be
+ * really destroyed when we get out of DispatchEvent. */
+ for (i = 0; i < number; i++)
+ {
+ Widget child = children [i];
+ if (!child->core.being_destroyed)
+ {
+ XtUnmanageChild (child);
+ XtDestroyWidget (child);
+ }
+ }
+ XtFree ((char *) children);
+ }
+}
+
+ /* update the label of anything subclass of a label */
+static void
+xm_update_label (widget_instance* instance, Widget widget, widget_value* val)
+{
+ XmString res_string = 0;
+ XmString built_string = 0;
+ XmString key_string = 0;
+ Arg al [256];
+ int ac;
+
+ ac = 0;
+
+ if (val->value)
+ {
+ res_string = resource_motif_string (widget, val->value);
+
+ if (res_string)
+ {
+ XtSetArg (al [ac], XmNlabelString, res_string); ac++;
+ }
+ else
+ {
+ built_string =
+ XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
+ XtSetArg (al [ac], XmNlabelString, built_string); ac++;
+ }
+ XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
+ }
+
+ if (val->key)
+ {
+ key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
+ XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
+ }
+
+ if (ac)
+ XtSetValues (widget, al, ac);
+
+ if (built_string)
+ XmStringFree (built_string);
+
+ if (key_string)
+ XmStringFree (key_string);
+}
+
+ /* update of list */
+static void
+xm_update_list (widget_instance* instance, Widget widget, widget_value* val)
+{
+ widget_value* cur;
+ int i;
+ XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
+ XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
+ instance);
+ for (cur = val->contents, i = 0; cur; cur = cur->next)
+ if (cur->value)
+ {
+ XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
+ i += 1;
+ XmListAddItem (widget, xmstr, 0);
+ if (cur->selected)
+ XmListSelectPos (widget, i, False);
+ XmStringFree (xmstr);
+ }
+}
+
+ /* update of buttons */
+static void
+xm_update_pushbutton (widget_instance* instance, Widget widget,
+ widget_value* val)
+{
+ XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, 0);
+ XtRemoveAllCallbacks (widget, XmNactivateCallback);
+ XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
+}
+
+static void
+xm_update_cascadebutton (widget_instance* instance, Widget widget,
+ widget_value* val)
+{
+ /* Should also rebuild the menu by calling ...update_menu... */
+ XtRemoveAllCallbacks (widget, XmNcascadingCallback);
+ XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
+ instance);
+}
+
+ /* update toggle and radiobox */
+static void
+xm_update_toggle (widget_instance* instance, Widget widget, widget_value* val)
+{
+ XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
+ XtAddCallback (widget, XmNvalueChangedCallback,
+ xm_internal_update_other_instances, instance);
+ XtVaSetValues (widget, XmNset, val->selected,
+ XmNalignment, XmALIGNMENT_BEGINNING, 0);
+}
+
+static void
+xm_update_radiobox (widget_instance* instance, Widget widget,
+ widget_value* val)
+{
+ Widget toggle;
+ widget_value* cur;
+
+ /* update the callback */
+ XtRemoveAllCallbacks (widget, XmNentryCallback);
+ XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
+
+ /* first update all the toggles */
+ /* Energize kernel interface is currently bad. It sets the selected widget
+ with the selected flag but returns it by its name. So we currently
+ have to support both setting the selection with the selected slot
+ of val contents and setting it with the "value" slot of val. The latter
+ has a higher priority. This to be removed when the kernel is fixed. */
+ for (cur = val->contents; cur; cur = cur->next)
+ {
+ toggle = XtNameToWidget (widget, cur->value);
+ if (toggle)
+ {
+ XtVaSetValues (toggle, XmNsensitive, cur->enabled, 0);
+ if (!val->value && cur->selected)
+ XtVaSetValues (toggle, XmNset, cur->selected, 0);
+ if (val->value && strcmp (val->value, cur->value))
+ XtVaSetValues (toggle, XmNset, False, 0);
+ }
+ }
+
+ /* The selected was specified by the value slot */
+ if (val->value)
+ {
+ toggle = XtNameToWidget (widget, val->value);
+ if (toggle)
+ XtVaSetValues (toggle, XmNset, True, 0);
+ }
+}
+
+ /* update a popup menu, pulldown menu or a menubar */
+static Boolean
+all_dashes_p (char* s)
+{
+ char* t;
+ for (t = s; *t; t++)
+ if (*t != '-')
+ return False;
+ return True;
+}
+
+static void
+make_menu_in_widget (widget_instance* instance, Widget widget,
+ widget_value* val)
+{
+ Widget* children = 0;
+ int num_children;
+ int child_index;
+ widget_value* cur;
+ Widget button = 0;
+ Widget menu;
+ Arg al [256];
+ int ac;
+ Boolean menubar_p;
+
+ /* Allocate the children array */
+ for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
+ children = (Widget*)XtMalloc (num_children * sizeof (Widget));
+
+ /* tricky way to know if this RowColumn is a menubar or a pulldown... */
+ menubar_p = False;
+ XtSetArg (al[0], XmNisHomogeneous, &menubar_p);
+ XtGetValues (widget, al, 1);
+
+ /* add the unmap callback for popups and pulldowns */
+ /*** this sounds bogus ***/
+ if (!menubar_p)
+ XtAddCallback (XtParent (widget), XmNpopdownCallback,
+ xm_pop_down_callback, (XtPointer)instance);
+
+ for (child_index = 0, cur = val; cur; child_index++, cur = cur->next)
+ {
+ ac = 0;
+ XtSetArg (al [ac], XmNsensitive, cur->enabled); ac++;
+ XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
+ XtSetArg (al [ac], XmNuserData, cur->call_data); ac++;
+
+ if (all_dashes_p (cur->name))
+ {
+ button = XmCreateSeparator (widget, cur->name, NULL, 0);
+ }
+ else if (!cur->contents)
+ {
+ if (menubar_p)
+ button = XmCreateCascadeButton (widget, cur->name, al, ac);
+ else if (!cur->call_data)
+ button = XmCreateLabel (widget, cur->name, al, ac);
+ else
+ button = XmCreatePushButtonGadget (widget, cur->name, al, ac);
+
+ xm_update_label (instance, button, cur);
+
+ /* don't add a callback to a simple label */
+ if (cur->call_data)
+ XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
+ (XtPointer)instance);
+ }
+ else
+ {
+ menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
+ make_menu_in_widget (instance, menu, cur->contents);
+ XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
+ button = XmCreateCascadeButton (widget, cur->name, al, ac);
+
+ xm_update_label (instance, button, cur);
+
+ XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
+ (XtPointer)instance);
+ }
+
+ children [child_index] = button;
+ }
+
+ XtManageChildren (children, num_children);
+
+ /* Last entry is the help button. Has to be done after managing
+ * the buttons otherwise the menubar is only 4 pixels high... */
+ if (button)
+ {
+ ac = 0;
+ XtSetArg (al [ac], XmNmenuHelpWidget, button); ac++;
+ XtSetValues (widget, al, ac);
+ }
+
+ XtFree ((char *) children);
+}
+
+static void
+update_one_menu_entry (widget_instance* instance, Widget widget,
+ widget_value* val, Boolean deep_p)
+{
+ Arg al [256];
+ int ac;
+ Widget menu;
+ widget_value* contents;
+
+ if (val->change == NO_CHANGE)
+ return;
+
+ /* update the sensitivity and userdata */
+ /* Common to all widget types */
+ XtVaSetValues (widget,
+ XmNsensitive, val->enabled,
+ XmNuserData, val->call_data,
+ 0);
+
+ /* update the menu button as a label. */
+ if (val->change >= VISIBLE_CHANGE)
+ xm_update_label (instance, widget, val);
+
+ /* update the pulldown/pullaside as needed */
+ ac = 0;
+ menu = NULL;
+ XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
+ XtGetValues (widget, al, ac);
+
+ contents = val->contents;
+
+ if (!menu)
+ {
+ if (contents)
+ {
+ menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
+ make_menu_in_widget (instance, menu, contents);
+ ac = 0;
+ XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
+ XtSetValues (widget, al, ac);
+ }
+ }
+ else if (!contents)
+ {
+ ac = 0;
+ XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
+ XtSetValues (widget, al, ac);
+ XtDestroyWidget (menu);
+ }
+ else if (deep_p && contents->change != NO_CHANGE)
+ xm_update_menu (instance, menu, val, 1);
+}
+
+static void
+xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
+ Boolean deep_p)
+{
+ /* Widget is a RowColumn widget whose contents have to be updated
+ * to reflect the list of items in val->contents */
+ if (val->contents->change == STRUCTURAL_CHANGE)
+ {
+ destroy_all_children (widget);
+ make_menu_in_widget (instance, widget, val->contents);
+ }
+ else
+ {
+ /* Update all the buttons of the RowColumn in order. */
+ Widget* children;
+ unsigned int num_children;
+ int i;
+ widget_value* cur;
+
+ children = XtCompositeChildren (widget, &num_children);
+ if (children)
+ {
+ for (i = 0, cur = val->contents; i < num_children; i++)
+ {
+ if (!cur)
+ abort ();
+ if (children [i]->core.being_destroyed
+ || strcmp (XtName (children [i]), cur->name))
+ continue;
+ update_one_menu_entry (instance, children [i], cur, deep_p);
+ cur = cur->next;
+ }
+ XtFree ((char *) children);
+ }
+ if (cur)
+ abort ();
+ }
+}
+
+
+/* update text widgets */
+
+static void
+xm_update_text (widget_instance* instance, Widget widget, widget_value* val)
+{
+ XmTextSetString (widget, val->value ? val->value : "");
+ XtRemoveAllCallbacks (widget, XmNactivateCallback);
+ XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
+ XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
+ XtAddCallback (widget, XmNvalueChangedCallback,
+ xm_internal_update_other_instances, instance);
+}
+
+static void
+xm_update_text_field (widget_instance* instance, Widget widget,
+ widget_value* val)
+{
+ XmTextFieldSetString (widget, val->value ? val->value : "");
+ XtRemoveAllCallbacks (widget, XmNactivateCallback);
+ XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
+ XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
+ XtAddCallback (widget, XmNvalueChangedCallback,
+ xm_internal_update_other_instances, instance);
+}
+
+
+/* update a motif widget */
+
+void
+xm_update_one_widget (widget_instance* instance, Widget widget,
+ widget_value* val, Boolean deep_p)
+{
+ WidgetClass class;
+
+ /* Mark as not edited */
+ val->edited = False;
+
+ /* Common to all widget types */
+ XtVaSetValues (widget,
+ XmNsensitive, val->enabled,
+ XmNuserData, val->call_data,
+ 0);
+
+ /* Common to all label like widgets */
+ if (XtIsSubclass (widget, xmLabelWidgetClass))
+ xm_update_label (instance, widget, val);
+
+ class = XtClass (widget);
+ /* Class specific things */
+ if (class == xmPushButtonWidgetClass ||
+ class == xmArrowButtonWidgetClass)
+ {
+ xm_update_pushbutton (instance, widget, val);
+ }
+ else if (class == xmCascadeButtonWidgetClass)
+ {
+ xm_update_cascadebutton (instance, widget, val);
+ }
+ else if (class == xmToggleButtonWidgetClass
+ || class == xmToggleButtonGadgetClass)
+ {
+ xm_update_toggle (instance, widget, val);
+ }
+ else if (class == xmRowColumnWidgetClass)
+ {
+ Boolean radiobox = 0;
+ int ac = 0;
+ Arg al [1];
+
+ XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
+ XtGetValues (widget, al, ac);
+
+ if (radiobox)
+ xm_update_radiobox (instance, widget, val);
+ else
+ xm_update_menu (instance, widget, val, deep_p);
+ }
+ else if (class == xmTextWidgetClass)
+ {
+ xm_update_text (instance, widget, val);
+ }
+ else if (class == xmTextFieldWidgetClass)
+ {
+ xm_update_text_field (instance, widget, val);
+ }
+ else if (class == xmListWidgetClass)
+ {
+ xm_update_list (instance, widget, val);
+ }
+}
+
+ /* getting the value back */
+void
+xm_update_one_value (widget_instance* instance, Widget widget,
+ widget_value* val)
+{
+ WidgetClass class = XtClass (widget);
+ widget_value *old_wv;
+
+ /* copy the call_data slot into the "return" widget_value */
+ for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
+ if (!strcmp (val->name, old_wv->name))
+ {
+ val->call_data = old_wv->call_data;
+ break;
+ }
+
+ if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
+ {
+ XtVaGetValues (widget, XmNset, &val->selected, 0);
+ val->edited = True;
+ }
+ else if (class == xmTextWidgetClass)
+ {
+ if (val->value)
+ free (val->value);
+ val->value = XmTextGetString (widget);
+ val->edited = True;
+ }
+ else if (class == xmTextFieldWidgetClass)
+ {
+ if (val->value)
+ free (val->value);
+ val->value = XmTextFieldGetString (widget);
+ val->edited = True;
+ }
+ else if (class == xmRowColumnWidgetClass)
+ {
+ Boolean radiobox = 0;
+ int ac = 0;
+ Arg al [1];
+
+ XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
+ XtGetValues (widget, al, ac);
+
+ if (radiobox)
+ {
+ CompositeWidget radio = (CompositeWidget)widget;
+ int i;
+ for (i = 0; i < radio->composite.num_children; i++)
+ {
+ int set = False;
+ Widget toggle = radio->composite.children [i];
+
+ XtVaGetValues (toggle, XmNset, &set, 0);
+ if (set)
+ {
+ if (val->value)
+ free (val->value);
+ val->value = strdup (XtName (toggle));
+ }
+ }
+ val->edited = True;
+ }
+ }
+ else if (class == xmListWidgetClass)
+ {
+ int pos_cnt;
+ int* pos_list;
+ if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
+ {
+ int i;
+ widget_value* cur;
+ for (cur = val->contents, i = 0; cur; cur = cur->next)
+ if (cur->value)
+ {
+ int j;
+ cur->selected = False;
+ i += 1;
+ for (j = 0; j < pos_cnt; j++)
+ if (pos_list [j] == i)
+ {
+ cur->selected = True;
+ val->value = strdup (cur->name);
+ }
+ }
+ val->edited = 1;
+ XtFree ((char *) pos_list);
+ }
+ }
+}
+
+
+/* This function is for activating a button from a program. It's wrong because
+ we pass a NULL argument in the call_data which is not Motif compatible.
+ This is used from the XmNdefaultAction callback of the List widgets to
+ have a dble-click put down a dialog box like the button woudl do.
+ I could not find a way to do that with accelerators.
+ */
+static void
+activate_button (Widget widget, XtPointer closure, XtPointer call_data)
+{
+ Widget button = (Widget)closure;
+ XtCallCallbacks (button, XmNactivateCallback, NULL);
+}
+
+/* creation functions */
+
+/* dialogs */
+static Widget
+make_dialog (char* name, Widget parent, Boolean pop_up_p,
+ char* shell_title, char* icon_name, Boolean text_input_slot,
+ Boolean radio_box, Boolean list,
+ int left_buttons, int right_buttons)
+{
+ Widget result;
+ Widget form;
+ Widget row;
+ Widget icon;
+ Widget icon_separator;
+ Widget message;
+ Widget value = 0;
+ Widget separator;
+ Widget button = 0;
+ Widget children [16]; /* for the final XtManageChildren */
+ int n_children;
+ Arg al[64]; /* Arg List */
+ int ac; /* Arg Count */
+ int i;
+
+ if (pop_up_p)
+ {
+ ac = 0;
+ XtSetArg(al[ac], XmNtitle, shell_title); ac++;
+ XtSetArg(al[ac], XtNallowShellResize, True); ac++;
+ XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
+ result = XmCreateDialogShell (parent, "dialog", al, ac);
+ ac = 0;
+ XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
+/* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
+ XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
+ form = XmCreateForm (result, shell_title, al, ac);
+ }
+ else
+ {
+ ac = 0;
+ XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
+ XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
+ form = XmCreateForm (parent, shell_title, al, ac);
+ result = form;
+ }
+
+ ac = 0;
+ XtSetArg(al[ac], XmNpacking, XmPACK_COLUMN); ac++;
+ XtSetArg(al[ac], XmNorientation, XmVERTICAL); ac++;
+ XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNspacing, 13); ac++;
+ XtSetArg(al[ac], XmNadjustLast, False); ac++;
+ XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
+ XtSetArg(al[ac], XmNisAligned, True); ac++;
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 13); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 13); ac++;
+ row = XmCreateRowColumn (form, "row", al, ac);
+
+ n_children = 0;
+ for (i = 0; i < left_buttons; i++)
+ {
+ char button_name [16];
+ sprintf (button_name, "button%d", i + 1);
+ ac = 0;
+ if (i == 0)
+ {
+ XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
+ XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
+ }
+ XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
+ children [n_children] = XmCreatePushButton (row, button_name, al, ac);
+
+ if (i == 0)
+ {
+ button = children [n_children];
+ ac = 0;
+ XtSetArg(al[ac], XmNdefaultButton, button); ac++;
+ XtSetValues (row, al, ac);
+ }
+
+ n_children++;
+ }
+
+ /* invisible seperator button */
+ ac = 0;
+ XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
+ children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
+ n_children++;
+
+ for (i = 0; i < right_buttons; i++)
+ {
+ char button_name [16];
+ sprintf (button_name, "button%d", left_buttons + i + 1);
+ ac = 0;
+ XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
+ children [n_children] = XmCreatePushButton (row, button_name, al, ac);
+ if (! button) button = children [n_children];
+ n_children++;
+ }
+
+ XtManageChildren (children, n_children);
+
+ ac = 0;
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
+ XtSetArg(al[ac], XmNbottomWidget, row); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 0); ac++;
+ separator = XmCreateSeparator (form, "", al, ac);
+
+ ac = 0;
+ XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNtopOffset, 13); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 13); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+ icon = XmCreateLabel (form, icon_name, al, ac);
+
+ ac = 0;
+ XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNtopOffset, 6); ac++;
+ XtSetArg(al[ac], XmNtopWidget, icon); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
+ XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+ icon_separator = XmCreateLabel (form, "", al, ac);
+
+ if (text_input_slot)
+ {
+ ac = 0;
+ XtSetArg(al[ac], XmNcolumns, 50); ac++;
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
+ XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 13); ac++;
+ XtSetArg(al[ac], XmNleftWidget, icon); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 13); ac++;
+ value = XmCreateTextField (form, "value", al, ac);
+ }
+ else if (radio_box)
+ {
+ Widget radio_butt;
+ ac = 0;
+ XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
+ XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
+ XtSetArg(al[ac], XmNspacing, 13); ac++;
+ XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
+ XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
+ XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 13); ac++;
+ XtSetArg(al[ac], XmNleftWidget, icon); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 13); ac++;
+ value = XmCreateRadioBox (form, "radiobutton1", al, ac);
+ ac = 0;
+ i = 0;
+ radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
+ children [i++] = radio_butt;
+ radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
+ children [i++] = radio_butt;
+ radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
+ children [i++] = radio_butt;
+ XtManageChildren (children, i);
+ }
+ else if (list)
+ {
+ ac = 0;
+ XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
+ XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 13); ac++;
+ XtSetArg(al[ac], XmNleftWidget, icon); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 13); ac++;
+ value = XmCreateScrolledList (form, "list", al, ac);
+
+ /* this is the easiest way I found to have the dble click in the
+ list activate the default button */
+ XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
+ }
+
+ ac = 0;
+ XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
+ XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNtopOffset, 13); ac++;
+ XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
+ XtSetArg(al[ac], XmNbottomWidget,
+ text_input_slot || radio_box || list ? value : separator); ac++;
+ XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+ XtSetArg(al[ac], XmNleftOffset, 13); ac++;
+ XtSetArg(al[ac], XmNleftWidget, icon); ac++;
+ XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+ XtSetArg(al[ac], XmNrightOffset, 13); ac++;
+ message = XmCreateLabel (form, "message", al, ac);
+
+ if (list)
+ XtManageChild (value);
+
+ i = 0;
+ children [i] = row; i++;
+ children [i] = separator; i++;
+ if (text_input_slot || radio_box)
+ {
+ children [i] = value; i++;
+ }
+ children [i] = message; i++;
+ children [i] = icon; i++;
+ children [i] = icon_separator; i++;
+ XtManageChildren (children, i);
+
+ if (text_input_slot || list)
+ {
+ XtInstallAccelerators (value, button);
+ XtSetKeyboardFocus (result, value);
+ }
+ else
+ {
+ XtInstallAccelerators (form, button);
+ XtSetKeyboardFocus (result, button);
+ }
+
+ return result;
+}
+
+static destroyed_instance*
+find_matching_instance (widget_instance* instance)
+{
+ destroyed_instance* cur;
+ destroyed_instance* prev;
+ char* type = instance->info->type;
+ char* name = instance->info->name;
+
+ for (prev = NULL, cur = all_destroyed_instances;
+ cur;
+ prev = cur, cur = cur->next)
+ {
+ if (!strcmp (cur->name, name)
+ && !strcmp (cur->type, type)
+ && cur->parent == instance->parent
+ && cur->pop_up_p == instance->pop_up_p)
+ {
+ if (prev)
+ prev->next = cur->next;
+ else
+ all_destroyed_instances = cur->next;
+ return cur;
+ }
+ /* do some cleanup */
+ else if (!cur->widget)
+ {
+ if (prev)
+ prev->next = cur->next;
+ else
+ all_destroyed_instances = cur->next;
+ free_destroyed_instance (cur);
+ cur = prev ? prev : all_destroyed_instances;
+ }
+ }
+ return NULL;
+}
+
+static void
+mark_dead_instance_destroyed (Widget widget, XtPointer closure,
+ XtPointer call_data)
+{
+ destroyed_instance* instance = (destroyed_instance*)closure;
+ instance->widget = NULL;
+}
+
+static void
+recenter_widget (Widget widget)
+{
+ Widget parent = XtParent (widget);
+ Screen* screen = XtScreen (widget);
+ Dimension screen_width = WidthOfScreen (screen);
+ Dimension screen_height = HeightOfScreen (screen);
+ Dimension parent_width = 0;
+ Dimension parent_height = 0;
+ Dimension child_width = 0;
+ Dimension child_height = 0;
+ Position x;
+ Position y;
+
+ XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, 0);
+ XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
+ 0);
+
+ x = (((Position)parent_width) - ((Position)child_width)) / 2;
+ y = (((Position)parent_height) - ((Position)child_height)) / 2;
+
+ XtTranslateCoords (parent, x, y, &x, &y);
+
+ if (x + child_width > screen_width)
+ x = screen_width - child_width;
+ if (x < 0)
+ x = 0;
+
+ if (y + child_height > screen_height)
+ y = screen_height - child_height;
+ if (y < 0)
+ y = 0;
+
+ XtVaSetValues (widget, XtNx, x, XtNy, y, 0);
+}
+
+static Widget
+recycle_instance (destroyed_instance* instance)
+{
+ Widget widget = instance->widget;
+
+ /* widget is NULL if the parent was destroyed. */
+ if (widget)
+ {
+ Widget focus;
+ Widget separator;
+
+ /* Remove the destroy callback as the instance is not in the list
+ anymore */
+ XtRemoveCallback (instance->parent, XtNdestroyCallback,
+ mark_dead_instance_destroyed,
+ (XtPointer)instance);
+
+ /* Give the focus to the initial item */
+ focus = XtNameToWidget (widget, "*value");
+ if (!focus)
+ focus = XtNameToWidget (widget, "*button1");
+ if (focus)
+ XtSetKeyboardFocus (widget, focus);
+
+ /* shrink the separator label back to their original size */
+ separator = XtNameToWidget (widget, "*separator_button");
+ if (separator)
+ XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, 0);
+
+ /* Center the dialog in its parent */
+ recenter_widget (widget);
+ }
+ free_destroyed_instance (instance);
+ return widget;
+}
+
+Widget
+xm_create_dialog (widget_instance* instance)
+{
+ char* name = instance->info->type;
+ Widget parent = instance->parent;
+ Widget widget;
+ Boolean pop_up_p = instance->pop_up_p;
+ char* shell_name = 0;
+ char* icon_name;
+ Boolean text_input_slot = False;
+ Boolean radio_box = False;
+ Boolean list = False;
+ int total_buttons;
+ int left_buttons = 0;
+ int right_buttons = 1;
+ destroyed_instance* dead_one;
+
+ /* try to find a widget to recycle */
+ dead_one = find_matching_instance (instance);
+ if (dead_one)
+ {
+ Widget recycled_widget = recycle_instance (dead_one);
+ if (recycled_widget)
+ return recycled_widget;
+ }
+
+ switch (name [0]){
+ case 'E': case 'e':
+ icon_name = "dbox-error";
+ shell_name = "Error";
+ break;
+
+ case 'I': case 'i':
+ icon_name = "dbox-info";
+ shell_name = "Information";
+ break;
+
+ case 'L': case 'l':
+ list = True;
+ icon_name = "dbox-question";
+ shell_name = "Prompt";
+ break;
+
+ case 'P': case 'p':
+ text_input_slot = True;
+ icon_name = "dbox-question";
+ shell_name = "Prompt";
+ break;
+
+ case 'Q': case 'q':
+ icon_name = "dbox-question";
+ shell_name = "Question";
+ break;
+ }
+
+ total_buttons = name [1] - '0';
+
+ if (name [3] == 'T' || name [3] == 't')
+ {
+ text_input_slot = False;
+ radio_box = True;
+ }
+ else if (name [3])
+ right_buttons = name [4] - '0';
+
+ left_buttons = total_buttons - right_buttons;
+
+ widget = make_dialog (name, parent, pop_up_p,
+ shell_name, icon_name, text_input_slot, radio_box,
+ list, left_buttons, right_buttons);
+
+ XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
+ (XtPointer) instance);
+ return widget;
+}
+
+static Widget
+make_menubar (widget_instance* instance)
+{
+ return XmCreateMenuBar (instance->parent, instance->info->name, NULL, 0);
+}
+
+static void
+remove_grabs (Widget shell, XtPointer closure, XtPointer call_data)
+{
+ XmRowColumnWidget menu = (XmRowColumnWidget) closure;
+ XmRemoveFromPostFromList (menu, XtParent (XtParent ((Widget) menu)));
+}
+
+static Widget
+make_popup_menu (widget_instance* instance)
+{
+ Widget parent = instance->parent;
+ Window parent_window = parent->core.window;
+ Widget result;
+
+ /* sets the parent window to 0 to fool Motif into not generating a grab */
+ parent->core.window = 0;
+ result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
+ XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
+ (XtPointer)result);
+ parent->core.window = parent_window;
+ return result;
+}
+
+ /* Table of functions to create widgets */
+
+#ifdef ENERGIZE
+
+/* interface with the XDesigner generated functions */
+typedef Widget (*widget_maker) (Widget);
+extern Widget create_project_p_sheet (Widget parent);
+extern Widget create_debugger_p_sheet (Widget parent);
+extern Widget create_breaklist_p_sheet (Widget parent);
+extern Widget create_le_browser_p_sheet (Widget parent);
+extern Widget create_class_browser_p_sheet (Widget parent);
+extern Widget create_call_browser_p_sheet (Widget parent);
+extern Widget create_build_dialog (Widget parent);
+extern Widget create_editmode_dialog (Widget parent);
+extern Widget create_search_dialog (Widget parent);
+extern Widget create_project_display_dialog (Widget parent);
+
+static Widget
+make_one (widget_instance* instance, widget_maker fn)
+{
+ Widget result;
+ Arg al [64];
+ int ac = 0;
+
+ if (instance->pop_up_p)
+ {
+ XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
+ result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
+ XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
+ (XtPointer) instance);
+ (*fn) (result);
+ }
+ else
+ {
+ result = (*fn) (instance->parent);
+ XtRealizeWidget (result);
+ }
+ return result;
+}
+
+static Widget
+make_project_p_sheet (widget_instance* instance)
+{
+ return make_one (instance, create_project_p_sheet);
+}
+
+static Widget
+make_debugger_p_sheet (widget_instance* instance)
+{
+ return make_one (instance, create_debugger_p_sheet);
+}
+
+static Widget
+make_breaklist_p_sheet (widget_instance* instance)
+{
+ return make_one (instance, create_breaklist_p_sheet);
+}
+
+static Widget
+make_le_browser_p_sheet (widget_instance* instance)
+{
+ return make_one (instance, create_le_browser_p_sheet);
+}
+
+static Widget
+make_class_browser_p_sheet (widget_instance* instance)
+{
+ return make_one (instance, create_class_browser_p_sheet);
+}
+
+static Widget
+make_call_browser_p_sheet (widget_instance* instance)
+{
+ return make_one (instance, create_call_browser_p_sheet);
+}
+
+static Widget
+make_build_dialog (widget_instance* instance)
+{
+ return make_one (instance, create_build_dialog);
+}
+
+static Widget
+make_editmode_dialog (widget_instance* instance)
+{
+ return make_one (instance, create_editmode_dialog);
+}
+
+static Widget
+make_search_dialog (widget_instance* instance)
+{
+ return make_one (instance, create_search_dialog);
+}
+
+static Widget
+make_project_display_dialog (widget_instance* instance)
+{
+ return make_one (instance, create_project_display_dialog);
+}
+
+#endif /* ENERGIZE */
+
+widget_creation_entry
+xm_creation_table [] =
+{
+ {"menubar", make_menubar},
+ {"popup", make_popup_menu},
+#ifdef ENERGIZE
+ {"project_p_sheet", make_project_p_sheet},
+ {"debugger_p_sheet", make_debugger_p_sheet},
+ {"breaklist_psheet", make_breaklist_p_sheet},
+ {"leb_psheet", make_le_browser_p_sheet},
+ {"class_browser_psheet", make_class_browser_p_sheet},
+ {"ctree_browser_psheet", make_call_browser_p_sheet},
+ {"build", make_build_dialog},
+ {"editmode", make_editmode_dialog},
+ {"search", make_search_dialog},
+ {"project_display", make_project_display_dialog},
+#endif /* ENERGIZE */
+ {NULL, NULL}
+};
+
+ /* Destruction of instances */
+void
+xm_destroy_instance (widget_instance* instance)
+{
+ Widget widget = instance->widget;
+ /* recycle the dialog boxes */
+ /* Disable the recycling until we can find a way to have the dialog box
+ get reasonable layout after we modify its contents. */
+ if (0
+ && XtClass (widget) == xmDialogShellWidgetClass)
+ {
+ destroyed_instance* dead_instance =
+ make_destroyed_instance (instance->info->name,
+ instance->info->type,
+ instance->widget,
+ instance->parent,
+ instance->pop_up_p);
+ dead_instance->next = all_destroyed_instances;
+ all_destroyed_instances = dead_instance;
+ XtUnmanageChild (first_child (instance->widget));
+ XFlush (XtDisplay (instance->widget));
+ XtAddCallback (instance->parent, XtNdestroyCallback,
+ mark_dead_instance_destroyed, (XtPointer)dead_instance);
+ }
+ else
+ {
+ /* This might not be necessary now that the nosel is attached to
+ popdown instead of destroy, but it can't hurt. */
+ XtRemoveCallback (instance->widget, XtNdestroyCallback,
+ xm_nosel_callback, (XtPointer)instance);
+ XtDestroyWidget (instance->widget);
+ }
+}
+
+ /* popup utility */
+void
+xm_popup_menu (Widget widget)
+{
+ XButtonPressedEvent dummy;
+ XEvent* event;
+
+ dummy.type = ButtonPress;
+ dummy.serial = 0;
+ dummy.send_event = 0;
+ dummy.display = XtDisplay (widget);
+ dummy.window = XtWindow (XtParent (widget));
+ dummy.time = 0;
+ dummy.button = 0;
+ XQueryPointer (dummy.display, dummy.window, &dummy.root,
+ &dummy.subwindow, &dummy.x_root, &dummy.y_root,
+ &dummy.x, &dummy.y, &dummy.state);
+ event = (XEvent *) &dummy;
+
+ if (event->type == ButtonPress || event->type == ButtonRelease)
+ {
+ /* This is so totally ridiculous: there's NO WAY to tell Motif
+ that *any* button can select a menu item. Only one button
+ can have that honor.
+ */
+ char *trans = 0;
+ if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
+ else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
+ else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
+ else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
+ else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
+ if (trans) XtVaSetValues (widget, XmNmenuPost, trans, 0);
+ XmMenuPosition (widget, (XButtonPressedEvent *) event);
+ }
+ XtManageChild (widget);
+}
+
+static void
+set_min_dialog_size (Widget w)
+{
+ short width;
+ short height;
+ XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, 0);
+ XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, 0);
+}
+
+void
+xm_pop_instance (widget_instance* instance, Boolean up)
+{
+ Widget widget = instance->widget;
+
+ if (XtClass (widget) == xmDialogShellWidgetClass)
+ {
+ Widget widget_to_manage = first_child (widget);
+ if (up)
+ {
+ XtManageChild (widget_to_manage);
+ set_min_dialog_size (widget);
+ XtSetKeyboardFocus (instance->parent, widget);
+ }
+ else
+ XtUnmanageChild (widget_to_manage);
+ }
+ else
+ {
+ if (up)
+ XtManageChild (widget);
+ else
+ XtUnmanageChild (widget);
+ }
+}
+
+
+/* motif callback */
+
+enum do_call_type { pre_activate, selection, no_selection, post_activate };
+
+static void
+do_call (Widget widget, XtPointer closure, enum do_call_type type)
+{
+ Arg al [256];
+ int ac;
+ XtPointer user_data;
+ widget_instance* instance = (widget_instance*)closure;
+ Widget instance_widget;
+ LWLIB_ID id;
+
+ if (!instance)
+ return;
+ if (widget->core.being_destroyed)
+ return;
+
+ instance_widget = instance->widget;
+ if (!instance_widget)
+ return;
+
+ id = instance->info->id;
+ ac = 0;
+ user_data = NULL;
+ XtSetArg (al [ac], XmNuserData, &user_data); ac++;
+ XtGetValues (widget, al, ac);
+ switch (type)
+ {
+ case pre_activate:
+ if (instance->info->pre_activate_cb)
+ instance->info->pre_activate_cb (widget, id, user_data);
+ break;
+ case selection:
+ if (instance->info->selection_cb)
+ instance->info->selection_cb (widget, id, user_data);
+ break;
+ case no_selection:
+ if (instance->info->selection_cb)
+ instance->info->selection_cb (widget, id, (XtPointer) -1);
+ break;
+ case post_activate:
+ if (instance->info->post_activate_cb)
+ instance->info->post_activate_cb (widget, id, user_data);
+ break;
+ default:
+ abort ();
+ }
+}
+
+/* Like lw_internal_update_other_instances except that it does not do
+ anything if its shell parent is not managed. This is to protect
+ lw_internal_update_other_instances to dereference freed memory
+ if the widget was ``destroyed'' by caching it in the all_destroyed_instances
+ list */
+static void
+xm_internal_update_other_instances (Widget widget, XtPointer closure,
+ XtPointer call_data)
+{
+ Widget parent;
+ for (parent = widget; parent; parent = XtParent (parent))
+ if (XtIsShell (parent))
+ break;
+ else if (!XtIsManaged (parent))
+ return;
+ lw_internal_update_other_instances (widget, closure, call_data);
+}
+
+static void
+xm_generic_callback (Widget widget, XtPointer closure, XtPointer call_data)
+{
+ lw_internal_update_other_instances (widget, closure, call_data);
+ do_call (widget, closure, selection);
+}
+
+static void
+xm_nosel_callback (Widget widget, XtPointer closure, XtPointer call_data)
+{
+ /* This callback is only called when a dialog box is dismissed with the wm's
+ destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
+ in that case, not just unmapped, so that it releases its keyboard grabs.
+ But there are problems with running our callbacks while the widget is in
+ the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
+ instead of XmDESTROY and then destroy it ourself after having run the
+ callback.
+ */
+ do_call (widget, closure, no_selection);
+ XtDestroyWidget (widget);
+}
+
+static void
+xm_pull_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
+{
+ do_call (widget, closure, pre_activate);
+}
+
+static void
+xm_pop_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
+{
+ do_call (widget, closure, post_activate);
+}
+
+
+/* set the keyboard focus */
+void
+xm_set_keyboard_focus (Widget parent, Widget w)
+{
+ XmProcessTraversal (w, 0);
+ XtSetKeyboardFocus (parent, w);
+}
diff --git a/lwlib/lwlib-Xm.h b/lwlib/lwlib-Xm.h
new file mode 100644
index 00000000000..e5568effcf9
--- /dev/null
+++ b/lwlib/lwlib-Xm.h
@@ -0,0 +1,34 @@
+#ifndef LWLIB_XM_H
+#define LWLIB_XM_H
+
+#include "lwlib-internal.h"
+
+extern widget_creation_entry xm_creation_table [];
+
+Widget
+xm_create_dialog (widget_instance* instance);
+
+Boolean
+lw_motif_widget_p (Widget widget);
+
+void
+xm_update_one_widget (widget_instance* instance, Widget widget,
+ widget_value* val, Boolean deep_p);
+
+void
+xm_update_one_value (widget_instance* instance, Widget widget,
+ widget_value* val);
+
+void
+xm_destroy_instance (widget_instance* instance);
+
+void
+xm_set_keyboard_focus (Widget parent, Widget w);
+
+void
+xm_popup_menu (Widget widget);
+
+void
+xm_pop_instance (widget_instance* instance, Boolean up);
+
+#endif /* LWLIB_XM_H */
diff --git a/lwlib/lwlib-Xol.h b/lwlib/lwlib-Xol.h
new file mode 100644
index 00000000000..ee4d6481cb3
--- /dev/null
+++ b/lwlib/lwlib-Xol.h
@@ -0,0 +1,29 @@
+#ifndef LWLIB_XOL_H
+#define LWLIB_XOL_H
+
+#include "lwlib-internal.h"
+
+extern widget_creation_entry xol_creation_table [];
+extern Widget xol_create_dialog (widget_instance *);
+
+Boolean
+lw_olit_widget_p (Widget widget);
+
+void
+xol_update_one_widget (widget_instance* instance, Widget widget,
+ widget_value* val, Boolean deep_p);
+
+void
+xol_update_one_value (widget_instance* instance, Widget widget,
+ widget_value* val);
+
+void
+xol_destroy_instance (widget_instance* instance);
+
+void
+xol_pop_instance (widget_instance* instance, Boolean up);
+
+void
+xol_popup_menu (Widget widget);
+
+#endif /* LWLIB_XOL_H */
diff --git a/lwlib/lwlib-int.h b/lwlib/lwlib-int.h
new file mode 100644
index 00000000000..0f2c594e7de
--- /dev/null
+++ b/lwlib/lwlib-int.h
@@ -0,0 +1,54 @@
+#ifndef LWLIB_INTERNAL_H
+#define LWLIB_INTERNAL_H
+
+#include "lwlib.h"
+
+/*
+extern char *strdup (const char *);
+extern int strcasecmp (const char *, const char *);
+*/
+
+typedef struct _widget_instance
+{
+ Widget widget;
+ Widget parent;
+ Boolean pop_up_p;
+ struct _widget_info* info;
+ struct _widget_instance* next;
+} widget_instance;
+
+typedef struct _widget_info
+{
+ char* type;
+ char* name;
+ LWLIB_ID id;
+ widget_value* val;
+ Boolean busy;
+ lw_callback pre_activate_cb;
+ lw_callback selection_cb;
+ lw_callback post_activate_cb;
+ struct _widget_instance* instances;
+ struct _widget_info* next;
+} widget_info;
+
+typedef Widget
+(*widget_creation_function) (widget_instance* instance);
+
+typedef struct _widget_creation_entry
+{
+ char* type;
+ widget_creation_function function;
+} widget_creation_entry;
+
+/* update all other instances of a widget. Can be used in a callback when
+ a wiget has been used by the user */
+void
+lw_internal_update_other_instances (Widget widget, XtPointer closure,
+ XtPointer call_data);
+
+/* get the widget_value for a widget in a given instance */
+widget_value*
+lw_get_widget_value_for_widget (widget_instance* instance, Widget w);
+
+#endif /* LWLIB_INTERNAL_H */
+
diff --git a/lwlib/lwlib-utils.c b/lwlib/lwlib-utils.c
new file mode 100644
index 00000000000..97952afce55
--- /dev/null
+++ b/lwlib/lwlib-utils.c
@@ -0,0 +1,162 @@
+/* Defines some widget utility functions.
+ Copyright (C) 1992 Lucid, Inc.
+
+This file is part of the Lucid Widget Library.
+
+The Lucid Widget Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+The Lucid Widget Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <memory.h>
+
+#include <X11/Xatom.h>
+#include <X11/IntrinsicP.h>
+#include <X11/ObjectP.h>
+#include "lwlib-utils.h"
+
+/* Redisplay the contents of the widget, without first clearing it. */
+void
+XtNoClearRefreshWidget (Widget widget)
+{
+ XEvent event;
+
+ event.type = Expose;
+ event.xexpose.serial = 0;
+ event.xexpose.send_event = 0;
+ event.xexpose.display = XtDisplay (widget);
+ event.xexpose.window = XtWindow (widget);
+ event.xexpose.x = 0;
+ event.xexpose.y = 0;
+ event.xexpose.width = widget->core.width;
+ event.xexpose.height = widget->core.height;
+ event.xexpose.count = 0;
+
+ (*widget->core.widget_class->core_class.expose)
+ (widget, &event, (Region)NULL);
+}
+
+
+/*
+ * Apply a function to all the subwidgets of a given widget recursively.
+*/
+void
+XtApplyToWidgets (Widget w, XtApplyToWidgetsProc proc, XtPointer arg)
+{
+ if (XtIsComposite (w))
+ {
+ CompositeWidget cw = (CompositeWidget) w;
+ /* We have to copy the children list before mapping over it, because
+ the procedure might add/delete elements, which would lose badly.
+ */
+ int nkids = cw->composite.num_children;
+ Widget *kids = (Widget *) malloc (sizeof (Widget) * nkids);
+ int i;
+ memcpy (kids, cw->composite.children, sizeof (Widget) * nkids);
+ for (i = 0; i < nkids; i++)
+/* This prevent us from using gadgets, why is it here? */
+/* if (XtIsWidget (kids [i])) */
+ {
+ /* do the kiddies first in case we're destroying */
+ XtApplyToWidgets (kids [i], proc, arg);
+ proc (kids [i], arg);
+ }
+ free (kids);
+ }
+}
+
+
+/*
+ * Apply a function to all the subwidgets of a given widget recursively.
+ * Stop as soon as the function returns non NULL and returns this as a value.
+ */
+void *
+XtApplyUntilToWidgets (Widget w, XtApplyUntilToWidgetsProc proc, XtPointer arg)
+{
+ void* result;
+ if (XtIsComposite (w))
+ {
+ CompositeWidget cw = (CompositeWidget)w;
+ int i;
+ for (i = 0; i < cw->composite.num_children; i++)
+ if (XtIsWidget (cw->composite.children [i])){
+ result = proc (cw->composite.children [i], arg);
+ if (result)
+ return result;
+ result = XtApplyUntilToWidgets (cw->composite.children [i], proc,
+ arg);
+ if (result)
+ return result;
+ }
+ }
+ return NULL;
+}
+
+
+/*
+ * Returns a copy of the list of all children of a composite widget
+ */
+Widget *
+XtCompositeChildren (Widget widget, unsigned int* number)
+{
+ CompositeWidget cw = (CompositeWidget)widget;
+ Widget* result;
+ int n;
+ int i;
+
+ if (!XtIsComposite (widget))
+ {
+ *number = 0;
+ return NULL;
+ }
+ n = cw->composite.num_children;
+ result = (Widget*)XtMalloc (n * sizeof (Widget));
+ *number = n;
+ for (i = 0; i < n; i++)
+ result [i] = cw->composite.children [i];
+ return result;
+}
+
+Boolean
+XtWidgetBeingDestroyedP (Widget widget)
+{
+ return widget->core.being_destroyed;
+}
+
+void
+XtSafelyDestroyWidget (Widget widget)
+{
+#if 0
+
+ /* this requires IntrinsicI.h (actually, InitialI.h) */
+
+ XtAppContext app = XtWidgetToApplicationContext(widget);
+
+ if (app->dispatch_level == 0)
+ {
+ app->dispatch_level = 1;
+ XtDestroyWidget (widget);
+ /* generates an event so that the event loop will be called */
+ XChangeProperty (XtDisplay (widget), XtWindow (widget),
+ XA_STRING, XA_STRING, 32, PropModeAppend, NULL, 0);
+ app->dispatch_level = 0;
+ }
+ else
+ XtDestroyWidget (widget);
+
+#else
+ abort ();
+#endif
+}
diff --git a/lwlib/lwlib-utils.h b/lwlib/lwlib-utils.h
new file mode 100644
index 00000000000..c5991f2d5e4
--- /dev/null
+++ b/lwlib/lwlib-utils.h
@@ -0,0 +1,20 @@
+#ifndef _LWLIB_UTILS_H_
+#define _LWLIB_UTILS_H_
+
+void XtNoClearRefreshWidget (Widget);
+
+typedef void (*XtApplyToWidgetsProc) (Widget, XtPointer);
+typedef void* (*XtApplyUntilToWidgetsProc) (Widget, XtPointer);
+
+void XtApplyToWidgets (Widget, XtApplyToWidgetsProc, XtPointer);
+void *XtApplyUntilToWidgets (Widget, XtApplyUntilToWidgetsProc, XtPointer);
+
+Widget *XtCompositeChildren (Widget, unsigned int *);
+
+/* returns True is the widget is being destroyed, False otherwise */
+Boolean
+XtWidgetBeingDestroyedP (Widget widget);
+
+void XtSafelyDestroyWidget (Widget);
+
+#endif /* _LWLIB_UTILS_H_ */
diff --git a/lwlib/lwlib.c b/lwlib/lwlib.c
new file mode 100644
index 00000000000..20f7682cfd4
--- /dev/null
+++ b/lwlib/lwlib.c
@@ -0,0 +1,1111 @@
+/* A general interface to the widgets of different toolkits.
+ Copyright (C) 1992, 1993 Lucid, Inc.
+
+This file is part of the Lucid Widget Library.
+
+The Lucid Widget Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The Lucid Widget Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef NeXT
+#undef __STRICT_BSD__ /* ick */
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <X11/StringDefs.h>
+#include "lwlib-internal.h"
+#include "lwlib-utils.h"
+
+#if defined(__GNUC__) && !defined(alloca)
+#define alloca __builtin_alloca
+#endif
+
+#if ((!__GNUC__) && !defined(__hpux)) && !defined(AIXV3)
+#include <alloca.h>
+#endif
+
+#if defined(AIXV3)
+#pragma alloca
+#endif
+
+#if defined (USE_LUCID)
+#include "lwlib-Xlw.h"
+#endif
+#if defined (USE_MOTIF)
+#include "lwlib-Xm.h"
+#endif
+#if defined (USE_OLIT)
+#include "lwlib-Xol.h"
+#endif
+
+#if !defined (USE_LUCID) && !defined (USE_MOTIF) && !defined (USE_OLIT)
+ERROR! At least one of USE_LUCID, USE_MOTIF or USE_OLIT must be defined.
+#endif
+
+#if defined (USE_MOTIF) && defined (USE_OLIT)
+ERROR! no more than one of USE_MOTIF and USE_OLIT may be defined.
+#endif
+
+/* List of all widgets managed by the library. */
+static widget_info*
+all_widget_info = NULL;
+
+ /* Forward declarations */
+static void
+instanciate_widget_instance (widget_instance* instance);
+
+ /* utility functions for widget_instance and widget_info */
+static char *
+safe_strdup (char* s)
+{
+ char *result;
+ if (! s) return 0;
+ result = (char *) malloc (strlen (s) + 1);
+ if (! result)
+ return 0;
+ strcpy (result, s);
+ return result;
+}
+
+static void
+safe_free_str (char* s)
+{
+ if (s) free (s);
+}
+
+static widget_value *widget_value_free_list = 0;
+
+widget_value *
+malloc_widget_value ()
+{
+ widget_value *wv;
+ if (widget_value_free_list)
+ {
+ wv = widget_value_free_list;
+ widget_value_free_list = wv->free_list;
+ wv->free_list = 0;
+ }
+ else
+ {
+ wv = (widget_value *) malloc (sizeof (widget_value));
+ }
+ memset (wv, 0, sizeof (widget_value));
+ return wv;
+}
+
+/* this is analagous to free(). It frees only what was allocated
+ by malloc_widget_value(), and no substructures.
+ */
+void
+free_widget_value (wv)
+ widget_value *wv;
+{
+ if (wv->free_list)
+ abort ();
+ wv->free_list = widget_value_free_list;
+ widget_value_free_list = wv;
+}
+
+static void
+free_widget_value_tree (widget_value* wv)
+{
+ if (!wv)
+ return;
+
+ if (wv->name) free (wv->name);
+ if (wv->value) free (wv->value);
+ if (wv->key) free (wv->key);
+
+ wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
+
+ if (wv->toolkit_data && wv->free_toolkit_data)
+ {
+ free (wv->toolkit_data);
+ wv->toolkit_data = (void *) 0xDEADBEEF;
+ }
+
+ if (wv->contents && (wv->contents != (widget_value*)1))
+ {
+ free_widget_value_tree (wv->contents);
+ wv->contents = (widget_value *) 0xDEADBEEF;
+ }
+ if (wv->next)
+ {
+ free_widget_value_tree (wv->next);
+ wv->next = (widget_value *) 0xDEADBEEF;
+ }
+ free_widget_value (wv);
+}
+
+static widget_value *
+copy_widget_value_tree (widget_value* val, change_type change)
+{
+ widget_value* copy;
+
+ if (!val)
+ return NULL;
+ if (val == (widget_value *) 1)
+ return val;
+
+ copy = malloc_widget_value ();
+ copy->name = safe_strdup (val->name);
+ copy->value = safe_strdup (val->value);
+ copy->key = safe_strdup (val->key);
+ copy->enabled = val->enabled;
+ copy->selected = val->selected;
+ copy->edited = False;
+ copy->change = change;
+ copy->contents = copy_widget_value_tree (val->contents, change);
+ copy->call_data = val->call_data;
+ copy->next = copy_widget_value_tree (val->next, change);
+ copy->toolkit_data = NULL;
+ copy->free_toolkit_data = False;
+ return copy;
+}
+
+static widget_info *
+allocate_widget_info (char* type, char* name, LWLIB_ID id, widget_value* val,
+ lw_callback pre_activate_cb, lw_callback selection_cb,
+ lw_callback post_activate_cb)
+{
+ widget_info* info = (widget_info*)malloc (sizeof (widget_info));
+ info->type = safe_strdup (type);
+ info->name = safe_strdup (name);
+ info->id = id;
+ info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
+ info->busy = False;
+ info->pre_activate_cb = pre_activate_cb;
+ info->selection_cb = selection_cb;
+ info->post_activate_cb = post_activate_cb;
+ info->instances = NULL;
+
+ info->next = all_widget_info;
+ all_widget_info = info;
+
+ return info;
+}
+
+static void
+free_widget_info (widget_info* info)
+{
+ safe_free_str (info->type);
+ safe_free_str (info->name);
+ free_widget_value_tree (info->val);
+ memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
+ free (info);
+}
+
+static void
+mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
+{
+ widget_instance* instance = (widget_instance*)closure;
+
+ /* be very conservative */
+ if (instance->widget == widget)
+ instance->widget = NULL;
+}
+
+static widget_instance *
+allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
+{
+ widget_instance* instance =
+ (widget_instance*)malloc (sizeof (widget_instance));
+ instance->parent = parent;
+ instance->pop_up_p = pop_up_p;
+ instance->info = info;
+ instance->next = info->instances;
+ info->instances = instance;
+
+ instanciate_widget_instance (instance);
+
+ XtAddCallback (instance->widget, XtNdestroyCallback,
+ mark_widget_destroyed, (XtPointer)instance);
+ return instance;
+}
+
+static void
+free_widget_instance (widget_instance* instance)
+{
+ memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
+ free (instance);
+}
+
+static widget_info *
+get_widget_info (LWLIB_ID id, Boolean remove_p)
+{
+ widget_info* info;
+ widget_info* prev;
+ for (prev = NULL, info = all_widget_info;
+ info;
+ prev = info, info = info->next)
+ if (info->id == id)
+ {
+ if (remove_p)
+ {
+ if (prev)
+ prev->next = info->next;
+ else
+ all_widget_info = info->next;
+ }
+ return info;
+ }
+ return NULL;
+}
+
+static widget_instance *
+get_widget_instance (Widget widget, Boolean remove_p)
+{
+ widget_info* info;
+ widget_instance* instance;
+ widget_instance* prev;
+ for (info = all_widget_info; info; info = info->next)
+ for (prev = NULL, instance = info->instances;
+ instance;
+ prev = instance, instance = instance->next)
+ if (instance->widget == widget)
+ {
+ if (remove_p)
+ {
+ if (prev)
+ prev->next = instance->next;
+ else
+ info->instances = instance->next;
+ }
+ return instance;
+ }
+ return (widget_instance *) 0;
+}
+
+static widget_instance*
+find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
+{
+ widget_info* info = get_widget_info (id, False);
+ widget_instance* instance;
+
+ if (info)
+ for (instance = info->instances; instance; instance = instance->next)
+ if (instance->parent == parent && instance->pop_up_p == pop_up_p)
+ return instance;
+
+ return NULL;
+}
+
+
+/* utility function for widget_value */
+static Boolean
+safe_strcmp (char* s1, char* s2)
+{
+ if (!!s1 ^ !!s2) return True;
+ return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
+}
+
+static int
+max (int i1, int i2)
+{
+ return i1 > i2 ? i1 : i2;
+}
+
+
+#if 0
+# define EXPLAIN(name, oc, nc, desc, a1, a2) \
+ printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
+ name, \
+ (oc == NO_CHANGE ? "none" : \
+ (oc == INVISIBLE_CHANGE ? "invisible" : \
+ (oc == VISIBLE_CHANGE ? "visible" : \
+ (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
+ oc, \
+ (nc == NO_CHANGE ? "none" : \
+ (nc == INVISIBLE_CHANGE ? "invisible" : \
+ (nc == VISIBLE_CHANGE ? "visible" : \
+ (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
+ nc, desc, a1, a2)
+#else
+# define EXPLAIN(name, oc, nc, desc, a1, a2)
+#endif
+
+
+static widget_value *
+merge_widget_value (widget_value* val1, widget_value* val2, int level)
+{
+ change_type change;
+ widget_value* merged_next;
+ widget_value* merged_contents;
+
+ if (!val1)
+ {
+ if (val2)
+ return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
+ else
+ return NULL;
+ }
+ if (!val2)
+ {
+ free_widget_value_tree (val1);
+ return NULL;
+ }
+
+ change = NO_CHANGE;
+
+ if (safe_strcmp (val1->name, val2->name))
+ {
+ EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
+ val1->name, val2->name);
+ change = max (change, STRUCTURAL_CHANGE);
+ safe_free_str (val1->name);
+ val1->name = safe_strdup (val2->name);
+ }
+ if (safe_strcmp (val1->value, val2->value))
+ {
+ EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
+ val1->value, val2->value);
+ change = max (change, VISIBLE_CHANGE);
+ safe_free_str (val1->value);
+ val1->value = safe_strdup (val2->value);
+ }
+ if (safe_strcmp (val1->key, val2->key))
+ {
+ EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
+ val1->key, val2->key);
+ change = max (change, VISIBLE_CHANGE);
+ safe_free_str (val1->key);
+ val1->key = safe_strdup (val2->key);
+ }
+ if (val1->enabled != val2->enabled)
+ {
+ EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
+ val1->enabled, val2->enabled);
+ change = max (change, VISIBLE_CHANGE);
+ val1->enabled = val2->enabled;
+ }
+ if (val1->selected != val2->selected)
+ {
+ EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
+ val1->selected, val2->selected);
+ change = max (change, VISIBLE_CHANGE);
+ val1->selected = val2->selected;
+ }
+ if (val1->call_data != val2->call_data)
+ {
+ EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
+ val1->call_data, val2->call_data);
+ change = max (change, INVISIBLE_CHANGE);
+ val1->call_data = val2->call_data;
+ }
+
+ if (level > 0)
+ {
+ merged_contents =
+ merge_widget_value (val1->contents, val2->contents, level - 1);
+
+ if (val1->contents && !merged_contents)
+ {
+ EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents gone)",
+ 0, 0);
+ change = max (change, INVISIBLE_CHANGE);
+ }
+ else if (merged_contents && merged_contents->change != NO_CHANGE)
+ {
+ EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
+ 0, 0);
+ change = max (change, INVISIBLE_CHANGE);
+ }
+
+ val1->contents = merged_contents;
+ }
+
+ merged_next = merge_widget_value (val1->next, val2->next, level);
+
+ if (val1->next && !merged_next)
+ {
+ EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
+ 0, 0);
+ change = max (change, STRUCTURAL_CHANGE);
+ }
+ else if (merged_next)
+ {
+ if (merged_next->change)
+ EXPLAIN (val1->name, change, merged_next->change, "(following change)",
+ 0, 0);
+ change = max (change, merged_next->change);
+ }
+
+ val1->next = merged_next;
+
+ val1->change = change;
+
+ if (change > NO_CHANGE && val1->toolkit_data)
+ {
+ if (val1->free_toolkit_data)
+ free (val1->toolkit_data);
+ val1->toolkit_data = NULL;
+ }
+
+ return val1;
+}
+
+
+/* modifying the widgets */
+static Widget
+name_to_widget (widget_instance* instance, char* name)
+{
+ Widget widget = NULL;
+
+ if (!instance->widget)
+ return NULL;
+
+ if (!strcmp (XtName (instance->widget), name))
+ widget = instance->widget;
+ else
+ {
+ int length = strlen (name) + 2;
+ char* real_name = (char *) alloca (length);
+ real_name [0] = '*';
+ strcpy (real_name + 1, name);
+
+ widget = XtNameToWidget (instance->widget, real_name);
+ }
+ return widget;
+}
+
+static void
+set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
+{
+ Widget widget = name_to_widget (instance, val->name);
+
+ if (widget)
+ {
+#if defined (USE_LUCID)
+ if (lw_lucid_widget_p (instance->widget))
+ xlw_update_one_widget (instance, widget, val, deep_p);
+#endif
+#if defined (USE_MOTIF)
+ if (lw_motif_widget_p (instance->widget))
+ xm_update_one_widget (instance, widget, val, deep_p);
+#endif
+#if defined (USE_OLIT)
+ if (lw_olit_widget_p (instance->widget))
+ xol_update_one_widget (instance, widget, val, deep_p);
+#endif
+ }
+}
+
+static void
+update_one_widget_instance (widget_instance* instance, Boolean deep_p)
+{
+ widget_value *val;
+
+ if (!instance->widget)
+ /* the widget was destroyed */
+ return;
+
+ for (val = instance->info->val; val; val = val->next)
+ if (val->change != NO_CHANGE)
+ set_one_value (instance, val, deep_p);
+}
+
+static void
+update_all_widget_values (widget_info* info, Boolean deep_p)
+{
+ widget_instance* instance;
+ widget_value* val;
+
+ for (instance = info->instances; instance; instance = instance->next)
+ update_one_widget_instance (instance, deep_p);
+
+ for (val = info->val; val; val = val->next)
+ val->change = NO_CHANGE;
+}
+
+void
+lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
+{
+ widget_info* info = get_widget_info (id, False);
+ widget_value* new_val;
+ widget_value* next_new_val;
+ widget_value* cur;
+ widget_value* prev;
+ widget_value* next;
+ int found;
+
+ if (!info)
+ return;
+
+ for (new_val = val; new_val; new_val = new_val->next)
+ {
+ next_new_val = new_val->next;
+ new_val->next = NULL;
+ found = False;
+ for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
+ if (!strcmp (cur->name, new_val->name))
+ {
+ found = True;
+ next = cur->next;
+ cur->next = NULL;
+ cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1);
+ if (prev)
+ prev->next = cur ? cur : next;
+ else
+ info->val = cur ? cur : next;
+ if (cur)
+ cur->next = next;
+ break;
+ }
+ if (!found)
+ {
+ /* Could not find it, add it */
+ if (prev)
+ prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
+ else
+ info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
+ }
+ new_val->next = next_new_val;
+ }
+
+ update_all_widget_values (info, deep_p);
+}
+
+
+/* creating the widgets */
+
+static void
+initialize_widget_instance (widget_instance* instance)
+{
+ widget_value* val;
+
+ for (val = instance->info->val; val; val = val->next)
+ val->change = STRUCTURAL_CHANGE;
+
+ update_one_widget_instance (instance, True);
+
+ for (val = instance->info->val; val; val = val->next)
+ val->change = NO_CHANGE;
+}
+
+
+static widget_creation_function
+find_in_table (char* type, widget_creation_entry* table)
+{
+ widget_creation_entry* cur;
+ for (cur = table; cur->type; cur++)
+ if (!strcasecmp (type, cur->type))
+ return cur->function;
+ return NULL;
+}
+
+static Boolean
+dialog_spec_p (char* name)
+{
+ /* return True if name matches [EILPQeilpq][1-9][Bb] or
+ [EILPQeilpq][1-9][Bb][Rr][1-9] */
+ if (!name)
+ return False;
+
+ switch (name [0])
+ {
+ case 'E': case 'I': case 'L': case 'P': case 'Q':
+ case 'e': case 'i': case 'l': case 'p': case 'q':
+ if (name [1] >= '0' && name [1] <= '9')
+ {
+ if (name [2] != 'B' && name [2] != 'b')
+ return False;
+ if (!name [3])
+ return True;
+ if ((name [3] == 'T' || name [3] == 't') && !name [4])
+ return True;
+ if ((name [3] == 'R' || name [3] == 'r')
+ && name [4] >= '0' && name [4] <= '9' && !name [5])
+ return True;
+ return False;
+ }
+ else
+ return False;
+
+ default:
+ return False;
+ }
+}
+
+static void
+instanciate_widget_instance (widget_instance* instance)
+{
+ widget_creation_function function = NULL;
+
+#if defined (USE_LUCID)
+ if (!function)
+ function = find_in_table (instance->info->type, xlw_creation_table);
+#endif
+#if defined(USE_MOTIF)
+ if (!function)
+ function = find_in_table (instance->info->type, xm_creation_table);
+#endif
+#if defined (USE_OLIT)
+ if (!function)
+ function = find_in_table (instance->info->type, xol_creation_table);
+#endif
+
+ if (!function)
+ {
+ if (dialog_spec_p (instance->info->type))
+ {
+#if defined (USE_LUCID)
+ /* not yet */
+#endif
+#if defined(USE_MOTIF)
+ if (!function)
+ function = xm_create_dialog;
+#endif
+#if defined (USE_OLIT)
+ /* not yet */
+#endif
+ }
+ }
+
+ if (!function)
+ {
+ printf ("No creation function for widget type %s\n",
+ instance->info->type);
+ abort ();
+ }
+
+ instance->widget = (*function) (instance);
+
+ if (!instance->widget)
+ abort ();
+
+ /* XtRealizeWidget (instance->widget);*/
+}
+
+void
+lw_register_widget (char* type, char* name, LWLIB_ID id, widget_value* val,
+ lw_callback pre_activate_cb, lw_callback selection_cb,
+ lw_callback post_activate_cb)
+{
+ if (!get_widget_info (id, False))
+ allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
+ post_activate_cb);
+}
+
+Widget
+lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
+{
+ widget_instance* instance;
+
+ instance = find_instance (id, parent, pop_up_p);
+ return instance ? instance->widget : NULL;
+}
+
+Widget
+lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
+{
+ widget_instance* instance;
+ widget_info* info;
+
+ instance = find_instance (id, parent, pop_up_p);
+ if (!instance)
+ {
+ info = get_widget_info (id, False);
+ if (!info)
+ return NULL;
+ instance = allocate_widget_instance (info, parent, pop_up_p);
+ initialize_widget_instance (instance);
+ }
+ if (!instance->widget)
+ abort ();
+ return instance->widget;
+}
+
+Widget
+lw_create_widget (char* type, char* name, LWLIB_ID id, widget_value* val,
+ Widget parent, Boolean pop_up_p, lw_callback pre_activate_cb,
+ lw_callback selection_cb, lw_callback post_activate_cb)
+{
+ lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
+ post_activate_cb);
+ return lw_make_widget (id, parent, pop_up_p);
+}
+
+
+/* destroying the widgets */
+static void
+destroy_one_instance (widget_instance* instance)
+{
+ /* Remove the destroy callback on the widget; that callback will try to
+ dereference the instance object (to set its widget slot to 0, since the
+ widget is dead.) Since the instance is now dead, we don't have to worry
+ about the fact that its widget is dead too.
+
+ This happens in the Phase2Destroy of the widget, so this callback would
+ not have been run until arbitrarily long after the instance was freed.
+ */
+ if (instance->widget)
+ XtRemoveCallback (instance->widget, XtNdestroyCallback,
+ mark_widget_destroyed, (XtPointer)instance);
+
+ if (instance->widget)
+ {
+ /* The else are pretty tricky here, including the empty statement
+ at the end because it would be very bad to destroy a widget
+ twice. */
+#if defined (USE_LUCID)
+ if (lw_lucid_widget_p (instance->widget))
+ xlw_destroy_instance (instance);
+ else
+#endif
+#if defined (USE_MOTIF)
+ if (lw_motif_widget_p (instance->widget))
+ xm_destroy_instance (instance);
+ else
+#endif
+#if defined (USE_OLIT)
+ if (lw_olit_widget_p (instance->widget))
+ xol_destroy_instance (instance);
+ else
+#endif
+ /* do not remove the empty statement */
+ ;
+ }
+
+ free_widget_instance (instance);
+}
+
+void
+lw_destroy_widget (Widget w)
+{
+ widget_instance* instance = get_widget_instance (w, True);
+
+ if (instance)
+ {
+ widget_info *info = instance->info;
+ /* instance has already been removed from the list; free it */
+ destroy_one_instance (instance);
+ /* if there are no instances left, free the info too */
+ if (!info->instances)
+ lw_destroy_all_widgets (info->id);
+ }
+}
+
+void
+lw_destroy_all_widgets (LWLIB_ID id)
+{
+ widget_info* info = get_widget_info (id, True);
+ widget_instance* instance;
+ widget_instance* next;
+
+ if (info)
+ {
+ for (instance = info->instances; instance; )
+ {
+ next = instance->next;
+ destroy_one_instance (instance);
+ instance = next;
+ }
+ free_widget_info (info);
+ }
+}
+
+void
+lw_destroy_everything ()
+{
+ while (all_widget_info)
+ lw_destroy_all_widgets (all_widget_info->id);
+}
+
+void
+lw_destroy_all_pop_ups ()
+{
+ widget_info* info;
+ widget_info* next;
+ widget_instance* instance;
+
+ for (info = all_widget_info; info; info = next)
+ {
+ next = info->next;
+ instance = info->instances;
+ if (instance && instance->pop_up_p)
+ lw_destroy_all_widgets (info->id);
+ }
+}
+
+#ifdef USE_MOTIF
+extern Widget first_child (Widget); /* garbage */
+#endif
+
+Widget
+lw_raise_all_pop_up_widgets ()
+{
+ widget_info* info;
+ widget_instance* instance;
+ Widget result = NULL;
+
+ for (info = all_widget_info; info; info = info->next)
+ for (instance = info->instances; instance; instance = instance->next)
+ if (instance->pop_up_p)
+ {
+ Widget widget = instance->widget;
+ if (widget)
+ {
+ if (XtIsManaged (widget)
+#ifdef USE_MOTIF
+ /* What a complete load of crap!!!!
+ When a dialogShell is on the screen, it is not managed!
+ */
+ || (lw_motif_widget_p (instance->widget) &&
+ XtIsManaged (first_child (widget)))
+#endif
+ )
+ {
+ if (!result)
+ result = widget;
+ XMapRaised (XtDisplay (widget), XtWindow (widget));
+ }
+ }
+ }
+ return result;
+}
+
+static void
+lw_pop_all_widgets (LWLIB_ID id, Boolean up)
+{
+ widget_info* info = get_widget_info (id, False);
+ widget_instance* instance;
+
+ if (info)
+ for (instance = info->instances; instance; instance = instance->next)
+ if (instance->pop_up_p && instance->widget)
+ {
+ if (!XtIsRealized (instance->widget))
+ XtRealizeWidget (instance->widget);
+#if defined (USE_LUCID)
+ if (lw_lucid_widget_p (instance->widget))
+ xlw_pop_instance (instance, up);
+#endif
+#if defined (USE_MOTIF)
+ if (lw_motif_widget_p (instance->widget))
+ xm_pop_instance (instance, up);
+#endif
+#if defined (USE_OLIT)
+ if (lw_olit_widget_p (instance->widget))
+ xol_pop_instance (instance, up);
+#endif
+ }
+}
+
+void
+lw_pop_up_all_widgets (LWLIB_ID id)
+{
+ lw_pop_all_widgets (id, True);
+}
+
+void
+lw_pop_down_all_widgets (LWLIB_ID id)
+{
+ lw_pop_all_widgets (id, False);
+}
+
+void
+lw_popup_menu (Widget widget)
+{
+#if defined (USE_LUCID)
+ if (lw_lucid_widget_p (widget))
+ xlw_popup_menu (widget);
+#endif
+#if defined (USE_MOTIF)
+ if (lw_motif_widget_p (widget))
+ xm_popup_menu (widget);
+#endif
+#if defined (USE_OLIT)
+ if (lw_olit_widget_p (widget))
+ xol_popup_menu (widget);
+#endif
+}
+
+ /* get the values back */
+static Boolean
+get_one_value (widget_instance* instance, widget_value* val)
+{
+ Widget widget = name_to_widget (instance, val->name);
+
+ if (widget)
+ {
+#if defined (USE_LUCID)
+ if (lw_lucid_widget_p (instance->widget))
+ xlw_update_one_value (instance, widget, val);
+#endif
+#if defined (USE_MOTIF)
+ if (lw_motif_widget_p (instance->widget))
+ xm_update_one_value (instance, widget, val);
+#endif
+#if defined (USE_OLIT)
+ if (lw_olit_widget_p (instance->widget))
+ xol_update_one_value (instance, widget, val);
+#endif
+ return True;
+ }
+ else
+ return False;
+}
+
+Boolean
+lw_get_some_values (LWLIB_ID id, widget_value* val_out)
+{
+ widget_info* info = get_widget_info (id, False);
+ widget_instance* instance;
+ widget_value* val;
+ Boolean result = False;
+
+ if (!info)
+ return False;
+
+ instance = info->instances;
+ if (!instance)
+ return False;
+
+ for (val = val_out; val; val = val->next)
+ if (get_one_value (instance, val))
+ result = True;
+
+ return result;
+}
+
+widget_value*
+lw_get_all_values (LWLIB_ID id)
+{
+ widget_info* info = get_widget_info (id, False);
+ widget_value* val = info->val;
+ if (lw_get_some_values (id, val))
+ return val;
+ else
+ return NULL;
+}
+
+/* internal function used by the library dependent implementation to get the
+ widget_value for a given widget in an instance */
+widget_value*
+lw_get_widget_value_for_widget (widget_instance* instance, Widget w)
+{
+ char* name = XtName (w);
+ widget_value* cur;
+ for (cur = instance->info->val; cur; cur = cur->next)
+ if (!strcmp (cur->name, name))
+ return cur;
+ return NULL;
+}
+
+ /* update other instances value when one thing changed */
+/* This function can be used as a an XtCallback for the widgets that get
+ modified to update other instances of the widgets. Closure should be the
+ widget_instance. */
+void
+lw_internal_update_other_instances (Widget widget, XtPointer closure,
+ XtPointer call_data)
+{
+ /* To forbid recursive calls */
+ static Boolean updating;
+
+ widget_instance* instance = (widget_instance*)closure;
+ char* name = XtName (widget);
+ widget_info* info;
+ widget_instance* cur;
+ widget_value* val;
+
+ /* never recurse as this could cause infinite recursions. */
+ if (updating)
+ return;
+
+ /* protect against the widget being destroyed */
+ if (XtWidgetBeingDestroyedP (widget))
+ return;
+
+ /* Return immediately if there are no other instances */
+ info = instance->info;
+ if (!info->instances->next)
+ return;
+
+ updating = True;
+
+ for (val = info->val; val && strcmp (val->name, name); val = val->next);
+
+ if (val && get_one_value (instance, val))
+ for (cur = info->instances; cur; cur = cur->next)
+ if (cur != instance)
+ set_one_value (cur, val, True);
+
+ updating = False;
+}
+
+
+ /* get the id */
+
+LWLIB_ID
+lw_get_widget_id (Widget w)
+{
+ widget_instance* instance = get_widget_instance (w, False);
+
+ return instance ? instance->info->id : 0;
+}
+
+ /* set the keyboard focus */
+void
+lw_set_keyboard_focus (Widget parent, Widget w)
+{
+#if defined (USE_MOTIF)
+ xm_set_keyboard_focus (parent, w);
+#else
+ XtSetKeyboardFocus (parent, w);
+#endif
+}
+
+ /* Show busy */
+static void
+show_one_widget_busy (Widget w, Boolean flag)
+{
+ Pixel foreground = 0;
+ Pixel background = 1;
+ Widget widget_to_invert = XtNameToWidget (w, "*sheet");
+ if (!widget_to_invert)
+ widget_to_invert = w;
+
+ XtVaGetValues (widget_to_invert,
+ XtNforeground, &foreground,
+ XtNbackground, &background,
+ 0);
+ XtVaSetValues (widget_to_invert,
+ XtNforeground, background,
+ XtNbackground, foreground,
+ 0);
+}
+
+void
+lw_show_busy (Widget w, Boolean busy)
+{
+ widget_instance* instance = get_widget_instance (w, False);
+ widget_info* info;
+ widget_instance* next;
+
+ if (instance)
+ {
+ info = instance->info;
+ if (info->busy != busy)
+ {
+ for (next = info->instances; next; next = next->next)
+ if (next->widget)
+ show_one_widget_busy (next->widget, busy);
+ info->busy = busy;
+ }
+ }
+}
diff --git a/lwlib/lwlib.h b/lwlib/lwlib.h
new file mode 100644
index 00000000000..195bbb5df8b
--- /dev/null
+++ b/lwlib/lwlib.h
@@ -0,0 +1,103 @@
+#ifndef LWLIB_H
+#define LWLIB_H
+
+#include <X11/Intrinsic.h>
+
+/*
+** Widget values depend on the Widget type:
+**
+** widget: (name value key enabled data contents/selected)
+**
+** label: ("name" "string" NULL NULL NULL NULL)
+** button: ("name" "string" "key" T/F data <default-button-p>)
+** button w/menu:
+** ("name" "string" "key" T/F data (label|button|button w/menu...))
+** menubar: ("name" NULL NULL T/F data (button w/menu))
+** selectable thing:
+** ("name" "string" "key" T/F data T/F)
+** checkbox: selectable thing
+** radio: ("name" NULL NULL T/F data (selectable thing...))
+** strings: ("name" NULL NULL T/F data (selectable thing...))
+** text: ("name" "string" <ign> T/F data)
+*/
+
+typedef unsigned long LWLIB_ID;
+
+typedef enum _change_type
+{
+ NO_CHANGE = 0,
+ INVISIBLE_CHANGE = 1,
+ VISIBLE_CHANGE = 2,
+ STRUCTURAL_CHANGE = 3
+} change_type;
+
+typedef struct _widget_value
+{
+ /* name of widget */
+ char* name;
+ /* value (meaning depend on widget type) */
+ char* value;
+ /* keyboard equivalent. no implications for XtTranslations */
+ char* key;
+ /* true if enabled */
+ Boolean enabled;
+ /* true if selected */
+ Boolean selected;
+ /* true if was edited (maintained by get_value) */
+ Boolean edited;
+ /* true if has changed (maintained by lw library) */
+ change_type change;
+ /* Contents of the sub-widgets, also selected slot for checkbox */
+ struct _widget_value* contents;
+ /* data passed to callback */
+ XtPointer call_data;
+ /* next one in the list */
+ struct _widget_value* next;
+ /* slot for the toolkit dependent part. Always initialize to NULL. */
+ void* toolkit_data;
+ /* tell us if we should free the toolkit data slot when freeing the
+ widget_value itself. */
+ Boolean free_toolkit_data;
+
+ /* we resource the widget_value structures; this points to the next
+ one on the free list if this one has been deallocated.
+ */
+ struct _widget_value *free_list;
+} widget_value;
+
+
+typedef void (*lw_callback) (Widget w, LWLIB_ID id, void* data);
+
+void lw_register_widget (char* type, char* name, LWLIB_ID id,
+ widget_value* val, lw_callback pre_activate_cb,
+ lw_callback selection_cb,
+ lw_callback post_activate_cb);
+Widget lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p);
+Widget lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p);
+Widget lw_create_widget (char* type, char* name, LWLIB_ID id,
+ widget_value* val, Widget parent, Boolean pop_up_p,
+ lw_callback pre_activate_cb,
+ lw_callback selection_cb,
+ lw_callback post_activate_cb);
+LWLIB_ID lw_get_widget_id (Widget w);
+void lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p);
+void lw_destroy_widget (Widget w);
+void lw_destroy_all_widgets (LWLIB_ID id);
+void lw_destroy_everything (void);
+void lw_destroy_all_pop_ups (void);
+Widget lw_raise_all_pop_up_widgets (void);
+widget_value* lw_get_all_values (LWLIB_ID id);
+Boolean lw_get_some_values (LWLIB_ID id, widget_value* val);
+void lw_pop_up_all_widgets (LWLIB_ID id);
+void lw_pop_down_all_widgets (LWLIB_ID id);
+widget_value *malloc_widget_value ();
+void free_widget_value (widget_value *);
+void lw_popup_menu (Widget);
+
+/* Toolkit independent way of focusing on a Widget at the Xt level. */
+void lw_set_keyboard_focus (Widget parent, Widget w);
+
+/* Silly Energize hack to invert the "sheet" button */
+void lw_show_busy (Widget w, Boolean busy);
+
+#endif /* LWLIB_H */
diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c
new file mode 100644
index 00000000000..4d4efd4a01c
--- /dev/null
+++ b/lwlib/xlwmenu.c
@@ -0,0 +1,1265 @@
+/* Implements a lightweight menubar widget.
+ Copyright (C) 1992 Lucid, Inc.
+
+This file is part of the Lucid Widget Library.
+
+The Lucid Widget Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The Lucid Widget Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Created by devin@lucid.com */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <X11/Xos.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/cursorfont.h>
+#include <X11/bitmaps/gray>
+#include "xlwmenuP.h"
+#include <string.h>
+
+static char
+xlwMenuTranslations [] =
+"<BtnDown>: start()\n\
+<BtnMotion>: drag()\n\
+<BtnUp>: select()\n\
+";
+
+#define offset(field) XtOffset(XlwMenuWidget, field)
+static XtResource
+xlwMenuResources[] =
+{
+ {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ offset(menu.font),XtRString, "XtDefaultFont"},
+ {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(menu.foreground), XtRString, "XtDefaultForeground"},
+ {XtNbuttonForeground, XtCButtonForeground, XtRPixel, sizeof(Pixel),
+ offset(menu.button_foreground), XtRString, "XtDefaultForeground"},
+ {XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
+ offset(menu.margin), XtRImmediate, (XtPointer)0},
+ {XtNhorizontalSpacing, XtCMargin, XtRDimension, sizeof(Dimension),
+ offset(menu.horizontal_spacing), XtRImmediate, (XtPointer)3},
+ {XtNverticalSpacing, XtCMargin, XtRDimension, sizeof(Dimension),
+ offset(menu.vertical_spacing), XtRImmediate, (XtPointer)1},
+ {XtNarrowSpacing, XtCMargin, XtRDimension, sizeof(Dimension),
+ offset(menu.arrow_spacing), XtRImmediate, (XtPointer)10},
+
+ {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
+ sizeof (Dimension), offset (menu.shadow_thickness),
+ XtRImmediate, (XtPointer) 2},
+ {XmNtopShadowColor, XmCTopShadowColor, XtRPixel, sizeof (Pixel),
+ offset (menu.top_shadow_color), XtRImmediate, (XtPointer)-1},
+ {XmNbottomShadowColor, XmCBottomShadowColor, XtRPixel, sizeof (Pixel),
+ offset (menu.bottom_shadow_color), XtRImmediate, (XtPointer)-1},
+ {XmNtopShadowPixmap, XmCTopShadowPixmap, XtRPixmap, sizeof (Pixmap),
+ offset (menu.top_shadow_pixmap), XtRImmediate, (XtPointer)None},
+ {XmNbottomShadowPixmap, XmCBottomShadowPixmap, XtRPixmap, sizeof (Pixmap),
+ offset (menu.bottom_shadow_pixmap), XtRImmediate, (XtPointer)None},
+
+ {XtNopen, XtCCallback, XtRCallback, sizeof(XtPointer),
+ offset(menu.open), XtRCallback, (XtPointer)NULL},
+ {XtNselect, XtCCallback, XtRCallback, sizeof(XtPointer),
+ offset(menu.select), XtRCallback, (XtPointer)NULL},
+ {XtNmenu, XtCMenu, XtRPointer, sizeof(XtPointer),
+ offset(menu.contents), XtRImmediate, (XtPointer)NULL},
+ {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
+ offset(menu.cursor_shape), XtRString, (XtPointer)"right_ptr"},
+ {XtNhorizontal, XtCHorizontal, XtRInt, sizeof(int),
+ offset(menu.horizontal), XtRImmediate, (XtPointer)True},
+};
+#undef offset
+
+static Boolean XlwMenuSetValues();
+static void XlwMenuRealize();
+static void XlwMenuRedisplay();
+static void XlwMenuResize();
+static void XlwMenuInitialize();
+static void XlwMenuRedisplay();
+static void XlwMenuDestroy();
+static void XlwMenuClassInitialize();
+static void Start();
+static void Drag();
+static void Select();
+
+static XtActionsRec
+xlwMenuActionsList [] =
+{
+ {"start", Start},
+ {"drag", Drag},
+ {"select", Select},
+};
+
+#define SuperClass ((CoreWidgetClass)&coreClassRec)
+
+XlwMenuClassRec xlwMenuClassRec =
+{
+ { /* CoreClass fields initialization */
+ (WidgetClass) SuperClass, /* superclass */
+ "XlwMenu", /* class_name */
+ sizeof(XlwMenuRec), /* size */
+ XlwMenuClassInitialize, /* class_initialize */
+ NULL, /* class_part_initialize */
+ FALSE, /* class_inited */
+ XlwMenuInitialize, /* initialize */
+ NULL, /* initialize_hook */
+ XlwMenuRealize, /* realize */
+ xlwMenuActionsList, /* actions */
+ XtNumber(xlwMenuActionsList), /* num_actions */
+ xlwMenuResources, /* resources */
+ XtNumber(xlwMenuResources), /* resource_count */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ TRUE, /* compress_exposure */
+ TRUE, /* compress_enterleave */
+ FALSE, /* visible_interest */
+ XlwMenuDestroy, /* destroy */
+ XlwMenuResize, /* resize */
+ XlwMenuRedisplay, /* expose */
+ XlwMenuSetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ xlwMenuTranslations, /* tm_table */
+ XtInheritQueryGeometry, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator */
+ NULL /* extension */
+ }, /* XlwMenuClass fields initialization */
+ {
+ 0 /* dummy */
+ },
+};
+
+WidgetClass xlwMenuWidgetClass = (WidgetClass) &xlwMenuClassRec;
+
+ /* Utilities */
+static void
+push_new_stack (XlwMenuWidget mw, widget_value* val)
+{
+ if (!mw->menu.new_stack)
+ {
+ mw->menu.new_stack_length = 10;
+ mw->menu.new_stack =
+ (widget_value**)XtCalloc (mw->menu.new_stack_length,
+ sizeof (widget_value*));
+ }
+ else if (mw->menu.new_depth == mw->menu.new_stack_length)
+ {
+ mw->menu.new_stack_length *= 2;
+ mw->menu.new_stack =
+ (widget_value**)XtRealloc ((char*)mw->menu.new_stack,
+ mw->menu.new_stack_length * sizeof (widget_value*));
+ }
+ mw->menu.new_stack [mw->menu.new_depth++] = val;
+}
+
+static void
+pop_new_stack_if_no_contents (XlwMenuWidget mw)
+{
+ if (mw->menu.new_depth)
+ {
+ if (!mw->menu.new_stack [mw->menu.new_depth - 1]->contents)
+ mw->menu.new_depth -= 1;
+ }
+}
+
+static void
+make_old_stack_space (XlwMenuWidget mw, int n)
+{
+ if (!mw->menu.old_stack)
+ {
+ mw->menu.old_stack_length = 10;
+ mw->menu.old_stack =
+ (widget_value**)XtCalloc (mw->menu.old_stack_length,
+ sizeof (widget_value*));
+ }
+ else if (mw->menu.old_stack_length < n)
+ {
+ mw->menu.old_stack_length *= 2;
+ mw->menu.old_stack =
+ (widget_value**)XtRealloc ((char*)mw->menu.old_stack,
+ mw->menu.old_stack_length * sizeof (widget_value*));
+ }
+}
+
+ /* Size code */
+static Boolean
+all_dashes_p (char* s)
+{
+ char* p;
+ for (p = s; *p == '-'; p++);
+ return !*p;
+}
+
+static int
+string_width (XlwMenuWidget mw, char* s)
+{
+ XCharStruct xcs;
+ int drop;
+
+ XTextExtents (mw->menu.font, s, strlen (s), &drop, &drop, &drop, &xcs);
+ return xcs.width;
+}
+
+static int
+arrow_width (XlwMenuWidget mw)
+{
+ return mw->menu.font->ascent / 2 | 1;
+}
+
+static XtResource
+nameResource[] =
+{
+ {"labelString", "LabelString", XtRString, sizeof(String),
+ 0, XtRImmediate, 0},
+};
+
+static char*
+resource_widget_value (XlwMenuWidget mw, widget_value* val)
+{
+ if (!val->toolkit_data)
+ {
+ char* resourced_name = NULL;
+ char* complete_name;
+ XtGetSubresources ((Widget) mw,
+ (XtPointer) &resourced_name,
+ val->name, val->name,
+ nameResource, 1, NULL, 0);
+ if (!resourced_name)
+ resourced_name = val->name;
+ if (!val->value)
+ complete_name = (char *) strdup (resourced_name);
+ else
+ {
+ int complete_length =
+ strlen (resourced_name) + strlen (val->value) + 2;
+ complete_name = XtMalloc (complete_length);
+ *complete_name = 0;
+ strcat (complete_name, resourced_name);
+ strcat (complete_name, " ");
+ strcat (complete_name, val->value);
+ }
+
+ val->toolkit_data = complete_name;
+ val->free_toolkit_data = True;
+ }
+ return (char*)val->toolkit_data;
+}
+
+/* Returns the sizes of an item */
+static void
+size_menu_item (XlwMenuWidget mw, widget_value* val, int horizontal_p,
+ int* label_width, int* rest_width, int* height)
+{
+ if (all_dashes_p (val->name))
+ {
+ *height = 2;
+ *label_width = 1;
+ *rest_width = 0;
+ }
+ else
+ {
+ *height =
+ mw->menu.font->ascent + mw->menu.font->descent
+ + 2 * mw->menu.vertical_spacing + 2 * mw->menu.shadow_thickness;
+
+ *label_width =
+ string_width (mw, resource_widget_value (mw, val))
+ + mw->menu.horizontal_spacing + mw->menu.shadow_thickness;
+
+ *rest_width = mw->menu.horizontal_spacing + mw->menu.shadow_thickness;
+ if (!horizontal_p)
+ {
+ if (val->contents)
+ *rest_width += arrow_width (mw) + mw->menu.arrow_spacing;
+ else if (val->key)
+ *rest_width +=
+ string_width (mw, val->key) + mw->menu.arrow_spacing;
+ }
+ }
+}
+
+static void
+size_menu (XlwMenuWidget mw, int level)
+{
+ int label_width = 0;
+ int rest_width = 0;
+ int max_rest_width = 0;
+ int height = 0;
+ int horizontal_p = mw->menu.horizontal && (level == 0);
+ widget_value* val;
+ window_state* ws;
+
+ if (level >= mw->menu.old_depth)
+ abort ();
+
+ ws = &mw->menu.windows [level];
+ ws->width = 0;
+ ws->height = 0;
+ ws->label_width = 0;
+
+ for (val = mw->menu.old_stack [level]->contents; val; val = val->next)
+ {
+ size_menu_item (mw, val, horizontal_p, &label_width, &rest_width,
+ &height);
+ if (horizontal_p)
+ {
+ ws->width += label_width + rest_width;
+ if (height > ws->height)
+ ws->height = height;
+ }
+ else
+ {
+ if (label_width > ws->label_width)
+ ws->label_width = label_width;
+ if (rest_width > max_rest_width)
+ max_rest_width = rest_width;
+ ws->height += height;
+ }
+ }
+
+ if (horizontal_p)
+ ws->label_width = 0;
+ else
+ ws->width = ws->label_width + max_rest_width;
+
+ ws->width += 2 * mw->menu.shadow_thickness;
+ ws->height += 2 * mw->menu.shadow_thickness;
+}
+
+
+ /* Display code */
+static void
+draw_arrow (XlwMenuWidget mw, Window window, GC gc, int x, int y, int width)
+{
+ XPoint points [3];
+ points [0].x = x;
+ points [0].y = y + mw->menu.font->ascent;
+ points [1].x = x;
+ points [1].y = y;
+ points [2].x = x + width;
+ points [2].y = y + mw->menu.font->ascent / 2;
+
+ XFillPolygon (XtDisplay (mw), window, gc, points, 3, Convex,
+ CoordModeOrigin);
+}
+
+static void
+draw_shadow_rectangle (XlwMenuWidget mw, Window window,
+ int x, int y, int width, int height, int erase_p)
+{
+ Display *dpy = XtDisplay (mw);
+ GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
+ GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
+ int thickness = mw->menu.shadow_thickness;
+ XPoint points [4];
+ points [0].x = x;
+ points [0].y = y;
+ points [1].x = x + width;
+ points [1].y = y;
+ points [2].x = x + width - thickness;
+ points [2].y = y + thickness;
+ points [3].x = x;
+ points [3].y = y + thickness;
+ XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
+ points [0].x = x;
+ points [0].y = y + thickness;
+ points [1].x = x;
+ points [1].y = y + height;
+ points [2].x = x + thickness;
+ points [2].y = y + height - thickness;
+ points [3].x = x + thickness;
+ points [3].y = y + thickness;
+ XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
+ points [0].x = x + width;
+ points [0].y = y;
+ points [1].x = x + width - thickness;
+ points [1].y = y + thickness;
+ points [2].x = x + width - thickness;
+ points [2].y = y + height - thickness;
+ points [3].x = x + width;
+ points [3].y = y + height - thickness;
+ XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
+ points [0].x = x;
+ points [0].y = y + height;
+ points [1].x = x + width;
+ points [1].y = y + height;
+ points [2].x = x + width;
+ points [2].y = y + height - thickness;
+ points [3].x = x + thickness;
+ points [3].y = y + height - thickness;
+ XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
+}
+
+
+/* Display the menu item and increment where.x and where.y to show how large
+** the menu item was.
+*/
+static void
+display_menu_item (XlwMenuWidget mw, widget_value* val, window_state* ws,
+ XPoint* where, Boolean highlighted_p, Boolean horizontal_p,
+ Boolean just_compute_p)
+{
+ GC deco_gc;
+ GC text_gc;
+ int font_ascent = mw->menu.font->ascent;
+ int font_descent = mw->menu.font->descent;
+ int shadow = mw->menu.shadow_thickness;
+ int separator_p = all_dashes_p (val->name);
+ int h_spacing = mw->menu.horizontal_spacing;
+ int v_spacing = mw->menu.vertical_spacing;
+ int label_width;
+ int rest_width;
+ int height;
+ int width;
+ int button_p;
+
+ /* compute the sizes of the item */
+ size_menu_item (mw, val, horizontal_p, &label_width, &rest_width, &height);
+
+ if (horizontal_p)
+ width = label_width + rest_width;
+ else
+ {
+ label_width = ws->label_width;
+ width = ws->width - 2 * shadow;
+ }
+
+ /* see if it should be a button in the menubar */
+ button_p = horizontal_p && val->call_data;
+
+ /* Only highlight an enabled item that has a callback. */
+ if (highlighted_p)
+ if (!val->enabled || !(val->call_data || val->contents))
+ highlighted_p = 0;
+
+ /* do the drawing. */
+ if (!just_compute_p)
+ {
+ /* Add the shadow border of the containing menu */
+ int x = where->x + shadow;
+ int y = where->y + shadow;
+
+ /* pick the foreground and background GC. */
+ if (val->enabled)
+ text_gc = button_p ? mw->menu.button_gc : mw->menu.foreground_gc;
+ else
+ text_gc =
+ button_p ? mw->menu.inactive_button_gc : mw->menu.inactive_gc;
+ deco_gc = mw->menu.foreground_gc;
+
+ if (separator_p)
+ {
+ XDrawLine (XtDisplay (mw), ws->window, mw->menu.shadow_bottom_gc,
+ x, y, x + width, y);
+ XDrawLine (XtDisplay (mw), ws->window, mw->menu.shadow_top_gc,
+ x, y + 1, x + width, y + 1);
+ }
+ else
+ {
+ char* display_string = resource_widget_value (mw, val);
+ draw_shadow_rectangle (mw, ws->window, x, y, width, height, True);
+ XDrawString (XtDisplay (mw), ws->window, text_gc,
+ x + h_spacing + shadow,
+ y + v_spacing + shadow + font_ascent,
+ display_string, strlen (display_string));
+
+ if (!horizontal_p)
+ {
+ if (val->contents)
+ {
+ int a_w = arrow_width (mw);
+ draw_arrow (mw, ws->window, deco_gc,
+ x + label_width + mw->menu.arrow_spacing,
+ y + v_spacing + shadow, a_w);
+ }
+ else if (val->key)
+ {
+ XDrawString (XtDisplay (mw), ws->window, text_gc,
+ x + label_width + mw->menu.arrow_spacing,
+ y + v_spacing + shadow + font_ascent,
+ val->key, strlen (val->key));
+ }
+ }
+
+ else if (button_p)
+ {
+#if 1
+ XDrawRectangle (XtDisplay (mw), ws->window, deco_gc,
+ x + shadow, y + shadow,
+ label_width + h_spacing - 1,
+ font_ascent + font_descent + 2 * v_spacing - 1);
+#else
+ highlighted_p = True;
+#endif
+ }
+
+ if (highlighted_p)
+ draw_shadow_rectangle (mw, ws->window, x, y, width, height, False);
+ }
+ }
+
+ where->x += width;
+ where->y += height;
+}
+
+static void
+display_menu (XlwMenuWidget mw, int level, Boolean just_compute_p,
+ XPoint* highlighted_pos, XPoint* hit, widget_value** hit_return,
+ widget_value* this, widget_value* that)
+{
+ widget_value* val;
+ widget_value* following_item;
+ window_state* ws;
+ XPoint where;
+ int horizontal_p = mw->menu.horizontal && (level == 0);
+ int highlighted_p;
+ int just_compute_this_one_p;
+
+ if (level >= mw->menu.old_depth)
+ abort ();
+
+ if (level < mw->menu.old_depth - 1)
+ following_item = mw->menu.old_stack [level + 1];
+ else
+ following_item = NULL;
+
+ if (hit)
+ *hit_return = NULL;
+
+ where.x = 0;
+ where.y = 0;
+
+ ws = &mw->menu.windows [level];
+ for (val = mw->menu.old_stack [level]->contents; val; val = val->next)
+ {
+ highlighted_p = val == following_item;
+ if (highlighted_p && highlighted_pos)
+ {
+ if (horizontal_p)
+ highlighted_pos->x = where.x;
+ else
+ highlighted_pos->y = where.y;
+ }
+
+ just_compute_this_one_p =
+ just_compute_p || ((this || that) && val != this && val != that);
+
+ display_menu_item (mw, val, ws, &where, highlighted_p, horizontal_p,
+ just_compute_this_one_p);
+
+ if (highlighted_p && highlighted_pos)
+ {
+ if (horizontal_p)
+ highlighted_pos->y = where.y;
+ else
+ highlighted_pos->x = where.x;
+ }
+
+ if (hit
+ && !*hit_return
+ && (horizontal_p ? hit->x < where.x : hit->y < where.y)
+ && !all_dashes_p (val->name))
+ *hit_return = val;
+
+ if (horizontal_p)
+ where.y = 0;
+ else
+ where.x = 0;
+ }
+
+ if (!just_compute_p)
+ draw_shadow_rectangle (mw, ws->window, 0, 0, ws->width, ws->height, False);
+}
+
+ /* Motion code */
+static void
+set_new_state (XlwMenuWidget mw, widget_value* val, int level)
+{
+ int i;
+
+ mw->menu.new_depth = 0;
+ for (i = 0; i < level; i++)
+ push_new_stack (mw, mw->menu.old_stack [i]);
+ push_new_stack (mw, val);
+}
+
+static void
+make_windows_if_needed (XlwMenuWidget mw, int n)
+{
+ int i;
+ int start_at;
+ XSetWindowAttributes xswa;
+ int mask;
+ Window root = RootWindowOfScreen (DefaultScreenOfDisplay (XtDisplay (mw)));
+ window_state* windows;
+
+ if (mw->menu.windows_length >= n)
+ return;
+
+ xswa.save_under = True;
+ xswa.override_redirect = True;
+ xswa.background_pixel = mw->core.background_pixel;
+ xswa.border_pixel = mw->core.border_pixel;
+ xswa.event_mask =
+ ExposureMask | ButtonMotionMask | PointerMotionHintMask
+ | ButtonReleaseMask | ButtonPressMask;
+ xswa.cursor = mw->menu.cursor_shape;
+ mask = CWSaveUnder | CWOverrideRedirect | CWBackPixel | CWBorderPixel
+ | CWEventMask | CWCursor;
+
+ if (!mw->menu.windows)
+ {
+ mw->menu.windows =
+ (window_state*)XtMalloc (n * sizeof (window_state));
+ start_at = 0;
+ }
+ else
+ {
+ mw->menu.windows =
+ (window_state*)XtRealloc ((char*)mw->menu.windows,
+ n * sizeof (window_state));
+ start_at = mw->menu.windows_length;
+ }
+ mw->menu.windows_length = n;
+
+ windows = mw->menu.windows;
+
+ for (i = start_at; i < n; i++)
+ {
+ windows [i].x = 0;
+ windows [i].y = 0;
+ windows [i].width = 1;
+ windows [i].height = 1;
+ windows [i].window =
+ XCreateWindow (XtDisplay (mw), root, 0, 0, 1, 1,
+ 0, 0, CopyFromParent, CopyFromParent, mask, &xswa);
+ }
+}
+
+/* Make the window fit in the screen */
+static void
+fit_to_screen (XlwMenuWidget mw, window_state* ws, window_state* previous_ws,
+ Boolean horizontal_p)
+{
+ int screen_width = WidthOfScreen (XtScreen (mw));
+ int screen_height = HeightOfScreen (XtScreen (mw));
+
+ if (ws->x < 0)
+ ws->x = 0;
+ else if (ws->x + ws->width > screen_width)
+ {
+ if (!horizontal_p)
+ ws->x = previous_ws->x - ws->width;
+ else
+ ws->x = screen_width - ws->width;
+ }
+ if (ws->y < 0)
+ ws->y = 0;
+ else if (ws->y + ws->height > screen_height)
+ {
+ if (horizontal_p)
+ ws->y = previous_ws->y - ws->height;
+ else
+ ws->y = screen_height - ws->height;
+ }
+}
+
+/* Updates old_stack from new_stack and redisplays. */
+static void
+remap_menubar (XlwMenuWidget mw)
+{
+ int i;
+ int last_same;
+ XPoint selection_position;
+ int old_depth = mw->menu.old_depth;
+ int new_depth = mw->menu.new_depth;
+ widget_value** old_stack;
+ widget_value** new_stack;
+ window_state* windows;
+ widget_value* old_selection;
+ widget_value* new_selection;
+
+ /* Check that enough windows and old_stack are ready. */
+ make_windows_if_needed (mw, new_depth);
+ make_old_stack_space (mw, new_depth);
+ windows = mw->menu.windows;
+ old_stack = mw->menu.old_stack;
+ new_stack = mw->menu.new_stack;
+
+ /* compute the last identical different entry */
+ for (i = 1; i < old_depth && i < new_depth; i++)
+ if (old_stack [i] != new_stack [i])
+ break;
+ last_same = i - 1;
+
+ /* Memorize the previously selected item to be able to refresh it */
+ old_selection = last_same + 1 < old_depth ? old_stack [last_same + 1] : NULL;
+ if (old_selection && !old_selection->enabled)
+ old_selection = NULL;
+ new_selection = last_same + 1 < new_depth ? new_stack [last_same + 1] : NULL;
+ if (new_selection && !new_selection->enabled)
+ new_selection = NULL;
+
+ /* updates old_state from new_state. It has to be done now because
+ display_menu (called below) uses the old_stack to know what to display. */
+ for (i = last_same + 1; i < new_depth; i++)
+ old_stack [i] = new_stack [i];
+ mw->menu.old_depth = new_depth;
+
+ /* refresh the last seletion */
+ selection_position.x = 0;
+ selection_position.y = 0;
+ display_menu (mw, last_same, new_selection == old_selection,
+ &selection_position, NULL, NULL, old_selection, new_selection);
+
+ /* Now popup the new menus */
+ for (i = last_same + 1; i < new_depth && new_stack [i]->contents; i++)
+ {
+ window_state* previous_ws = &windows [i - 1];
+ window_state* ws = &windows [i];
+
+ ws->x =
+ previous_ws->x + selection_position.x + mw->menu.shadow_thickness;
+ if (!mw->menu.horizontal || i > 1)
+ ws->x += mw->menu.shadow_thickness;
+ ws->y =
+ previous_ws->y + selection_position.y + mw->menu.shadow_thickness;
+
+ size_menu (mw, i);
+
+ fit_to_screen (mw, ws, previous_ws, mw->menu.horizontal && i == 1);
+
+ XClearWindow (XtDisplay (mw), ws->window);
+ XMoveResizeWindow (XtDisplay (mw), ws->window, ws->x, ws->y,
+ ws->width, ws->height);
+ XMapRaised (XtDisplay (mw), ws->window);
+ display_menu (mw, i, False, &selection_position, NULL, NULL, NULL, NULL);
+ }
+
+ /* unmap the menus that popped down */
+ for (i = new_depth - 1; i < old_depth; i++)
+ if (i >= new_depth || !new_stack [i]->contents)
+ XUnmapWindow (XtDisplay (mw), windows [i].window);
+}
+
+static Boolean
+motion_event_is_in_menu (XlwMenuWidget mw, XMotionEvent* ev, int level,
+ XPoint* relative_pos)
+{
+ window_state* ws = &mw->menu.windows [level];
+ int x = level == 0 ? ws->x : ws->x + mw->menu.shadow_thickness;
+ int y = level == 0 ? ws->y : ws->y + mw->menu.shadow_thickness;
+ relative_pos->x = ev->x_root - x;
+ relative_pos->y = ev->y_root - y;
+ return (x < ev->x_root && ev->x_root < x + ws->width
+ && y < ev->y_root && ev->y_root < y + ws->height);
+}
+
+static Boolean
+map_event_to_widget_value (XlwMenuWidget mw, XMotionEvent* ev,
+ widget_value** val, int* level)
+{
+ int i;
+ XPoint relative_pos;
+ window_state* ws;
+
+ *val = NULL;
+
+ /* Find the window */
+ for (i = mw->menu.old_depth - 1; i >= 0; i--)
+ {
+ ws = &mw->menu.windows [i];
+ if (ws && motion_event_is_in_menu (mw, ev, i, &relative_pos))
+ {
+ display_menu (mw, i, True, NULL, &relative_pos, val, NULL, NULL);
+
+ if (*val)
+ {
+ *level = i + 1;
+ return True;
+ }
+ }
+ }
+ return False;
+}
+
+ /* Procedures */
+static void
+make_drawing_gcs (XlwMenuWidget mw)
+{
+ XGCValues xgcv;
+
+ xgcv.font = mw->menu.font->fid;
+ xgcv.foreground = mw->menu.foreground;
+ xgcv.background = mw->core.background_pixel;
+ mw->menu.foreground_gc = XtGetGC ((Widget)mw,
+ GCFont | GCForeground | GCBackground,
+ &xgcv);
+
+ xgcv.font = mw->menu.font->fid;
+ xgcv.foreground = mw->menu.button_foreground;
+ xgcv.background = mw->core.background_pixel;
+ mw->menu.button_gc = XtGetGC ((Widget)mw,
+ GCFont | GCForeground | GCBackground,
+ &xgcv);
+
+ xgcv.font = mw->menu.font->fid;
+ xgcv.foreground = mw->menu.foreground;
+ xgcv.background = mw->core.background_pixel;
+ xgcv.fill_style = FillStippled;
+ xgcv.stipple = mw->menu.gray_pixmap;
+ mw->menu.inactive_gc = XtGetGC ((Widget)mw,
+ (GCFont | GCForeground | GCBackground
+ | GCFillStyle | GCStipple), &xgcv);
+
+ xgcv.font = mw->menu.font->fid;
+ xgcv.foreground = mw->menu.button_foreground;
+ xgcv.background = mw->core.background_pixel;
+ xgcv.fill_style = FillStippled;
+ xgcv.stipple = mw->menu.gray_pixmap;
+ mw->menu.inactive_button_gc = XtGetGC ((Widget)mw,
+ (GCFont | GCForeground | GCBackground
+ | GCFillStyle | GCStipple), &xgcv);
+
+ xgcv.font = mw->menu.font->fid;
+ xgcv.foreground = mw->core.background_pixel;
+ xgcv.background = mw->menu.foreground;
+ mw->menu.background_gc = XtGetGC ((Widget)mw,
+ GCFont | GCForeground | GCBackground,
+ &xgcv);
+}
+
+static void
+release_drawing_gcs (XlwMenuWidget mw)
+{
+ XtReleaseGC ((Widget) mw, mw->menu.foreground_gc);
+ XtReleaseGC ((Widget) mw, mw->menu.button_gc);
+ XtReleaseGC ((Widget) mw, mw->menu.inactive_gc);
+ XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
+ XtReleaseGC ((Widget) mw, mw->menu.background_gc);
+ /* let's get some segvs if we try to use these... */
+ mw->menu.foreground_gc = (GC) -1;
+ mw->menu.button_gc = (GC) -1;
+ mw->menu.inactive_gc = (GC) -1;
+ mw->menu.inactive_button_gc = (GC) -1;
+ mw->menu.background_gc = (GC) -1;
+}
+
+#define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
+ ? ((unsigned long) (x)) : ((unsigned long) (y)))
+
+static void
+make_shadow_gcs (XlwMenuWidget mw)
+{
+ XGCValues xgcv;
+ unsigned long pm = 0;
+ Display *dpy = XtDisplay ((Widget) mw);
+ Colormap cmap = DefaultColormapOfScreen (XtScreen ((Widget) mw));
+ XColor topc, botc;
+ int top_frobbed = 0, bottom_frobbed = 0;
+
+ if (mw->menu.top_shadow_color == -1)
+ mw->menu.top_shadow_color = mw->core.background_pixel;
+ if (mw->menu.bottom_shadow_color == -1)
+ mw->menu.bottom_shadow_color = mw->menu.foreground;
+
+ if (mw->menu.top_shadow_color == mw->core.background_pixel ||
+ mw->menu.top_shadow_color == mw->menu.foreground)
+ {
+ topc.pixel = mw->core.background_pixel;
+ XQueryColor (dpy, cmap, &topc);
+ /* don't overflow/wrap! */
+ topc.red = MINL (65535, topc.red * 1.2);
+ topc.green = MINL (65535, topc.green * 1.2);
+ topc.blue = MINL (65535, topc.blue * 1.2);
+ if (XAllocColor (dpy, cmap, &topc))
+ {
+ mw->menu.top_shadow_color = topc.pixel;
+ top_frobbed = 1;
+ }
+ }
+ if (mw->menu.bottom_shadow_color == mw->menu.foreground ||
+ mw->menu.bottom_shadow_color == mw->core.background_pixel)
+ {
+ botc.pixel = mw->core.background_pixel;
+ XQueryColor (dpy, cmap, &botc);
+ botc.red *= 0.6;
+ botc.green *= 0.6;
+ botc.blue *= 0.6;
+ if (XAllocColor (dpy, cmap, &botc))
+ {
+ mw->menu.bottom_shadow_color = botc.pixel;
+ bottom_frobbed = 1;
+ }
+ }
+
+ if (top_frobbed && bottom_frobbed)
+ {
+ int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
+ int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
+ if (bot_avg > top_avg)
+ {
+ Pixel tmp = mw->menu.top_shadow_color;
+ mw->menu.top_shadow_color = mw->menu.bottom_shadow_color;
+ mw->menu.bottom_shadow_color = tmp;
+ }
+ else if (topc.pixel == botc.pixel)
+ {
+ if (botc.pixel == mw->menu.foreground)
+ mw->menu.top_shadow_color = mw->core.background_pixel;
+ else
+ mw->menu.bottom_shadow_color = mw->menu.foreground;
+ }
+ }
+
+ if (!mw->menu.top_shadow_pixmap &&
+ mw->menu.top_shadow_color == mw->core.background_pixel)
+ {
+ mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap;
+ mw->menu.top_shadow_color = mw->menu.foreground;
+ }
+ if (!mw->menu.bottom_shadow_pixmap &&
+ mw->menu.bottom_shadow_color == mw->core.background_pixel)
+ {
+ mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap;
+ mw->menu.bottom_shadow_color = mw->menu.foreground;
+ }
+
+ xgcv.fill_style = FillStippled;
+ xgcv.foreground = mw->menu.top_shadow_color;
+ xgcv.stipple = mw->menu.top_shadow_pixmap;
+ pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
+ mw->menu.shadow_top_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+
+ xgcv.foreground = mw->menu.bottom_shadow_color;
+ xgcv.stipple = mw->menu.bottom_shadow_pixmap;
+ pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
+ mw->menu.shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+}
+
+
+static void
+release_shadow_gcs (XlwMenuWidget mw)
+{
+ XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc);
+ XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc);
+}
+
+static void
+XlwMenuInitialize (Widget request, Widget new, ArgList args,
+ Cardinal *num_args)
+{
+ /* Get the GCs and the widget size */
+ XlwMenuWidget mw = (XlwMenuWidget)new;
+
+ XSetWindowAttributes xswa;
+ int mask;
+
+ Window window = RootWindowOfScreen (DefaultScreenOfDisplay (XtDisplay (mw)));
+ Display* display = XtDisplay (mw);
+
+/* mw->menu.cursor = XCreateFontCursor (display, mw->menu.cursor_shape); */
+ mw->menu.cursor = mw->menu.cursor_shape;
+
+ mw->menu.gray_pixmap = XCreatePixmapFromBitmapData (display, window,
+ gray_bits, gray_width,
+ gray_height, 1, 0, 1);
+
+ make_drawing_gcs (mw);
+ make_shadow_gcs (mw);
+
+ xswa.background_pixel = mw->core.background_pixel;
+ xswa.border_pixel = mw->core.border_pixel;
+ mask = CWBackPixel | CWBorderPixel;
+
+ mw->menu.popped_up = False;
+
+ mw->menu.old_depth = 1;
+ mw->menu.old_stack = (widget_value**)XtMalloc (sizeof (widget_value*));
+ mw->menu.old_stack_length = 1;
+ mw->menu.old_stack [0] = mw->menu.contents;
+
+ mw->menu.new_depth = 0;
+ mw->menu.new_stack = 0;
+ mw->menu.new_stack_length = 0;
+ push_new_stack (mw, mw->menu.contents);
+
+ mw->menu.windows = (window_state*)XtMalloc (sizeof (window_state));
+ mw->menu.windows_length = 1;
+ mw->menu.windows [0].x = 0;
+ mw->menu.windows [0].y = 0;
+ mw->menu.windows [0].width = 0;
+ mw->menu.windows [0].height = 0;
+ size_menu (mw, 0);
+
+ mw->core.width = mw->menu.windows [0].width;
+ mw->core.height = mw->menu.windows [0].height;
+}
+
+static void
+XlwMenuClassInitialize ()
+{
+}
+
+static void
+XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
+{
+ XlwMenuWidget mw = (XlwMenuWidget)w;
+ XSetWindowAttributes xswa;
+ int mask;
+
+ (*xlwMenuWidgetClass->core_class.superclass->core_class.realize)
+ (w, valueMask, attributes);
+
+ xswa.save_under = True;
+ xswa.cursor = mw->menu.cursor_shape;
+ mask = CWSaveUnder | CWCursor;
+ XChangeWindowAttributes (XtDisplay (w), XtWindow (w), mask, &xswa);
+
+ mw->menu.windows [0].window = XtWindow (w);
+ mw->menu.windows [0].x = w->core.x;
+ mw->menu.windows [0].y = w->core.y;
+ mw->menu.windows [0].width = w->core.width;
+ mw->menu.windows [0].height = w->core.height;
+}
+
+/* Only the toplevel menubar/popup is a widget so it's the only one that
+ receives expose events through Xt. So we repaint all the other panes
+ when receiving an Expose event. */
+static void
+XlwMenuRedisplay (Widget w, XEvent* ev, Region region)
+{
+ XlwMenuWidget mw = (XlwMenuWidget)w;
+ int i;
+
+ for (i = 0; i < mw->menu.old_depth; i++)
+ display_menu (mw, i, False, NULL, NULL, NULL, NULL, NULL);
+}
+
+static void
+XlwMenuDestroy (Widget w)
+{
+ int i;
+ XlwMenuWidget mw = (XlwMenuWidget) w;
+
+ release_drawing_gcs (mw);
+ release_shadow_gcs (mw);
+
+ /* this doesn't come from the resource db but is created explicitly
+ so we must free it ourselves. */
+ XFreePixmap (XtDisplay (mw), mw->menu.gray_pixmap);
+ mw->menu.gray_pixmap = (Pixmap) -1;
+
+ /* Don't free mw->menu.contents because that comes from our creator.
+ The `*_stack' elements are just pointers into `contents' so leave
+ that alone too. But free the stacks themselves. */
+ if (mw->menu.old_stack) XtFree ((char *) mw->menu.old_stack);
+ if (mw->menu.new_stack) XtFree ((char *) mw->menu.new_stack);
+
+ /* Remember, you can't free anything that came from the resource
+ database. This includes:
+ mw->menu.cursor
+ mw->menu.top_shadow_pixmap
+ mw->menu.bottom_shadow_pixmap
+ mw->menu.font
+ Also the color cells of top_shadow_color, bottom_shadow_color,
+ foreground, and button_foreground will never be freed until this
+ client exits. Nice, eh?
+ */
+
+ /* start from 1 because the one in slot 0 is w->core.window */
+ for (i = 1; i < mw->menu.windows_length; i++)
+ XDestroyWindow (XtDisplay (mw), mw->menu.windows [i].window);
+ if (mw->menu.windows)
+ XtFree ((char *) mw->menu.windows);
+}
+
+static Boolean
+XlwMenuSetValues (Widget current, Widget request, Widget new)
+{
+ XlwMenuWidget oldmw = (XlwMenuWidget)current;
+ XlwMenuWidget newmw = (XlwMenuWidget)new;
+ Boolean redisplay = False;
+ int i;
+
+ if (newmw->menu.contents
+ && newmw->menu.contents->contents
+ && newmw->menu.contents->contents->change >= VISIBLE_CHANGE)
+ redisplay = True;
+
+ if (newmw->core.background_pixel != oldmw->core.background_pixel
+ || newmw->menu.foreground != oldmw->menu.foreground)
+ {
+ release_drawing_gcs (newmw);
+ make_drawing_gcs (newmw);
+ redisplay = True;
+
+ for (i = 0; i < oldmw->menu.windows_length; i++)
+ {
+ XSetWindowBackground (XtDisplay (oldmw),
+ oldmw->menu.windows [i].window,
+ newmw->core.background_pixel);
+ /* clear windows and generate expose events */
+ XClearArea (XtDisplay (oldmw), oldmw->menu.windows[i].window,
+ 0, 0, 0, 0, True);
+ }
+ }
+
+ return redisplay;
+}
+
+static void
+XlwMenuResize (Widget w)
+{
+ XlwMenuWidget mw = (XlwMenuWidget)w;
+
+ mw->menu.windows [0].width = mw->core.width;
+ mw->menu.windows [0].height = mw->core.height;
+}
+
+ /* Action procedures */
+static void
+handle_single_motion_event (XlwMenuWidget mw, XMotionEvent* ev)
+{
+ widget_value* val;
+ int level;
+
+ if (!map_event_to_widget_value (mw, ev, &val, &level))
+ pop_new_stack_if_no_contents (mw);
+ else
+ set_new_state (mw, val, level);
+ remap_menubar (mw);
+
+ /* Sync with the display. Makes it feel better on X terms. */
+ XSync (XtDisplay (mw), False);
+}
+
+static void
+handle_motion_event (XlwMenuWidget mw, XMotionEvent* ev)
+{
+ int x = ev->x_root;
+ int y = ev->y_root;
+ int state = ev->state;
+
+ handle_single_motion_event (mw, ev);
+
+ /* allow motion events to be generated again */
+ if (ev->is_hint
+ && XQueryPointer (XtDisplay (mw), ev->window,
+ &ev->root, &ev->subwindow,
+ &ev->x_root, &ev->y_root,
+ &ev->x, &ev->y,
+ &ev->state)
+ && ev->state == state
+ && (ev->x_root != x || ev->y_root != y))
+ handle_single_motion_event (mw, ev);
+}
+
+static void
+Start (Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+ XlwMenuWidget mw = (XlwMenuWidget)w;
+
+ XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
+
+ /* notes the absolute position of the menubar window */
+ mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x;
+ mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y;
+
+ /* handles the down like a move, slots are compatible */
+ handle_motion_event (mw, &ev->xmotion);
+}
+
+static void
+Drag (Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+ XlwMenuWidget mw = (XlwMenuWidget)w;
+ handle_motion_event (mw, &ev->xmotion);
+}
+
+static void
+Select (Widget w, XEvent *ev, String *params, Cardinal *num_params)
+{
+ XlwMenuWidget mw = (XlwMenuWidget)w;
+ widget_value* selected_item = mw->menu.old_stack [mw->menu.old_depth - 1];
+
+ /* pop down everything */
+ mw->menu.new_depth = 1;
+ remap_menubar (mw);
+
+ if (mw->menu.popped_up)
+ {
+ mw->menu.popped_up = False;
+ XtUngrabPointer ((Widget)mw, ev->xmotion.time);
+ XtPopdown (XtParent (mw));
+ }
+
+ /* callback */
+ XtCallCallbackList ((Widget)mw, mw->menu.select, (XtPointer)selected_item);
+
+}
+
+
+ /* Special code to pop-up a menu */
+void
+pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent* event)
+{
+ int x = event->x_root;
+ int y = event->y_root;
+ int w;
+ int h;
+ int borderwidth = mw->menu.shadow_thickness;
+ Screen* screen = XtScreen (mw);
+
+ XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
+
+ size_menu (mw, 0);
+
+ w = mw->menu.windows [0].width;
+ h = mw->menu.windows [0].height;
+
+ x -= borderwidth;
+ y -= borderwidth;
+ if (x < borderwidth)
+ x = borderwidth;
+ if (x + w + 2 * borderwidth > WidthOfScreen (screen))
+ x = WidthOfScreen (screen) - w - 2 * borderwidth;
+ if (y < borderwidth)
+ y = borderwidth;
+ if (y + h + 2 * borderwidth> HeightOfScreen (screen))
+ y = HeightOfScreen (screen) - h - 2 * borderwidth;
+
+ mw->menu.popped_up = True;
+ XtConfigureWidget (XtParent (mw), x, y, w, h,
+ XtParent (mw)->core.border_width);
+ XtPopup (XtParent (mw), XtGrabExclusive);
+ display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
+ XtGrabPointer ((Widget)mw, False,
+ (ButtonMotionMask | PointerMotionHintMask | ButtonReleaseMask
+ | ButtonPressMask),
+ GrabModeAsync, GrabModeAsync, None, mw->menu.cursor_shape,
+ event->time);
+
+ mw->menu.windows [0].x = x + borderwidth;
+ mw->menu.windows [0].y = y + borderwidth;
+
+ handle_motion_event (mw, (XMotionEvent*)event);
+}
diff --git a/lwlib/xlwmenu.h b/lwlib/xlwmenu.h
new file mode 100644
index 00000000000..e8d3c93778f
--- /dev/null
+++ b/lwlib/xlwmenu.h
@@ -0,0 +1,50 @@
+#ifndef _XlwMenu_h
+#define _XlwMenu_h
+
+/***********************************************************************
+ *
+ * XlwMenu Widget
+ *
+ ***********************************************************************/
+
+#include "lwlib.h"
+
+/* Resource names used by the XlwMenu widget */
+#define XtNbuttonForeground "buttonForeground"
+#define XtCButtonForeground "ButtonForeground"
+#define XtNmargin "margin"
+#define XtNhorizontalSpacing "horizontalSpacing"
+#define XtNverticalSpacing "verticalSpacing"
+#define XtNarrowSpacing "arrowSpacing"
+#define XtNmenu "menu"
+#define XtCMenu "Menu"
+#define XtNopen "open"
+#define XtNselect "select"
+#define XtNmenuBorderWidth "menuBorderWidth"
+#define XtNhorizontal "horizontal"
+#define XtCHorizontal "Horizontal"
+#define XtNcursor "cursor"
+#define XtNCursor "Cursor"
+
+/* Motif-compatible resource names */
+#define XmNshadowThickness "shadowThickness"
+#define XmCShadowThickness "ShadowThickness"
+#define XmNtopShadowColor "topShadowColor"
+#define XmCTopShadowColor "TopShadowColor"
+#define XmNbottomShadowColor "bottomShadowColor"
+#define XmCBottomShadowColor "BottomShadowColor"
+#define XmNtopShadowPixmap "topShadowPixmap"
+#define XmCTopShadowPixmap "TopShadowPixmap"
+#define XmNbottomShadowPixmap "bottomShadowPixmap"
+#define XmCBottomShadowPixmap "BottomShadowPixmap"
+#define XmRHorizontalDimension "HorizontalDimension"
+
+typedef struct _XlwMenuRec *XlwMenuWidget;
+typedef struct _XlwMenuClassRec *XlwMenuWidgetClass;
+
+extern WidgetClass xlwMenuWidgetClass;
+
+void
+pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent* event);
+
+#endif /* _XlwMenu_h */