Subject: bug#15398: 24.3; Frame redraw completely screwed

From: Dmitry Antipov <[email-masked]>
Date: Fri, 20 Sep 2013 12:00:46 +0400

On 09/20/2013 10:47 AM, Jan Djärv wrote:

> 20 sep 2013 kl. 05:41 skrev Dmitry Antipov <[email-masked]>:
>
>> On 09/19/2013 08:41 PM, Jan Djärv wrote:
>>
>>> I don't recall all the details, but I think the comment actually means "for GTK 2.6 and newer".
>>
>> Ugh. Reverted in r114402 (for visible frames; in general, I think
>> that it is possible to handle Expose events a bit more intelligently).
>
> Not as long as we do pure X-calls on Gtk-widgets.

Yes, mixing Xlib and Gtk is ugly. But I would like to get your comments on this first
(also I'm looking for brave testers).

Dmitry

=== modified file 'src/frame.h'
--- src/frame.h	2013-09-17 12:59:45 +0000
+++ src/frame.h	2013-09-20 07:39:22 +0000
@@ -395,6 +395,12 @@
      selected window on this frame have frozen window starts.  */
   unsigned frozen_window_starts : 1;
 
+#ifdef USE_GTK
+  /* If menu or tooltip window disappeared, this is set to number
+     of Expose events we should handle with call to x_clear_area.  */
+  unsigned gtk_clear_expose;
+#endif
+
   /* Nonzero if we should actually display the scroll bars on this frame.  */
   enum vertical_scroll_bar_type vertical_scroll_bar_type;

=== modified file 'src/xterm.c'
--- src/xterm.c	2013-09-20 03:30:50 +0000
+++ src/xterm.c	2013-09-20 07:53:19 +0000
@@ -5788,6 +5788,33 @@
 
   return GDK_FILTER_CONTINUE;
 }
+
+/* Find the frame which has the same root X window as W.  */
+
+static struct frame *
+x_frame_root_match (struct x_display_info *dpyinfo, Window w)
+{
+  XWindowAttributes xww, xwf;
+
+  if (XGetWindowAttributes (dpyinfo->display, w, &xww))
+    {
+      Lisp_Object tail, frame;
+
+      FOR_EACH_FRAME (tail, frame)
+	{
+	  struct frame *f = XFRAME (frame);
+
+	  if (FRAME_X_P (f) && FRAME_X_OUTPUT (f)
+	      && FRAME_DISPLAY_INFO (f) == dpyinfo
+	      && XGetWindowAttributes (dpyinfo->display,
+		   FRAME_X_OUTPUT (f)->window_desc, &xwf))
+	    if (xww.root == xwf.root)
+	      return f;
+	}
+    }
+  return NULL;
+}
+
 #endif /* USE_GTK */

@@ -6111,12 +6138,23 @@
           else
 	    {
 #ifdef USE_GTK
-	      /* This seems to be needed for GTK 2.6 and later, see
-		 http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398.  */
-	      x_clear_area (event->xexpose.display,
-			    event->xexpose.window,
-			    event->xexpose.x, event->xexpose.y,
-			    event->xexpose.width, event->xexpose.height);
+	      /* This is an attempt to call x_clear_area only if needed,
+		 see http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398.  */
+
+	      if (f->gtk_clear_expose == 1)
+		/* Collection of Expose events was requested, do that.  */
+		f->gtk_clear_expose += event->xexpose.count;
+
+	      /* Next, handle all collected Expose events
+		 with an extra call to x_clear_area.  */
+	      if (f->gtk_clear_expose > 0)
+		{
+		  x_clear_area (event->xexpose.display,
+				event->xexpose.window,
+				event->xexpose.x, event->xexpose.y,
+				event->xexpose.width, event->xexpose.height);
+		  f->gtk_clear_expose--;
+		}
 #endif
 	      expose_frame (f, event->xexpose.x, event->xexpose.y,
 			    event->xexpose.width, event->xexpose.height);
@@ -6205,6 +6243,16 @@
               XSETFRAME (inev.ie.frame_or_window, f);
             }
         }
+#ifdef USE_GTK
+      else
+	{
+	  f = x_frame_root_match (dpyinfo, event->xunmap.window);
+	  if (f)
+	    /* Menu or tooltip window on F has disappeared.
+	       Request collecting Expose events on this frame.  */
+	    f->gtk_clear_expose = 1;
+	}
+#endif
       goto OTHER;
 
     case MapNotify: