+/* Check for special colors used in face spec for region face.
+ The colors are fetched from the Gtk+ theme.
+ Return true if color was found, false if not. */
+
+bool
+xg_check_special_colors (struct frame *f,
+ const char *color_name,
+ XColor *color)
+{
+ bool success_p = 0;
+ bool get_bg = strcmp ("gtk_selection_bg_color", color_name) == 0;
+ bool get_fg = !get_bg && strcmp ("gtk_selection_fg_color", color_name) == 0;
+
+ if (! FRAME_GTK_WIDGET (f) || ! (get_bg || get_fg))
+ return success_p;
+
+ block_input ();
+ {
+#ifdef HAVE_GTK3
+ GtkStyleContext *gsty
+ = gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
+ GdkRGBA col;
+ char buf[sizeof "rgbi://" + 3 * (DBL_MAX_10_EXP + sizeof "-1.000000" - 1)];
+ int state = GTK_STATE_FLAG_SELECTED|GTK_STATE_FLAG_FOCUSED;
+ if (get_fg)
+ gtk_style_context_get_color (gsty, state, &col);
+ else
+ gtk_style_context_get_background_color (gsty, state, &col);
+
+ sprintf (buf, "rgbi:%lf/%lf/%lf", col.red, col.green, col.blue);
+ success_p = (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
+ buf, color)
+ != 0);
+#else
+ GtkStyle *gsty = gtk_widget_get_style (FRAME_GTK_WIDGET (f));
+ GdkColor *grgb = get_bg
+ ? &gsty->bg[GTK_STATE_SELECTED]
+ : &gsty->fg[GTK_STATE_SELECTED];
+
+ color->red = grgb->red;
+ color->green = grgb->green;
+ color->blue = grgb->blue;
+ color->pixel = grgb->pixel;
+ success_p = 1;
+#endif
+
+ }
+ unblock_input ();
+ return success_p;
+}
+
+
+\f
+/***********************************************************************
+ Tooltips
+ ***********************************************************************/
+/* Gtk+ calls this callback when the parent of our tooltip dummy changes.
+ We use that to pop down the tooltip. This happens if Gtk+ for some
+ reason wants to change or hide the tooltip. */
+
+#ifdef USE_GTK_TOOLTIP
+
+static void
+hierarchy_ch_cb (GtkWidget *widget,
+ GtkWidget *previous_toplevel,
+ gpointer user_data)
+{
+ FRAME_PTR f = (FRAME_PTR) user_data;
+ struct x_output *x = f->output_data.x;
+ GtkWidget *top = gtk_widget_get_toplevel (x->ttip_lbl);
+
+ if (! top || ! GTK_IS_WINDOW (top))
+ gtk_widget_hide (previous_toplevel);
+}
+
+/* Callback called when Gtk+ thinks a tooltip should be displayed.
+ We use it to get the tooltip window and the tooltip widget so
+ we can manipulate the ourselves.
+
+ Return FALSE ensures that the tooltip is not shown. */
+
+static gboolean
+qttip_cb (GtkWidget *widget,
+ gint xpos,
+ gint ypos,
+ gboolean keyboard_mode,
+ GtkTooltip *tooltip,
+ gpointer user_data)
+{
+ FRAME_PTR f = (FRAME_PTR) user_data;
+ struct x_output *x = f->output_data.x;
+ if (x->ttip_widget == NULL)
+ {
+ GtkWidget *p;
+ GList *list, *iter;
+
+ g_object_set (G_OBJECT (widget), "has-tooltip", FALSE, NULL);
+ x->ttip_widget = tooltip;
+ g_object_ref (G_OBJECT (tooltip));
+ x->ttip_lbl = gtk_label_new ("");
+ g_object_ref (G_OBJECT (x->ttip_lbl));
+ gtk_tooltip_set_custom (tooltip, x->ttip_lbl);
+ x->ttip_window = GTK_WINDOW (gtk_widget_get_toplevel (x->ttip_lbl));
+
+ /* Change stupid Gtk+ default line wrapping. */
+ p = gtk_widget_get_parent (x->ttip_lbl);
+ list = gtk_container_get_children (GTK_CONTAINER (p));
+ for (iter = list; iter; iter = g_list_next (iter))
+ {
+ GtkWidget *w = GTK_WIDGET (iter->data);
+ if (GTK_IS_LABEL (w))
+ gtk_label_set_line_wrap (GTK_LABEL (w), FALSE);
+ }
+ g_list_free (list);
+
+ /* ATK needs an empty title for some reason. */
+ gtk_window_set_title (x->ttip_window, "");
+ /* Realize so we can safely get screen later on. */
+ gtk_widget_realize (GTK_WIDGET (x->ttip_window));
+ gtk_widget_realize (x->ttip_lbl);
+
+ g_signal_connect (x->ttip_lbl, "hierarchy-changed",
+ G_CALLBACK (hierarchy_ch_cb), f);
+ }
+ return FALSE;
+}
+
+#endif /* USE_GTK_TOOLTIP */
+
+/* Prepare a tooltip to be shown, i.e. calculate WIDTH and HEIGHT.
+ Return true if a system tooltip is available. */
+
+bool
+xg_prepare_tooltip (FRAME_PTR f,
+ Lisp_Object string,
+ int *width,
+ int *height)
+{
+#ifndef USE_GTK_TOOLTIP
+ return 0;
+#else
+ struct x_output *x = f->output_data.x;
+ GtkWidget *widget;
+ GdkWindow *gwin;
+ GdkScreen *screen;
+ GtkSettings *settings;
+ gboolean tt_enabled = TRUE;
+ GtkRequisition req;
+ Lisp_Object encoded_string;
+
+ if (!x->ttip_lbl) return 0;
+
+ block_input ();
+ encoded_string = ENCODE_UTF_8 (string);
+ widget = GTK_WIDGET (x->ttip_lbl);
+ gwin = gtk_widget_get_window (GTK_WIDGET (x->ttip_window));
+ screen = gdk_window_get_screen (gwin);
+ settings = gtk_settings_get_for_screen (screen);
+ g_object_get (settings, "gtk-enable-tooltips", &tt_enabled, NULL);
+ if (tt_enabled)
+ {
+ g_object_set (settings, "gtk-enable-tooltips", FALSE, NULL);
+ /* Record that we disabled it so it can be enabled again. */
+ g_object_set_data (G_OBJECT (x->ttip_window), "restore-tt",
+ (gpointer)f);
+ }
+
+ /* Prevent Gtk+ from hiding tooltip on mouse move and such. */
+ g_object_set_data (G_OBJECT
+ (gtk_widget_get_display (GTK_WIDGET (x->ttip_window))),
+ "gdk-display-current-tooltip", NULL);
+
+ /* Put our dummy widget in so we can get callbacks for unrealize and
+ hierarchy-changed. */
+ gtk_tooltip_set_custom (x->ttip_widget, widget);
+ gtk_tooltip_set_text (x->ttip_widget, SSDATA (encoded_string));
+ gtk_widget_get_preferred_size (GTK_WIDGET (x->ttip_window), NULL, &req);
+ if (width) *width = req.width;
+ if (height) *height = req.height;
+
+ unblock_input ();
+
+ return 1;
+#endif /* USE_GTK_TOOLTIP */
+}
+
+/* Show the tooltip at ROOT_X and ROOT_Y.
+ xg_prepare_tooltip must have been called before this function. */
+
+void
+xg_show_tooltip (FRAME_PTR f, int root_x, int root_y)
+{
+#ifdef USE_GTK_TOOLTIP
+ struct x_output *x = f->output_data.x;
+ if (x->ttip_window)
+ {
+ block_input ();
+ gtk_window_move (x->ttip_window, root_x, root_y);
+ gtk_widget_show_all (GTK_WIDGET (x->ttip_window));
+ unblock_input ();
+ }
+#endif
+}
+
+/* Hide tooltip if shown. Do nothing if not shown.
+ Return true if tip was hidden, false if not (i.e. not using
+ system tooltips). */
+
+bool
+xg_hide_tooltip (FRAME_PTR f)
+{
+ bool ret = 0;
+#ifdef USE_GTK_TOOLTIP
+ if (f->output_data.x->ttip_window)
+ {
+ GtkWindow *win = f->output_data.x->ttip_window;
+ block_input ();
+ gtk_widget_hide (GTK_WIDGET (win));
+
+ if (g_object_get_data (G_OBJECT (win), "restore-tt"))
+ {
+ GdkWindow *gwin = gtk_widget_get_window (GTK_WIDGET (win));
+ GdkScreen *screen = gdk_window_get_screen (gwin);
+ GtkSettings *settings = gtk_settings_get_for_screen (screen);
+ g_object_set (settings, "gtk-enable-tooltips", TRUE, NULL);
+ }
+ unblock_input ();
+
+ ret = 1;
+ }
+#endif
+ return ret;
+}