Subject: GNOME Patch (sorry it took so long!)

From: Jay Painter <[email-masked]>
Date: Sun, 28 Mar 1999 22:47:51 -0800 (PST)

Here's the patch for GNOME window manager hint support for the CVS head
version of fvwm.  I noticed the session managment is working much better
these days; I'm going to try layers next.

GNOME hints are enabled by the --enable-gnome flag to the configure
script, and are off by default.  Everything is #ifdef'ed in a similar
fashion to session managment.

This patch also adds the function GNOMEButton which can be set on mouse
clicks.  This is for proxying root-window button clicks.

I'll try to get a nice sample gnome.fvwm2rc file to sumbit; perhaps using
the gtkmenu module.

-----------------------------------------------------------------------
Jay Painter -- [email-masked] -- [email-masked] -- [email-masked]
http://www.serv.net/~jpaint/
diff -Nur fvwm.orig/acconfig.h fvwm/acconfig.h
--- fvwm.orig/acconfig.h	Sun Mar 28 18:25:52 1999
+++ fvwm/acconfig.h	Sun Mar 28 19:49:01 1999
@@ -20,6 +20,9 @@
 /* Suffix for config filenames */
 #define FVWMRC ".fvwm2rc"
 
+/* define if GNOME WM hints are enabled */
+#undef GNOME
+
 /* Where to search for images.  */
 #undef FVWM_IMAGEPATH
 
diff -Nur fvwm.orig/configure.in fvwm/configure.in
--- fvwm.orig/configure.in	Sun Mar 28 18:25:52 1999
+++ fvwm/configure.in	Sun Mar 28 19:37:05 1999
@@ -53,6 +53,17 @@
 AC_DEFINE_UNQUOTED(FVWM_IMAGEPATH, "$val")
 AC_MSG_RESULT($val)
 
+dnl Enable GNOME-WM Hints
+AC_ARG_ENABLE(gnome, [  --enable-gnome      turn on GNOME Window Manager Hints [default=no]],,enable_gnome=no)
+
+AC_MSG_CHECKING(whether to enable GNOME window manager hints)
+if test "x$enable_gnome" = "xyes"; then
+  AC_DEFINE(GNOME, 1)
+  AC_SUBST(GNOME)
+  AC_MSG_RESULT(yes)
+else
+  AC_MSG_RESULT(no)
+fi
 
 dnl Minimal checks for programs: enough to enable checking for
 dnl optional libraries.
diff -Nur fvwm.orig/fvwm/CVS/Entries fvwm/fvwm/CVS/Entries
--- fvwm.orig/fvwm/CVS/Entries	Sun Mar 28 18:41:53 1999
+++ fvwm/fvwm/CVS/Entries	Sun Mar 28 18:26:05 1999
@@ -9,6 +9,7 @@
 /module.h/1.7/Fri Mar  5 22:45:30 1999//
 /read.c/1.15/Thu Mar 11 14:26:45 1999//
 /windows.c/1.19/Sun Mar  7 02:40:43 1999//
+/Makefile.am/1.13/Mon Mar 29 02:25:56 1999//
 /add_window.c/1.43/Mon Mar 29 02:25:57 1999//
 /bindings.c/1.18/Mon Mar 29 02:25:57 1999//
 /borders.c/1.24/Mon Mar 29 02:25:57 1999//
@@ -35,5 +36,4 @@
 /session.c/1.8/Mon Mar 29 02:26:04 1999//
 /style.c/1.12/Mon Mar 29 02:26:04 1999//
 /virtual.c/1.20/Mon Mar 29 02:26:05 1999//
-/Makefile.am/1.13/Mon Mar 29 02:41:52 1999//
 D
diff -Nur fvwm.orig/fvwm/Makefile.am fvwm/fvwm/Makefile.am
--- fvwm.orig/fvwm/Makefile.am	Sun Mar 28 18:41:52 1999
+++ fvwm/fvwm/Makefile.am	Sun Mar 28 18:40:43 1999
@@ -10,7 +10,7 @@
 	functions.h fvwm.c fvwm.h fvwmdebug.c fvwmdebug.h icccm2.c icons.c \
 	menus.c menus.h misc.c misc.h modconf.c module.c module.h move.c   \
 	parse.h placement.c read.c resize.c screen.h session.c style.c	   \
-	virtual.c windows.c
+	virtual.c windows.c gnome.c
 
 fvwm2_DEPENDENCIES = $(top_builddir)/libs/libfvwm.a
 
diff -Nur fvwm.orig/fvwm/add_window.c fvwm/fvwm/add_window.c
--- fvwm.orig/fvwm/add_window.c	Sun Mar 28 18:25:57 1999
+++ fvwm/fvwm/add_window.c	Sun Mar 28 19:54:36 1999
@@ -51,6 +51,7 @@
 #endif /* SHAPE */
 #include "module.h"
 
+
 /* Used to parse command line of clients for specific desk requests. */
 /* Todo: check for multiple desks. */
 static XrmDatabase db;
@@ -244,6 +245,11 @@
 
   SelectDecor(tmp_win,styles.on_flags,styles.border_width,styles.resize_width);
 
