mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-05-01 02:31:23 -07:00
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.
This commit is contained in:
parent
5cf8af2290
commit
f3d9371a89
9 changed files with 505 additions and 23 deletions
77
src/frame.c
77
src/frame.c
|
|
@ -777,6 +777,7 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height,
|
|||
int old_text_width = FRAME_TEXT_WIDTH (f);
|
||||
int old_text_height = FRAME_TEXT_HEIGHT (f);
|
||||
bool inhibit_horizontal, inhibit_vertical;
|
||||
bool size_and_position = EQ (parameter, Qsize_and_position);
|
||||
Lisp_Object frame;
|
||||
|
||||
XSETFRAME (frame, f);
|
||||
|
|
@ -855,7 +856,8 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height,
|
|||
/* For inhibit == 1 call the window_size_hook only if a native
|
||||
size changes. For inhibit == 0 or inhibit == 2 always call
|
||||
it. */
|
||||
&& ((!inhibit_horizontal
|
||||
&& (size_and_position
|
||||
|| (!inhibit_horizontal
|
||||
&& (new_native_width != old_native_width
|
||||
|| inhibit == 0 || inhibit == 2))
|
||||
|| (!inhibit_vertical
|
||||
|
|
@ -907,7 +909,13 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height,
|
|||
f->new_size_p = false;
|
||||
}
|
||||
|
||||
if (FRAME_TERMINAL (f)->set_window_size_hook)
|
||||
if (size_and_position)
|
||||
/* The caller must have set the new position and gravity and
|
||||
made sure that set_window_size_and_position_hook has been
|
||||
defined. */
|
||||
FRAME_TERMINAL (f)->set_window_size_and_position_hook
|
||||
(f, new_native_width, new_native_height);
|
||||
else if (FRAME_TERMINAL (f)->set_window_size_hook)
|
||||
FRAME_TERMINAL (f)->set_window_size_hook
|
||||
(f, 0, new_native_width, new_native_height);
|
||||
f->resized_p = true;
|
||||
|
|
@ -4545,6 +4553,69 @@ bottom edge of FRAME's display. */)
|
|||
return Qt;
|
||||
}
|
||||
|
||||
DEFUN ("set-frame-size-and-position-pixelwise", Fset_frame_size_and_position_pixelwise,
|
||||
Sset_frame_size_and_position_pixelwise, 5, 6, 0,
|
||||
doc: /* Set FRAME's size to WIDTH and HEIGHT and its position to (X, Y).
|
||||
FRAME must be a live frame and defaults to the selected one.
|
||||
|
||||
WIDTH and HEIGHT must be positive integers and specify the new pixel
|
||||
width and height of FRAME's text area in pixels. If WIDTH or HEIGHT do
|
||||
not secify a value that is a multiple of FRAME's character sizes, you
|
||||
may have to set `frame-resize-pixelwise' to a non-nil value in order to
|
||||
get the exact size in pixels.
|
||||
|
||||
X and Y specify the coordinates of the left and top edge of FRAME's
|
||||
outer frame in pixels relative to an origin (0, 0) of FRAME's display or
|
||||
parent frame. Negative values mean the top or left edge may be outside
|
||||
the display or parent frame.
|
||||
|
||||
GRAVITY specifies the new gravity of FRAME and must be a value in the
|
||||
range 0..10. It defaults to 1.
|
||||
|
||||
This function uses any existing backend of the toolkit to resize and
|
||||
move FRAME in one compound step. If the backend does not provide such a
|
||||
function, it calls `set-frame-size' followed by `set-frame-position'
|
||||
instead. See 'set-frame-size-and-position'. */)
|
||||
(Lisp_Object frame, Lisp_Object width, Lisp_Object height,
|
||||
Lisp_Object x, Lisp_Object y, Lisp_Object gravity)
|
||||
{
|
||||
struct frame *f = decode_live_frame (frame);
|
||||
|
||||
if (NILP (gravity))
|
||||
f->win_gravity = 1;
|
||||
else
|
||||
f->win_gravity = check_integer_range (gravity, 0, 10);
|
||||
|
||||
if (FRAME_WINDOW_P (f)
|
||||
&& FRAME_TERMINAL (f)->set_window_size_and_position_hook)
|
||||
{
|
||||
int text_width = check_integer_range (width, 1, INT_MAX);
|
||||
int text_height = check_integer_range (height, 1, INT_MAX);
|
||||
|
||||
f->left_pos = check_integer_range (x, INT_MIN, INT_MAX);
|
||||
f->top_pos = check_integer_range (y, INT_MIN, INT_MAX);
|
||||
|
||||
adjust_frame_size (f, text_width, text_height, 1, false,
|
||||
Qsize_and_position);
|
||||
}
|
||||
else
|
||||
{
|
||||
Fset_frame_size (frame, width, height, Qt);
|
||||
|
||||
int left_pos = check_integer_range (x, INT_MIN, INT_MAX);
|
||||
int top_pos = check_integer_range (y, INT_MIN, INT_MAX);
|
||||
|
||||
Lisp_Object left
|
||||
= Fcons (Qleft, left_pos < 0 ? list2 (Qplus, x) : x);
|
||||
Lisp_Object top
|
||||
= Fcons (Qtop, top_pos < 0 ? list2 (Qplus, y) : y);
|
||||
|
||||
Fmodify_frame_parameters (frame, list2 (left, top));
|
||||
}
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
DEFUN ("frame-window-state-change", Fframe_window_state_change,
|
||||
Sframe_window_state_change, 0, 1, 0,
|
||||
doc: /* Return t if FRAME's window state change flag is set, nil otherwise.
|
||||
|
|
@ -7113,6 +7184,7 @@ syms_of_frame (void)
|
|||
DEFSYM (Qmin_height, "min-height");
|
||||
DEFSYM (Qmouse_wheel_frame, "mouse-wheel-frame");
|
||||
DEFSYM (Qkeep_ratio, "keep-ratio");
|
||||
DEFSYM (Qsize_and_position, "size-and-position");
|
||||
DEFSYM (Qwidth_only, "width-only");
|
||||
DEFSYM (Qheight_only, "height-only");
|
||||
DEFSYM (Qleft_only, "left-only");
|
||||
|
|
@ -7593,6 +7665,7 @@ The default is \\+`inhibit' in NS builds and nil everywhere else. */);
|
|||
defsubr (&Sset_frame_size);
|
||||
defsubr (&Sframe_position);
|
||||
defsubr (&Sset_frame_position);
|
||||
defsubr (&Sset_frame_size_and_position_pixelwise);
|
||||
defsubr (&Sframe_pointer_visible_p);
|
||||
defsubr (&Smouse_position_in_root_frame);
|
||||
defsubr (&Sframe__set_was_invisible);
|
||||
|
|
|
|||
108
src/gtkutil.c
108
src/gtkutil.c
|
|
@ -1384,6 +1384,67 @@ xg_height_or_width_changed (struct frame *f)
|
|||
}
|
||||
#endif
|
||||
|
||||
/** Move and resize the outer window of frame F. WIDTH and HEIGHT are
|
||||
the new native pixel sizes of F. */
|
||||
void
|
||||
xg_frame_set_size_and_position (struct frame *f, int width, int height)
|
||||
{
|
||||
int outer_height
|
||||
= height + FRAME_TOOLBAR_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
|
||||
int outer_width = width + FRAME_TOOLBAR_WIDTH (f);
|
||||
int scale = xg_get_scale (f);
|
||||
int x = f->left_pos;
|
||||
int y = f->top_pos;
|
||||
GdkWindow *gwin = NULL;
|
||||
int flags = 0;
|
||||
|
||||
if (FRAME_GTK_OUTER_WIDGET (f))
|
||||
gwin = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
|
||||
else
|
||||
gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
|
||||
|
||||
outer_height /= scale;
|
||||
outer_width /= scale;
|
||||
|
||||
/* Full force ahead. For top-level frames the gravity will get reset
|
||||
to NorthWestGravity anyway. */
|
||||
flags |= USSize;
|
||||
if (f->win_gravity == 3 || f->win_gravity == 9)
|
||||
flags |= XNegative;
|
||||
if (f->win_gravity == 6 || f->win_gravity == 9)
|
||||
flags |= YNegative;
|
||||
flags |= USPosition;
|
||||
|
||||
xg_wm_set_size_hint (f, flags, true);
|
||||
|
||||
#ifndef HAVE_PGTK
|
||||
gdk_window_move_resize (gwin, x, y, outer_width, outer_height);
|
||||
#else
|
||||
if (FRAME_GTK_OUTER_WIDGET (f))
|
||||
gdk_window_move_resize (gwin, x, y, outer_width, outer_height);
|
||||
else
|
||||
gtk_widget_set_size_request (FRAME_GTK_WIDGET (f),
|
||||
outer_width, outer_height);
|
||||
#endif
|
||||
|
||||
SET_FRAME_GARBAGED (f);
|
||||
cancel_mouse_face (f);
|
||||
|
||||
if (FRAME_VISIBLE_P (f))
|
||||
{
|
||||
/* Must call this to flush out events */
|
||||
(void)gtk_events_pending ();
|
||||
gdk_flush ();
|
||||
#ifndef HAVE_PGTK
|
||||
x_wait_for_event (f, ConfigureNotify);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
adjust_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, width),
|
||||
FRAME_PIXEL_TO_TEXT_HEIGHT (f, height),
|
||||
5, 0, Qxg_frame_set_char_size);
|
||||
}
|
||||
|
||||
#ifndef HAVE_PGTK
|
||||
/* Convert an X Window WSESC on display DPY to its corresponding GtkWidget.
|
||||
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)
|
|||
|
||||
/* These currently have a one to one mapping with the X values, but I
|
||||
don't think we should rely on that. */
|
||||
hint_flags |= GDK_HINT_WIN_GRAVITY;
|
||||
size_hints.win_gravity = 0;
|
||||
if (win_gravity == NorthWestGravity)
|
||||
if (FRAME_PARENT_FRAME (f))
|
||||
{
|
||||
hint_flags |= GDK_HINT_WIN_GRAVITY;
|
||||
size_hints.win_gravity = 0;
|
||||
if (win_gravity == NorthWestGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
|
||||
else if (win_gravity == NorthGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_NORTH;
|
||||
else if (win_gravity == NorthEastGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
|
||||
else if (win_gravity == WestGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_WEST;
|
||||
else if (win_gravity == CenterGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_CENTER;
|
||||
else if (win_gravity == EastGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_EAST;
|
||||
else if (win_gravity == SouthWestGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
|
||||
else if (win_gravity == SouthGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_SOUTH;
|
||||
else if (win_gravity == SouthEastGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
|
||||
else if (win_gravity == StaticGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_STATIC;
|
||||
}
|
||||
else
|
||||
size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
|
||||
else if (win_gravity == NorthGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_NORTH;
|
||||
else if (win_gravity == NorthEastGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
|
||||
else if (win_gravity == WestGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_WEST;
|
||||
else if (win_gravity == CenterGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_CENTER;
|
||||
else if (win_gravity == EastGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_EAST;
|
||||
else if (win_gravity == SouthWestGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
|
||||
else if (win_gravity == SouthGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_SOUTH;
|
||||
else if (win_gravity == SouthEastGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
|
||||
else if (win_gravity == StaticGravity)
|
||||
size_hints.win_gravity = GDK_GRAVITY_STATIC;
|
||||
|
||||
if (flags & PPosition)
|
||||
hint_flags |= GDK_HINT_POS;
|
||||
|
|
|
|||
|
|
@ -163,6 +163,8 @@ extern void xg_frame_resized (struct frame *f,
|
|||
int pixelwidth,
|
||||
int pixelheight);
|
||||
extern void xg_frame_set_char_size (struct frame *f, int width, int height);
|
||||
extern void xg_frame_set_size_and_position (struct frame *f, int width,
|
||||
int height);
|
||||
extern GtkWidget * xg_win_to_widget (Display *dpy, Window wdesc);
|
||||
|
||||
extern int xg_get_scale (struct frame *f);
|
||||
|
|
|
|||
|
|
@ -684,6 +684,11 @@ struct terminal
|
|||
void (*set_window_size_hook) (struct frame *f, bool change_gravity,
|
||||
int width, int height);
|
||||
|
||||
/* This hook is called to change the size and position of frame F's
|
||||
native (underlying) window. */
|
||||
void (*set_window_size_and_position_hook) (struct frame *f, int width,
|
||||
int height);
|
||||
|
||||
/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
|
||||
to really change the position, and 0 when calling from
|
||||
*_make_frame_visible (in that case, XOFF and YOFF are the current
|
||||
|
|
|
|||
|
|
@ -7237,6 +7237,85 @@ w32_set_window_size (struct frame *f, bool change_gravity,
|
|||
|
||||
do_pending_window_change (false);
|
||||
}
|
||||
|
||||
/* Change the size of frame F's Windows window to WIDTH and HEIGHT
|
||||
pixels and its position to those stored in f->left_pos and
|
||||
f->top_pos. */
|
||||
static void
|
||||
w32_set_window_size_and_position (struct frame *f, int width, int height)
|
||||
{
|
||||
RECT rect;
|
||||
MENUBARINFO info;
|
||||
int menu_bar_height;
|
||||
|
||||
block_input ();
|
||||
|
||||
/* Get the height of the menu bar here. It's used below to detect
|
||||
whether the menu bar is wrapped. It's also used to specify the
|
||||
third argument for AdjustWindowRect. See bug#22105. */
|
||||
info.cbSize = sizeof (info);
|
||||
info.rcBar.top = info.rcBar.bottom = 0;
|
||||
GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &info);
|
||||
menu_bar_height = info.rcBar.bottom - info.rcBar.top;
|
||||
|
||||
if (w32_add_wrapped_menu_bar_lines)
|
||||
{
|
||||
/* When the menu bar wraps sending a SetWindowPos shrinks the
|
||||
height of the frame then the wrapped menu bar lines are not
|
||||
accounted for (Bug#15174 and Bug#18720). Here we add these
|
||||
extra lines to the frame height. */
|
||||
int default_menu_bar_height;
|
||||
|
||||
/* Why is (apparently) SM_CYMENUSIZE needed here instead of
|
||||
SM_CYMENU ?? */
|
||||
default_menu_bar_height = GetSystemMetrics (SM_CYMENUSIZE);
|
||||
|
||||
if ((default_menu_bar_height > 0)
|
||||
&& (menu_bar_height > default_menu_bar_height)
|
||||
&& ((menu_bar_height % default_menu_bar_height) == 0))
|
||||
height = height + menu_bar_height - default_menu_bar_height;
|
||||
}
|
||||
|
||||
f->win_gravity = NorthWestGravity;
|
||||
w32_wm_set_size_hint (f, (long) 0, false);
|
||||
|
||||
rect.left = f->left_pos;
|
||||
rect.top = f->top_pos;
|
||||
rect.right = rect.left + width;
|
||||
rect.bottom = rect.top + height;
|
||||
|
||||
AdjustWindowRect (&rect, f->output_data.w32->dwStyle, menu_bar_height > 0);
|
||||
|
||||
if (!FRAME_PARENT_FRAME (f))
|
||||
my_set_window_pos (FRAME_W32_WINDOW (f), NULL,
|
||||
f->left_pos, f->top_pos,
|
||||
rect.right - rect.left,
|
||||
rect.bottom - rect.top,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
else
|
||||
my_set_window_pos (FRAME_W32_WINDOW (f), HWND_TOP,
|
||||
f->left_pos, f->top_pos,
|
||||
rect.right - rect.left,
|
||||
rect.bottom - rect.top,
|
||||
SWP_NOACTIVATE);
|
||||
|
||||
change_frame_size (f, width, height, false, true, false);
|
||||
SET_FRAME_GARBAGED (f);
|
||||
|
||||
/* If cursor was outside the new size, mark it as off. */
|
||||
mark_window_cursors_off (XWINDOW (f->root_window));
|
||||
|
||||
/* Clear out any recollection of where the mouse highlighting was,
|
||||
since it might be in a place that's outside the new frame size.
|
||||
Actually checking whether it is outside is a pain in the neck,
|
||||
so don't try--just let the highlighting be done afresh with new
|
||||
size. */
|
||||
cancel_mouse_face (f);
|
||||
|
||||
unblock_input ();
|
||||
|
||||
do_pending_window_change (false);
|
||||
}
|
||||
|
||||
/* Mouse warping. */
|
||||
|
||||
|
|
@ -7891,6 +7970,7 @@ w32_create_terminal (struct w32_display_info *dpyinfo)
|
|||
terminal->fullscreen_hook = w32fullscreen_hook;
|
||||
terminal->iconify_frame_hook = w32_iconify_frame;
|
||||
terminal->set_window_size_hook = w32_set_window_size;
|
||||
terminal->set_window_size_and_position_hook = w32_set_window_size_and_position;
|
||||
terminal->set_frame_offset_hook = w32_set_offset;
|
||||
terminal->set_frame_alpha_hook = w32_set_frame_alpha;
|
||||
terminal->set_new_font_hook = w32_new_font;
|
||||
|
|
|
|||
54
src/xterm.c
54
src/xterm.c
|
|
@ -28563,6 +28563,59 @@ x_set_window_size (struct frame *f, bool change_gravity,
|
|||
do_pending_window_change (false);
|
||||
}
|
||||
|
||||
static void
|
||||
x_set_window_size_and_position_1 (struct frame *f, int width, int height)
|
||||
{
|
||||
int x = f->left_pos;
|
||||
int y = f->top_pos;
|
||||
|
||||
x_wm_set_size_hint (f, 0, false);
|
||||
|
||||
XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
|
||||
x, y, width, height + FRAME_MENUBAR_HEIGHT (f));
|
||||
|
||||
SET_FRAME_GARBAGED (f);
|
||||
|
||||
if (FRAME_VISIBLE_P (f))
|
||||
x_wait_for_event (f, ConfigureNotify);
|
||||
else
|
||||
/* Call adjust_frame_size right away as with GTK. It might be
|
||||
tempting to clear out f->new_width and f->new_height here. */
|
||||
adjust_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, width),
|
||||
FRAME_PIXEL_TO_TEXT_HEIGHT (f, height),
|
||||
5, 0, Qx_set_window_size_1);
|
||||
}
|
||||
|
||||
void
|
||||
x_set_window_size_and_position (struct frame *f, int width, int height)
|
||||
{
|
||||
block_input ();
|
||||
|
||||
#ifdef USE_GTK
|
||||
if (FRAME_GTK_WIDGET (f))
|
||||
xg_frame_set_size_and_position (f, width, height);
|
||||
else
|
||||
x_set_window_size_and_position_1 (f, width, height);
|
||||
#else /* not USE_GTK */
|
||||
x_set_window_size_and_position_1 (f, width, height);
|
||||
#endif /* USE_GTK */
|
||||
|
||||
x_clear_under_internal_border (f);
|
||||
|
||||
/* If cursor was outside the new size, mark it as off. */
|
||||
mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
|
||||
|
||||
/* Clear out any recollection of where the mouse highlighting was,
|
||||
since it might be in a place that's outside the new frame size.
|
||||
Actually checking whether it is outside is a pain in the neck,
|
||||
so don't try--just let the highlighting be done afresh with new size. */
|
||||
cancel_mouse_face (f);
|
||||
|
||||
unblock_input ();
|
||||
|
||||
do_pending_window_change (false);
|
||||
}
|
||||
|
||||
/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
|
||||
|
||||
void
|
||||
|
|
@ -32148,6 +32201,7 @@ x_create_terminal (struct x_display_info *dpyinfo)
|
|||
terminal->fullscreen_hook = XTfullscreen_hook;
|
||||
terminal->iconify_frame_hook = x_iconify_frame;
|
||||
terminal->set_window_size_hook = x_set_window_size;
|
||||
terminal->set_window_size_and_position_hook = x_set_window_size_and_position;
|
||||
terminal->set_frame_offset_hook = x_set_offset;
|
||||
terminal->set_frame_alpha_hook = x_set_frame_alpha;
|
||||
terminal->set_new_font_hook = x_new_font;
|
||||
|
|
|
|||
|
|
@ -1766,6 +1766,7 @@ extern void x_ignore_errors_for_next_request (struct x_display_info *,
|
|||
extern void x_stop_ignoring_errors (struct x_display_info *);
|
||||
extern void x_clear_errors (Display *);
|
||||
extern void x_set_window_size (struct frame *, bool, int, int);
|
||||
extern void x_set_window_size_and_position (struct frame *, int, int);
|
||||
extern void x_set_last_user_time_from_lisp (struct x_display_info *, Time);
|
||||
extern void x_make_frame_visible (struct frame *);
|
||||
extern void x_make_frame_invisible (struct frame *);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue