Subject: bug#25851: 25.2; GTK warning when starting Emacs when desktop file has more than one frame

From: martin rudalics <[email-masked]>
Date: Sat, 25 Mar 2017 10:25:36 +0100

> Sorry for the delay. I haven't used master for a while and it doesn't
 > like my init file. I've been spending my time on troubleshooting
 > that. But now I have things mostly up and running.
 >
 > 1. I am currently running master from earlier today which includes
 > your patch from the 23rd (commit
 > fe3af8d4f2a4cd67958f76d1b708e8a78e68cd4f) which I assume is the
 > one you want me to test?

Yes.  I attach it so you can (hopefully) apply it to your Emacs 25
instead of ...

 > 2. I have not applied your proposed definition of
 > `xg_set_geometry' from Message #122
 > (https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25851#122). [But I
 > still have that in my 25.2 rc2 Emacs, which is currently my
 > everyday Emacs.]

... this and test it in your everyday work.

 > 3. I have put
 >
 >    (setq x-gtk-use-window-move t)
 >
 > in the working part of my init file [the rest of my init file --
 > about 10% of it -- is commented out right now].
 >
 > 4. In my desktop file I have three frames specified each with
 > a distinctive size and position.
 >
 > The result is that:
 >
 > - Frames are successfully restored to their former size and
 > position.
 >
 > - No GTK warning messages are being emitted.

OK.

 > However:
 >
 > - When I switch between frames using the window manager Alt-tab
 > window switching, there is a big flash almost every time when an
 > Emacs frame is displayed. I've never seen this problem before.
 > (Occasionally I've seen a single line of the display flicker while
 > scrolling, but I've never seen Emacs make the whole screen flash
 > like this before.)
 >
 > [The flash is too fast to describe other than to say it is light
 > in colour and appears to be horizontal, almost as if there is a
 > white or grey highlight being applied randomly to about half the
 > lines in the frame and then turned off again.]
 >
 > [This was after I'd maximized the three frames so that I could use
 > them, rather than when they were the smaller size at which they
 > were specified in the desktop file I tested with. I tried
 > restoring them down to their previous size and didn't see the
 > flash, then maximised them again and the flashing was back. I
 > suppose that the flashing might also be happening when they're
 > small but that my eye isn't fast enough to detect it; not sure.]
 >
 > Of course this flashing might be unrelated, it might be due to a
 > change elsewhere in master.

I'm sure that Eli's suggestion is correct, so please inhibit double
buffering in your init file.

 > The display antics at startup are slightly different but still
 > there. The sequence seems to be (with three frames in my desktop
 > file with distinctive sizes and positions):
 >
 > a) A largish light-colour-scheme frame is displayed.
 >
 > b) It shrinks but is still a light colour scheme. (Presumably my
 > default font is applied here.)
 >
 > c) It changes to a dark colour scheme. (Presumably my colour
 > scheme is being applied here.)

I don't know what a colour scheme is.  Please send me yours and I'll try
adding it to my .emacs to see which behavior it causes.

BTW I never thought about possible mergings of `initial-frame-alist' or
`default-frame-alist' and the parameter alists applied by desktop.

 > d) It sits there for a bit with the various startup messages
 > appearing in the echo area.
 >
 > e) It disappears and the three frames in my init file appear.
 > (Alternative explanation: It changes its size and position to that
 > of one of the frames in my init file, and the other two frames
 > from my init file are displayed.)

I suppose you mean "desktop" instead of "init" file here?

 > These antics are different from with Emacs 25 where I never see a
 > light-colour-scheme frame unless I start with `-Q'.

To get one aspect right: Do you see the light-colour-scheme frame also
when you don't restore the desktop - with one or three initial frames?
(And what else does master dislike about your init file?)

