summaryrefslogtreecommitdiff
path: root/src/pgtkterm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pgtkterm.c')
-rw-r--r--src/pgtkterm.c307
1 files changed, 242 insertions, 65 deletions
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 <https://www.gnu.org/licenses/>. */
#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",