+#ifdef GNOME
+  /* set GNOME window hints & FVWM flags translated from those hints */
+  GNOME_GetHints(tmp_win);
+#endif
+
 #ifdef SHAPE
   /* set boundary width to zero for shaped windows */
   if (tmp_win->wShaped) tmp_win->boundary_width = 0;
@@ -829,6 +835,12 @@
       resize_window(&Event , tmp_win->w, tmp_win, C_WINDOW, "", 0);
     }
   InstallWindowColormaps(colormap_win);
+
+#ifdef GNOME
+  /* set GNOME hints on the window from flags set on tmp_win */
+  GNOME_SetHints(tmp_win);
+#endif
+
   return (tmp_win);
 }
 
diff -Nur fvwm.orig/fvwm/events.c fvwm/fvwm/events.c
--- fvwm.orig/fvwm/events.c	Sun Mar 28 18:26:00 1999
+++ fvwm/fvwm/events.c	Sun Mar 28 19:54:14 1999
@@ -675,6 +675,14 @@
 
   DBUG("HandleClientMessage","Routine Entered");
 
+#ifdef GNOME
+  /* Process GNOME Messages */
+  if (GNOME_ProcessClientMessage(Tmp_win, &Event))
+    {
+      return;
+    }
+#endif
+
   if ((Event.xclient.message_type == _XA_WM_CHANGE_STATE)&&
       (Tmp_win)&&(Event.xclient.data.l[0]==IconicState)&&
       !(Tmp_win->flags & ICONIFIED))
@@ -758,6 +766,10 @@
   DBUG("HandleDestroyNotify","Routine Entered");
 
   Destroy(Tmp_win);
+
+#ifdef GNOME
+  GNOME_SetClientList();
+#endif
 }

@@ -910,6 +922,10 @@
      can only influence the initial transition from withdrawn state */
   Tmp_win->flags &= ~STARTICONIC;
 #endif
+
+#ifdef GNOME
+  GNOME_SetClientList();
+#endif
 }

@@ -1144,6 +1160,10 @@
   MyXUngrabServer(dpy);
 
   XFlush (dpy);
+
+#ifdef GNOME
+  GNOME_SetClientList();
+#endif
 }

diff -Nur fvwm.orig/fvwm/functions.c fvwm/fvwm/functions.c
--- fvwm.orig/fvwm/functions.c	Sun Mar 28 18:26:00 1999
+++ fvwm/fvwm/functions.c	Sun Mar 28 19:54:23 1999
@@ -27,6 +27,7 @@
 #include "screen.h"
 #include "module.h"
 
+
 static char *expand(char *input, char *arguments[],FvwmWindow *tmp_win);
 static Bool IsClick(int x,int y,unsigned EndMask, XEvent *d,Bool may_time_out);
 
@@ -116,6 +117,9 @@
   {"FOCUS",        focus_func,       F_FOCUS,               FUNC_NEEDS_WINDOW},
   {"FUNCTION",     ComplexFunction,  F_FUNCTION,            FUNC_NO_WINDOW},
   {"GLOBALOPTS",   SetGlobalOptions, F_GLOBAL_OPTS,         FUNC_NO_WINDOW},
+#ifdef GNOME
+  {"GNOMEButton",  GNOME_ButtonFunc, F_MOUSE,               FUNC_NO_WINDOW},
+#endif /* GNOME */
   {"GOTOPAGE",     goto_page_func,   F_GOTO_PAGE,           FUNC_NO_WINDOW},
   {"HILIGHTCOLOR", SetHiColor,       F_HICOLOR,             FUNC_NO_WINDOW},
   {"ICONFONT",     LoadIconFont,     F_ICONFONT,            FUNC_NO_WINDOW},
diff -Nur fvwm.orig/fvwm/fvwm.c fvwm/fvwm/fvwm.c
--- fvwm.orig/fvwm/fvwm.c	Sun Mar 28 18:26:00 1999
+++ fvwm/fvwm/fvwm.c	Sun Mar 28 19:54:57 1999
@@ -43,7 +43,6 @@
 
 #define MAXHOSTNAME 255
 
-
 #ifndef lint
 static char sccsid[] = "@(#)fvwm.c " VERSION " " __DATE__ " fvwm";
 #endif
@@ -550,6 +549,10 @@
 
 #ifdef SESSION
   SessionInit(client_id);
+#endif
+
+#ifdef GNOME
+  GNOME_Init();
 #endif
 
   HandleEvents();