martin
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 3a00e36..63f0143 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -783,33 +783,55 @@ struct xg_frame_tb_info
 {
   if (f->size_hint_flags & (USPosition | PPosition))
     {
-      int left = f->left_pos;
-      int xneg = f->size_hint_flags & XNegative;
-      int top = f->top_pos;
-      int yneg = f->size_hint_flags & YNegative;
-      char geom_str[sizeof "=x--" + 4 * INT_STRLEN_BOUND (int)];
-      guint id;
-
-      if (xneg)
-        left = -left;
-      if (yneg)
-        top = -top;
-
-      sprintf (geom_str, "=%dx%d%c%d%c%d",
-               FRAME_PIXEL_WIDTH (f),
-               FRAME_PIXEL_HEIGHT (f),
-               (xneg ? '-' : '+'), left,
-               (yneg ? '-' : '+'), top);
-
-      /* Silence warning about visible children.  */
-      id = g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
-                              | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
-
-      if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-                                      geom_str))
-        fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
-
-      g_log_remove_handler ("Gtk", id);
+      if (x_gtk_use_window_move)
+	{
+	  /* Handle negative positions without consulting
+	     gtk_window_parse_geometry (Bug#25851).  The position will
+	     be off by scrollbar width + window manager decorations.  */
+	  if (f->size_hint_flags & XNegative)
+	    f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
+			   - FRAME_PIXEL_WIDTH (f) + f->left_pos);
+
+	  if (f->size_hint_flags & YNegative)
+	    f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
+			  - FRAME_PIXEL_HEIGHT (f) + f->top_pos);
+
+	  gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+			   f->left_pos, f->top_pos);
+
+	  /* Reset size hint flags.  */
+	  f->size_hint_flags &= ~ (XNegative | YNegative);
+	}
+      else
+	{
+	  int left = f->left_pos;
+	  int xneg = f->size_hint_flags & XNegative;
+	  int top = f->top_pos;
+	  int yneg = f->size_hint_flags & YNegative;
+	  char geom_str[sizeof "=x--" + 4 * INT_STRLEN_BOUND (int)];
+	  guint id;
+
+	  if (xneg)
+	    left = -left;
+	  if (yneg)
+	    top = -top;
+
+	  sprintf (geom_str, "=%dx%d%c%d%c%d",
+		   FRAME_PIXEL_WIDTH (f),
+		   FRAME_PIXEL_HEIGHT (f),
+		   (xneg ? '-' : '+'), left,
+		   (yneg ? '-' : '+'), top);
+
+	  /* Silence warning about visible children.  */
+	  id = g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
+				  | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
+
+	  if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+					  geom_str))
+	    fprintf (stderr, "Failed to parse: '%s'\n", geom_str);
+
+	  g_log_remove_handler ("Gtk", id);
+	}
     }
 }
 
@@ -1406,6 +1428,13 @@ struct xg_frame_tb_info
   else if (win_gravity == StaticGravity)
     size_hints.win_gravity = GDK_GRAVITY_STATIC;
 
+  if (x_gtk_use_window_move)
+    {
+      if (flags & PPosition) hint_flags |= GDK_HINT_POS;
+      if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS;
+      if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE;
+    }
+
   if (user_position)
     {
       hint_flags &= ~GDK_HINT_POS;
diff --git a/src/xterm.c b/src/xterm.c
index 7856793..4f9eff6 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10056,11 +10056,26 @@ struct x_error_message_stack {
 	f->size_hint_flags |= YNegative;
       f->win_gravity = NorthWestGravity;
     }
+
   x_calc_absolute_position (f);
 
   block_input ();
   x_wm_set_size_hint (f, 0, false);
 
+#ifdef USE_GTK
+  if (x_gtk_use_window_move)
+    {
+      /* When a position change was requested and the outer GTK widget
+	 has been realized already, leave it to gtk_window_move to DTRT
+	 and return.  Used for Bug#25851 and Bug#25943.  */
+      if (change_gravity != 0 && FRAME_GTK_OUTER_WIDGET (f))
+	gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+			 f->left_pos, f->top_pos);
+      unblock_input ();
+      return;
+    }
+#endif /* USE_GTK */
+
   modified_left = f->left_pos;
   modified_top = f->top_pos;
 
@@ -12905,4 +12920,11 @@ click on a frame to select it (give it focus).  In that case, a value
 Set this variable only if your window manager cannot handle the
 transition between the various maximization states.  */);
   x_frame_normalize_before_maximize = false;
+
+  DEFVAR_BOOL ("x-gtk-use-window-move", x_gtk_use_window_move,
+    doc: /* Non-nil means rely on gtk_window_move to set frame positions.
+If this variable is t, the GTK build uses the function gtk_window_move
+to set or store frame positions and disables some time consuming frame
+position adjustments.  */);
+  x_gtk_use_window_move = false;
 }