From xemacs-m  Mon Mar  3 13:48:36 1997
Received: from frege.math.ethz.ch (root@frege-d-math-north-g-west.math.ethz.ch [129.132.145.3])
	by xemacs.org (8.8.5/8.8.5) with SMTP id NAA20651
	for <xemacs-beta@xemacs.org>; Mon, 3 Mar 1997 13:48:03 -0600 (CST)
Received: from fresnel.math.ethz.ch (vroonhof@fresnel [129.132.145.6]) by frege.math.ethz.ch (8.6.12/Main-STAT-mailer) with ESMTP id UAA04979; Mon, 3 Mar 1997 20:47:44 +0100
Received: (vroonhof@localhost) by fresnel.math.ethz.ch (8.6.9/D-MATH-client) id UAA01426; Mon, 3 Mar 1997 20:46:08 +0100
Sender: vroonhof@math.ethz.ch
To: xemacs-beta@xemacs.org, Kyle Jones <kyle_jones@wonderworks.com>,
        steve@miranova.com
Subject: Visibility mega patch [please test]
Mime-Version: 1.0 (generated by tm-edit 7.105)
Content-Type: text/plain; charset=US-ASCII
From: Jan Vroonhof <vroonhof@math.ethz.ch>
Date: 03 Mar 1997 20:46:07 +0100
In-Reply-To: Kyle Jones's message of Mon, 3 Mar 1997 04:20:15 -0500 (EST)
Message-ID: <by67z8ep34.fsf_-_@math.ethz.ch>
Lines: 433
X-Mailer: Gnus v5.4.16/XEmacs 19.15

Kyle Jones <kyle_jones@wonderworks.com> writes:

> Can we just agree that virtual desktops are an abomination before
> the Lord and go back to the old frame visibility model?

No we cannot. Here is a patch (against vanilla 19.15-b96) that

- Optimizes the display for virtual desktops.
- Has no "Attempt to delete the ..." problems
- Changes frame-visible-p to output the new status
- Changes some things in prime/frame.el to reflect the changes.

It works for me. Now it needs some testing under different window
managers. I am not entirely happy with the exact implementation of
frame-visible-p yet. It is incompatible with the FSF version but I
thinks "ours is better" :-). (We were already incompatible, we are now
more incompatible).

I have checked the lisp trees of XEmacs 19.15 and FSF Emacs 19.34
and of the packages that run under XEmacs there are two packages that
need to be checked out by others because I cannot decide what is intended.

  scroll-in-place.el
     uses "(eq (t (frame-visible-p" to search for another window to
     scroll. I think here we should keep the t because you would want
     to scroll a window you can actually see.

  VM.
     I cannot see why vm wants to use totally-visible-p (and actually uses
     frame-visible-p).

Jan

--- src/frame.h.orig	Sun Feb  2 06:07:16 1997
+++ src/frame.h	Mon Mar  3 17:36:15 1997
@@ -112,6 +112,16 @@
 #include "frameslots.h"
 #undef MARKED_SLOT
 
+    /* Nonzero if frame is currently displayed.
+       Mutally exclusive with iconfied
+       JV: This now a tristate flag:
+Value : Emacs meaning                           :f-v-p : X meaning
+0     : not displayed                           : nil  : unmapped
+>0    : user can access it,needs repainting     : t    : mapped and visible
+<0    : user can access it,needs no repainting  : hidden :mapped and invisible
+     where f-v-p is the return value of frame-visible-p */
+  int visible;
+
   /* one-bit flags: */
 
   /* Are we finished initializing? */
@@ -126,9 +136,6 @@
   /* Nonzero if last attempt at redisplay on this frame was preempted.  */
   unsigned int display_preempted :1;
 
-  /* Nonzero if frame is currently displayed.  */
-  unsigned int visible :1;
-
   /* Nonzero if window is currently iconified.
      This and visible are mutually exclusive.  */
   unsigned int iconified :1;
@@ -332,6 +339,7 @@
 #define FRAME_CURSOR_X(f) ((f)->cursor_x)
 #define FRAME_CURSOR_Y(f) ((f)->cursor_y)
 #define FRAME_VISIBLE_P(f) ((f)->visible)
+#define FRAME_REPAINT_P(f) ((f)->visible>0)      
 #define FRAME_NO_SPLIT_P(f) ((f)->no_split)
 #define FRAME_ICONIFIED_P(f) ((f)->iconified)
 #define FRAME_FOCUS_FRAME(f) ((f)->focus_frame)
--- src/redisplay.c.orig	Mon Feb 10 00:52:47 1997
+++ src/redisplay.c	Mon Mar  3 15:45:31 1997
@@ -5254,7 +5254,7 @@
     {
       struct frame *f = XFRAME (XCAR (frmcons));
 
-      if (FRAME_VISIBLE_P (f))
+      if (FRAME_REPAINT_P (f))
 	map_windows (f, reset_buffer_changes_mapfun, 0);
     }
 }
