patch: fix WM bindings for vncviewer -fullscreen

Mark Rainford Mark.Rainford "at" jet.uk
Fri Jan 30 17:12:00 2004


Applicability:

	3.3.3r2 -> 3.3.7 unix vncviewer
	Dunno 'bout later versions, sorry.

Symptom:

	vncviewer -fullscreen breaks window manager bindings: the user cannot 
lower/raise the window, and cannot gotoDesk (fvwm). Worse, on a 
multi-head display (non-xinerama), once the pointer leaves vncviewer 
-fullscreen it never regains focus, so F8 no longer pops up the menu, 
and it is impossible to exit vncviewer other than by kill from another 
process.

Fix:

	The patch below changes fullscreen.c and misc.c to retain WM control of 
the window, while removing/adding WM decorations upon 
fullscreen/restore. This fixes it under fvwm-2.4.3 at least.

Patch:

	cd vnc-3.3.*/vnc_unixsrc/vncviewer
	patch -lp3  <<Ooof

Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: Imakefile
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: README
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: Vncviewer
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: argsresources.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: colour.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: corre.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: desktop.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: dialogs.c
diff -Bwru6 -X /home/usrlocal/pd/vnc/Patches/Excludes vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer/fullscreen.c vnc-3.3.3r2-JETpatch/vnc_unixsrc/vncviewer/fullscreen.c
--- vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer/fullscreen.c  1999-08-12 17:16:03.000000000 +0100
+++ vnc-3.3.3r2-JETpatch/vnc_unixsrc/vncviewer/fullscreen.c     2004-01-30 16:40:09.808000000 +0000
@@ -33,16 +33,67 @@
 static Bool scrollLeft, scrollRight, scrollUp, scrollDown;
 static Position desktopX, desktopY;
 static Dimension viewportWidth, viewportHeight;
 static Dimension scrollbarWidth, scrollbarHeight;
 
 
