From 36d60b1ae51e6c82fb7a46f195007275fd47d6df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberts=20Muktup=C4=81vels?= Date: Sat, 4 Sep 2021 14:41:56 +0300 Subject: tooltip: request client side decorations https://gitlab.gnome.org/GNOME/metacity/-/issues/25 --- configure.ac | 6 +- src/Makefile.am | 2 + src/ui/meta-request-csd.c | 294 ++++++++++++++++++++++++++++++++++++++++++++++ src/ui/meta-request-csd.h | 29 +++++ src/ui/meta-tooltip.c | 5 +- 5 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 src/ui/meta-request-csd.c create mode 100644 src/ui/meta-request-csd.h diff --git a/configure.ac b/configure.ac index 04aafb94..6dba484d 100644 --- a/configure.ac +++ b/configure.ac @@ -90,7 +90,7 @@ dnl Check for required packages dnl ************************************************************************** GLIB_REQUIRED_VERSION=2.67.3 -GTK_REQUIRED_VERSION=3.22.0 +GTK_REQUIRED_VERSION=3.24.6 PANGO_REQUIRED_VERSION=1.2.0 XCOMPOSITE_REQUIRED_VERSION=0.3 @@ -342,6 +342,10 @@ if test x"$ZENITY" = xno; then AC_MSG_ERROR([zenity not found in your path - needed for dialogs]) fi +AC_SEARCH_LIBS([dlsym], [dl], [], [ + AC_MSG_ERROR([unable to find the dlsym() function]) +]) + dnl ************************************************************************** dnl Check for Vulkan support dnl ************************************************************************** diff --git a/src/Makefile.am b/src/Makefile.am index 4aa3fdae..37da0f52 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -121,6 +121,8 @@ metacity_SOURCES = \ ui/menu.h \ ui/metaaccellabel.c \ ui/metaaccellabel.h \ + ui/meta-request-csd.c \ + ui/meta-request-csd.h \ ui/meta-tooltip.c \ ui/meta-tooltip.h \ ui/resizepopup.c \ diff --git a/src/ui/meta-request-csd.c b/src/ui/meta-request-csd.c new file mode 100644 index 00000000..3670397b --- /dev/null +++ b/src/ui/meta-request-csd.c @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2021 Alberts Muktupāvels + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define _GNU_SOURCE + +#include "config.h" +#include "meta-request-csd.h" + +#include + +typedef GType (* RegisterStaticSimple) (GType parent_type, + const gchar *type_name, + guint class_size, + GClassInitFunc class_init, + guint instance_size, + GInstanceInitFunc instance_init, + GTypeFlags flags); + +typedef gint (* AddInstancePrivateFunc) (GType class_type, + gsize private_size); + +typedef struct _GtkMnemnonicHash GtkMnemonicHash; +typedef struct _GtkCssNode GtkCssNode; + +struct _GtkWindowPrivate +{ + GtkMnemonicHash *mnemonic_hash; + + GtkWidget *attach_widget; + GtkWidget *default_widget; + GtkWidget *initial_focus; + GtkWidget *focus_widget; + GtkWindow *transient_parent; + GtkWindowGeometryInfo *geometry_info; + GtkWindowGroup *group; + GdkScreen *screen; + GdkDisplay *display; + GtkApplication *application; + + GList *popovers; + + GdkModifierType mnemonic_modifier; + + gchar *startup_id; + gchar *title; + gchar *wmclass_class; + gchar *wmclass_name; + gchar *wm_role; + + guint keys_changed_handler; + guint delete_event_handler; + + guint32 initial_timestamp; + + guint16 configure_request_count; + + guint mnemonics_display_timeout_id; + + gint scale; + + gint title_height; + GtkWidget *title_box; + GtkWidget *titlebar; + GtkWidget *popup_menu; + + GdkWindow *border_window[8]; + gint initial_fullscreen_monitor; + guint edge_constraints; + + guint need_default_position : 1; + guint need_default_size : 1; + + guint above_initially : 1; + guint accept_focus : 1; + guint below_initially : 1; + guint builder_visible : 1; + guint configure_notify_received : 1; + guint decorated : 1; + guint deletable : 1; + guint destroy_with_parent : 1; + guint focus_on_map : 1; + guint fullscreen_initially : 1; + guint has_focus : 1; + guint has_user_ref_count : 1; + guint has_toplevel_focus : 1; + guint hide_titlebar_when_maximized : 1; + guint iconify_initially : 1; + guint is_active : 1; + guint maximize_initially : 1; + guint mnemonics_visible : 1; + guint mnemonics_visible_set : 1; + guint focus_visible : 1; + guint modal : 1; + guint position : 3; + guint resizable : 1; + guint skips_pager : 1; + guint skips_taskbar : 1; + guint stick_initially : 1; + guint transient_parent_group : 1; + guint type : 4; + guint urgent : 1; + guint gravity : 5; + guint csd_requested : 1; + guint client_decorated : 1; + guint use_client_shadow : 1; + guint maximized : 1; + guint fullscreen : 1; + guint tiled : 1; + guint unlimited_guessed_size_x : 1; + guint unlimited_guessed_size_y : 1; + guint force_resize : 1; + guint fixate_size : 1; + + guint use_subsurface : 1; + + GdkWindowTypeHint type_hint; + + GtkGesture *multipress_gesture; + GtkGesture *drag_gesture; + + GdkWindow *hardcoded_window; + + GtkCssNode *decoration_node; +}; + +static RegisterStaticSimple register_static_simple_orig_func = NULL; +static RegisterStaticSimple register_static_simple_func = NULL; +static GType gtk_window_type = 0; + +static AddInstancePrivateFunc add_instance_private_orig_func = NULL; +static AddInstancePrivateFunc add_instance_private_func = NULL; +static gsize gtk_window_private_size = 0; + +static GType +find_gtk_window_type (GType parent_type, + const gchar *type_name, + guint class_size, + GClassInitFunc class_init, + guint instance_size, + GInstanceInitFunc instance_init, + GTypeFlags flags) +{ + GType type_id; + + type_id = register_static_simple_orig_func (parent_type, + type_name, + class_size, + class_init, + instance_size, + instance_init, + flags); + + if (g_strcmp0 (type_name, "GtkWindow") == 0) + { + register_static_simple_func = register_static_simple_orig_func; + gtk_window_type = type_id; + } + + return type_id; +} + +static gint +find_gtk_window_private_size (GType class_type, + gsize private_size) +{ + if (class_type == gtk_window_type) + { + add_instance_private_func = add_instance_private_orig_func; + gtk_window_private_size = private_size; + } + + return add_instance_private_orig_func (class_type, private_size); +} + +__attribute__((constructor)) +static void +add_instance_private_init (void) +{ + void *func; + + func = dlsym (RTLD_NEXT, "g_type_register_static_simple"); + register_static_simple_orig_func = func; + register_static_simple_func = find_gtk_window_type; + + func = dlsym (RTLD_NEXT, "g_type_add_instance_private"); + add_instance_private_orig_func = func; + add_instance_private_func = find_gtk_window_private_size; +} + +GType +g_type_register_static_simple (GType parent_type, + const gchar *type_name, + guint class_size, + GClassInitFunc class_init, + guint instance_size, + GInstanceInitFunc instance_init, + GTypeFlags flags) +{ + return register_static_simple_func (parent_type, + type_name, + class_size, + class_init, + instance_size, + instance_init, + flags); +} + +gint +g_type_add_instance_private (GType class_type, + gsize private_size) +{ + return add_instance_private_func (class_type, private_size); +} + +static gboolean +check_gtk_window_private (void) +{ + static gboolean ret = FALSE; + static gboolean checked = FALSE; + + if (!checked) + { + GtkWindow *window; + + if (gtk_window_private_size < sizeof (GtkWindowPrivate)) + { + checked = TRUE; + return FALSE; + } + + window = g_object_new (GTK_TYPE_WINDOW, + "type", GTK_WINDOW_POPUP, + "type-hint", GDK_WINDOW_TYPE_HINT_TOOLTIP, + NULL); + + while (TRUE) + { + GtkWindowPrivate *priv; + GtkWidget *titlebar; + + priv = window->priv; + + if (priv->type != GTK_WINDOW_POPUP || + priv->type_hint != GDK_WINDOW_TYPE_HINT_TOOLTIP) + break; + + gtk_window_set_gravity (window, GDK_GRAVITY_STATIC); + + if (priv->gravity != GDK_GRAVITY_STATIC) + break; + + titlebar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_window_set_titlebar (window, titlebar); + + if (priv->title_box != titlebar || + !priv->client_decorated) + break; + + if (priv->csd_requested) + break; + + ret = TRUE; + break; + } + + gtk_widget_destroy (GTK_WIDGET (window)); + checked = TRUE; + } + + return ret; +} + +void +meta_request_csd (GtkWindow *window) +{ + if (!check_gtk_window_private ()) + return; + + window->priv->csd_requested = TRUE; +} diff --git a/src/ui/meta-request-csd.h b/src/ui/meta-request-csd.h new file mode 100644 index 00000000..11ecb082 --- /dev/null +++ b/src/ui/meta-request-csd.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 Alberts Muktupāvels + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef META_REQUEST_CSD_H +#define META_REQUEST_CSD_H + +#include + +G_BEGIN_DECLS + +void meta_request_csd (GtkWindow *window); + +G_END_DECLS + +#endif diff --git a/src/ui/meta-tooltip.c b/src/ui/meta-tooltip.c index f338b8b0..270b1166 100644 --- a/src/ui/meta-tooltip.c +++ b/src/ui/meta-tooltip.c @@ -16,9 +16,10 @@ */ #include "config.h" - #include "meta-tooltip.h" +#include "meta-request-csd.h" + struct _MetaTooltip { GtkWindow parent; @@ -85,6 +86,8 @@ meta_tooltip_init (MetaTooltip *tooltip) gtk_label_set_line_wrap (GTK_LABEL (tooltip->label), TRUE); gtk_label_set_max_width_chars (GTK_LABEL (tooltip->label), 70); + + meta_request_csd (GTK_WINDOW (tooltip)); } GtkWidget * -- cgit v1.2.1