@@ -5459,7 +5459,7 @@
   if (f->icon_changed || f->windows_changed)
     update_frame_icon (f);
 
-  if (FRAME_VISIBLE_P (f))
+  if (FRAME_REPAINT_P (f))
     {
       if (f->buffers_changed || f->clip_changed || f->extents_changed
 	  || f->faces_changed || f->frame_changed || f->menubar_changed
@@ -5493,7 +5493,7 @@
       if (f->icon_changed || f->windows_changed)
 	update_frame_icon (f);
 
-      if (FRAME_VISIBLE_P (f))
+      if (FRAME_REPAINT_P (f))
 	{
 	  if (f->buffers_changed || f->clip_changed || f->extents_changed
 	      || f->faces_changed || f->frame_changed || f->menubar_changed
@@ -7739,7 +7739,7 @@
 	{
 	  struct frame *f = XFRAME (XCAR (frmcons));
 
-	  if (FRAME_VISIBLE_P (f) && FRAME_HAS_MINIBUF_P (f))
+	  if (FRAME_REPAINT_P (f) && FRAME_HAS_MINIBUF_P (f))
 	    {
 	      Lisp_Object window = FRAME_MINIBUF_WINDOW (f);
 	      redisplay_window (window, 0);
--- src/frame.c.orig	Sun Feb 16 02:30:05 1997
+++ src/frame.c	Mon Mar  3 18:53:36 1997
@@ -103,6 +103,8 @@
 
 Lisp_Object Vframe_icon_glyph;
 
+Lisp_Object Qhidden;
+
 Lisp_Object Qvisible, Qiconic, Qinvisible, Qvisible_iconic, Qinvisible_iconic;
 Lisp_Object Qnomini, Qvisible_nomini, Qiconic_nomini, Qinvisible_nomini;
 Lisp_Object Qvisible_iconic_nomini, Qinvisible_iconic_nomini;
@@ -1867,15 +1869,20 @@
 /* FSF returns 'icon for iconized frames.  What a crock! */
 
 DEFUN ("frame-visible-p", Fframe_visible_p, 0, 1, 0, /*
-Return t if FRAME is now \"visible\" (actually in use for display).
+Return non NIL if FRAME is now \"visible\" (actually in use for display).
 A frame that is not visible is not updated, and, if it works through a
 window system, may not show at all.
+N.B. Under X \"visible\" means Mapped. It the window is mapped but not
+actually visible on screen then frame_visible returns 'hidden.
 */
        (frame))
 {
+  int visible;
+  
   struct frame *f = decode_frame (frame);
-  return (FRAMEMETH_OR_GIVEN (f, frame_visible_p, (f), f->visible)
-			      ? Qt : Qnil);
+  visible = FRAMEMETH_OR_GIVEN (f, frame_visible_p, (f), f->visible);
+  return ( visible ? ( visible > 0 ? Qt : Qhidden )
+			     : Qnil);
 }
 
 DEFUN ("frame-totally-visible-p", Fframe_totally_visible_p, 0, 1, 0, /*
@@ -1908,6 +1915,8 @@
 DEFUN ("visible-frame-list", Fvisible_frame_list, 0, 1, 0, /*
 Return a list of all frames now \"visible\" (being updated).
 If DEVICE is specified only frames on that device will be returned.
+Note that under virtual window managers not all these frame are necessarily
+really updated.
 */
        (device))
 {
@@ -1929,7 +1938,7 @@
 	    {
 	      Lisp_Object frame = XCAR (frmcons);
 	      f = XFRAME (frame);
-	      if (f->visible)
+	      if (FRAME_VISIBLE_P(f))
 		value = Fcons (frame, value);
 	    }
 	}
@@ -2836,6 +2845,7 @@
   defsymbol (&Qframe_title_format, "frame-title-format");
   defsymbol (&Qframe_icon_title_format, "frame-icon-title-format");
 
+  defsymbol (&Qhidden, "hidden");
   defsymbol (&Qvisible, "visible");
   defsymbol (&Qiconic, "iconic");
   defsymbol (&Qinvisible, "invisible");
--- src/frame-x.c.orig	Mon Feb 10 00:52:36 1997
+++ src/frame-x.c	Mon Mar  3 18:58:34 1997
@@ -2184,7 +2184,7 @@
   unsigned int flags;
   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
 
-  if (f->visible || force)
+  if (FRAME_VISIBLE_P(f) || force)
     {
       emacs_window = XtWindow (FRAME_X_SHELL_WIDGET (f));
       /* first raises all the dialog boxes, then put emacs just below the 
@@ -2223,7 +2223,7 @@
   XWindowChanges xwc;
   unsigned int flags;
   
-  if (f->visible)
+  if (FRAME_VISIBLE_P(f))
     {
       xwc.stack_mode = Below;
       flags = CWStackMode;
@@ -2239,7 +2239,7 @@
 {
   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
 
-  if (!f->visible)
+  if (!FRAME_VISIBLE_P(f))
     XMapRaised (display, XtWindow (FRAME_X_SHELL_WIDGET (f)));
   else
     x_raise_frame_1 (f, 0);
@@ -2251,7 +2251,7 @@
 {
   Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
 
-  if (!f->visible)
+  if (!FRAME_VISIBLE_P(f))
     return;
 
   if (!XWithdrawWindow (display,
@@ -2267,15 +2267,40 @@
   XWindowAttributes xwa;
   int result;
 
+  /* JV:
+     This is bad, very bad :-(
+     It is not compatible with our tristate visible and
+     it should never ever change the visibility for us, this leads to
+     the frame-freeze problem under fvwm because with the pager
+
+     Mappedness != Viewability != Visibility != Emacs f->visible
+
+     This first unequalness is the reason for the frame freezing problem
+     under fvwm (it happens when the frame is another fvwm-page)
+
+     The second unequalness happen when it is on the same fvwm-page
+     but in an invisible part of the visible screen.
+
+     For now we just return the XEmacs internal value --- which might not be up
+     to date. Is that a problem? ---. Otherwise we should
+     use async visibility like in standard Emacs.
+     */
+
+#if 0
   if (!XGetWindowAttributes (display,
 			     XtWindow (FRAME_X_SHELL_WIDGET (f)),
 			     &xwa))
     result = 0;
   else
     result = xwa.map_state == IsViewable;
+  /* In this implementation it should at least be != IsUnmapped
+     JV */
 
   f->visible = result;
   return result;
+#endif
+  
+  return f->visible;
 }
 
 static int
@@ -2304,6 +2329,7 @@
 {
   XWindowAttributes xwa;
   Widget shell_widget;
+  int viewable;
 
   assert (FRAME_X_P (f));
 
@@ -2327,9 +2353,15 @@
   if (XGetWindowAttributes (XtDisplay (shell_widget),
 			    XtWindow (shell_widget),
 			    &xwa))
-    f->visible = xwa.map_state == IsViewable;
+    /* JV: it is bad to change the visibility like this, so we don't for the
+       moment, at least change_frame_visibility should be called
+       Note also that under fvwm a frame can me Viewable (and thus Mapped)
+       but still X-invisible 
+    f->visible = xwa.map_state == IsViewable; */
+    viewable = xwa.map_state == IsViewable;
+
       
-  if (f->visible)
+  if (viewable)
     {
       Window focus;
       int revert_to;
--- src/event-Xt.c.orig	Sun Mar  2 04:44:21 1997
+++ src/event-Xt.c	Mon Mar  3 16:07:22 1997
@@ -992,7 +992,49 @@
   handle_focus_event_1 (f, event->type == FocusIn);
 }
 
+/* both MapNotify and VisibilityNotify can cause this
+   JV is_visible has the same semantics as f->visible*/
 static void
+change_frame_visibility (struct frame *f, int is_visible)
+{
+  Lisp_Object frame = Qnil;
+
+  XSETFRAME (frame, f);
+
+  if (!FRAME_VISIBLE_P (f) && is_visible)
+    {
+      FRAME_VISIBLE_P (f) = is_visible;
+      /* This improves the double flicker when uniconifying a frame
+	 some.  A lot of it is not showing a buffer which has changed
+	 while the frame was iconified.  To fix it further requires
+	 the good 'ol double redisplay structure. */
+      MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
+      va_run_hook_with_args (Qmap_frame_hook, 1, frame);
+#ifdef EPOCH
+      dispatch_epoch_event (f, event, Qx_map);
+#endif
+    }
+  else if (FRAME_VISIBLE_P (f) && !is_visible) 
+    {
+      FRAME_VISIBLE_P (f) = 0;
+      va_run_hook_with_args (Qunmap_frame_hook, 1, frame);
+#ifdef EPOCH
+      dispatch_epoch_event (f, event, Qx_unmap);
+#endif
+    }
+  else if (FRAME_VISIBLE_P (f) * is_visible < 0)
+    {
+      FRAME_VISIBLE_P(f) = - FRAME_VISIBLE_P(f);
+      if (FRAME_REPAINT_P(f))
+	      MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
+      va_run_hook_with_args (Qmap_frame_hook, 1, frame);
+#ifdef EPOCH
+      dispatch_epoch_event (f, event, Qx_map);
+#endif
+    }
+}
+
+static void
 handle_map_event (struct frame *f, XEvent *event)
 {
   Lisp_Object frame = Qnil;
@@ -1048,34 +1090,14 @@
 	 rather than consulting some internal (and likely
 	 inaccurate) state flag.  Therefore, ignoring the MapNotify
 	 is correct. */
-      if (!f->visible && NILP (Fframe_iconified_p (frame)))
-#endif
-      if (!f->visible)
-	{
-	  f->visible = 1;
-	  /* This improves the double flicker when uniconifying a frame
-	     some.  A lot of it is not showing a buffer which has changed
-	     while the frame was iconified.  To fix it further requires
-	     the good 'ol double redisplay structure. */
-	  MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
-	  va_run_hook_with_args (Qmap_frame_hook, 1, frame);
-#ifdef EPOCH
-	  dispatch_epoch_event (f, event, Qx_map);
+      if (!FRAME_VISIBLE_P (f) && NILP (Fframe_iconified_p (frame)))
 #endif
-	}
+      change_frame_visibility (f, 1);
     }
   else
     {
       FRAME_X_TOTALLY_VISIBLE_P (f) = 0;
-      if (f->visible)
-	{
-	  f->visible = 0;
-	  va_run_hook_with_args (Qunmap_frame_hook, 1, frame);
-#ifdef EPOCH
-	  dispatch_epoch_event (f, event, Qx_unmap);
-#endif
-	}
-
+      change_frame_visibility (f, 0);
       /* Calling Fframe_iconified_p is the only way we have to
          correctly update FRAME_ICONIFIED_P */
       Fframe_iconified_p (frame);
@@ -1221,19 +1243,21 @@
       break;
       
     case VisibilityNotify: /* window visiblity has changed */
-#if 0 /* This causes all kinds of strange behavior I don't like. -sb */
+      if (event->xvisibility.window == XtWindow (FRAME_X_SHELL_WIDGET (f)))
 	{
-	  /* Note that the fvwm pager only sends VisibilityNotify when
-	     changing pages. Is this all we need to do ? JV */
-	  FRAME_VISIBLE_P (f) =
-	    ( event->xvisibility.state != VisibilityFullyObscured);
 	  FRAME_X_TOTALLY_VISIBLE_P (f) =
 	    (event->xvisibility.state == VisibilityUnobscured);
+	  /* Note that the fvwm pager only sends VisibilityNotify when
+	     changing pages. Is this all we need to do ? JV */
+	  /* Nope.  We must at least trigger a redisplay here.  
+             Since this case seems similar to MapNotify, I've 
+             factored out some code to change_frame_visibility(). 
+	     This triggers the necessary redisplay and runs
+	     (un)map-frame-hook.  - dkindred@cs.cmu.edu */
+	  /* Changed it again to support the tristate visibility flag */
+	  change_frame_visibility (f, (event->xvisibility.state
+				       != VisibilityFullyObscured) ? 1 : -1);
 	}
-#else
-        FRAME_X_TOTALLY_VISIBLE_P (f) =
-	  (event->xvisibility.state == VisibilityUnobscured);
-#endif
       break;
       
     case ConfigureNotify:
--- lisp/prim/frame.el.orig	Sun Feb 16 02:29:24 1997
+++ lisp/prim/frame.el	Mon Mar  3 19:37:34 1997
@@ -848,6 +848,7 @@
 	;; Sort the list so that iconic frames will be found last.  They
 	;; will be used too, but mapped frames take precedence.  And
 	;; fully visible frames come before occluded frames.
+        ;; Hidden frames come after really visible ones
 	(setq frames
 	      (sort (frame-list)
 		    #'(lambda (s1 s2)
@@ -855,6 +856,8 @@
 			       nil)
 			      ((not (frame-visible-p s2))
 			       (frame-visible-p s1))
+			      ((eq (frame-visible-p s2) 'hidden)
+			       (eq (frame-visible-p s1) t ))
 			      ((not (frame-totally-visible-p s2))
 			       (and (frame-visible-p s1)
 				    (frame-totally-visible-p s1)))))))
@@ -902,6 +905,8 @@
 		    #'(lambda (s1 s2)
 			(cond ((and (frame-visible-p s1)
 				    (not (frame-visible-p s2))))
+			      ((and (eq (frame-visible-p s1) t)
+				    (eq (frame-visible-p s2) 'hidden)))
 			      ((and (frame-visible-p s2)
 				    (not (frame-visible-p s1)))
 			       nil)
@@ -1002,7 +1007,7 @@
 	    (setq save-frame next-frame)
 	  (and 
 	   (or (not visible-only)
-	       (eq t (frame-visible-p next-frame)))
+	       (frame-visible-p next-frame))
 	   (setq frames (append frames (list next-frame))))))
 	(setq list (cdr list)))
 