+/*
+** 30.01.04 mr "at" jet.uk  - patch for fullscreen
+**
+** This patch enables fullscreen while retaining WM control of the window -
+** thus the user can still lower/raise and gotoDesk.
+** 
+** The window manager notices changes to decoration-hints when the window
+** is mapped, so (elsewhere) we:
+** 
+** (1) ensure the toplevel widget is initially unmanaged, giving us a
+** chance to hide decorations before mapping a fullscreen window, and
+** (2) unmap/remap the window when toggling fullscreen
+** 
+** A modified copy of rdesktop's mwm_hide_decorations() is used
+** rdesktop is copiable under the same GPL terms as this source file.
+*/
+/* MWM decorations */
+#define MWM_HINTS_DECORATIONS   (1L << 1)
+#define PROP_MOTIF_WM_HINTS_ELEMENTS    5
+typedef struct
+{
+        CARD32 flags;
+        CARD32 functions;
+        CARD32 decorations;
+        INT32  inputMode;
+        CARD32 status;
+}
+PropMotifWmHints;
+
+void
+mwm_hide_decorations(Boolean hide)
+{
+        PropMotifWmHints motif_hints;
+        Atom hintsatom;
+
+        /* setup the property */
+        motif_hints.flags = MWM_HINTS_DECORATIONS;
+        motif_hints.decorations = ! hide;
+
+        /* get the atom for the property */
+        hintsatom = XInternAtom(dpy, "_MOTIF_WM_HINTS", False);
+        if (!hintsatom)
+        {
+                fprintf(stderr,"Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
+                return;
+        }
+
+        XChangeProperty(dpy, XtWindow(toplevel), hintsatom, hintsatom, 32, PropModeReplace,
+                        (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
+}
+
 
 /*
- * FullScreenOn goes into full-screen mode.  It makes the toplevel window
- * unmanaged by the window manager and sets its geometry appropriately.
+ * FullScreenOn goes into full-screen mode.  It removes window
+ * manager decoration and sets geometry appropriately.
  *
  * We have toplevel -> form -> viewport -> desktop.  "form" must always be the
  * same size as "toplevel".  "desktop" should always be fixed at the size of
  * the VNC desktop.  Normally "viewport" is the same size as "toplevel" (<=
  * size of "desktop"), and "viewport" deals with any difference by putting up
  * scrollbars.
@@ -82,12 +133,17 @@
 FullScreenOn()
 {
   Dimension toplevelWidth, toplevelHeight;
   Dimension oldViewportWidth, oldViewportHeight, clipWidth, clipHeight;
   Position viewportX, viewportY;
 
+       /*
+       ** Unmap the window so WM will notice changed hints upon remapping
+       */
+       XtUnmapWidget(toplevel);
+
   appData.fullScreen = True;
 
   if (si.framebufferWidth > dpyWidth || si.framebufferHeight > dpyHeight) {
 
     XtVaSetValues(viewport, XtNforceBars, True, NULL);
     XtVaGetValues(viewport, XtNwidth, &oldViewportWidth,
@@ -120,22 +176,13 @@
   }
 
   viewportX = (toplevelWidth - viewportWidth) / 2;
   viewportY = (toplevelHeight - viewportHeight) / 2;
 
 
-  /* We want to stop the window manager from managing our toplevel window.
-     This is not really a nice thing to do, so may not work properly with every
-     window manager.  We do this simply by setting overrideRedirect and
-     reparenting our window to the root.  The window manager will get a
-     ReparentNotify and hopefully clean up its frame window. */
-
-  XtVaSetValues(toplevel, XtNoverrideRedirect, True, NULL);
-
-  XReparentWindow(dpy, XtWindow(toplevel), DefaultRootWindow(dpy), 0, 0);
-
+       mwm_hide_decorations(True);
 
   /* Now we want to fix the size of "viewport".  We shouldn't just change it
      directly.  Instead we set "toplevel" to the required size (which should
      propagate through "form" to "viewport").  Then we remove "viewport" from
      being managed by "form", change its resources to position it and make sure
      that "form" won't attempt to resize it, then ask "form" to manage it
@@ -157,26 +204,30 @@
   XtManageChild(viewport);
 
   /* Now we can set "toplevel" to its proper size. */
 
   XtResizeWidget(toplevel, toplevelWidth, toplevelHeight, 0);
 
+
   /* Set the popup to overrideRedirect too */
 
   XtVaSetValues(popup, XtNoverrideRedirect, True, NULL);
 
-  /* Finally try to get the input focus.  With some WMs we might have to grab
-     the keyboard, but this seems to be OK with the ones I've tried. */
 
-  XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
+       /*
+       ** Remap the window: WM will notice decoration hints
+       */
+       XtMapWidget(toplevel);
+       XSync(dpy, False);
+
 }
 
 
 /*
- * FullScreenOff leaves full-screen mode.  It makes the toplevel window
- * managed by the window manager and sets its geometry appropriately.
+ * FullScreenOff leaves full-screen mode.  It restores window
+ * manager decoration and sets geometry appropriately.
  *
  * We also want to reestablish the link between the geometry of "form" and
  * "viewport".  We do this similarly to the way we broke it in FullScreenOn, by
  * making "viewport" unmanaged, changing certain resources on it and asking
  * "form" to manage it again.
  *
@@ -215,13 +266,16 @@
                XtNtop, XtChainTop,
                XtNbottom, XtChainBottom,
                NULL);
 
   XtManageChild(viewport);
 
-  XtVaSetValues(toplevel, XtNoverrideRedirect, False, NULL);
+       /*
+       ** Restore WM decorations
+       */
+       mwm_hide_decorations(False);
 
   if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth)
     toplevelWidth = dpyWidth - appData.wmDecorationWidth;
 
   if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight)
     toplevelHeight = dpyHeight - appData.wmDecorationHeight;
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: hextile.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: listen.c
diff -Bwru6 -X /home/usrlocal/pd/vnc/Patches/Excludes vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer/misc.c vnc-3.3.3r2-JETpatch/vnc_unixsrc/vncviewer/misc.c
--- vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer/misc.c        1999-08-10 18:52:02.000000000 +0100
+++ vnc-3.3.3r2-JETpatch/vnc_unixsrc/vncviewer/misc.c   2004-01-30 16:40:26.126000000 +0000
@@ -64,14 +64,17 @@
 
   if (appData.fullScreen) {
 
     /* full screen - set position to 0,0, but defer size calculation until
        widgets are realized */
 
-    XtVaSetValues(toplevel, XtNoverrideRedirect, True,
-                 XtNgeometry, "+0+0", NULL);
+       /*
+       ** Start with toplevel unmapped: this gives us a chance to set WM
+       ** decoration hints before mapping the window.
+       */
+       XtSetMappedWhenManaged(toplevel, False);
 
   } else {
 
     /* not full screen - work out geometry for middle of screen unless
        specified by user */
 
@@ -140,12 +143,13 @@
 void
 ToplevelInitAfterRealization()
 {
   if (appData.fullScreen) {
     FullScreenOn();
   }
+       XtMapWidget(toplevel);
 
   wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
   XSetWMProtocols(dpy, XtWindow(toplevel), &wmDeleteWindow, 1);
   XtOverrideTranslations
       (toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()"));
 }
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: popup.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: rfbproto.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: rre.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: selection.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: shm.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: sockets.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: vncviewer.c
Only in vnc-3.3.3r2-FCS/vnc_unixsrc/vncviewer: vncviewer.h


Ooof

-- 

Regards,  Mark.