diff -Nur fvwm.orig/fvwm/gnome.c fvwm/fvwm/gnome.c
--- fvwm.orig/fvwm/gnome.c	Wed Dec 31 16:00:00 1969
+++ fvwm/fvwm/gnome.c	Sun Mar 28 19:53:48 1999
@@ -0,0 +1,749 @@
+/*********************************************************/
+/* GNOME WM Compliance adapted for FVWM                  */
+/* Properties set on the root window (or desktop window) */
+/*                                                       */
+/* Even though the rest of E is GPL consider this file   */
+/* Public Domain - use it howvere you see fit to make    */
+/* your WM GNOME compiant                                */
+/*                                                       */
+/* written by Raster                                     */
+/* adapted for FVWM by Jay Painter <[email-masked]>      */ 
+/*********************************************************/
+#include "config.h"
+#ifdef GNOME
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xmd.h>
+#include <X11/Xatom.h>
+
+#include "fvwm.h"
+#include "screen.h"
+#include "misc.h"
+
+
+
+/*********************************************************/
+/* Properties set on the root window (or desktop window) */
+/*********************************************************/
+
+/* WIN_AREA CARD32[2] contains the current desktop area X,Y */
+#define XA_WIN_AREA                        "_WIN_AREA"
+
+/* WIN_AREA CARD32[2] contains the current desktop area size WxH */
+#define XA_WIN_AREA_COUNT                        "_WIN_AREA_COUNT"
+
+/* array of atoms - atom being one of the following atoms */
+#define XA_WIN_PROTOCOLS                   "_WIN_PROTOCOLS"
+
+/* array of iocn in various sizes */
+/* Type: array of CARD32 */
+/*       first item is icon count (n) */
+/*       second item is icon record length (in CARD32s) */
+/*       this is followed by (n) icon records as follows */
+/*           pixmap (XID) */
+/*           mask (XID) */
+/*           width (CARD32) */
+/*           height (CARD32) */
+/*           depth (of pixmap, mask is assumed to be of depth 1) (CARD32) */
+/*           drawable (screen root drawable of pixmap) (XID) */
+/*           ... additional fields can be added at the end of this list */
+#define XA_WIN_ICONS                    "_WIN_ICONS"
+
+/* WIN_WORKSPACE CARD32 contains the current desktop number */
+#define XA_WIN_WORKSPACE                   "_WIN_WORKSPACE"
+/* WIN_WORKSPACE_COUNT CARD32 contains the number of desktops */
+#define XA_WIN_WORKSPACE_COUNT             "_WIN_WORKSPACE_COUNT"
+
+/* WIN_WORKSPACE_NAMES StringList (Text Property) of workspace names */
+/* unused by enlightenment */
+#define XA_WIN_WORKSPACE_NAMES             "_WIN_WORKSPACE_NAMES"
+
+/* ********** Don't use this.. iffy at best. *********** */
+/* The available work area for client windows. The WM can set this and the WM */
+/* and/or clients may change it at any time. If it is changed the WM and/or  */
+/* clients should honor the changes. If this property does not exist a client */
+/* or WM can create it. */
+/*
+ * CARD32              min_x;
+ * CARD32              min_y;
+ * CARD32              max_x;
+ * CARD32              max_y;
+ */
+#define XA_WIN_WORKAREA                    "_WIN_WORKAREA"
+/* array of 4 CARD32's */
+
+/* This is a list of window id's the WM is currently managing - primarily */
+/* for being able to have external "tasklist" apps */
+#define XA_WIN_CLIENT_LIST                 "_WIN_CLIENT_LIST"
+/* array of N XID's */
+
+/*********************************************************/
+/* Properties on client windows                          */
+/*********************************************************/
+
+/* The layer the window exists in */
+/*      0 = Desktop */
+/*      1 = Below */
+/*      2 = Normal (default app layer) */
+/*      4 = OnTop */
+/*      6 = Dock (always on top - for panel) */
+/* The app sets this alone, not the WM. If this property changes the WM */
+/* should comply and change the appearance/behavior of the Client window */
+/* if this hint does nto exist the WM Will create it ont he Client window */
+#define WIN_LAYER_DESKTOP                0
+#define WIN_LAYER_BELOW                  2
+#define WIN_LAYER_NORMAL                 4
+#define WIN_LAYER_ONTOP                  6
+#define WIN_LAYER_DOCK                   8
+#define WIN_LAYER_ABOVE_DOCK             10
+#define WIN_LAYER_MENU                   12
+#define XA_WIN_LAYER                     "_WIN_LAYER"
+/* WIN_LAYER = CARD32 */
+
+/* flags for the window's state. The WM will change these as needed when */
+/* state changes. If the property contains info on client map, E will modify */
+/* the windows state accordingly. if the Hint does not exist the WM will */
+/* create it on the client window. 0 for the bit means off, 1 means on. */
+/* unused (default) values are 0 */
+
+/* removed Minimized - no explanation of what it really means - ambiguity */
+/* should not be here if not clear */
+#define WIN_STATE_STICKY          (1<<0)	/* everyone knows sticky */
+#define WIN_STATE_RESERVED_BIT1   (1<<1)	/* removed minimize here */
+#define WIN_STATE_MAXIMIZED_VERT  (1<<2)	/* window in maximized V state */
+#define WIN_STATE_MAXIMIZED_HORIZ (1<<3)	/* window in maximized H state */
+#define WIN_STATE_HIDDEN          (1<<4)	/* not on taskbar but window visible */
+#define WIN_STATE_SHADED          (1<<5)	/* shaded (NeXT style) */
+#define WIN_STATE_HID_WORKSPACE   (1<<6)	/* not on current desktop */
+#define WIN_STATE_HID_TRANSIENT   (1<<7)	/* owner of transient is hidden */
+#define WIN_STATE_FIXED_POSITION  (1<<8)	/* window is fixed in position even */
+#define WIN_STATE_ARRANGE_IGNORE  (1<<9)	/* ignore for auto arranging */
+					 /* when scrolling about large */
+					 /* virtual desktops ala fvwm */
+#define XA_WIN_STATE              "_WIN_STATE"
+/* WIN_STATE = CARD32 */
+
+/* Preferences for behavior for app */
+/* ONLY the client sets this */
+#define WIN_HINTS_SKIP_FOCUS             (1<<0)		/* "alt-tab" skips this win */
+#define WIN_HINTS_SKIP_WINLIST           (1<<1)		/* not in win list */
+#define WIN_HINTS_SKIP_TASKBAR           (1<<2)		/* not on taskbar */
+#define WIN_HINTS_GROUP_TRANSIENT        (1<<3)		/* ??????? */
+#define WIN_HINTS_FOCUS_ON_CLICK         (1<<4)		/* app only accepts focus when clicked */
+#define XA_WIN_HINTS                     "_WIN_HINTS"
+/* WIN_HINTS = CARD32 */
+
+/* Application state - also "color reactiveness" - the app can keep changing */
+/* this property when it changes its state and the WM or monitoring program */
+/* will pick this up and dpylay somehting accordingly. ONLY the client sets */
+/* this. */
+#define WIN_APP_STATE_NONE                 0
+#define WIN_APP_STATE_ACTIVE1              1
+#define WIN_APP_STATE_ACTIVE2              2
+#define WIN_APP_STATE_ERROR1               3
+#define WIN_APP_STATE_ERROR2               4
+#define WIN_APP_STATE_FATAL_ERROR1         5
+#define WIN_APP_STATE_FATAL_ERROR2         6
+#define WIN_APP_STATE_IDLE1                7
+#define WIN_APP_STATE_IDLE2                8
+#define WIN_APP_STATE_WAITING1             9
+#define WIN_APP_STATE_WAITING2             10
+#define WIN_APP_STATE_WORKING1             11
+#define WIN_APP_STATE_WORKING2             12
+#define WIN_APP_STATE_NEED_USER_INPUT1     13
+#define WIN_APP_STATE_NEED_USER_INPUT2     14
+#define WIN_APP_STATE_STRUGGLING1          15
+#define WIN_APP_STATE_STRUGGLING2          16
+#define WIN_APP_STATE_DISK_TRAFFIC1        17
+#define WIN_APP_STATE_DISK_TRAFFIC2        18
+#define WIN_APP_STATE_NETWORK_TRAFFIC1     19
+#define WIN_APP_STATE_NETWORK_TRAFFIC2     20
+#define WIN_APP_STATE_OVERLOADED1          21
+#define WIN_APP_STATE_OVERLOADED2          22
+#define WIN_APP_STATE_PERCENT000_1         23
+#define WIN_APP_STATE_PERCENT000_2         24
+#define WIN_APP_STATE_PERCENT010_1         25
+#define WIN_APP_STATE_PERCENT010_2         26
+#define WIN_APP_STATE_PERCENT020_1         27
+#define WIN_APP_STATE_PERCENT020_2         28
+#define WIN_APP_STATE_PERCENT030_1         29
+#define WIN_APP_STATE_PERCENT030_2         30
+#define WIN_APP_STATE_PERCENT040_1         31
+#define WIN_APP_STATE_PERCENT040_2         32
+#define WIN_APP_STATE_PERCENT050_1         33
+#define WIN_APP_STATE_PERCENT050_2         34
+#define WIN_APP_STATE_PERCENT060_1         35
+#define WIN_APP_STATE_PERCENT060_2         36
+#define WIN_APP_STATE_PERCENT070_1         37
+#define WIN_APP_STATE_PERCENT070_2         38
+#define WIN_APP_STATE_PERCENT080_1         39
+#define WIN_APP_STATE_PERCENT080_2         40
+#define WIN_APP_STATE_PERCENT090_1         41
+#define WIN_APP_STATE_PERCENT090_2         42
+#define WIN_APP_STATE_PERCENT100_1         43
+#define WIN_APP_STATE_PERCENT100_2         44
+#define XA_WIN_APP_STATE                   "_WIN_APP_STATE"
+/* WIN_APP_STATE = CARD32 */
+
+/* Expanded space occupied - this is the area on screen the app's window */
+/* will occupy when "expanded" - ie if you have a button on an app that */
+/* "hides" it by reducing its size, this is the geometry of the expanded */
+/* window - so the window manager can allow for this when doign auto */
+/* positioing of client windows assuming the app can at any point use this */
+/* this area and thus try and keep it clear. ONLY the client sets this */
+/*
+ * CARD32              x;
+ * CARD32              y;
+ * CARD32              width;
+ * CARD32              height;
+ */
+#define XA_WIN_EXPANDED_SIZE               "_WIN_EXPANDED_SIZE"
+/* array of 4 CARD32's */
+
+/* CARD32 that contians the desktop number the application is on If the */
+/* application's state is "sticky" it is irrelevant. Only the WM should */
+/* change this. */
+#define XA_WIN_WORKSPACE                   "_WIN_WORKSPACE"
+
+/* This atom is a 32-bit integer that is either 0 or 1 (currently). */
+/* 0 denotes everything is as per usual but 1 denotes that ALL configure */
+/* requests by the client on the client window with this property are */
+/* not just a simple "moving" of the window, but the result of a user */
+/* moving the window BUT the client handling that interaction by moving */
+/* its own window. The window manager should respond accordingly by assuming */
+/* any configure requests for this window whilst this atom is "active" in */
+/* the "1" state are a client move and should handle flipping desktops if */
+/* the window is being dragged "off screem" or across desktop boundaries */
+/* etc. This atom is ONLY ever set by the client */
+#define XA_WIN_CLIENT_MOVING               "_WIN_CLIENT_MOVING"
+/* WIN_CLIENT_MOVING = CARD32 */
+
+/* Designed for checking if the WIN_ supporting WM is still there  */
+/* and kicking about - basically check this property - check the window */
+/* ID it points to - then check that window Id has this property too */
+/* if that is the case the WIN_ supporting WM is there and alive and the */
+/* list of WIN_PROTOCOLS is valid */
+#define XA_WIN_SUPPORTING_WM_CHECK         "_WIN_SUPPORTING_WM_CHECK"
+/* CARD32 */
+
+/* for root window button clicks */
+#define XA_WIN_DESKTOP_BUTTON_PROXY        "_WIN_DESKTOP_BUTTON_PROXY"
+/* CARD32 */
+
+
+/* for the root window clicks */
+static Window __button_proxy = 0;
+
+
+void *
+AtomGet(Window win, Atom to_get, Atom type, int *size)
+{
+  unsigned char      *retval;
+  Atom                type_ret;
+  unsigned long       bytes_after, num_ret;
+  int                 format_ret;
+  long                length;
+  void               *data;
+  
+  retval = NULL;
+  length = 0x7fffffff;
+  XGetWindowProperty(dpy, win, to_get, 0,
+		     length,
+		     False, type,
+		     &type_ret,
+		     &format_ret,
+		     &num_ret,
+		     &bytes_after,
+		     &retval);
+
+  if ((retval) && (num_ret > 0) && (format_ret > 0))
+    {
+      data = safemalloc(num_ret * (format_ret >> 3));
+      if (data)
+	memcpy(data, retval, num_ret * (format_ret >> 3));
+      XFree(retval);
+      *size = num_ret * (format_ret >> 3);
+      return data;
+    }
+
+  return NULL;
+}
+
+
+/*** GET WINDOW PROPERTIES ***/
+
+void
+GNOME_GetHintIcons(FvwmWindow *fwin)
+{
+   Atom                atom_get;
+   CARD32             *retval;
+   int                 size;
+   unsigned int        i;
+   Pixmap              pmap;
+   Pixmap              mask;
+
+   atom_get = XInternAtom(dpy, XA_WIN_ICONS, False);
+   retval = AtomGet(fwin->w, atom_get, XA_PIXMAP, &size);
+   if (retval)
+     {
+	for (i = 0; i < (size / (sizeof(CARD32))); i += 2)
+	  {
+	     pmap = retval[i];
+	     mask = retval[i + 1];
+	  }
+	free(retval);
+     }
+}
+
+void
+GNOME_GetHintLayer(FvwmWindow *fwin)
+{
+   Atom atom_get;
+   CARD32 *retval;
+   int size;
+
+   atom_get = XInternAtom(dpy, XA_WIN_LAYER, False);
+   retval = AtomGet(fwin->w, atom_get, XA_CARDINAL, &size);
+   if (retval)
+     {
+	fwin->layer = *retval;
+	free(retval);
+     }
+}
+
+void
+GNOME_GetHintState(FvwmWindow *fwin)
+{
+  Atom atom_get;
+  CARD32 *retval;
+  int size;
+
+  atom_get = XInternAtom(dpy, XA_WIN_STATE, False);
+  retval = AtomGet(fwin->w, atom_get, XA_CARDINAL, &size);
+  if (retval)
+    {
+      if (*retval & WIN_STATE_STICKY)
+	fwin->flags |= STICKY;
+
+#ifdef WINDOWSHADE
+      if (*retval & WIN_STATE_SHADED)
+	fwin->buttons |= WSHADE;
+#endif /* WINDOWSHADE */
+      
+      free(retval);
+    }
+}
+
+void
+GNOME_GetHintAppState(FvwmWindow *fwin)
+{
+  Atom atom_get;
+  unsigned char *retval;
+  int size;
+  
+  /* have nothing interesting to do with an app state (lamp) right now */
+  atom_get = XInternAtom(dpy, XA_WIN_APP_STATE, False);
+  retval = AtomGet(fwin->w, atom_get, XA_CARDINAL, &size);
+  if (retval)
+    {
+      free(retval);
+    }
+}
+
+void
+GNOME_GetHintDesktop(FvwmWindow *fwin)
+{
+  Atom atom_get;
+  unsigned char *retval;
+  int size;
+  int *desk;
+  
+  atom_get = XInternAtom(dpy, XA_WIN_WORKSPACE, False);
+  retval = AtomGet(fwin->w, atom_get, XA_CARDINAL, &size);
+  if (retval)
+    {
+      desk = (int *)retval;
+      fwin->Desk = *desk;
+
+      /* XXX: hide window if it's not on the current desktop! */
+
+      free(retval);
+    }
+}
+
+void
+GNOME_GetHint(FvwmWindow *fwin)
+{
+  Atom atom_get;
+  int *retval;
+  int size;
+  
+  atom_get = XInternAtom(dpy, XA_WIN_HINTS, False);
+  retval = AtomGet(fwin->w, atom_get, XA_CARDINAL, &size);
+  if (retval)
+    {
+      if (*retval & WIN_HINTS_SKIP_WINLIST)
+	fwin->flags |= WINDOWLISTSKIP;
+
+      /* XXX: unimplimented */
+      if (*retval & WIN_HINTS_SKIP_TASKBAR);
+      if (*retval & WIN_HINTS_SKIP_FOCUS);
+      if (*retval & WIN_HINTS_FOCUS_ON_CLICK);
+      /* if (*retval & WIN_HINTS_DO_NOT_COVER);*/
+     
+      free(retval);
+    }
+}
+
+void
+GNOME_SetHints(FvwmWindow *fwin)
+{
+  Atom atom_set;
+  int val;
+  
+  atom_set = XInternAtom(dpy, XA_WIN_STATE, False);
+  val = 0;
+  
+  if (fwin->flags & STICKY)
+    val |= WIN_STATE_STICKY;
+  
+#ifdef WINDOWSHADE
+  if (fwin->buttons & WSHADE)
+    val |= WIN_STATE_SHADED;
+#endif
+  
+  XChangeProperty(dpy, fwin->w, atom_set, XA_CARDINAL, 32,
+		  PropModeReplace, (unsigned char *)&val, 1);
+}
+
+
+void
+GNOME_GetExpandedSize(FvwmWindow *fwin)
+{
+  Atom atom_get;
+  CARD32 *retval;
+  int size;
+
+  /* unimplimented */
+  int expanded_x, expanded_y, expanded_width, expanded_height;
+
+  atom_get = XInternAtom(dpy, XA_WIN_EXPANDED_SIZE, False);
+  retval = AtomGet(fwin->w, atom_get, XA_CARDINAL, &size);
+  if (retval)
+    {
+      expanded_x = retval[0];
+      expanded_y = retval[1];
+      expanded_width = retval[2];
+      expanded_height = retval[3];
+      free(retval);
+    }
+}
+
+
+void
+GNOME_GetHints(FvwmWindow *fwin)
+{
+  GNOME_GetHintDesktop(fwin);
+  GNOME_GetHintIcons(fwin);
+  GNOME_GetHintLayer(fwin);
+  GNOME_GetHintState(fwin);
+  GNOME_GetHintAppState(fwin);
+  GNOME_GetHint(fwin);
+  GNOME_GetExpandedSize(fwin);
+}
+
+
+/*** SET WINDOW PROPERTIES ***/
+void
+GNOME_SetDesk(FvwmWindow *fwin)
+{
+  Atom atom_set;
+  int val;
+
+  atom_set = XInternAtom(dpy, XA_WIN_WORKSPACE, False);
+  val = fwin->Desk;
+  XChangeProperty(dpy, fwin->w, atom_set, XA_CARDINAL, 32,
+		  PropModeReplace, (unsigned char *)&val, 1);
+}
+
+
+
+
+/*** INITALIZE GNOME WM SUPPORT ***/
+
+/* sets the virtual desktop grid properties */
+void
+GNOME_SetAreaCount()
+{
+  Atom atom_set;
+  CARD32 val[2];
+  
+  atom_set = XInternAtom(dpy, XA_WIN_AREA_COUNT, False);
+  
+  val[0] = (Scr.VxMax + Scr.MyDisplayWidth) / Scr.MyDisplayWidth;
+  val[1] = (Scr.VyMax + Scr.MyDisplayHeight) / Scr.MyDisplayHeight;
+  
+  XChangeProperty(dpy, Scr.Root, atom_set, XA_CARDINAL, 32, PropModeReplace,
+		  (unsigned char *)val, 2);
+}
+
+
+/* sets the property indicating the current virtual desktop
+ * location
+ */
+void
+GNOME_SetCurrentArea()
+{
+  Atom atom_set;
+  CARD32 val[2];
+  
+  atom_set = XInternAtom(dpy, XA_WIN_AREA, False);
+  
+  val[0] = Scr.Vx / Scr.MyDisplayWidth;
+  val[1] = Scr.Vy / Scr.MyDisplayHeight;
+  
+  XChangeProperty(dpy, Scr.Root, atom_set, XA_CARDINAL, 32, PropModeReplace,
+		  (unsigned char *)val, 2);
+}
+
+
+/* XXX: this function is hard-coded to one desktop! -JMP */
+void
+GNOME_SetDeskCount()
+{
+  Atom atom_set;
+  CARD32 val;
+  
+  atom_set = XInternAtom(dpy, XA_WIN_WORKSPACE_COUNT, False);
+  val = 1;
+  XChangeProperty(dpy, Scr.Root, atom_set, XA_CARDINAL, 32, PropModeReplace,
+		  (unsigned char *)&val, 1);
+}
+
+
+/* XXX: this function is hard-coded to one! -JMP */
+void
+GNOME_SetCurrentDesk()
+{
+  Atom atom_set;
+  CARD32 val;
+  
+  atom_set = XInternAtom(dpy, XA_WIN_WORKSPACE, False);
+  val = (CARD32) Scr.CurrentDesk;
+  XChangeProperty(dpy, Scr.Root, atom_set, XA_CARDINAL, 32, PropModeReplace,
+		  (unsigned char *)&val, 1);
+  GNOME_SetCurrentArea();
+}
+
+
+/* sets the names assigned to the desktops */
+void
+GNOME_SetDeskNames()
+{
+  Atom atom_set;
+  XTextProperty text;
+  char *names[1];
+  int i;
+  
+  atom_set = XInternAtom(dpy, XA_WIN_WORKSPACE_NAMES, False);
+  
+  names[0] = "GNOME Desktop";
+  
+  if (XStringListToTextProperty(names, 1, &text))
+    {
+      XSetTextProperty(dpy, Scr.Root, &text, atom_set);
+      XFree(text.value);
+    }
+}
+
+
+void
+GNOME_SetClientList()
+{
+  Atom atom_set;
+  Window wl[256];
+  int i = 0;
+  FvwmWindow *t;
+  
+  atom_set = XInternAtom(dpy, XA_WIN_CLIENT_LIST, False);
+  
+  for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
+    {
+      if (!(t->flags & WINDOWLISTSKIP))
+	{
+	  wl[i++] = t->w;
+	}
+    }
+  
+  if (i > 0)
+    {
+      XChangeProperty(dpy, Scr.Root, atom_set, XA_CARDINAL, 32, 
+		      PropModeReplace, (unsigned char *)wl, i);
+    }
+  else
+    {
+      XChangeProperty(dpy, Scr.Root, atom_set, XA_CARDINAL, 32, 
+		      PropModeReplace, (unsigned char *)NULL, 0);
+    }
+}
+
+
+void
+GNOME_Init()
+{
+  int i;
+  Atom atom_set, list[11];
+  CARD32 val;
+  Window win;
+  
+
+  atom_set = XInternAtom(dpy, XA_WIN_PROTOCOLS, False);
+
+  /* these indicate what GNOME compliance properties have
+   * been implimented
+   */
+  i = 0;
+  list[i++] = XInternAtom(dpy, XA_WIN_LAYER, False);
+  list[i++] = XInternAtom(dpy, XA_WIN_STATE, False);
+  list[i++] = XInternAtom(dpy, XA_WIN_HINTS, False);
+  /* list[i++] = XInternAtom(dpy, XA_WIN_APP_STATE, False); */
+  /* list[i++] = XInternAtom(dpy, XA_WIN_EXPANDED_SIZE, False); */
+  /* list[i++] = XInternAtom(dpy, XA_WIN_ICONS, False); */
+  list[i++] = XInternAtom(dpy, XA_WIN_WORKSPACE, False);
+  list[i++] = XInternAtom(dpy, XA_WIN_WORKSPACE_COUNT, False);
+  list[i++] = XInternAtom(dpy, XA_WIN_WORKSPACE_NAMES, False);
+  list[i++] = XInternAtom(dpy, XA_WIN_CLIENT_LIST, False);
+  list[i++] = XInternAtom(dpy, XA_WIN_DESKTOP_BUTTON_PROXY, False);
+  
+  XChangeProperty(dpy, Scr.Root, atom_set, XA_ATOM, 32, PropModeReplace,
+		  (unsigned char *)list, i);
+
+
+  /* create a window which is a child of the root window and set the
+   * XA_WIN_SUPPORTING_WM_CHECK property on it, and also set the
+   * same property on the root window with the window ID of of the
+   * window we just created 
+   */
+  win = XCreateWindow(dpy, Scr.Root, -10, -10, 10, 10, 0, 0,
+		      InputOnly, CopyFromParent, 0, NULL);
+  
+  atom_set = XInternAtom(dpy, XA_WIN_SUPPORTING_WM_CHECK, False);
+  val = win;
+  XChangeProperty(dpy, Scr.Root, atom_set, XA_CARDINAL, 32, PropModeReplace,
+		  (unsigned char *)&val, 1);
+  XChangeProperty(dpy, win, atom_set, XA_CARDINAL, 32, PropModeReplace,
+		  (unsigned char *)&val, 1);
+
+
+  /* create a window which is the child of the root window for proxying
+   * root window clicks
+   */
+    
+  __button_proxy = XCreateWindow(dpy, Scr.Root, -10, -10, 10, 10, 0, 0,
+				 InputOnly, CopyFromParent, 0, NULL);
+  
+  atom_set = XInternAtom(dpy, XA_WIN_DESKTOP_BUTTON_PROXY, False);
+  val = __button_proxy;
+
+  XChangeProperty(dpy, Scr.Root, atom_set, XA_CARDINAL, 32,
+		  PropModeReplace, (unsigned char *)&val, 1);
+  XChangeProperty(dpy, __button_proxy, atom_set, XA_CARDINAL, 32,
+		  PropModeReplace, (unsigned char *)&val, 1);
+
+
+  /* some inital settings */
+  GNOME_SetDeskCount();
+  GNOME_SetCurrentDesk();
+  GNOME_SetDeskNames();
+
+  GNOME_SetAreaCount();
+  GNOME_SetCurrentArea();
+
+  GNOME_SetClientList();
+}
+
+
+
+
+/*** RECIVING MESSAGES ***/
+int
+GNOME_ProcessClientMessage(FvwmWindow *fwin, XEvent *ev)
+{
+  int x, y;
+  Atom a;
+
+  a = XInternAtom(dpy, "_WIN_AREA", False);
+  if (ev->xclient.message_type == a)
+    {
+      /* convert to integer grid */
+      x = ev->xclient.data.l[0] * Scr.MyDisplayWidth;
+      y = ev->xclient.data.l[1] * Scr.MyDisplayHeight;
+
+      MoveViewport(x, y, 1);
+      return 1;
+    }
+
+  a = XInternAtom(dpy, "_WIN_WORKSPACE", False);
+  if (ev->xclient.message_type == a)
+    {
+      changeDesks(ev->xclient.data.l[0]);
+      return 1;
+    }
+
+  a = XInternAtom(dpy, "_WIN_LAYER", False);
+  if (ev->xclient.message_type == a && fwin)
+    {
+      /* support for layers in a fvwm requires adding significant
+       * new functionallity
+       */
+#if 0
+      fwin->layer = ev->xclient.data.l[0];
+#endif
+      XChangeProperty(dpy, fwin->w, a, XA_CARDINAL, 32,
+		      PropModeReplace,
+		      (unsigned char *)(&(ev->xclient.data.l[0])), 1);
+      
+      /* need to restack the windows */
+      return 1;
+    }
+
+  return 0;
+}
+
+
+void
+GNOME_ProxyButtonEvent(XEvent *ev)
+{
+  switch (ev->type)
+    {
+    case ButtonPress:
+      XUngrabPointer(dpy, CurrentTime);
+      XSendEvent(dpy, __button_proxy, False, SubstructureNotifyMask, ev);
+      break;
+
+    case ButtonRelease:
+      XSendEvent(dpy, __button_proxy, False, SubstructureNotifyMask, ev);
+      break;
+    }
+}
+
+
+/* this is the function entered into FVWM's functions table */
+void
+GNOME_ButtonFunc(XEvent *eventp, Window w, FvwmWindow *fwin,
+		 unsigned long context, char *action, int *Module)
+{
+  /* send off the button press event */
+  GNOME_ProxyButtonEvent(eventp);
+}
+
+
+#endif /* GNOME */
diff -Nur fvwm.orig/fvwm/misc.h fvwm/fvwm/misc.h
--- fvwm.orig/fvwm/misc.h	Sun Mar 28 18:26:03 1999
+++ fvwm/fvwm/misc.h	Sun Mar 28 19:50:41 1999
@@ -490,6 +490,38 @@
 void MatchWinToSM(FvwmWindow *t, int *, int *, int *, int *, int *, int *);
 #endif
 
