From: Martin Rudalics <rudalics@gmx.at>
Date: Mon, 10 Mar 2025 08:33:17 +0000 (+0100)
Subject: Fix handling of frame position values
X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=2dbdd8a9a2dfa4a9c2b3466cb97651fd3cce944f;p=emacs.git

Fix handling of frame position values

* src/frame.c (tty_child_pos_param): Handle additional position
values.  New SIZE argument.
(tty_child_frame_rect): Process size before position.
(Fmake_terminal_frame): Do not store calculated size/position
values in parameters to avoid that a negative absolute position
is later interpreted as position relative to bottom/right edge
of parent.
(Fmodify_frame_parameters): For tty child frames process size
before position values so the latter can take a new size into
account.
* src/frame.h: Adjust declaration of tty_child_pos_param.
* src/gtkutil.c (xg_set_geometry): Handle negative frame
position specifications.
* src/msdos.c (IT_set_frame_parameters): For tty child frames
process size before position parameters.
* src/xfns.c (x_window): In the non-GTK toolkit variant leave
negative position values unchanged - the toolkit should know how
to handle them.  Process child frame position parameters
separately.  In the non-toolkit variant process child frame
parameters separately.

(cherry picked from commit cbad6215cf4fef826fa9c3600765a7c696872eaf)
---

diff --git a/src/frame.c b/src/frame.c
index 55f5a02c8d5..b3a92ce463b 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1489,17 +1489,43 @@ get_future_frame_param (Lisp_Object parameter,
 #endif
 
 int
-tty_child_pos_param (struct frame *child, Lisp_Object key,
-		     Lisp_Object params, int dflt)
+tty_child_pos_param (struct frame *f, Lisp_Object key,
+		     Lisp_Object params, int pos, int size)
 {
+  struct frame *p = XFRAME (f->parent_frame);
   Lisp_Object val = Fassq (key, params);
+
   if (CONSP (val))
     {
       val = XCDR (val);
-      if (FIXNUMP (val))
-	return XFIXNUM (val);
+
+      if (EQ (val, Qminus))
+	pos = (EQ (key, Qtop)
+	       ? p->pixel_height - size
+	       : p->pixel_width - size);
+      else if (TYPE_RANGED_FIXNUMP (int, val))
+	{
+	  pos = XFIXNUM (val);
+
+	  if (pos < 0)
+	    /* Handle negative value. */
+	    pos = (EQ (key, Qtop)
+		   ? p->pixel_height - size + pos
+		   : p->pixel_width - size + pos);
+	}
+      else if (CONSP (val) && EQ (XCAR (val), Qplus)
+	       && CONSP (XCDR (val))
+	       && TYPE_RANGED_FIXNUMP (int, XCAR (XCDR (val))))
+	pos = XFIXNUM (XCAR (XCDR (val)));
+      else if (CONSP (val) && EQ (XCAR (val), Qminus)
+	       && CONSP (XCDR (val))
+	       && RANGED_FIXNUMP (-INT_MAX, XCAR (XCDR (val)), INT_MAX))
+	pos = (EQ (key, Qtop)
+	       ? p->pixel_height - size - XFIXNUM (XCAR (XCDR (val)))
+	       : p->pixel_width - size - XFIXNUM (XCAR (XCDR (val))));
     }
-  return dflt;
+
+  return pos;
 }
 
 int
@@ -1546,10 +1572,10 @@ static void
 tty_child_frame_rect (struct frame *f, Lisp_Object params,
 		      int *x, int *y, int *w, int *h)
 {
-  *x = tty_child_pos_param (f, Qleft, params, 0);
-  *y = tty_child_pos_param (f, Qtop, params, 0);
   *w = tty_child_size_param (f, Qwidth, params, FRAME_TOTAL_COLS (f));
   *h = tty_child_size_param (f, Qheight, params, FRAME_TOTAL_LINES (f));
+  *x = tty_child_pos_param (f, Qleft, params, 0, *w);
+  *y = tty_child_pos_param (f, Qtop, params, 0, *h);
 }
 
 #endif /* !HAVE_ANDROID */
@@ -1688,10 +1714,6 @@ affects all frames on the same terminal device.  */)
 
   f->left_pos = x;
   f->top_pos = y;
-  store_in_alist (&parms, Qleft, make_fixnum (x));
-  store_in_alist (&parms, Qtop, make_fixnum (y));
-  store_in_alist (&parms, Qwidth, make_fixnum (width));
-  store_in_alist (&parms, Qheight, make_fixnum (height));
 
   store_in_alist (&parms, Qtty_type, build_string (t->display_info.tty->type));
   store_in_alist (&parms, Qtty,
@@ -3951,8 +3973,11 @@ list, but are otherwise ignored.  */)
 
       if (is_tty_child_frame (f))
 	{
-	  int x = tty_child_pos_param (f, Qleft, params, f->left_pos);
-	  int y = tty_child_pos_param (f, Qtop, params, f->top_pos);
+	  int w = tty_child_size_param (f, Qwidth, params, f->total_cols);
+	  int h = tty_child_size_param (f, Qheight, params, f->total_lines);
+	  int x = tty_child_pos_param (f, Qleft, params, f->left_pos, w);
+	  int y = tty_child_pos_param (f, Qtop, params, f->top_pos, h);
+
 	  if (x != f->left_pos || y != f->top_pos)
 	    {
 	      f->left_pos = x;
@@ -3960,8 +3985,6 @@ list, but are otherwise ignored.  */)
 	      SET_FRAME_GARBAGED (root_frame (f));
 	    }
 
-	  int w = tty_child_size_param (f, Qwidth, params, f->total_cols);
-	  int h = tty_child_size_param (f, Qheight, params, f->total_lines);
 	  if (w != f->total_cols || h != f->total_lines)
 	    change_frame_size (f, w, h, false, false, false);
 
diff --git a/src/frame.h b/src/frame.h
index c9cc65e597d..a70d9caf5df 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -1461,7 +1461,7 @@ extern struct frame *make_initial_frame (void);
 extern struct frame *make_frame (bool);
 extern bool frame_redisplay_p (struct frame *);
 extern int tty_child_pos_param (struct frame *, Lisp_Object,
-				Lisp_Object, int);
+				Lisp_Object, int, int);
 extern int tty_child_size_param (struct frame *, Lisp_Object,
 				 Lisp_Object, int);
 #ifdef HAVE_WINDOW_SYSTEM
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 0770874eb40..c192102730c 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1070,19 +1070,27 @@ xg_set_geometry (struct frame *f)
 	     be off by scrollbar width + window manager decorations.  */
 #ifndef HAVE_PGTK
 	  if (f->size_hint_flags & XNegative)
-	    f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
+	    f->left_pos = ((FRAME_PARENT_FRAME (f)
+			    ? FRAME_PIXEL_WIDTH (FRAME_PARENT_FRAME (f))
+			    : 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))
+	    f->top_pos = ((FRAME_PARENT_FRAME (f)
+			   ? FRAME_PIXEL_HEIGHT (FRAME_PARENT_FRAME (f))
+			   : x_display_pixel_height (FRAME_DISPLAY_INFO (f)))
 			  - FRAME_PIXEL_HEIGHT (f) + f->top_pos);
 #else
 	  if (f->size_hint_flags & XNegative)
-	    f->left_pos = (pgtk_display_pixel_width (FRAME_DISPLAY_INFO (f))
+	    f->left_pos = ((FRAME_PARENT_FRAME (f)
+			    ? FRAME_PIXEL_WIDTH (FRAME_PARENT_FRAME (f))
+			    : pgtk_display_pixel_width (FRAME_DISPLAY_INFO (f)))
 			   - FRAME_PIXEL_WIDTH (f) + f->left_pos);
 
 	  if (f->size_hint_flags & YNegative)
-	    f->top_pos = (pgtk_display_pixel_height (FRAME_DISPLAY_INFO (f))
+	    f->top_pos = ((FRAME_PARENT_FRAME (f)
+			   ? FRAME_PIXEL_HEIGHT (FRAME_PARENT_FRAME (f))
+			   : pgtk_display_pixel_height (FRAME_DISPLAY_INFO (f)))
 			  - FRAME_PIXEL_HEIGHT (f) + f->top_pos);
 #endif
 
diff --git a/src/msdos.c b/src/msdos.c
index 49403ba72f4..ec36d0b2df3 100644
--- a/src/msdos.c
+++ b/src/msdos.c
@@ -1715,8 +1715,13 @@ IT_set_frame_parameters (struct frame *f, Lisp_Object alist)
      a nuumber of other flags.  */
   if (is_tty_child_frame (f))
     {
-      int x = tty_child_pos_param (f, Qleft, alist, f->left_pos);
-      int y = tty_child_pos_param (f, Qtop, alist, f->top_pos);
+      int w = tty_child_size_param (f, Qwidth, alist, f->total_cols);
+      int h = tty_child_size_param (f, Qheight, alist, f->total_lines);
+      if (w != f->total_cols || h != f->total_lines)
+	change_frame_size (f, w, h, false, false, false);
+
+      int x = tty_child_pos_param (f, Qleft, alist, f->left_pos, w);
+      int y = tty_child_pos_param (f, Qtop, alist, f->top_pos, h);
       if (x != f->left_pos || y != f->top_pos)
 	{
 	  f->left_pos = x;
@@ -1724,11 +1729,6 @@ IT_set_frame_parameters (struct frame *f, Lisp_Object alist)
 	  SET_FRAME_GARBAGED (root_frame (f));
 	}
 
-      int w = tty_child_size_param (f, Qwidth, alist, f->total_cols);
-      int h = tty_child_size_param (f, Qheight, alist, f->total_lines);
-      if (w != f->total_cols || h != f->total_lines)
-	change_frame_size (f, w, h, false, false, false);
-
       Lisp_Object visible = Fassq (Qvisibility, alist);
       if (CONSP (visible))
 	SET_FRAME_VISIBLE (f, !NILP (Fcdr (visible)));
diff --git a/src/xfns.c b/src/xfns.c
index d8a3ce0b3b1..67b15428bf0 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4251,37 +4251,42 @@ x_window (struct frame *f, long window_prompting)
        Note that we do not specify here whether the position
        is a user-specified or program-specified one.
        We pass that information later, in x_wm_set_size_hint.  */
-    {
-      int left = f->left_pos;
-      bool xneg = (window_prompting & XNegative) != 0;
-      int top = f->top_pos;
-      bool yneg = (window_prompting & YNegative) != 0;
-      if (xneg)
-	left = -left;
-      if (yneg)
-	top = -top;
-
-      if (window_prompting & USPosition)
-	sprintf (f->shell_position, "=%dx%d%c%d%c%d",
+    bool xneg = (window_prompting & XNegative) != 0;
+    bool yneg = (window_prompting & YNegative) != 0;
+
+    if (FRAME_PARENT_FRAME (f))
+      {
+	if (window_prompting & XNegative)
+	  f->left_pos = (FRAME_PIXEL_WIDTH (FRAME_PARENT_FRAME (f))
+			 - FRAME_PIXEL_WIDTH (f) + f->left_pos);
+
+	if (window_prompting & YNegative)
+	  f->top_pos = (FRAME_PIXEL_HEIGHT (FRAME_PARENT_FRAME (f))
+			- FRAME_PIXEL_HEIGHT (f) + f->top_pos);
+
+	window_prompting &= ~ (XNegative | YNegative);
+      }
+
+    if (window_prompting & USPosition)
+      sprintf (f->shell_position, "=%dx%d%c%d%c%d",
+	       FRAME_PIXEL_WIDTH (f) + extra_borders,
+	       FRAME_PIXEL_HEIGHT (f) + menubar_size + extra_borders,
+	       (xneg ? '-' : '+'), f->left_pos,
+	       (yneg ? '-' : '+'), f->top_pos);
+    else
+      {
+	sprintf (f->shell_position, "=%dx%d",
 		 FRAME_PIXEL_WIDTH (f) + extra_borders,
-		 FRAME_PIXEL_HEIGHT (f) + menubar_size + extra_borders,
-		 (xneg ? '-' : '+'), left,
-		 (yneg ? '-' : '+'), top);
-      else
-        {
-          sprintf (f->shell_position, "=%dx%d",
-                   FRAME_PIXEL_WIDTH (f) + extra_borders,
-                   FRAME_PIXEL_HEIGHT (f) + menubar_size + extra_borders);
-
-          /* Setting x and y when the position is not specified in
-             the geometry string will set program position in the WM hints.
-             If Emacs had just one program position, we could set it in
-             fallback resources, but since each make-frame call can specify
-             different program positions, this is easier.  */
-          XtSetArg (gal[gac], XtNx, left); gac++;
-          XtSetArg (gal[gac], XtNy, top); gac++;
-        }
-    }
+		 FRAME_PIXEL_HEIGHT (f) + menubar_size + extra_borders);
+
+	/* Setting x and y when the position is not specified in
+	   the geometry string will set program position in the WM hints.
+	   If Emacs had just one program position, we could set it in
+	   fallback resources, but since each make-frame call can specify
+	   different program positions, this is easier.  */
+	XtSetArg (gal[gac], XtNx, f->left_pos); gac++;
+	XtSetArg (gal[gac], XtNy, f->top_pos); gac++;
+      }
 
     XtSetArg (gal[gac], XtNgeometry, f->shell_position); gac++;
     XtSetValues (shell_widget, gal, gac);
@@ -4460,6 +4465,19 @@ x_window (struct frame *f)
   attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
 		    | CWOverrideRedirect | CWColormap);
 
+  if (FRAME_PARENT_FRAME (f))
+    {
+      if (f->size_hint_flags & XNegative)
+	f->left_pos = (FRAME_PIXEL_WIDTH (FRAME_PARENT_FRAME (f))
+		       - FRAME_PIXEL_WIDTH (f) + f->left_pos);
+
+      if (f->size_hint_flags & YNegative)
+	f->top_pos = (FRAME_PIXEL_HEIGHT (FRAME_PARENT_FRAME (f))
+		      - FRAME_PIXEL_HEIGHT (f) + f->top_pos);
+
+      f->size_hint_flags &= ~ (XNegative | YNegative);
+    }
+
   block_input ();
   FRAME_X_WINDOW (f)
     = XCreateWindow (FRAME_X_DISPLAY (f),