aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Rudalics2025-12-22 11:01:53 +0100
committerMartin Rudalics2025-12-22 11:01:53 +0100
commitf3d9371a890699fe4047f693adfcd4d8dbe2fb7d (patch)
treed37fd603addf836483df8ebcf78c53cd0407d991
parent5cf8af22900d359c18a75d9efed44f7c1d8fc06c (diff)
downloademacs-f3d9371a890699fe4047f693adfcd4d8dbe2fb7d.tar.gz
emacs-f3d9371a890699fe4047f693adfcd4d8dbe2fb7d.zip
Add functions to set frame size and position in one compound step
* lisp/frame.el (set-frame-size-and-position): New function. * src/frame.c (adjust_frame_size): Handle requests to set size and position. (Fset_frame_size_and_position_pixelwise): New function. * src/gtkutil.c (xg_frame_set_size_and_position): New function. (xg_wm_set_size_hint): Handle any non-NorthWestGravity values for child frames only. Some GTK implementations don't like them. * src/gtkutil.h (xg_frame_set_size_and_position.): Add external declaration. * src/termhooks.h (set_window_size_and_position_hook): New hook. * src/w32term.c (w32_set_window_size_and_position): New function. (w32_create_terminal): Make it the Microsoft Windows API set_window_size_and_position_hook. * src/xterm.c (x_set_window_size_and_position_1) (x_set_window_size_and_position): New functions. (x_create_terminal): Make x_set_window_size_and_position the set_window_size_and_position_hook for the X protocol. * src/xterm.h (x_set_window_size_and_position): Add external declaration. * etc/NEWS: Announce new functions.
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/frame.el194
-rw-r--r--src/frame.c77
-rw-r--r--src/gtkutil.c108
-rw-r--r--src/gtkutil.h2
-rw-r--r--src/termhooks.h5
-rw-r--r--src/w32term.c80
-rw-r--r--src/xterm.c54
-rw-r--r--src/xterm.h1
9 files changed, 505 insertions, 23 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 6777d6c3b5e..f1b2225100d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -465,6 +465,13 @@ either resize the frame and change the fullscreen status accordingly or
465keep the frame size unchanged. The value t means to first reset the 465keep the frame size unchanged. The value t means to first reset the
466fullscreen status and then resize the frame. 466fullscreen status and then resize the frame.
467 467
468*** New commands to set frame size and position in one compound step.
469'set-frame-size-and-position' sets the new size and position of a frame
470in one compound step. Both, size and position, can be specified as with
471the corresponding frame parameters 'width', 'height', 'left' and 'top'.
472'set-frame-size-and-position-pixelwise' is similar but has a more
473restricted set of values for specifying size and position.
474
468*** New commands 'split-frame' and 'merge-frames'. 475*** New commands 'split-frame' and 'merge-frames'.
469'split-frame' moves a specified number of windows from an existing frame 476'split-frame' moves a specified number of windows from an existing frame
470to a newly-created frame. 'merge-frames' merges all windows from two 477to a newly-created frame. 'merge-frames' merges all windows from two
diff --git a/lisp/frame.el b/lisp/frame.el
index 307312ef71a..d521d49c175 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -1535,6 +1535,200 @@ Functions on this hook are called with the theme name as a symbol:
1535already be set to one of these values as well.") 1535already be set to one of these values as well.")
1536 1536
1537 1537
1538(defun set-frame-size-and-position (&optional frame width height left top)
1539 "Set size and position of specified FRAME in one compound step.
1540WIDTH and HEIGHT stand for the new width and height of FRAME. They can
1541be specified as follows where \"display area\" stands for the entire
1542display area of FRAME's dominating monitor, \"work area\" stands for the
1543work area (the usable space) of FRAME's display area and \"parent area\"
1544stands for the area occupied by the native rectangle of FRAME's parent
1545provided FRAME is a child frame.
1546
1547- An integer specifies the size of FRAME's text area in characters.
1548
1549- A cons cell with the symbol `text-pixels' in its car specifies in its
1550 cdr the size of FRAME's text area in pixels.
1551
1552- A floating-point number between 0.0 and 1.0 specifies the ratio of
1553 FRAME's outer size to the size of its work or parent area.
1554
1555Unless you use a plain integer value, you may have to set
1556`frame-resize-pixelwise' to a non-nil value in order to get the exact
1557size in pixels. A value of nil means to leave the width or height
1558unaltered. Any other value will signal an error.
1559
1560LEFT and TOP stand for FRAME's outer position relative to coordinates of
1561its display, work or parent area. They can be specified as follows:
1562
1563- An integer where a positive value relates the left or top edge of
1564 FRAME to the origin of its display or parent area. A negative value
1565 relates the right or bottom edge of FRAME to the right or bottom edge
1566 of its display or parent area.
1567
1568- The symbol `-' means to place the right or bottom edge of FRAME at the
1569 right or bottom edge of its display or parent area.
1570
1571- A list with `+' as its first and an integer as its second element
1572 specifies the position of the left or top edge of FRAME relative to
1573 the left or top edge of its display or parent area. If the second
1574 element is negative, this means a position outside FRAME's display or
1575 parent area.
1576
1577- A list with `-' as its first and an integer as its second element
1578 specifies the position of the right or bottom edge of FRAME relative
1579 to the right or bottom edge of its display or parent area. If the
1580 second element is negative, this means a position outside the area of
1581 its display or parent area.
1582
1583- A floating-point number between 0.0 and 1.0 specifies the ratio of
1584 FRAME's outer position to the size of its work or parent area. Thus,
1585 a value of 0.0 flushes FRAME to the left or top, a value of 0.5
1586 centers it and a ratio of 1.0 flushes it to the right or bottom of its
1587 work or parent area.
1588
1589Calculating a position relative to the right or bottom edge of FRAME's
1590display, work or parent area proceeds by calculating the new size of
1591FRAME first and then relate the new prospective outer edges of FRAME to
1592the respective edges of its display, work or parent area.
1593
1594A value of nil means to leave the position in this direction unchanged.
1595Any other value will signal an error.
1596
1597This function calls `set-frame-size-and-position-pixelwise' to actually
1598resize and move FRAME."
1599 (let* ((frame (window-normalize-frame frame))
1600 (parent (frame-parent frame))
1601 (monitor-attributes
1602 (unless parent
1603 (frame-monitor-attributes frame)))
1604 (geometry
1605 (unless parent
1606 (cdr (assq 'geometry monitor-attributes))))
1607 (parent-or-display-width
1608 (if parent
1609 (frame-native-width parent)
1610 (nth 2 geometry)))
1611 (parent-or-display-height
1612 (if parent
1613 (frame-native-height parent)
1614 (nth 3 geometry)))
1615 (parent-or-workarea
1616 (if parent
1617 `(0 0 ,parent-or-display-width ,parent-or-display-height)
1618 (cdr (assq 'workarea monitor-attributes))))
1619 (outer-edges (frame-edges frame 'outer-edges))
1620 (outer-left (nth 0 outer-edges))
1621 (outer-top (nth 1 outer-edges))
1622 (outer-width (if outer-edges
1623 (- (nth 2 outer-edges) outer-left)
1624 (frame-pixel-width frame)))
1625 (outer-minus-text-width
1626 (- outer-width (frame-text-width frame)))
1627 (outer-height (if outer-edges
1628 (- (nth 3 outer-edges) outer-top)
1629 (frame-pixel-height frame)))
1630 (outer-minus-text-height
1631 (- outer-height (frame-text-height frame)))
1632 (old-text-width (frame-text-width frame))
1633 (old-text-height (frame-text-height frame))
1634 (text-width old-text-width)
1635 (text-height old-text-height)
1636 (char-width (frame-char-width frame))
1637 (char-height (frame-char-height frame))
1638 (gravity 1)
1639 negative)
1640
1641 (cond
1642 ((and (integerp width) (> width 0))
1643 (setq text-width (* width char-width)))
1644 ((and (consp width) (eq (car width) 'text-pixels)
1645 (integerp (cdr width)) (> (cdr width) 0))
1646 (setq text-width (cdr width)))
1647 ((and (floatp width) (> width 0.0) (<= width 1.0))
1648 (setq text-width
1649 (- (round (* width (- (nth 2 parent-or-workarea)
1650 (nth 0 parent-or-workarea))))
1651 outer-minus-text-width)))
1652 (width
1653 (user-error "Invalid width specification")))
1654
1655 (cond
1656 ((and (integerp height) (> height 0))
1657 (setq text-height (* height char-height)))
1658 ((and (consp height) (eq (car height) 'text-pixels)
1659 (integerp (cdr height)) (> (cdr height) 0))
1660 (setq text-height (cdr height)))
1661 ((and (floatp height) (> height 0.0) (<= height 1.0))
1662 (setq text-height
1663 (- (round (* height (- (nth 3 parent-or-workarea)
1664 (nth 1 parent-or-workarea))))
1665 outer-minus-text-height)))
1666 (width
1667 (user-error "Invalid height specification")))
1668
1669 (cond
1670 ((eq left '-)
1671 (setq left 0)
1672 (setq negative t))
1673 ((integerp left)
1674 (setq negative (< left 0)))
1675 ((consp left)
1676 (cond
1677 ((and (eq (car left) '-) (integerp (cadr left)))
1678 (setq left (- (cadr left)))
1679 (setq negative t))
1680 ((and (eq (car left) '+) (integerp (cadr left)))
1681 (setq left (cadr left)))
1682 (t
1683 (user-error "Invalid position specification"))))
1684 ((floatp left)
1685 (setq left
1686 (round (* left (- (nth 2 parent-or-workarea)
1687 (nth 0 parent-or-workarea))))))
1688 (t (setq left outer-left)))
1689
1690 (when negative
1691 (setq gravity 3)
1692 (setq left (- parent-or-display-width (- left)
1693 (+ text-width
1694 (frame-scroll-bar-width frame)
1695 (frame-fringe-width frame)
1696 (* 2 (frame-internal-border-width frame))
1697 outer-minus-text-width))))
1698
1699 (setq negative nil)
1700 (cond
1701 ((eq top '-)
1702 (setq top 0)
1703 (setq negative t))
1704 ((integerp top)
1705 (setq negative (< top 0)))
1706 ((consp top)
1707 (cond
1708 ((and (eq (car top) '-) (integerp (cadr top)))
1709 (setq top (- (cadr top)))
1710 (setq negative t))
1711 ((and (eq (car top) '+) (integerp (cadr top)))
1712 (setq top (cadr top)))
1713 (t
1714 (user-error "Invalid position specification"))))
1715 ((floatp top)
1716 (setq top
1717 (round (* top (- (nth 3 parent-or-workarea)
1718 (nth 1 parent-or-workarea))))))
1719 (t (setq top outer-top)))
1720
1721 (when negative
1722 ;; This should get us 7 or 9.
1723 (setq gravity (+ gravity 6))
1724 (setq top (- parent-or-display-height (- top)
1725 (+ text-height
1726 (* 2 (frame-internal-border-width frame)))
1727 outer-minus-text-height)))
1728
1729 (set-frame-size-and-position-pixelwise
1730 frame text-width text-height left top gravity)))
1731
1538;;;; Frame configurations 1732;;;; Frame configurations
1539 1733
1540(defun current-frame-configuration () 1734(defun current-frame-configuration ()
diff --git a/src/frame.c b/src/frame.c
index 49317379354..c226852bc09 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -777,6 +777,7 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height,
777 int old_text_width = FRAME_TEXT_WIDTH (f); 777 int old_text_width = FRAME_TEXT_WIDTH (f);
778 int old_text_height = FRAME_TEXT_HEIGHT (f); 778 int old_text_height = FRAME_TEXT_HEIGHT (f);
779 bool inhibit_horizontal, inhibit_vertical; 779 bool inhibit_horizontal, inhibit_vertical;
780 bool size_and_position = EQ (parameter, Qsize_and_position);
780 Lisp_Object frame; 781 Lisp_Object frame;
781 782
782 XSETFRAME (frame, f); 783 XSETFRAME (frame, f);
@@ -855,7 +856,8 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height,
855 /* For inhibit == 1 call the window_size_hook only if a native 856 /* For inhibit == 1 call the window_size_hook only if a native
856 size changes. For inhibit == 0 or inhibit == 2 always call 857 size changes. For inhibit == 0 or inhibit == 2 always call
857 it. */ 858 it. */
858 && ((!inhibit_horizontal 859 && (size_and_position
860 || (!inhibit_horizontal
859 && (new_native_width != old_native_width 861 && (new_native_width != old_native_width
860 || inhibit == 0 || inhibit == 2)) 862 || inhibit == 0 || inhibit == 2))
861 || (!inhibit_vertical 863 || (!inhibit_vertical
@@ -907,7 +909,13 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height,
907 f->new_size_p = false; 909 f->new_size_p = false;
908 } 910 }
909 911
910 if (FRAME_TERMINAL (f)->set_window_size_hook) 912 if (size_and_position)
913 /* The caller must have set the new position and gravity and
914 made sure that set_window_size_and_position_hook has been
915 defined. */
916 FRAME_TERMINAL (f)->set_window_size_and_position_hook
917 (f, new_native_width, new_native_height);
918 else if (FRAME_TERMINAL (f)->set_window_size_hook)
911 FRAME_TERMINAL (f)->set_window_size_hook 919 FRAME_TERMINAL (f)->set_window_size_hook
912 (f, 0, new_native_width, new_native_height); 920 (f, 0, new_native_width, new_native_height);
913 f->resized_p = true; 921 f->resized_p = true;
@@ -4545,6 +4553,69 @@ bottom edge of FRAME's display. */)
4545 return Qt; 4553 return Qt;
4546} 4554}
4547 4555
4556DEFUN ("set-frame-size-and-position-pixelwise", Fset_frame_size_and_position_pixelwise,
4557 Sset_frame_size_and_position_pixelwise, 5, 6, 0,
4558 doc: /* Set FRAME's size to WIDTH and HEIGHT and its position to (X, Y).
4559FRAME must be a live frame and defaults to the selected one.
4560
4561WIDTH and HEIGHT must be positive integers and specify the new pixel
4562width and height of FRAME's text area in pixels. If WIDTH or HEIGHT do
4563not secify a value that is a multiple of FRAME's character sizes, you
4564may have to set `frame-resize-pixelwise' to a non-nil value in order to
4565get the exact size in pixels.
4566
4567X and Y specify the coordinates of the left and top edge of FRAME's
4568outer frame in pixels relative to an origin (0, 0) of FRAME's display or
4569parent frame. Negative values mean the top or left edge may be outside
4570the display or parent frame.
4571
4572GRAVITY specifies the new gravity of FRAME and must be a value in the
4573range 0..10. It defaults to 1.
4574
4575This function uses any existing backend of the toolkit to resize and
4576move FRAME in one compound step. If the backend does not provide such a
4577function, it calls `set-frame-size' followed by `set-frame-position'
4578instead. See 'set-frame-size-and-position'. */)
4579 (Lisp_Object frame, Lisp_Object width, Lisp_Object height,
4580 Lisp_Object x, Lisp_Object y, Lisp_Object gravity)
4581{
4582 struct frame *f = decode_live_frame (frame);
4583
4584 if (NILP (gravity))
4585 f->win_gravity = 1;
4586 else
4587 f->win_gravity = check_integer_range (gravity, 0, 10);
4588
4589 if (FRAME_WINDOW_P (f)
4590 && FRAME_TERMINAL (f)->set_window_size_and_position_hook)
4591 {
4592 int text_width = check_integer_range (width, 1, INT_MAX);
4593 int text_height = check_integer_range (height, 1, INT_MAX);
4594
4595 f->left_pos = check_integer_range (x, INT_MIN, INT_MAX);
4596 f->top_pos = check_integer_range (y, INT_MIN, INT_MAX);
4597
4598 adjust_frame_size (f, text_width, text_height, 1, false,
4599 Qsize_and_position);
4600 }
4601 else
4602 {
4603 Fset_frame_size (frame, width, height, Qt);
4604
4605 int left_pos = check_integer_range (x, INT_MIN, INT_MAX);
4606 int top_pos = check_integer_range (y, INT_MIN, INT_MAX);
4607
4608 Lisp_Object left
4609 = Fcons (Qleft, left_pos < 0 ? list2 (Qplus, x) : x);
4610 Lisp_Object top
4611 = Fcons (Qtop, top_pos < 0 ? list2 (Qplus, y) : y);
4612
4613 Fmodify_frame_parameters (frame, list2 (left, top));
4614 }
4615
4616 return Qnil;
4617}
4618
4548DEFUN ("frame-window-state-change", Fframe_window_state_change, 4619DEFUN ("frame-window-state-change", Fframe_window_state_change,
4549 Sframe_window_state_change, 0, 1, 0, 4620 Sframe_window_state_change, 0, 1, 0,
4550 doc: /* Return t if FRAME's window state change flag is set, nil otherwise. 4621 doc: /* Return t if FRAME's window state change flag is set, nil otherwise.
@@ -7113,6 +7184,7 @@ syms_of_frame (void)
7113 DEFSYM (Qmin_height, "min-height"); 7184 DEFSYM (Qmin_height, "min-height");
7114 DEFSYM (Qmouse_wheel_frame, "mouse-wheel-frame"); 7185 DEFSYM (Qmouse_wheel_frame, "mouse-wheel-frame");
7115 DEFSYM (Qkeep_ratio, "keep-ratio"); 7186 DEFSYM (Qkeep_ratio, "keep-ratio");
7187 DEFSYM (Qsize_and_position, "size-and-position");
7116 DEFSYM (Qwidth_only, "width-only"); 7188 DEFSYM (Qwidth_only, "width-only");
7117 DEFSYM (Qheight_only, "height-only"); 7189 DEFSYM (Qheight_only, "height-only");
7118 DEFSYM (Qleft_only, "left-only"); 7190 DEFSYM (Qleft_only, "left-only");
@@ -7593,6 +7665,7 @@ The default is \\+`inhibit' in NS builds and nil everywhere else. */);
7593 defsubr (&Sset_frame_size); 7665 defsubr (&Sset_frame_size);
7594 defsubr (&Sframe_position); 7666 defsubr (&Sframe_position);
7595 defsubr (&Sset_frame_position); 7667 defsubr (&Sset_frame_position);
7668 defsubr (&Sset_frame_size_and_position_pixelwise);
7596 defsubr (&Sframe_pointer_visible_p); 7669 defsubr (&Sframe_pointer_visible_p);
7597 defsubr (&Smouse_position_in_root_frame); 7670 defsubr (&Smouse_position_in_root_frame);
7598 defsubr (&Sframe__set_was_invisible); 7671 defsubr (&Sframe__set_was_invisible);
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 7ad6c7ce8c4..9eaf4723bb0 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1384,6 +1384,67 @@ xg_height_or_width_changed (struct frame *f)
1384} 1384}
1385#endif 1385#endif
1386 1386
1387/** Move and resize the outer window of frame F. WIDTH and HEIGHT are
1388 the new native pixel sizes of F. */
1389void
1390xg_frame_set_size_and_position (struct frame *f, int width, int height)
1391{
1392 int outer_height
1393 = height + FRAME_TOOLBAR_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
1394 int outer_width = width + FRAME_TOOLBAR_WIDTH (f);
1395 int scale = xg_get_scale (f);
1396 int x = f->left_pos;
1397 int y = f->top_pos;
1398 GdkWindow *gwin = NULL;
1399 int flags = 0;
1400
1401 if (FRAME_GTK_OUTER_WIDGET (f))
1402 gwin = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
1403 else
1404 gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
1405
1406 outer_height /= scale;
1407 outer_width /= scale;
1408
1409 /* Full force ahead. For top-level frames the gravity will get reset
1410 to NorthWestGravity anyway. */
1411 flags |= USSize;
1412 if (f->win_gravity == 3 || f->win_gravity == 9)
1413 flags |= XNegative;
1414 if (f->win_gravity == 6 || f->win_gravity == 9)
1415 flags |= YNegative;
1416 flags |= USPosition;
1417
1418 xg_wm_set_size_hint (f, flags, true);
1419
1420#ifndef HAVE_PGTK
1421 gdk_window_move_resize (gwin, x, y, outer_width, outer_height);
1422#else
1423 if (FRAME_GTK_OUTER_WIDGET (f))
1424 gdk_window_move_resize (gwin, x, y, outer_width, outer_height);
1425 else
1426 gtk_widget_set_size_request (FRAME_GTK_WIDGET (f),
1427 outer_width, outer_height);
1428#endif
1429
1430 SET_FRAME_GARBAGED (f);
1431 cancel_mouse_face (f);
1432
1433 if (FRAME_VISIBLE_P (f))
1434 {
1435 /* Must call this to flush out events */
1436 (void)gtk_events_pending ();
1437 gdk_flush ();
1438#ifndef HAVE_PGTK
1439 x_wait_for_event (f, ConfigureNotify);
1440#endif
1441 }
1442 else
1443 adjust_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, width),
1444 FRAME_PIXEL_TO_TEXT_HEIGHT (f, height),
1445 5, 0, Qxg_frame_set_char_size);
1446}
1447
1387#ifndef HAVE_PGTK 1448#ifndef HAVE_PGTK
1388/* Convert an X Window WSESC on display DPY to its corresponding GtkWidget. 1449/* Convert an X Window WSESC on display DPY to its corresponding GtkWidget.
1389 Must be done like this, because GtkWidget:s can have "hidden" 1450 Must be done like this, because GtkWidget:s can have "hidden"
@@ -2041,28 +2102,33 @@ xg_wm_set_size_hint (struct frame *f, long int flags, bool user_position)
2041 2102
2042 /* These currently have a one to one mapping with the X values, but I 2103 /* These currently have a one to one mapping with the X values, but I
2043 don't think we should rely on that. */ 2104 don't think we should rely on that. */
2044 hint_flags |= GDK_HINT_WIN_GRAVITY; 2105 if (FRAME_PARENT_FRAME (f))
2045 size_hints.win_gravity = 0; 2106 {
2046 if (win_gravity == NorthWestGravity) 2107 hint_flags |= GDK_HINT_WIN_GRAVITY;
2108 size_hints.win_gravity = 0;
2109 if (win_gravity == NorthWestGravity)
2110 size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
2111 else if (win_gravity == NorthGravity)
2112 size_hints.win_gravity = GDK_GRAVITY_NORTH;
2113 else if (win_gravity == NorthEastGravity)
2114 size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
2115 else if (win_gravity == WestGravity)
2116 size_hints.win_gravity = GDK_GRAVITY_WEST;
2117 else if (win_gravity == CenterGravity)
2118 size_hints.win_gravity = GDK_GRAVITY_CENTER;
2119 else if (win_gravity == EastGravity)
2120 size_hints.win_gravity = GDK_GRAVITY_EAST;
2121 else if (win_gravity == SouthWestGravity)
2122 size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
2123 else if (win_gravity == SouthGravity)
2124 size_hints.win_gravity = GDK_GRAVITY_SOUTH;
2125 else if (win_gravity == SouthEastGravity)
2126 size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
2127 else if (win_gravity == StaticGravity)
2128 size_hints.win_gravity = GDK_GRAVITY_STATIC;
2129 }
2130 else
2047 size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST; 2131 size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
2048 else if (win_gravity == NorthGravity)
2049 size_hints.win_gravity = GDK_GRAVITY_NORTH;
2050 else if (win_gravity == NorthEastGravity)
2051 size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
2052 else if (win_gravity == WestGravity)
2053 size_hints.win_gravity = GDK_GRAVITY_WEST;
2054 else if (win_gravity == CenterGravity)
2055 size_hints.win_gravity = GDK_GRAVITY_CENTER;
2056 else if (win_gravity == EastGravity)
2057 size_hints.win_gravity = GDK_GRAVITY_EAST;
2058 else if (win_gravity == SouthWestGravity)
2059 size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
2060 else if (win_gravity == SouthGravity)
2061 size_hints.win_gravity = GDK_GRAVITY_SOUTH;
2062 else if (win_gravity == SouthEastGravity)
2063 size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
2064 else if (win_gravity == StaticGravity)
2065 size_hints.win_gravity = GDK_GRAVITY_STATIC;
2066 2132
2067 if (flags & PPosition) 2133 if (flags & PPosition)
2068 hint_flags |= GDK_HINT_POS; 2134 hint_flags |= GDK_HINT_POS;
diff --git a/src/gtkutil.h b/src/gtkutil.h
index e6c1e19c765..849315a826a 100644
--- a/src/gtkutil.h
+++ b/src/gtkutil.h
@@ -163,6 +163,8 @@ extern void xg_frame_resized (struct frame *f,
163 int pixelwidth, 163 int pixelwidth,
164 int pixelheight); 164 int pixelheight);
165extern void xg_frame_set_char_size (struct frame *f, int width, int height); 165extern void xg_frame_set_char_size (struct frame *f, int width, int height);
166extern void xg_frame_set_size_and_position (struct frame *f, int width,
167 int height);
166extern GtkWidget * xg_win_to_widget (Display *dpy, Window wdesc); 168extern GtkWidget * xg_win_to_widget (Display *dpy, Window wdesc);
167 169
168extern int xg_get_scale (struct frame *f); 170extern int xg_get_scale (struct frame *f);
diff --git a/src/termhooks.h b/src/termhooks.h
index e688ed40c0f..5e861051498 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -684,6 +684,11 @@ struct terminal
684 void (*set_window_size_hook) (struct frame *f, bool change_gravity, 684 void (*set_window_size_hook) (struct frame *f, bool change_gravity,
685 int width, int height); 685 int width, int height);
686 686
687 /* This hook is called to change the size and position of frame F's
688 native (underlying) window. */
689 void (*set_window_size_and_position_hook) (struct frame *f, int width,
690 int height);
691
687 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position, 692 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
688 to really change the position, and 0 when calling from 693 to really change the position, and 0 when calling from
689 *_make_frame_visible (in that case, XOFF and YOFF are the current 694 *_make_frame_visible (in that case, XOFF and YOFF are the current
diff --git a/src/w32term.c b/src/w32term.c
index 9387cc3e7b7..80b072d6b5d 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -7237,6 +7237,85 @@ w32_set_window_size (struct frame *f, bool change_gravity,
7237 7237
7238 do_pending_window_change (false); 7238 do_pending_window_change (false);
7239} 7239}
7240
7241/* Change the size of frame F's Windows window to WIDTH and HEIGHT
7242 pixels and its position to those stored in f->left_pos and
7243 f->top_pos. */
7244static void
7245w32_set_window_size_and_position (struct frame *f, int width, int height)
7246{
7247 RECT rect;
7248 MENUBARINFO info;
7249 int menu_bar_height;
7250
7251 block_input ();
7252
7253 /* Get the height of the menu bar here. It's used below to detect
7254 whether the menu bar is wrapped. It's also used to specify the
7255 third argument for AdjustWindowRect. See bug#22105. */
7256 info.cbSize = sizeof (info);
7257 info.rcBar.top = info.rcBar.bottom = 0;
7258 GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &info);
7259 menu_bar_height = info.rcBar.bottom - info.rcBar.top;
7260
7261 if (w32_add_wrapped_menu_bar_lines)
7262 {
7263 /* When the menu bar wraps sending a SetWindowPos shrinks the
7264 height of the frame then the wrapped menu bar lines are not
7265 accounted for (Bug#15174 and Bug#18720). Here we add these
7266 extra lines to the frame height. */
7267 int default_menu_bar_height;
7268
7269 /* Why is (apparently) SM_CYMENUSIZE needed here instead of
7270 SM_CYMENU ?? */
7271 default_menu_bar_height = GetSystemMetrics (SM_CYMENUSIZE);
7272
7273 if ((default_menu_bar_height > 0)
7274 && (menu_bar_height > default_menu_bar_height)
7275 && ((menu_bar_height % default_menu_bar_height) == 0))
7276 height = height + menu_bar_height - default_menu_bar_height;
7277 }
7278
7279 f->win_gravity = NorthWestGravity;
7280 w32_wm_set_size_hint (f, (long) 0, false);
7281
7282 rect.left = f->left_pos;
7283 rect.top = f->top_pos;
7284 rect.right = rect.left + width;
7285 rect.bottom = rect.top + height;
7286
7287 AdjustWindowRect (&rect, f->output_data.w32->dwStyle, menu_bar_height > 0);
7288
7289 if (!FRAME_PARENT_FRAME (f))
7290 my_set_window_pos (FRAME_W32_WINDOW (f), NULL,
7291 f->left_pos, f->top_pos,
7292 rect.right - rect.left,
7293 rect.bottom - rect.top,
7294 SWP_NOZORDER | SWP_NOACTIVATE);
7295 else
7296 my_set_window_pos (FRAME_W32_WINDOW (f), HWND_TOP,
7297 f->left_pos, f->top_pos,
7298 rect.right - rect.left,
7299 rect.bottom - rect.top,
7300 SWP_NOACTIVATE);
7301
7302 change_frame_size (f, width, height, false, true, false);
7303 SET_FRAME_GARBAGED (f);
7304
7305 /* If cursor was outside the new size, mark it as off. */
7306 mark_window_cursors_off (XWINDOW (f->root_window));
7307
7308 /* Clear out any recollection of where the mouse highlighting was,
7309 since it might be in a place that's outside the new frame size.
7310 Actually checking whether it is outside is a pain in the neck,
7311 so don't try--just let the highlighting be done afresh with new
7312 size. */
7313 cancel_mouse_face (f);
7314
7315 unblock_input ();
7316
7317 do_pending_window_change (false);
7318}
7240 7319
7241/* Mouse warping. */ 7320/* Mouse warping. */
7242 7321
@@ -7891,6 +7970,7 @@ w32_create_terminal (struct w32_display_info *dpyinfo)
7891 terminal->fullscreen_hook = w32fullscreen_hook; 7970 terminal->fullscreen_hook = w32fullscreen_hook;
7892 terminal->iconify_frame_hook = w32_iconify_frame; 7971 terminal->iconify_frame_hook = w32_iconify_frame;
7893 terminal->set_window_size_hook = w32_set_window_size; 7972 terminal->set_window_size_hook = w32_set_window_size;
7973 terminal->set_window_size_and_position_hook = w32_set_window_size_and_position;
7894 terminal->set_frame_offset_hook = w32_set_offset; 7974 terminal->set_frame_offset_hook = w32_set_offset;
7895 terminal->set_frame_alpha_hook = w32_set_frame_alpha; 7975 terminal->set_frame_alpha_hook = w32_set_frame_alpha;
7896 terminal->set_new_font_hook = w32_new_font; 7976 terminal->set_new_font_hook = w32_new_font;
diff --git a/src/xterm.c b/src/xterm.c
index 9a6131ebb7d..088eaee83c9 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -28563,6 +28563,59 @@ x_set_window_size (struct frame *f, bool change_gravity,
28563 do_pending_window_change (false); 28563 do_pending_window_change (false);
28564} 28564}
28565 28565
28566static void
28567x_set_window_size_and_position_1 (struct frame *f, int width, int height)
28568{
28569 int x = f->left_pos;
28570 int y = f->top_pos;
28571
28572 x_wm_set_size_hint (f, 0, false);
28573
28574 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
28575 x, y, width, height + FRAME_MENUBAR_HEIGHT (f));
28576
28577 SET_FRAME_GARBAGED (f);
28578
28579 if (FRAME_VISIBLE_P (f))
28580 x_wait_for_event (f, ConfigureNotify);
28581 else
28582 /* Call adjust_frame_size right away as with GTK. It might be
28583 tempting to clear out f->new_width and f->new_height here. */
28584 adjust_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, width),
28585 FRAME_PIXEL_TO_TEXT_HEIGHT (f, height),
28586 5, 0, Qx_set_window_size_1);
28587}
28588
28589void
28590x_set_window_size_and_position (struct frame *f, int width, int height)
28591{
28592 block_input ();
28593
28594#ifdef USE_GTK
28595 if (FRAME_GTK_WIDGET (f))
28596 xg_frame_set_size_and_position (f, width, height);
28597 else
28598 x_set_window_size_and_position_1 (f, width, height);
28599#else /* not USE_GTK */
28600 x_set_window_size_and_position_1 (f, width, height);
28601#endif /* USE_GTK */
28602
28603 x_clear_under_internal_border (f);
28604
28605 /* If cursor was outside the new size, mark it as off. */
28606 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
28607
28608 /* Clear out any recollection of where the mouse highlighting was,
28609 since it might be in a place that's outside the new frame size.
28610 Actually checking whether it is outside is a pain in the neck,
28611 so don't try--just let the highlighting be done afresh with new size. */
28612 cancel_mouse_face (f);
28613
28614 unblock_input ();
28615
28616 do_pending_window_change (false);
28617}
28618
28566/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */ 28619/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
28567 28620
28568void 28621void
@@ -32148,6 +32201,7 @@ x_create_terminal (struct x_display_info *dpyinfo)
32148 terminal->fullscreen_hook = XTfullscreen_hook; 32201 terminal->fullscreen_hook = XTfullscreen_hook;
32149 terminal->iconify_frame_hook = x_iconify_frame; 32202 terminal->iconify_frame_hook = x_iconify_frame;
32150 terminal->set_window_size_hook = x_set_window_size; 32203 terminal->set_window_size_hook = x_set_window_size;
32204 terminal->set_window_size_and_position_hook = x_set_window_size_and_position;
32151 terminal->set_frame_offset_hook = x_set_offset; 32205 terminal->set_frame_offset_hook = x_set_offset;
32152 terminal->set_frame_alpha_hook = x_set_frame_alpha; 32206 terminal->set_frame_alpha_hook = x_set_frame_alpha;
32153 terminal->set_new_font_hook = x_new_font; 32207 terminal->set_new_font_hook = x_new_font;
diff --git a/src/xterm.h b/src/xterm.h
index 661f6ae78b7..199fcd2edf0 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1766,6 +1766,7 @@ extern void x_ignore_errors_for_next_request (struct x_display_info *,
1766extern void x_stop_ignoring_errors (struct x_display_info *); 1766extern void x_stop_ignoring_errors (struct x_display_info *);
1767extern void x_clear_errors (Display *); 1767extern void x_clear_errors (Display *);
1768extern void x_set_window_size (struct frame *, bool, int, int); 1768extern void x_set_window_size (struct frame *, bool, int, int);
1769extern void x_set_window_size_and_position (struct frame *, int, int);
1769extern void x_set_last_user_time_from_lisp (struct x_display_info *, Time); 1770extern void x_set_last_user_time_from_lisp (struct x_display_info *, Time);
1770extern void x_make_frame_visible (struct frame *); 1771extern void x_make_frame_visible (struct frame *);
1771extern void x_make_frame_invisible (struct frame *); 1772extern void x_make_frame_invisible (struct frame *);