+#ifdef GNOME
+/* GNOME window manager hints support */
+
+/* initalization */
+void GNOME_Init();
+
+/* client messages; setting hints on a window comes through this mechanism */
+int  GNOME_ProcessClientMessage(FvwmWindow *fwin, XEvent *ev);
+
+/* hook into .fvwm2rc functions */
+void GNOME_ButtonFunc(
+         XEvent *eventp, 
+	 Window w,
+	 FvwmWindow *fwin, 
+	 unsigned long context, 
+	 char *action, 
+	 int *Module);
+
+/* get hints on a window; sets parameters in a FvwmWindow */
+void GNOME_GetHints(FvwmWindow *fwin);
+
+/* set hints on a window from parameters in FvwmWindow */
+void GNOME_SetHints(FvwmWindow *fwin);
+
+/* update public window manager information */
+void GNOME_SetCurrentArea();
+void GNOME_SetCurrentDesk();
+void GNOME_SetClientList();
+
+#endif /* GNOME */
+
+
 #endif /* MISC_H */

diff -Nur fvwm.orig/fvwm/virtual.c fvwm/fvwm/virtual.c
--- fvwm.orig/fvwm/virtual.c	Sun Mar 28 18:26:05 1999
+++ fvwm/fvwm/virtual.c	Sun Mar 28 19:54:32 1999
@@ -612,6 +612,11 @@
     StashEventTime(&Event);
   if(grab)
     MyXUngrabServer(dpy);
