From: Yuuki Harano Date: Sun, 6 Sep 2020 14:27:45 +0000 (+0900) Subject: Re-implement childframe with emacsgtkfixed X-Git-Tag: emacs-29.0.90~3777 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=28073ba59bbabec1194977d654b471800ce63f45;p=emacs.git Re-implement childframe with emacsgtkfixed * src/emacsgtkfixed.c (G_DEFINE_TYPE): Make emacs_fixed_get_type public. * src/emacsgtkfixed.h (EMACS_TYPE_FIXED): Make emacs_fixed_get_type public. * src/gtkutil.c (xg_frame_set_char_size): Call appropriate functions by whether the frame is a child frame or not. (xg_create_frame_widgets): Use GTK_WINDOW_TOPLEVEL when creating child frame. (xg_create_frame_outer_widgets): New function. (xg_set_skip_taskbar): Call only when top-level frame. (xg_set_no_accept_focus): See appropriate widget. * src/gtkutil.h: New declaration. * src/pgtkfns.c (pgtk_set_name_internal): Do only when top-level frame. (Fx_create_frame): Reparent the frame. (frame_geometry): Call appropriate functions (syms_of_pgtkfns): Port from X code. * src/pgtkterm.c (x_free_frame_resources): Destroy appropriate widget. (x_calc_absolute_position): Port from X code. (x_set_offset): Re-port from X code. (pgtk_set_window_size): Use appropriate widget. (pgtk_make_frame_visible): Use appropriate widget. (pgtk_make_frame_invisible): Use appropriate widget. (x_set_parent_frame): Reparent the frame. (x_set_z_group): Process only when top-level frame. (pgtk_text_icon): Process only when top-level frame. (set_fullscreen_state): Process only when top-level frame. (frame_highlight): Hold ref. (frame_unhighlight): Hold ref. (pgtk_window_is_of_frame_recursive): Prune child frames. (pgtk_window_is_of_frame): Prune child frames. (print_widget_tree_recursive): Don't call this when not debugging. (pgtk_handle_draw): Don't call this when not debugging. (pgtk_set_event_handler): expect map-event for edit_widget not outer widget. * src/pgtkterm.h (FRAME_WIDGET): New macro. --- diff --git a/src/emacsgtkfixed.c b/src/emacsgtkfixed.c index 4128f81cce9..d2a7fcbbc10 100644 --- a/src/emacsgtkfixed.c +++ b/src/emacsgtkfixed.c @@ -51,7 +51,6 @@ static void emacs_fixed_get_preferred_width (GtkWidget *widget, static void emacs_fixed_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural); -static GType emacs_fixed_get_type (void); G_DEFINE_TYPE (EmacsFixed, emacs_fixed, GTK_TYPE_FIXED) static EmacsFixed * diff --git a/src/emacsgtkfixed.h b/src/emacsgtkfixed.h index b230a4d4d8a..f2fb1f269a2 100644 --- a/src/emacsgtkfixed.h +++ b/src/emacsgtkfixed.h @@ -27,6 +27,9 @@ struct frame; G_BEGIN_DECLS +#define EMACS_TYPE_FIXED (emacs_fixed_get_type ()) +#define EMACS_IS_FIXED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMACS_TYPE_FIXED)) + struct frame; typedef struct _EmacsFixedPrivate EmacsFixedPrivate; @@ -44,6 +47,8 @@ struct _EmacsFixedClass GtkFixedClass parent_class; }; +extern GType emacs_fixed_get_type (void); + extern GtkWidget *emacs_fixed_new (struct frame *f); G_END_DECLS diff --git a/src/gtkutil.c b/src/gtkutil.c index 3956c581d9d..0f1a51fbbbb 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -1060,8 +1060,20 @@ xg_frame_set_char_size (struct frame *f, int width, int height) if (FRAME_PIXEL_HEIGHT (f) == 0) return; +#ifndef HAVE_PGTK gtk_window_get_size (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), &gwidth, &gheight); +#else + if (FRAME_GTK_OUTER_WIDGET (f)) { + gtk_window_get_size (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + &gwidth, &gheight); + } else { + GtkAllocation alloc; + gtk_widget_get_allocation (FRAME_GTK_WIDGET (f), &alloc); + gwidth = alloc.width; + gheight = alloc.height; + } +#endif /* Do this before resize, as we don't know yet if we will be resized. */ FRAME_RIF (f)->clear_under_internal_border (f); @@ -1101,11 +1113,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height) else if (FRAME_PARENT_FRAME (f) && FRAME_VISIBLE_P (f)) { was_visible = true; -#ifndef HAVE_PGTK hide_child_frame = EQ (x_gtk_resize_child_frames, Qhide); -#else - hide_child_frame = true; -#endif // !HAVE_PGTK if (totalwidth != gwidth || totalheight != gheight) { @@ -1116,17 +1124,35 @@ xg_frame_set_char_size (struct frame *f, int width, int height) if (hide_child_frame) { block_input (); +#ifndef HAVE_PGTK gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f)); +#else + gtk_widget_hide (FRAME_WIDGET (f)); +#endif unblock_input (); } +#ifndef HAVE_PGTK gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), totalwidth, totalheight); +#else + if (FRAME_GTK_OUTER_WIDGET (f)) { + gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + totalwidth, totalheight); + } else { + gtk_widget_set_size_request (FRAME_GTK_WIDGET (f), + totalwidth, totalheight); + } +#endif if (hide_child_frame) { block_input (); +#ifndef HAVE_PGTK gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f)); +#else + gtk_widget_show_all (FRAME_WIDGET (f)); +#endif unblock_input (); } @@ -1138,8 +1164,18 @@ xg_frame_set_char_size (struct frame *f, int width, int height) frame_size_history_add (f, Qxg_frame_set_char_size_3, width, height, list2i (totalwidth, totalheight)); +#ifndef HAVE_PGTK gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), totalwidth, totalheight); +#else + if (FRAME_GTK_OUTER_WIDGET (f)) { + gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + totalwidth, totalheight); + } else { + gtk_widget_set_size_request (FRAME_GTK_WIDGET (f), + totalwidth, totalheight); + } +#endif fullscreen = Qnil; } @@ -1355,7 +1391,7 @@ xg_create_frame_widgets (struct frame *f) else wtop = gtk_window_new (type); #else - if (!NILP(f->parent_frame) || f->tooltip) + if (f->tooltip) { type = GTK_WINDOW_POPUP; } @@ -1546,6 +1582,107 @@ xg_create_frame_widgets (struct frame *f) return 1; } +#ifdef HAVE_PGTK +void +xg_create_frame_outer_widgets (struct frame *f) +{ + GtkWidget *wtop; + GtkWidget *wvbox, *whbox; + GtkWindowType type = GTK_WINDOW_TOPLEVEL; + char *title = 0; + + PGTK_TRACE ("xg_create_frame_outer_widgets."); + block_input (); + + wtop = gtk_window_new (type); + gtk_widget_add_events(wtop, GDK_ALL_EVENTS_MASK); + + xg_set_screen (wtop, f); + + wvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + whbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous (GTK_BOX (wvbox), FALSE); + gtk_box_set_homogeneous (GTK_BOX (whbox), FALSE); + + /* Use same names as the Xt port does. I.e. Emacs.pane.emacs by default */ + gtk_widget_set_name (wtop, EMACS_CLASS); + gtk_widget_set_name (wvbox, "pane"); + + /* If this frame has a title or name, set it in the title bar. */ + if (! NILP (f->title)) + title = SSDATA (ENCODE_UTF_8 (f->title)); + else if (! NILP (f->name)) + title = SSDATA (ENCODE_UTF_8 (f->name)); + + if (title) + gtk_window_set_title (GTK_WINDOW (wtop), title); + + if (FRAME_UNDECORATED (f)) + { + gtk_window_set_decorated (GTK_WINDOW (wtop), FALSE); + store_frame_param (f, Qundecorated, Qt); + } + + FRAME_GTK_OUTER_WIDGET (f) = wtop; + f->output_data.xp->vbox_widget = wvbox; + f->output_data.xp->hbox_widget = whbox; + + gtk_container_add (GTK_CONTAINER (wtop), wvbox); + gtk_box_pack_start (GTK_BOX (wvbox), whbox, TRUE, TRUE, 0); + + if (FRAME_EXTERNAL_TOOL_BAR (f)) + update_frame_tool_bar (f); + +#if ! GTK_CHECK_VERSION (3, 22, 0) + gtk_window_set_wmclass (GTK_WINDOW (wtop), + SSDATA (Vx_resource_name), + SSDATA (Vx_resource_class)); +#endif + + /* Convert our geometry parameters into a geometry string + and specify it. + GTK will itself handle calculating the real position this way. */ + xg_set_geometry (f); + f->win_gravity + = gtk_window_get_gravity (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))); + + gtk_window_set_resizable (GTK_WINDOW (wtop), TRUE); + + if (FRAME_OVERRIDE_REDIRECT (f)) + { + GdkWindow *gwin = gtk_widget_get_window (wtop); + + if (gwin) + gdk_window_set_override_redirect (gwin, TRUE); + } + + /* Steal a tool tip window we can move ourselves. */ + f->output_data.xp->ttip_widget = 0; + f->output_data.xp->ttip_lbl = 0; + f->output_data.xp->ttip_window = 0; + gtk_widget_set_tooltip_text (wtop, "Dummy text"); + g_signal_connect (wtop, "query-tooltip", G_CALLBACK (qttip_cb), f); + + { + GdkScreen *screen = gtk_widget_get_screen (wtop); + GtkSettings *gs = gtk_settings_get_for_screen (screen); + /* Only connect this signal once per screen. */ + if (! g_signal_handler_find (G_OBJECT (gs), + G_SIGNAL_MATCH_FUNC, + 0, 0, 0, + (gpointer) G_CALLBACK (style_changed_cb), + 0)) + { + g_signal_connect (G_OBJECT (gs), "notify::gtk-theme-name", + G_CALLBACK (style_changed_cb), + gdk_screen_get_display (screen)); + } + } + + unblock_input (); +} +#endif + void xg_free_frame_widgets (struct frame *f) { @@ -1784,10 +1921,17 @@ void xg_set_skip_taskbar (struct frame *f, Lisp_Object skip_taskbar) { block_input (); +#ifndef HAVE_PGTK if (FRAME_GTK_WIDGET (f)) gdk_window_set_skip_taskbar_hint (gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f)), NILP (skip_taskbar) ? FALSE : TRUE); +#else + if (FRAME_GTK_OUTER_WIDGET (f)) + gdk_window_set_skip_taskbar_hint + (gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f)), + NILP (skip_taskbar) ? FALSE : TRUE); +#endif unblock_input (); } @@ -1812,7 +1956,13 @@ void xg_set_no_accept_focus (struct frame *f, Lisp_Object no_accept_focus) { block_input (); - if (FRAME_GTK_WIDGET (f)) + if ( +#ifndef HAVE_PGTK + FRAME_GTK_WIDGET (f) +#else + FRAME_GTK_OUTER_WIDGET (f) +#endif + ) { GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)); gboolean g_no_accept_focus = NILP (no_accept_focus) ? TRUE : FALSE; diff --git a/src/gtkutil.h b/src/gtkutil.h index b7f67ba9281..04007343f27 100644 --- a/src/gtkutil.h +++ b/src/gtkutil.h @@ -179,6 +179,9 @@ extern void xg_set_background_color (struct frame *f, unsigned long bg); extern bool xg_check_special_colors (struct frame *f, const char *color_name, Emacs_Color *color); +#ifdef HAVE_PGTK +extern void xg_create_frame_outer_widgets (struct frame *f); +#endif #ifndef HAVE_PGTK extern void xg_set_frame_icon (struct frame *f, diff --git a/src/pgtkfns.c b/src/pgtkfns.c index 06fb4e206f4..c6909ba3d63 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -231,7 +231,7 @@ x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) static void pgtk_set_name_internal (struct frame *f, Lisp_Object name) { - if (FRAME_GTK_WIDGET (f)) + if (FRAME_GTK_OUTER_WIDGET (f)) { block_input (); { @@ -1523,18 +1523,32 @@ This function is an internal primitive--use `make-frame' instead. */ ) struct frame *p = XFRAME (parent_frame); block_input (); + PGTK_TRACE ("x_set_parent_frame x: %d, y: %d", f->left_pos, f->top_pos); - gtk_window_set_transient_for (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), - GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (p))); - gtk_window_set_attached_to (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), - FRAME_GTK_WIDGET (p)); - gtk_window_set_destroy_with_parent (GTK_WINDOW - (FRAME_GTK_OUTER_WIDGET (f)), TRUE); - gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f)); + GtkWidget *fixed = FRAME_GTK_WIDGET (f); + GtkWidget *fixed_of_p = FRAME_GTK_WIDGET (p); + GtkWidget *whbox_of_f = gtk_widget_get_parent (fixed); + g_object_ref (fixed); + gtk_container_remove (GTK_CONTAINER (whbox_of_f), fixed); + gtk_fixed_put (GTK_FIXED (fixed_of_p), fixed, f->left_pos, f->top_pos); + gtk_widget_show_all (fixed); + g_object_unref (fixed); + + gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f)); + FRAME_GTK_OUTER_WIDGET (f) = NULL; + FRAME_OUTPUT_DATA (f)->vbox_widget = NULL; + FRAME_OUTPUT_DATA (f)->hbox_widget = NULL; + FRAME_OUTPUT_DATA (f)->menubar_widget = NULL; + FRAME_OUTPUT_DATA (f)->toolbar_widget = NULL; + FRAME_OUTPUT_DATA (f)->ttip_widget = NULL; + FRAME_OUTPUT_DATA (f)->ttip_lbl = NULL; + FRAME_OUTPUT_DATA (f)->ttip_window = NULL; + unblock_input (); } - gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f)); + if (FRAME_GTK_OUTER_WIDGET (f)) + gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f)); gui_default_parameter (f, parms, Qno_focus_on_map, Qnil, NULL, NULL, RES_TYPE_BOOLEAN); @@ -3298,8 +3312,15 @@ frame_geometry (Lisp_Object frame, Lisp_Object attribute) /* Get these here because they can't be got in configure_event(). */ int left_pos, top_pos; - gtk_window_get_position (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), - &left_pos, &top_pos); + if (FRAME_GTK_OUTER_WIDGET (f)) { + gtk_window_get_position (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + &left_pos, &top_pos); + } else { + GtkAllocation alloc; + gtk_widget_get_allocation (FRAME_GTK_WIDGET (f), &alloc); + left_pos = alloc.x; + top_pos = alloc.y; + } int native_left = left_pos + border; int native_top = top_pos + border + title_height; @@ -3647,6 +3668,8 @@ syms_of_pgtkfns (void) DEFSYM (Qframe_title_format, "frame-title-format"); DEFSYM (Qicon_title_format, "icon-title-format"); DEFSYM (Qdark, "dark"); + DEFSYM (Qhide, "hide"); + DEFSYM (Qresize_mode, "resize-mode"); DEFVAR_LISP ("x-cursor-fore-pixel", Vx_cursor_fore_pixel, doc: /* A string indicating the foreground color of the cursor box. */); @@ -3799,6 +3822,28 @@ When using Gtk+ tooltips, the tooltip face is not used. */); Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */); Vx_max_tooltip_size = Fcons (make_fixnum (80), make_fixnum (40)); + 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 unpleasant 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; + DEFSYM (Qmono, "mono"); DEFSYM (Qassq_delete_all, "assq-delete-all"); diff --git a/src/pgtkterm.c b/src/pgtkterm.c index 6d8b1ece877..d62e2a3b16d 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -60,6 +60,7 @@ along with GNU Emacs. If not, see . */ #include "font.h" #include "xsettings.h" #include "pgtkselect.h" +#include "emacsgtkfixed.h" #define STORE_KEYSYM_FOR_DEBUG(keysym) ((void)0) @@ -227,10 +228,10 @@ x_free_frame_resources (struct frame *f) if (FRAME_X_OUTPUT (f)->border_color_css_provider != NULL) { - GtkStyleContext *ctxt = - gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f)); + GtkStyleContext *ctxt = gtk_widget_get_style_context (FRAME_WIDGET (f)); GtkCssProvider *old = FRAME_X_OUTPUT (f)->border_color_css_provider; gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (old)); + g_object_unref (old); FRAME_X_OUTPUT (f)->border_color_css_provider = NULL; } @@ -250,7 +251,7 @@ x_free_frame_resources (struct frame *f) FRAME_X_OUTPUT (f)->scrollbar_background_css_provider = NULL; } - gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f)); + gtk_widget_destroy (FRAME_WIDGET (f)); if (FRAME_X_OUTPUT (f)->cr_surface_visible_bell != NULL) { @@ -286,6 +287,80 @@ x_destroy_window (struct frame *f) dpyinfo->reference_count--; } +/* Calculate the absolute position in frame F + from its current recorded position values and gravity. */ + +static void +x_calc_absolute_position (struct frame *f) +{ + int flags = f->size_hint_flags; + struct frame *p = FRAME_PARENT_FRAME (f); + + /* We have nothing to do if the current position + is already for the top-left corner. */ + if (! ((flags & XNegative) || (flags & YNegative))) + return; + + /* Treat negative positions as relative to the leftmost bottommost + position that fits on the screen. */ + if ((flags & XNegative) && (f->left_pos <= 0)) + { + int width = FRAME_PIXEL_WIDTH (f); + + /* A frame that has been visible at least once should have outer + edges. */ + if (f->output_data.pgtk->has_been_visible && !p) + { + Lisp_Object frame; + Lisp_Object edges = Qnil; + + XSETFRAME (frame, f); + edges = Fpgtk_frame_edges (frame, Qouter_edges); + if (!NILP (edges)) + width = (XFIXNUM (Fnth (make_fixnum (2), edges)) + - XFIXNUM (Fnth (make_fixnum (0), edges))); + } + + if (p) + f->left_pos = (FRAME_PIXEL_WIDTH (p) - width - 2 * f->border_width + + f->left_pos); + else + f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f)) + - width + f->left_pos); + + } + + if ((flags & YNegative) && (f->top_pos <= 0)) + { + int height = FRAME_PIXEL_HEIGHT (f); + + if (f->output_data.pgtk->has_been_visible && !p) + { + Lisp_Object frame; + Lisp_Object edges = Qnil; + + XSETFRAME (frame, f); + if (NILP (edges)) + edges = Fpgtk_frame_edges (frame, Qouter_edges); + if (!NILP (edges)) + height = (XFIXNUM (Fnth (make_fixnum (3), edges)) + - XFIXNUM (Fnth (make_fixnum (1), edges))); + } + + if (p) + f->top_pos = (FRAME_PIXEL_HEIGHT (p) - height - 2 * f->border_width + + f->top_pos); + else + f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f)) + - height + f->top_pos); + } + + /* The left_pos and top_pos + are now relative to the top and left screen edges, + so the flags should correspond. */ + f->size_hint_flags &= ~ (XNegative | YNegative); +} + /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position, to really change the position, and 0 when calling from x_make_frame_visible (in that case, XOFF and YOFF are the current @@ -300,48 +375,60 @@ x_set_offset (struct frame *f, int xoff, int yoff, int change_gravity) { PGTK_TRACE ("x_set_offset: %d,%d,%d.", xoff, yoff, change_gravity); - struct frame *parent = FRAME_PARENT_FRAME (f); - GtkAllocation a = { 0 }; - int surface_pos_x = 0; - int surface_pos_y = 0; - - if (parent) - { - /* determing the "height" of the titlebar, by finding the - location of the "emacsfixed" widget on the surface/window */ - GtkWidget *w = FRAME_GTK_WIDGET (parent); - gtk_widget_get_allocation (w, &a); - } + int modified_top, modified_left; if (change_gravity > 0) { - f->size_hint_flags &= ~(XNegative | YNegative); - f->left_pos = xoff; f->top_pos = yoff; - + f->left_pos = xoff; + f->size_hint_flags &= ~ (XNegative | YNegative); if (xoff < 0) - { - f->size_hint_flags |= XNegative; - } + f->size_hint_flags |= XNegative; if (yoff < 0) - { - f->size_hint_flags |= YNegative; - } + f->size_hint_flags |= YNegative; f->win_gravity = NorthWestGravity; } + x_calc_absolute_position (f); + block_input (); - surface_pos_y = f->top_pos + a.y; - surface_pos_x = f->left_pos + a.x; + x_wm_set_size_hint (f, 0, false); - /* 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)) + if (x_gtk_use_window_move) + { + if (change_gravity != 0) + { + if (FRAME_GTK_OUTER_WIDGET (f)) + { + gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + f->left_pos, f->top_pos); + } + else + { + GtkWidget *fixed = FRAME_GTK_WIDGET (f); + GtkWidget *parent = gtk_widget_get_parent (fixed); + gtk_fixed_move (GTK_FIXED (parent), fixed, + f->left_pos, f->top_pos); + } + } + unblock_input (); + return; + } + + modified_left = f->left_pos; + modified_top = f->top_pos; + + if (FRAME_GTK_OUTER_WIDGET (f)) { - PGTK_TRACE ("x_set_offset: move to %d,%d.", surface_pos_x, surface_pos_y); gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), - surface_pos_x, surface_pos_y); + modified_left, modified_top); + } + else + { + GtkWidget *fixed = FRAME_GTK_WIDGET (f); + GtkWidget *parent = gtk_widget_get_parent (fixed); + gtk_fixed_move (GTK_FIXED (parent), fixed, + modified_left, modified_top); } unblock_input (); @@ -397,7 +484,7 @@ pgtk_set_window_size (struct frame *f, x_wm_set_size_hint (f, 0, 0); xg_frame_set_char_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, pixelwidth), FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelheight)); - gtk_widget_queue_resize (FRAME_GTK_OUTER_WIDGET (f)); + gtk_widget_queue_resize (FRAME_WIDGET (f)); unblock_input (); } @@ -488,8 +575,9 @@ pgtk_make_frame_visible (struct frame *f) if (!FRAME_VISIBLE_P (f)) { - gtk_widget_show (win); - gtk_window_deiconify (GTK_WINDOW (win)); + gtk_widget_show (FRAME_WIDGET (f)); + if (win) + gtk_window_deiconify (GTK_WINDOW (win)); if (FLOATP (Vpgtk_wait_for_event_timeout)) { @@ -498,7 +586,7 @@ pgtk_make_frame_visible (struct frame *f) int found = 0; int timed_out = 0; gulong id = - g_signal_connect (win, "map-event", + g_signal_connect (FRAME_WIDGET (f), "map-event", G_CALLBACK (pgtk_make_frame_visible_wait_for_map_event_cb), &found); @@ -508,7 +596,7 @@ pgtk_make_frame_visible (struct frame *f) &timed_out); while (!found && !timed_out) gtk_main_iteration (); - g_signal_handler_disconnect (win, id); + g_signal_handler_disconnect (FRAME_WIDGET (f), id); if (!timed_out) g_source_remove (src); } @@ -524,9 +612,7 @@ pgtk_make_frame_invisible (struct frame *f) { PGTK_TRACE ("pgtk_make_frame_invisible"); - GtkWidget *win = FRAME_OUTPUT_DATA (f)->widget; - - gtk_widget_hide (win); + gtk_widget_hide (FRAME_WIDGET (f)); SET_FRAME_VISIBLE (f, 0); SET_FRAME_ICONIFIED (f, false); @@ -668,25 +754,89 @@ x_set_parent_frame (struct frame *f, Lisp_Object new_value, -------------------------------------------------------------------------- */ { struct frame *p = NULL; - PGTK_TRACE ("x_set_parent_frame x: %d, y: %d", f->left_pos, f->top_pos); if (!NILP (new_value) && (!FRAMEP (new_value) - || !FRAME_LIVE_P (p = XFRAME (new_value)) || !FRAME_PGTK_P (p))) + || !FRAME_LIVE_P (p = XFRAME (new_value)) + || !FRAME_PGTK_P (p))) { store_frame_param (f, Qparent_frame, old_value); error ("Invalid specification of `parent-frame'"); } - if (p != FRAME_PARENT_FRAME (f) && (p != NULL)) + if (p != FRAME_PARENT_FRAME (f)) { block_input (); - gtk_window_set_transient_for (FRAME_NATIVE_WINDOW (f), - FRAME_NATIVE_WINDOW (p)); - gtk_window_set_attached_to (FRAME_NATIVE_WINDOW (f), - FRAME_GTK_WIDGET (p)); - gtk_window_move (FRAME_NATIVE_WINDOW (f), f->left_pos, f->top_pos); - gtk_window_set_keep_above (FRAME_NATIVE_WINDOW (f), true); + + if (p != NULL) + { + if (FRAME_DISPLAY_INFO (f) != FRAME_DISPLAY_INFO (p)) + error ("Cross display reparent."); + } + + GtkWidget *fixed = FRAME_GTK_WIDGET (f); + + GtkAllocation alloc; + gtk_widget_get_allocation(fixed, &alloc); + g_object_ref (fixed); + + GtkCssProvider *provider = FRAME_X_OUTPUT (f)->border_color_css_provider; + + { + GtkWidget *whbox_of_f = gtk_widget_get_parent (fixed); + gtk_container_remove (GTK_CONTAINER (whbox_of_f), fixed); + + GtkStyleContext *ctxt = gtk_widget_get_style_context (FRAME_WIDGET (f)); + gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (provider)); + + if (FRAME_GTK_OUTER_WIDGET (f)) + { + gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f)); + FRAME_GTK_OUTER_WIDGET (f) = NULL; + FRAME_OUTPUT_DATA (f)->vbox_widget = NULL; + FRAME_OUTPUT_DATA (f)->hbox_widget = NULL; + FRAME_OUTPUT_DATA (f)->menubar_widget = NULL; + FRAME_OUTPUT_DATA (f)->toolbar_widget = NULL; + FRAME_OUTPUT_DATA (f)->ttip_widget = NULL; + FRAME_OUTPUT_DATA (f)->ttip_lbl = NULL; + FRAME_OUTPUT_DATA (f)->ttip_window = NULL; + } + } + + if (p == NULL) + { + xg_create_frame_outer_widgets (f); + pgtk_set_event_handler (f); + gtk_box_pack_start (GTK_BOX (f->output_data.pgtk->hbox_widget), fixed, TRUE, TRUE, 0); + f->output_data.pgtk->preferred_width = alloc.width; + f->output_data.pgtk->preferred_height = alloc.height; + x_wm_set_size_hint (f, 0, 0); + xg_frame_set_char_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, alloc.width), + FRAME_PIXEL_TO_TEXT_HEIGHT (f, alloc.height)); + gtk_widget_queue_resize (FRAME_WIDGET (f)); + gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f)); + } + else + { + GtkWidget *fixed_of_p = FRAME_GTK_WIDGET (p); + gtk_fixed_put (GTK_FIXED (fixed_of_p), fixed, f->left_pos, f->top_pos); + gtk_widget_set_size_request (fixed, alloc.width, alloc.height); + gtk_widget_show_all (fixed); + } + + GtkStyleContext *ctxt = gtk_widget_get_style_context (FRAME_WIDGET (f)); + gtk_style_context_add_provider (ctxt, GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_USER); + + g_object_unref (fixed); + + if (FRAME_GTK_OUTER_WIDGET (f)) { + 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); + } + unblock_input (); fset_parent_frame (f, new_value); @@ -748,6 +898,9 @@ x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) /* doesn't work on wayland. */ PGTK_TRACE ("x_set_z_group"); + if (!FRAME_GTK_OUTER_WIDGET (f)) + return; + if (NILP (new_value)) { gtk_window_set_keep_above (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), @@ -2900,8 +3053,10 @@ pgtk_bitmap_icon (struct frame *f, Lisp_Object file) bool pgtk_text_icon (struct frame *f, const char *icon_name) { - gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), NULL); - gtk_window_set_title (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), icon_name); + if (FRAME_GTK_OUTER_WIDGET (f)) { + gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), NULL); + gtk_window_set_title (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), icon_name); + } return false; } @@ -4392,6 +4547,9 @@ pgtk_judge_scroll_bars (struct frame *f) static void set_fullscreen_state (struct frame *f) { + if (!FRAME_GTK_OUTER_WIDGET (f)) + return; + GtkWindow *widget = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)); switch (f->want_fullscreen) { @@ -4571,24 +4729,27 @@ frame_highlight (struct frame *f) using that same window-manager binary for ever. Let's not crash just because of this (bug#9310). */ + GtkWidget *w = FRAME_WIDGET (f); + char *css = g_strdup_printf ("decoration { border: solid %dpx #%06x; }", f->border_width, - (unsigned int) FRAME_X_OUTPUT (f)-> - border_pixel & 0x00ffffff); - GtkStyleContext *ctxt = - gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f)); + (unsigned int) FRAME_X_OUTPUT (f)->border_pixel & 0x00ffffff); + + GtkStyleContext *ctxt = gtk_widget_get_style_context (w); GtkCssProvider *css_provider = gtk_css_provider_new (); gtk_css_provider_load_from_data (css_provider, css, -1, NULL); gtk_style_context_add_provider (ctxt, GTK_STYLE_PROVIDER (css_provider), GTK_STYLE_PROVIDER_PRIORITY_USER); - g_object_unref (css_provider); g_free (css); GtkCssProvider *old = FRAME_X_OUTPUT (f)->border_color_css_provider; FRAME_X_OUTPUT (f)->border_color_css_provider = css_provider; if (old != NULL) - gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (old)); + { + gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (old)); + g_object_unref (old); + } unblock_input (); gui_update_cursor (f, true); @@ -4605,22 +4766,26 @@ frame_unhighlight (struct frame *f) block_input (); /* Same as above for XSetWindowBorder (bug#9310). */ + GtkWidget *w = FRAME_WIDGET (f); + char *css = g_strdup_printf ("decoration { border: dotted %dpx #ffffff; }", f->border_width); - GtkStyleContext *ctxt = - gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f)); + + GtkStyleContext *ctxt = gtk_widget_get_style_context (w); GtkCssProvider *css_provider = gtk_css_provider_new (); gtk_css_provider_load_from_data (css_provider, css, -1, NULL); gtk_style_context_add_provider (ctxt, GTK_STYLE_PROVIDER (css_provider), GTK_STYLE_PROVIDER_PRIORITY_USER); - g_object_unref (css_provider); g_free (css); GtkCssProvider *old = FRAME_X_OUTPUT (f)->border_color_css_provider; FRAME_X_OUTPUT (f)->border_color_css_provider = css_provider; if (old != NULL) - gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (old)); + { + gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (old)); + g_object_unref (old); + } unblock_input (); gui_update_cursor (f, true); @@ -4793,6 +4958,7 @@ struct pgtk_window_is_of_frame_recursive_t { GdkWindow *window; bool result; + GtkWidget *emacs_gtk_fixed; // stop on emacsgtkfixed other than this. }; static void @@ -4803,15 +4969,19 @@ pgtk_window_is_of_frame_recursive (GtkWidget * widget, gpointer data) if (datap->result) return; + if (EMACS_IS_FIXED (widget) && widget != datap->emacs_gtk_fixed) + return; + if (gtk_widget_get_window (widget) == datap->window) { datap->result = true; return; } - if (GTK_IS_CONTAINER (widget)) + if (GTK_IS_CONTAINER (widget)) { gtk_container_foreach (GTK_CONTAINER (widget), pgtk_window_is_of_frame_recursive, datap); + } } static bool @@ -4820,7 +4990,8 @@ pgtk_window_is_of_frame (struct frame *f, GdkWindow * window) struct pgtk_window_is_of_frame_recursive_t data; data.window = window; data.result = false; - pgtk_window_is_of_frame_recursive (FRAME_GTK_OUTER_WIDGET (f), &data); + data.emacs_gtk_fixed = FRAME_GTK_WIDGET (f); + pgtk_window_is_of_frame_recursive (FRAME_WIDGET (f), &data); return data.result; } @@ -5068,6 +5239,8 @@ pgtk_clear_under_internal_border (struct frame *f) } } +#ifdef HAVE_PGTK + static void print_widget_tree_recursive (GtkWidget * w, gpointer user_data) { @@ -5108,6 +5281,8 @@ print_widget_tree (GtkWidget * w) print_widget_tree_recursive (w, indent); } +#endif + static gboolean pgtk_handle_draw (GtkWidget * widget, cairo_t * cr, gpointer * data) { @@ -5115,7 +5290,9 @@ pgtk_handle_draw (GtkWidget * widget, cairo_t * cr, gpointer * data) PGTK_TRACE ("pgtk_handle_draw"); +#ifdef HAVE_PGTK print_widget_tree (widget); +#endif GdkWindow *win = gtk_widget_get_window (widget); @@ -6385,11 +6562,11 @@ pgtk_set_event_handler (struct frame *f) NULL); g_signal_connect (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), "delete-event", G_CALLBACK (delete_event), NULL); - g_signal_connect (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), "map-event", - G_CALLBACK (map_event), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), "event", G_CALLBACK (pgtk_handle_event), NULL); + g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "map-event", + G_CALLBACK (map_event), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "size-allocate", G_CALLBACK (size_allocate), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "key-press-event", diff --git a/src/pgtkterm.h b/src/pgtkterm.h index cff16332921..ad66039648b 100644 --- a/src/pgtkterm.h +++ b/src/pgtkterm.h @@ -428,6 +428,9 @@ enum #define FRAME_FONT(f) (FRAME_X_OUTPUT(f)->font) #define FRAME_GTK_OUTER_WIDGET(f) (FRAME_X_OUTPUT(f)->widget) #define FRAME_GTK_WIDGET(f) (FRAME_X_OUTPUT(f)->edit_widget) +#define FRAME_WIDGET(f) (FRAME_GTK_OUTER_WIDGET(f) ? \ + FRAME_GTK_OUTER_WIDGET(f) : \ + FRAME_GTK_WIDGET(f)) /* aliases */ #define FRAME_PGTK_VIEW(f) FRAME_GTK_WIDGET(f)