diff --git a/src/frame.c b/src/frame.c index ecf175f4f99..4dd8bb18041 100644 --- a/src/frame.c +++ b/src/frame.c @@ -5943,6 +5943,7 @@ syms_of_frame (void) DEFSYM (Qxg_frame_set_char_size_1, "xg-frame-set-char-size-1"); DEFSYM (Qxg_frame_set_char_size_2, "xg-frame-set-char-size-2"); DEFSYM (Qxg_frame_set_char_size_3, "xg-frame-set-char-size-3"); + DEFSYM (Qxg_frame_set_char_size_4, "xg-frame-set-char-size-4"); DEFSYM (Qx_set_window_size_1, "x-set-window-size-1"); DEFSYM (Qx_set_window_size_2, "x-set-window-size-2"); DEFSYM (Qx_set_window_size_3, "x-set-window-size-3"); diff --git a/src/gtkutil.c b/src/gtkutil.c index 5e7cf3d2114..e374bdbe037 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -941,9 +941,8 @@ xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight) } } -/* Resize the outer window of frame F after changing the height. - COLUMNS/ROWS is the size the edit area shall have after the resize. */ - +/** Resize the outer window of frame F. WIDTH and HEIGHT are the new + pixel sizes of F's text area. */ void xg_frame_set_char_size (struct frame *f, int width, int height) { @@ -954,6 +953,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height) int totalheight = pixelheight + FRAME_TOOLBAR_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f); int totalwidth = pixelwidth + FRAME_TOOLBAR_WIDTH (f); + bool was_visible = false; if (FRAME_PIXEL_HEIGHT (f) == 0) return; @@ -996,12 +996,35 @@ xg_frame_set_char_size (struct frame *f, int width, int height) gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), totalwidth, gheight); } + else if (FRAME_PARENT_FRAME (f) && FRAME_VISIBLE_P (f) + && EQ (x_gtk_resize_child_frames, Qhide)) + { + was_visible = true; + + if (totalwidth != gwidth || totalheight != gheight) + { + frame_size_history_add + (f, Qxg_frame_set_char_size_4, width, height, + list2i (totalwidth, totalheight)); + block_input (); + gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f)); + unblock_input (); + + gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + totalwidth, totalheight); + + block_input (); + gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f)); + unblock_input (); + + fullscreen = Qnil; + } + } else { frame_size_history_add (f, Qxg_frame_set_char_size_3, width, height, list2i (totalwidth, totalheight)); - gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), totalwidth, totalheight); fullscreen = Qnil; @@ -1017,7 +1040,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height) size as fast as possible. For unmapped windows, we can set rows/cols. When the frame is mapped again we will (hopefully) get the correct size. */ - if (FRAME_VISIBLE_P (f)) + if (FRAME_VISIBLE_P (f) && !was_visible) { /* Must call this to flush out events */ (void)gtk_events_pending (); diff --git a/src/xfns.c b/src/xfns.c index afe1ceef81a..0fc553012bd 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -861,6 +861,12 @@ x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), p ? FRAME_X_WINDOW (p) : DefaultRootWindow (FRAME_X_DISPLAY (f)), f->left_pos, f->top_pos); +#ifdef USE_GTK + if (EQ (x_gtk_resize_child_frames, Qresize_mode)) + gtk_container_set_resize_mode + (GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)), + p ? GTK_RESIZE_IMMEDIATE : GTK_RESIZE_QUEUE); +#endif unblock_input (); fset_parent_frame (f, new_value); @@ -4084,6 +4090,11 @@ This function is an internal primitive--use `make-frame' instead. */) block_input (); XReparentWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), FRAME_X_WINDOW (p), f->left_pos, f->top_pos); +#ifdef USE_GTK + if (EQ (x_gtk_resize_child_frames, Qresize_mode)) + gtk_container_set_resize_mode + (GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)), GTK_RESIZE_IMMEDIATE); +#endif unblock_input (); } @@ -7742,6 +7753,22 @@ Note: Text drawn with the `x' font backend is shown with hollow boxes. */) #endif /* USE_GTK */ #endif /* USE_CAIRO */ +#ifdef USE_GTK +#ifdef HAVE_GTK3 +DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 0, + doc: /* Toggle interactive GTK debugging. */) + (Lisp_Object enable) +{ + gboolean enable_debug = !NILP (enable); + + block_input (); + gtk_window_set_interactive_debugging (enable_debug); + unblock_input (); + + return NILP (enable) ? Qnil : Qt; +} +#endif /* HAVE_GTK3 */ +#endif /* USE_GTK */ /*********************************************************************** Initialization @@ -7810,6 +7837,8 @@ syms_of_xfns (void) DEFSYM (Qfont_parameter, "font-parameter"); DEFSYM (Qmono, "mono"); DEFSYM (Qassq_delete_all, "assq-delete-all"); + DEFSYM (Qhide, "hide"); + DEFSYM (Qresize_mode, "resize-mode"); #ifdef USE_CAIRO DEFSYM (Qpdf, "pdf"); @@ -7986,6 +8015,28 @@ Otherwise use Emacs own tooltip implementation. When using Gtk+ tooltips, the tooltip face is not used. */); x_gtk_use_system_tooltips = true; + DEFVAR_LISP ("x-gtk-resize-child-frames", x_gtk_resize_child_frames, + doc: /* If non-nil, resize child frames specially with GTK builds. +If this is nil, resize child frames like any other frames. This is the +default and usually works with most desktops. Some desktop environments +(GNOME shell in particular when using the mutter window manager), +however, may refuse to resize a child frame when Emacs is built with +GTK3. For those environments, the two settings below are provided. + +If this equals the symbol 'hide', Emacs temporarily hides the child +frame during resizing. This approach seems to work reliably, may +however induce some flicker when the frame is made visible again. + +If this equals the symbol 'resize-mode', Emacs uses GTK's resize mode to +always trigger an immediate resize of the child frame. This method is +deprecated by GTK and may not work in future versions of that toolkit. +It also may freeze Emacs when used with other desktop environments. It +avoids, however, the unpleasent flicker induced by the hiding approach. + +This variable is considered a temporary workaround and will be hopefully +eliminated in future versions of Emacs. */); + x_gtk_resize_child_frames = Qnil; + /* Tell Emacs about this window system. */ Fprovide (Qx, Qnil); @@ -8101,4 +8152,9 @@ When using Gtk+ tooltips, the tooltip face is not used. */); defsubr (&Sx_print_frames_dialog); #endif #endif +#ifdef USE_GTK +#ifdef HAVE_GTK3 + defsubr (&Sx_gtk_debug); +#endif +#endif } diff --git a/src/xterm.c b/src/xterm.c index bda976fcbbd..44396955ed0 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -10608,26 +10608,29 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_ modified_left, modified_top); #endif - x_sync_with_move (f, f->left_pos, f->top_pos, - FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN); + /* 'x_sync_with_move' is too costly for dragging child frames. */ + if (!FRAME_PARENT_FRAME (f)) + { + x_sync_with_move (f, f->left_pos, f->top_pos, + FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN); - /* change_gravity is non-zero when this function is called from Lisp to - programmatically move a frame. In that case, we call - x_check_expected_move to discover if we have a "Type A" or "Type B" - window manager, and, for a "Type A" window manager, adjust the position - of the frame. + /* change_gravity is non-zero when this function is called from Lisp to + programmatically move a frame. In that case, we call + x_check_expected_move to discover if we have a "Type A" or "Type B" + window manager, and, for a "Type A" window manager, adjust the position + of the frame. - We call x_check_expected_move if a programmatic move occurred, and - either the window manager type (A/B) is unknown or it is Type A but we - need to compute the top/left offset adjustment for this frame. */ + We call x_check_expected_move if a programmatic move occurred, and + either the window manager type (A/B) is unknown or it is Type A but we + need to compute the top/left offset adjustment for this frame. */ - if (change_gravity != 0 - && !FRAME_PARENT_FRAME (f) - && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN - || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A - && (FRAME_X_OUTPUT (f)->move_offset_left == 0 - && FRAME_X_OUTPUT (f)->move_offset_top == 0)))) - x_check_expected_move (f, modified_left, modified_top); + if (change_gravity != 0 + && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN + || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A + && (FRAME_X_OUTPUT (f)->move_offset_left == 0 + && FRAME_X_OUTPUT (f)->move_offset_top == 0)))) + x_check_expected_move (f, modified_left, modified_top); + } unblock_input (); }