+
+#ifdef GNOME
+  /* update GNOME pager */
+  GNOME_SetCurrentArea();
+#endif
 }
 
 /**************************************************************************

---

From: Matthias Clasen <[email-masked]>
Date: Tue, 30 Mar 1999 00:08:21 +0200

Jay, nice to see the gnome support appear...

> I'll try to get a nice sample gnome.fvwm2rc file to sumbit; perhaps using

Not that it changed its name to FvwmGtk (and is in CVS now) and it
also does dialogs these days.

Regards, Matthias

-- 
Matthias Clasen, 
Tel. 0761/203-5606
Email: [email-masked]
Mathematisches Institut, Albert-Ludwigs-Universitaet Freiburg
--
Visit the official FVWM web page at <URL:http://www.fvwm.org/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked]

---

From: Dominik Vogt <[email-masked]>
Date: Tue, 30 Mar 1999 19:02:18 +0200

> I'll try to get a nice sample gnome.fvwm2rc file to sumbit; perhaps using

Would you please create another patch with

 - ChangeLog entries
 - NEWS update
 - manpage update      <--- !!!!!

Bye

Dominik ^_^

--
Dominik Vogt, [email-masked]
Reply-To: [email-masked]
--
Visit the official FVWM web page at <URL:http://www.fvwm.org/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked]