From abd802add388760345c74029be3b036f19f253be Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Sun, 12 Nov 2023 17:36:49 +0800 Subject: [PATCH 01/50] meson: disable all build target for now We disable all build target and enable them when the gtk4 port is considered finished. Signed-off-by: Qiu Wenbo --- help/meson.build | 1 - meson.build | 19 ++++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/help/meson.build b/help/meson.build index 18969cbbf..895ccfceb 100644 --- a/help/meson.build +++ b/help/meson.build @@ -1,4 +1,3 @@ -enable_user_doc = get_option('user_doc') if enable_gtk_doc glib_prefix = glib_dep.get_variable(pkgconfig: 'prefix') gtk_prefix = gtk_dep.get_variable(pkgconfig: 'prefix') diff --git a/meson.build b/meson.build index 662433701..930acab54 100644 --- a/meson.build +++ b/meson.build @@ -206,6 +206,7 @@ endif # *** GObject Introspection *** enable_introspection = get_option('introspection') +enable_user_doc = get_option('user_doc') enable_gtk_doc = get_option('gtk_doc') if enable_introspection dependency('gobject-introspection-1.0', version: '>= 1.0') @@ -430,31 +431,31 @@ mime_types_conf.set('EVINCE_MIME_TYPES', ';'.join(evince_mime_types)) mime_types_conf.set('PACKAGE_ICON_NAME', app_id) subdir('cut-n-paste') -subdir('libdocument') -subdir('backend') -subdir('libview') -subdir('libmisc') -subdir('properties') +#subdir('libdocument') +#subdir('backend') +#subdir('libview') +#subdir('libmisc') +#subdir('properties') # *** Document Viewer *** enable_viewer = get_option('viewer') if enable_viewer - subdir('shell') + #subdir('shell') endif subdir('po') -subdir('help') +#subdir('help') # *** Thumbnailer *** enable_thumbnailer = get_option('thumbnailer') if enable_thumbnailer - subdir('thumbnailer') + #subdir('thumbnailer') endif # Print Previewer enable_previewer = get_option('previewer') if enable_previewer - subdir('previewer') + #subdir('previewer') endif subdir('data') -- GitLab From 7628f58fee59c4078817c4ddcbea813f6bd86e0f Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Tue, 3 Aug 2021 10:04:44 +0800 Subject: [PATCH 02/50] meson: Move to gtk4 related dependecies Signed-off-by: Qiu Wenbo --- libdocument/meson.build | 4 ++-- libview/meson.build | 4 ++-- meson.build | 15 ++++++++------- previewer/meson.build | 2 +- shell/meson.build | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/libdocument/meson.build b/libdocument/meson.build index 16e2c9182..5379a88dd 100644 --- a/libdocument/meson.build +++ b/libdocument/meson.build @@ -181,11 +181,11 @@ pkg.generate( # GObject Introspection if enable_introspection incs = [ - 'Gdk-3.0', + 'Gdk-4.0', 'GdkPixbuf-2.0', 'Gio-2.0', 'GLib-2.0', - 'Gtk-3.0', + 'Gtk-4.0', ] libevdocument_gir = gnome.generate_gir( diff --git a/libview/meson.build b/libview/meson.build index da9eb6a0b..53fc3f351 100644 --- a/libview/meson.build +++ b/libview/meson.build @@ -111,12 +111,12 @@ pkg.generate( # GObject Introspection if enable_introspection incs = [ - 'Gdk-3.0', + 'Gdk-4.0', 'GdkPixbuf-2.0', 'Gio-2.0', 'GLib-2.0', 'GObject-2.0', - 'Gtk-3.0', + 'Gtk-4.0', libevdocument_gir[0], ] diff --git a/meson.build b/meson.build index 930acab54..0bed24bd7 100644 --- a/meson.build +++ b/meson.build @@ -137,8 +137,9 @@ po_dir = join_paths(source_root, 'po') top_inc = include_directories('.') glib_req_version = '>= 2.75.0' -gtk_req_version = '>= 3.22.0' -hdy_req_version = '>= 1.5.0' +gtk_req_version = '>= 4.6.0' +libaw_req_version = '>= 1.2.0' +libxml_req_version = '>= 2.5.0' exempi_req_version = '>= 2.0' gdk_pixbuf_dep = dependency('gdk-pixbuf-2.0', version: '>= 2.40.0') @@ -148,9 +149,9 @@ config_h.set_quoted('EXTRA_GDK_PIXBUF_LOADERS_DIR', gio_dep = dependency('gio-2.0', version: glib_req_version) glib_dep = dependency('glib-2.0', version: glib_req_version) gmodule_dep = dependency('gmodule-2.0') -gtk_dep = dependency('gtk+-3.0', version: gtk_req_version) +gtk_dep = dependency('gtk4', version: gtk_req_version) gthread_dep = dependency('gthread-2.0', version: glib_req_version) -hdy_dep = dependency('libhandy-1', version: hdy_req_version) +libaw_dep = dependency('libadwaita-1', version: libaw_req_version) exempi_dep = dependency('exempi-2.0', version: exempi_req_version) m_dep = cc.find_library('m') @@ -167,7 +168,7 @@ if ev_platform == 'gnome' # *** Nautilus property page build *** enable_nautilus = get_option('nautilus') if enable_nautilus - libnautilus_extension_dep = dependency('libnautilus-extension', version: ['>= 3.28.0', '< 42.20']) + libnautilus_extension_dep = dependency('libnautilus-extension-4', version: ['>= 43']) nautilus_extension_dir = libnautilus_extension_dep.get_variable(pkgconfig: 'extensiondir', pkgconfig_define: ['libdir', ev_libdir]) endif @@ -185,7 +186,7 @@ if ev_platform == 'gnome' config_h.set('WITH_KEYRING', enable_keyring) # GKT+ Unix Printing - gtk_unix_print_dep = dependency('gtk+-unix-print-3.0', version: gtk_req_version, required: get_option('gtk_unix_print')) + gtk_unix_print_dep = dependency('gtk4-unix-print', version: gtk_req_version, required: get_option('gtk_unix_print')) enable_gtk_unix_print = gtk_unix_print_dep.found() config_h.set10('GTKUNIXPRINT_ENABLED', enable_gtk_unix_print) @@ -216,7 +217,7 @@ else endif # *** GNOME Desktop (Thumbnail cache) *** -gnome_desktop_dep = dependency('gnome-desktop-3.0', required: get_option('thumbnail_cache')) +gnome_desktop_dep = dependency('gnome-desktop-4', required: get_option('thumbnail_cache')) enable_thumbnail_cache = gdk_pixbuf_dep.found() and gnome_desktop_dep.found() config_h.set('HAVE_LIBGNOME_DESKTOP', enable_thumbnail_cache) diff --git a/previewer/meson.build b/previewer/meson.build index 4d8a8f81d..e0499361f 100644 --- a/previewer/meson.build +++ b/previewer/meson.build @@ -17,7 +17,7 @@ previewer_deps = [ libevdocument_dep, libevmisc_dep, libevview_dep, - hdy_dep + libaw_dep ] if enable_gtk_unix_print diff --git a/shell/meson.build b/shell/meson.build index 6497c8c2c..cc0464d88 100644 --- a/shell/meson.build +++ b/shell/meson.build @@ -43,7 +43,7 @@ evince_sources += gnome.compile_resources( evince_deps = [ gdk_pixbuf_dep, gnome_desktop_dep, - hdy_dep, + libaw_dep, libevmisc_dep, libevdocument_dep, libevview_dep, -- GitLab From a40865f6454b300c332d5c69e8774c813d694a8f Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Wed, 12 Jul 2023 15:27:50 +0800 Subject: [PATCH 03/50] cut-n-paste: Remove libgd The following GTK4 port simply don't use libgd. So we remove it before the actual port. Signed-off-by: Qiu Wenbo --- cut-n-paste/libgd/gd-icon-utils.c | 394 ------------- cut-n-paste/libgd/gd-icon-utils.h | 49 -- cut-n-paste/libgd/gd-two-lines-renderer.c | 643 ---------------------- cut-n-paste/libgd/gd-two-lines-renderer.h | 45 -- cut-n-paste/libgd/meson.build | 22 - cut-n-paste/meson.build | 1 - shell/meson.build | 1 - 7 files changed, 1155 deletions(-) delete mode 100644 cut-n-paste/libgd/gd-icon-utils.c delete mode 100644 cut-n-paste/libgd/gd-icon-utils.h delete mode 100644 cut-n-paste/libgd/gd-two-lines-renderer.c delete mode 100644 cut-n-paste/libgd/gd-two-lines-renderer.h delete mode 100644 cut-n-paste/libgd/meson.build diff --git a/cut-n-paste/libgd/gd-icon-utils.c b/cut-n-paste/libgd/gd-icon-utils.c deleted file mode 100644 index 6c9dd4015..000000000 --- a/cut-n-paste/libgd/gd-icon-utils.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (c) 2011, 2012, 2015, 2016 Red Hat, Inc. - * - * Gnome Documents 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. - * - * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Author: Cosimo Cecchi - * - */ - -#include "gd-icon-utils.h" - -#include -#include -#include - -#define _BG_MIN_SIZE 20 -#define _EMBLEM_MIN_SIZE 8 - -/** - * gd_copy_image_surface: - * @surface: - * - * Returns: (transfer full): - */ -cairo_surface_t * -gd_copy_image_surface (cairo_surface_t *surface) -{ - cairo_surface_t *copy = NULL; - cairo_t *cr; - gdouble scale_x; - gdouble scale_y; - - copy = cairo_surface_create_similar_image (surface, CAIRO_FORMAT_ARGB32, - cairo_image_surface_get_width (surface), - cairo_image_surface_get_height (surface)); - cairo_surface_get_device_scale (surface, &scale_x, &scale_y); - cairo_surface_set_device_scale (copy, scale_x, scale_y); - - cr = cairo_create (copy); - cairo_set_source_surface (cr, surface, 0, 0); - cairo_paint (cr); - cairo_destroy (cr); - - return copy; -} - -/** - * gd_create_surface_with_counter: - * @widget: - * @base: - * @number: - * - * Returns: (transfer full): - */ -cairo_surface_t * -gd_create_surface_with_counter (GtkWidget *widget, cairo_surface_t *base, gint number) -{ - GtkStyleContext *context; - cairo_t *cr, *emblem_cr; - cairo_surface_t *emblem_surface; - cairo_surface_t *surface; - gint height; - gint height_scaled; - gint width; - gint width_scaled; - gint layout_width, layout_height; - gint emblem_size; - gint emblem_size_scaled; - gdouble scale; - gdouble scale_x; - gdouble scale_y; - gchar *str; - PangoLayout *layout; - PangoAttrList *attr_list; - PangoAttribute *attr; - PangoFontDescription *desc; - GdkRGBA color; - - context = gtk_widget_get_style_context (GTK_WIDGET (widget)); - gtk_style_context_save (context); - gtk_style_context_add_class (context, "documents-counter"); - - width_scaled = cairo_image_surface_get_width (base); - height_scaled = cairo_image_surface_get_height (base); - cairo_surface_get_device_scale (base, &scale_x, &scale_y); - - width = width_scaled / (gint) floor (scale_x), - height = height_scaled / (gint) floor (scale_y); - - surface = cairo_surface_create_similar_image (base, CAIRO_FORMAT_ARGB32, - width_scaled, height_scaled); - cairo_surface_set_device_scale (surface, scale_x, scale_y); - - cr = cairo_create (surface); - cairo_set_source_surface (cr, base, 0, 0); - cairo_paint (cr); - - emblem_size_scaled = MIN (width_scaled / 2, height_scaled / 2); - emblem_size = MIN (width / 2, height / 2); - - emblem_surface = cairo_surface_create_similar_image (base, CAIRO_FORMAT_ARGB32, - emblem_size_scaled, emblem_size_scaled); - cairo_surface_set_device_scale (emblem_surface, scale_x, scale_y); - - emblem_cr = cairo_create (emblem_surface); - gtk_render_background (context, emblem_cr, - 0, 0, emblem_size, emblem_size); - - if (number > 99) - number = 99; - if (number < -99) - number = -99; - - str = g_strdup_printf ("%d", number); - layout = gtk_widget_create_pango_layout (GTK_WIDGET (widget), str); - g_free (str); - - pango_layout_get_pixel_size (layout, &layout_width, &layout_height); - - /* scale the layout to be 0.5 of the size still available for drawing */ - scale = (emblem_size * 0.50) / (MAX (layout_width, layout_height)); - attr_list = pango_attr_list_new (); - - attr = pango_attr_scale_new (scale); - pango_attr_list_insert (attr_list, attr); - pango_layout_set_attributes (layout, attr_list); - - gtk_style_context_get (context, GTK_STATE_FLAG_NORMAL, "font", &desc, NULL); - pango_layout_set_font_description (layout, desc); - pango_font_description_free (desc); - - gtk_style_context_get_color (context, 0, &color); - gdk_cairo_set_source_rgba (emblem_cr, &color); - - /* update these values */ - pango_layout_get_pixel_size (layout, &layout_width, &layout_height); - - cairo_move_to (emblem_cr, - emblem_size / 2 - layout_width / 2, - emblem_size / 2 - layout_height / 2); - - pango_cairo_show_layout (emblem_cr, layout); - - g_object_unref (layout); - pango_attr_list_unref (attr_list); - cairo_destroy (emblem_cr); - - cairo_set_source_surface (cr, emblem_surface, - width - emblem_size, height - emblem_size); - cairo_paint (cr); - cairo_destroy (cr); - - cairo_surface_destroy (emblem_surface); - gtk_style_context_restore (context); - - return surface; -} - -/** - * gd_create_symbolic_icon_for_scale: - * @name: - * @base_size: - * @scale: - * - * Returns: (transfer full): - */ -GIcon * -gd_create_symbolic_icon_for_scale (const gchar *name, - gint base_size, - gint scale) -{ - gchar *symbolic_name; - GIcon *icon, *retval = NULL; - cairo_surface_t *icon_surface; - cairo_surface_t *surface; - cairo_t *cr; - GtkStyleContext *style; - GtkWidgetPath *path; - GdkPixbuf *pixbuf; - GtkIconTheme *theme; - GtkIconInfo *info; - gint bg_size; - gint emblem_size; - gint total_size; - gint total_size_scaled; - - total_size = base_size / 2; - total_size_scaled = total_size * scale; - - bg_size = MAX (total_size / 2, _BG_MIN_SIZE); - emblem_size = MAX (bg_size - 8, _EMBLEM_MIN_SIZE); - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, total_size_scaled, total_size_scaled); - cairo_surface_set_device_scale (surface, (gdouble) scale, (gdouble) scale); - cr = cairo_create (surface); - - style = gtk_style_context_new (); - - path = gtk_widget_path_new (); - gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW); - gtk_style_context_set_path (style, path); - gtk_widget_path_unref (path); - - gtk_style_context_add_class (style, "documents-icon-bg"); - - gtk_render_background (style, cr, (total_size - bg_size) / 2, (total_size - bg_size) / 2, bg_size, bg_size); - - symbolic_name = g_strconcat (name, "-symbolic", NULL); - icon = g_themed_icon_new_with_default_fallbacks (symbolic_name); - g_free (symbolic_name); - - theme = gtk_icon_theme_get_default(); - info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon, emblem_size, scale, - GTK_ICON_LOOKUP_FORCE_SIZE); - g_object_unref (icon); - - if (info == NULL) - goto out; - - pixbuf = gtk_icon_info_load_symbolic_for_context (info, style, NULL, NULL); - g_object_unref (info); - - if (pixbuf == NULL) - goto out; - - icon_surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, NULL); - g_object_unref (pixbuf); - - gtk_render_icon_surface (style, cr, icon_surface, (total_size - emblem_size) / 2, (total_size - emblem_size) / 2); - cairo_surface_destroy (icon_surface); - - retval = G_ICON (gdk_pixbuf_get_from_surface (surface, 0, 0, total_size_scaled, total_size_scaled)); - - out: - g_object_unref (style); - cairo_surface_destroy (surface); - cairo_destroy (cr); - - return retval; -} - -/** - * gd_create_symbolic_icon: - * @name: - * @base_size: - * - * Returns: (transfer full): - */ -GIcon * -gd_create_symbolic_icon (const gchar *name, - gint base_size) -{ - return gd_create_symbolic_icon_for_scale (name, base_size, 1); -} - -/** - * gd_embed_surface_in_frame: - * @source_image: - * @frame_image_url: - * @slice_width: - * @border_width: - * - * Returns: (transfer full): - */ -cairo_surface_t * -gd_embed_surface_in_frame (cairo_surface_t *source_image, - const gchar *frame_image_url, - GtkBorder *slice_width, - GtkBorder *border_width) -{ - cairo_surface_t *surface; - cairo_t *cr; - int source_width, source_height; - gchar *css_str; - GtkCssProvider *provider; - GtkStyleContext *context; - GError *error = NULL; - GtkWidgetPath *path; - gdouble scale_x, scale_y; - - cairo_surface_get_device_scale (source_image, &scale_x, &scale_y); - - source_width = cairo_image_surface_get_width (source_image) / (gint) floor (scale_x), - source_height = cairo_image_surface_get_height (source_image) / (gint) floor (scale_y); - - css_str = g_strdup_printf (".embedded-image { border-image: url(\"%s\") %d %d %d %d / %dpx %dpx %dpx %dpx }", - frame_image_url, - slice_width->top, slice_width->right, slice_width->bottom, slice_width->left, - border_width->top, border_width->right, border_width->bottom, border_width->left); - provider = gtk_css_provider_new (); - gtk_css_provider_load_from_data (provider, css_str, -1, &error); - - if (error != NULL) - { - g_warning ("Unable to create the thumbnail frame image: %s", error->message); - g_error_free (error); - g_free (css_str); - - return g_object_ref (source_image); - } - - surface = cairo_surface_create_similar (source_image, - CAIRO_CONTENT_COLOR_ALPHA, - source_width, source_height); - cr = cairo_create (surface); - - context = gtk_style_context_new (); - path = gtk_widget_path_new (); - gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW); - - gtk_style_context_set_path (context, path); - gtk_style_context_add_provider (context, - GTK_STYLE_PROVIDER (provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - - cairo_save (cr); - cairo_rectangle (cr, - border_width->left, - border_width->top, - source_width - border_width->left - border_width->right, - source_height - border_width->top - border_width->bottom); - cairo_clip (cr); - gtk_render_icon_surface (context, cr, - source_image, - 0, 0); - cairo_restore (cr); - - gtk_style_context_save (context); - gtk_style_context_add_class (context, "embedded-image"); - - gtk_render_frame (context, cr, - 0, 0, - source_width, source_height); - - gtk_style_context_restore (context); - cairo_destroy (cr); - - gtk_widget_path_unref (path); - g_object_unref (provider); - g_object_unref (context); - g_free (css_str); - - return surface; -} - -/** - * gd_embed_image_in_frame: - * @source_image: - * @frame_image_url: - * @slice_width: - * @border_width: - * - * Returns: (transfer full): - */ -GdkPixbuf * -gd_embed_image_in_frame (GdkPixbuf *source_image, - const gchar *frame_image_url, - GtkBorder *slice_width, - GtkBorder *border_width) -{ - cairo_surface_t *surface, *embedded_surface; - GdkPixbuf *retval; - - surface = gdk_cairo_surface_create_from_pixbuf (source_image, - 0, NULL); - - /* Force the device scale to 1.0, since pixbufs are always in unscaled - * dimensions. - */ - cairo_surface_set_device_scale (surface, 1.0, 1.0); - embedded_surface = gd_embed_surface_in_frame (surface, frame_image_url, - slice_width, border_width); - retval = gdk_pixbuf_get_from_surface (embedded_surface, - 0, 0, - cairo_image_surface_get_width (embedded_surface), - cairo_image_surface_get_height (embedded_surface)); - - cairo_surface_destroy (embedded_surface); - cairo_surface_destroy (surface); - - return retval; -} diff --git a/cut-n-paste/libgd/gd-icon-utils.h b/cut-n-paste/libgd/gd-icon-utils.h deleted file mode 100644 index 12f4f0682..000000000 --- a/cut-n-paste/libgd/gd-icon-utils.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2011, 2012, 2015, 2016 Red Hat, Inc. - * - * Gnome Documents 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. - * - * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Author: Cosimo Cecchi - * - */ - -#ifndef __GD_CREATE_SYMBOLIC_ICON_H__ -#define __GD_CREATE_SYMBOLIC_ICON_H__ - -#include -#include - -cairo_surface_t *gd_copy_image_surface (cairo_surface_t *surface); - -cairo_surface_t *gd_create_surface_with_counter (GtkWidget *widget, - cairo_surface_t *base, - gint number); - -GIcon *gd_create_symbolic_icon (const gchar *name, - gint base_size); -GIcon *gd_create_symbolic_icon_for_scale (const gchar *name, - gint base_size, - gint scale); - -GdkPixbuf *gd_embed_image_in_frame (GdkPixbuf *source_image, - const gchar *frame_image_url, - GtkBorder *slice_width, - GtkBorder *border_width); -cairo_surface_t *gd_embed_surface_in_frame (cairo_surface_t *source_image, - const gchar *frame_image_url, - GtkBorder *slice_width, - GtkBorder *border_width); - -#endif /* __GD_CREATE_SYMBOLIC_ICON_H__ */ diff --git a/cut-n-paste/libgd/gd-two-lines-renderer.c b/cut-n-paste/libgd/gd-two-lines-renderer.c deleted file mode 100644 index 57cb1eca5..000000000 --- a/cut-n-paste/libgd/gd-two-lines-renderer.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * Copyright (c) 2011 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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 Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Author: Cosimo Cecchi - * - */ - -#include "gd-two-lines-renderer.h" -#include - -#define SUBTITLE_DIM_PERCENTAGE 0.55 -#define SUBTITLE_SIZE_PERCENTAGE 0.82 - -typedef struct _GdTwoLinesRendererPrivate GdTwoLinesRendererPrivate; - -struct _GdTwoLinesRendererPrivate { - gchar *line_two; - gint text_lines; -}; - -enum { - PROP_TEXT_LINES = 1, - PROP_LINE_TWO, - NUM_PROPERTIES -}; - -static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; - -G_DEFINE_TYPE_WITH_PRIVATE (GdTwoLinesRenderer, gd_two_lines_renderer, GTK_TYPE_CELL_RENDERER_TEXT) - -static PangoLayout * -create_layout_with_attrs (GtkWidget *widget, - const GdkRectangle *cell_area, - GdTwoLinesRenderer *self, - PangoEllipsizeMode ellipsize) -{ - PangoLayout *layout; - gint wrap_width, xpad; - PangoWrapMode wrap_mode; - PangoAlignment alignment; - - g_object_get (self, - "wrap-width", &wrap_width, - "wrap-mode", &wrap_mode, - "alignment", &alignment, - "xpad", &xpad, - NULL); - - layout = pango_layout_new (gtk_widget_get_pango_context (widget)); - - pango_layout_set_ellipsize (layout, ellipsize); - pango_layout_set_alignment (layout, alignment); - - if (wrap_width != -1) - { - pango_layout_set_width (layout, wrap_width * PANGO_SCALE); - pango_layout_set_wrap (layout, wrap_mode); - } - else - { - if (cell_area != NULL) - pango_layout_set_width (layout, (cell_area->width - 2 * xpad) * PANGO_SCALE); - else - pango_layout_set_width (layout, -1); - - pango_layout_set_wrap (layout, PANGO_WRAP_CHAR); - } - -#if PANGO_VERSION_CHECK (1, 44, 0) - { - PangoAttrList *attr_list = pango_attr_list_new (); - - pango_attr_list_insert (attr_list, pango_attr_insert_hyphens_new (FALSE)); - pango_layout_set_attributes (layout, attr_list); - - pango_attr_list_unref (attr_list); - } -#endif - - return layout; -} - -static void -apply_subtitle_style_to_layout (GtkStyleContext *context, - PangoLayout *layout, - GtkStateFlags flags) -{ - PangoFontDescription *desc; - PangoAttrList *layout_attr; - PangoAttribute *attr_alpha; - - gtk_style_context_save (context); - gtk_style_context_set_state (context, flags); - gtk_style_context_get (context, gtk_style_context_get_state (context), - "font", &desc, - NULL); - gtk_style_context_restore (context); - - /* Set the font size */ - pango_font_description_set_size (desc, pango_font_description_get_size (desc) * SUBTITLE_SIZE_PERCENTAGE); - pango_layout_set_font_description (layout, desc); - pango_font_description_free (desc); - - /* Set the font alpha */ - layout_attr = pango_attr_list_new (); - attr_alpha = pango_attr_foreground_alpha_new (SUBTITLE_DIM_PERCENTAGE * 65535); - pango_attr_list_insert (layout_attr, attr_alpha); - - pango_layout_set_attributes (layout, layout_attr); - pango_attr_list_unref (layout_attr); -} - -static void -gd_two_lines_renderer_prepare_layouts (GdTwoLinesRenderer *self, - const GdkRectangle *cell_area, - GtkWidget *widget, - PangoLayout **layout_one, - PangoLayout **layout_two) -{ - GdTwoLinesRendererPrivate *priv; - PangoLayout *line_one; - PangoLayout *line_two = NULL; - gchar *text = NULL; - - priv = gd_two_lines_renderer_get_instance_private (self); - - g_object_get (self, - "text", &text, - NULL); - - line_one = create_layout_with_attrs (widget, cell_area, - self, PANGO_ELLIPSIZE_MIDDLE); - - if (priv->line_two == NULL || - g_strcmp0 (priv->line_two, "") == 0) - { - pango_layout_set_height (line_one, - (priv->text_lines)); - - if (text != NULL) - pango_layout_set_text (line_one, text, -1); - } - else - { - GtkStyleContext *context; - - line_two = create_layout_with_attrs (widget, cell_area, - self, PANGO_ELLIPSIZE_END); - - context = gtk_widget_get_style_context (widget); - gtk_style_context_save (context); - apply_subtitle_style_to_layout (context, line_two, GTK_STATE_FLAG_NORMAL); - gtk_style_context_restore (context); - - pango_layout_set_height (line_one, - (priv->text_lines - 1)); - pango_layout_set_height (line_two, -1); - pango_layout_set_text (line_two, priv->line_two, -1); - - if (text != NULL) - pango_layout_set_text (line_one, text, -1); - } - - if (layout_one) - *layout_one = line_one; - if (layout_two) - *layout_two = line_two; - - g_free (text); -} - -static void -gd_two_lines_renderer_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - PangoLayout *layout_1, - PangoLayout *layout_2, - gint *width, - gint *height, - const GdkRectangle *cell_area, - gint *x_offset_1, - gint *x_offset_2, - gint *y_offset) -{ - GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (cell); - gint xpad, ypad; - PangoLayout *layout_one, *layout_two; - GdkRectangle layout_one_rect, layout_two_rect, layout_union; - - if (layout_1 == NULL) - { - gd_two_lines_renderer_prepare_layouts (self, cell_area, widget, &layout_one, &layout_two); - } - else - { - layout_one = g_object_ref (layout_1); - - if (layout_2 != NULL) - layout_two = g_object_ref (layout_2); - else - layout_two = NULL; - } - - gtk_cell_renderer_get_padding (cell, &xpad, &ypad); - pango_layout_get_pixel_extents (layout_one, NULL, (PangoRectangle *) &layout_one_rect); - - if (layout_two != NULL) - { - pango_layout_get_pixel_extents (layout_two, NULL, (PangoRectangle *) &layout_two_rect); - - layout_union.width = MAX (layout_one_rect.width, layout_two_rect.width); - layout_union.height = layout_one_rect.height + layout_two_rect.height; - } - else - { - layout_union = layout_one_rect; - } - - if (cell_area) - { - gfloat xalign, yalign; - - gtk_cell_renderer_get_alignment (cell, &xalign, &yalign); - - layout_union.width = MIN (layout_union.width, cell_area->width - 2 * xpad); - layout_union.height = MIN (layout_union.height, cell_area->height - 2 * ypad); - - if (x_offset_1) - { - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - *x_offset_1 = (1.0 - xalign) * (cell_area->width - (layout_one_rect.width + (2 * xpad))); - else - *x_offset_1 = xalign * (cell_area->width - (layout_one_rect.width + (2 * xpad))); - - *x_offset_1 = MAX (*x_offset_1, 0); - } - if (x_offset_2) - { - if (layout_two != NULL) - { - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - *x_offset_2 = (1.0 - xalign) * (cell_area->width - (layout_two_rect.width + (2 * xpad))); - else - *x_offset_2 = xalign * (cell_area->width - (layout_two_rect.width + (2 * xpad))); - - *x_offset_2 = MAX (*x_offset_2, 0); - } - else - { - *x_offset_2 = 0; - } - } - - if (y_offset) - { - *y_offset = yalign * (cell_area->height - (layout_union.height + (2 * ypad))); - *y_offset = MAX (*y_offset, 0); - } - } - else - { - if (x_offset_1) *x_offset_1 = 0; - if (x_offset_2) *x_offset_2 = 0; - if (y_offset) *y_offset = 0; - } - - g_clear_object (&layout_one); - g_clear_object (&layout_two); - - if (height) - *height = ypad * 2 + layout_union.height; - - if (width) - *width = xpad * 2 + layout_union.width; -} - -static void -gd_two_lines_renderer_render (GtkCellRenderer *cell, - cairo_t *cr, - GtkWidget *widget, - const GdkRectangle *background_area, - const GdkRectangle *cell_area, - GtkCellRendererState flags) -{ - GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (cell); - GtkStyleContext *context; - gint line_one_height; - GtkStateFlags state; - GdkRectangle area, render_area = *cell_area; - gint xpad, ypad, x_offset_1, x_offset_2, y_offset; - PangoLayout *layout_one, *layout_two; - PangoRectangle layout_rect; - - /* fetch common information */ - context = gtk_widget_get_style_context (widget); - gd_two_lines_renderer_prepare_layouts (self, cell_area, widget, &layout_one, &layout_two); - gd_two_lines_renderer_get_size (cell, widget, - layout_one, layout_two, - NULL, NULL, - cell_area, - &x_offset_1, &x_offset_2, &y_offset); - gtk_cell_renderer_get_padding (cell, &xpad, &ypad); - - area = *cell_area; - area.x += xpad; - area.y += ypad; - - /* now render the first layout */ - pango_layout_get_pixel_extents (layout_one, NULL, &layout_rect); - - render_area = area; - render_area.x += x_offset_1 - layout_rect.x; - render_area.y += y_offset; - - gtk_render_layout (context, cr, - render_area.x, - render_area.y, - layout_one); - - /* render the second layout */ - if (layout_two != NULL) - { - pango_layout_get_pixel_size (layout_one, - NULL, &line_one_height); - - gtk_style_context_save (context); - - apply_subtitle_style_to_layout (context, layout_two, flags); - - state = gtk_cell_renderer_get_state (cell, widget, flags); - gtk_style_context_set_state (context, state); - - pango_layout_get_pixel_extents (layout_two, NULL, &layout_rect); - - render_area = area; - render_area.x += x_offset_2 - layout_rect.x; - render_area.y += y_offset + line_one_height; - - gtk_render_layout (context, cr, - render_area.x, - render_area.y, - layout_two); - - gtk_style_context_restore (context); - } - - g_clear_object (&layout_one); - g_clear_object (&layout_two); -} - -static void -gd_two_lines_renderer_get_preferred_width (GtkCellRenderer *cell, - GtkWidget *widget, - gint *minimum_size, - gint *natural_size) -{ - PangoContext *context; - PangoFontMetrics *metrics; - PangoFontDescription *font_desc; - GtkStyleContext *style_context; - gint nat_width, min_width; - gint xpad, char_width, wrap_width, text_width; - gint width_chars, ellipsize_chars; - - g_object_get (cell, - "xpad", &xpad, - "width-chars", &width_chars, - "wrap-width", &wrap_width, - NULL); - style_context = gtk_widget_get_style_context (widget); - gtk_cell_renderer_get_padding (cell, &xpad, NULL); - - gd_two_lines_renderer_get_size (cell, widget, - NULL, NULL, - &text_width, NULL, - NULL, - NULL, NULL, NULL); - - /* Fetch the average size of a character */ - context = gtk_widget_get_pango_context (widget); - gtk_style_context_save (style_context); - gtk_style_context_set_state (style_context, 0); - gtk_style_context_get (style_context, gtk_style_context_get_state (style_context), - "font", &font_desc, NULL); - gtk_style_context_restore (style_context); - metrics = pango_context_get_metrics (context, font_desc, - pango_context_get_language (context)); - - char_width = pango_font_metrics_get_approximate_char_width (metrics); - - pango_font_metrics_unref (metrics); - pango_font_description_free (font_desc); - - /* enforce minimum width for ellipsized labels at ~3 chars */ - ellipsize_chars = 3; - - /* If no width-chars set, minimum for wrapping text will be the wrap-width */ - if (wrap_width > -1) - min_width = xpad * 2 + MIN (text_width, wrap_width); - else - min_width = xpad * 2 + - MIN (text_width, - (PANGO_PIXELS (char_width) * MAX (width_chars, ellipsize_chars))); - - if (width_chars > 0) - nat_width = xpad * 2 + - MAX ((PANGO_PIXELS (char_width) * width_chars), text_width); - else - nat_width = xpad * 2 + text_width; - - nat_width = MAX (nat_width, min_width); - - if (minimum_size) - *minimum_size = min_width; - - if (natural_size) - *natural_size = nat_width; -} - -static void -gd_two_lines_renderer_get_preferred_height_for_width (GtkCellRenderer *cell, - GtkWidget *widget, - gint width, - gint *minimum_size, - gint *natural_size) -{ - GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (cell); - PangoLayout *layout_one, *layout_two; - gint text_height, wrap_width; - gint xpad, ypad; - - gtk_cell_renderer_get_padding (cell, &xpad, &ypad); - g_object_get (cell, "wrap-width", &wrap_width, NULL); - gd_two_lines_renderer_prepare_layouts (self, NULL, widget, &layout_one, &layout_two); - - if (wrap_width != -1) - wrap_width = MIN (width - 2 * xpad, wrap_width); - else - wrap_width = width - 2 * xpad; - - pango_layout_set_width (layout_one, wrap_width); - if (layout_two != NULL) - pango_layout_set_width (layout_two, wrap_width); - - gd_two_lines_renderer_get_size (cell, widget, - layout_one, layout_two, - NULL, &text_height, - NULL, - NULL, NULL, NULL); - - text_height += 2 * ypad; - - if (minimum_size != NULL) - *minimum_size = text_height; - - if (natural_size != NULL) - *natural_size = text_height; - - g_clear_object (&layout_one); - g_clear_object (&layout_two); -} - -static void -gd_two_lines_renderer_get_preferred_height (GtkCellRenderer *cell, - GtkWidget *widget, - gint *minimum_size, - gint *natural_size) -{ - gint min_width; - - gtk_cell_renderer_get_preferred_width (cell, widget, &min_width, NULL); - gd_two_lines_renderer_get_preferred_height_for_width (cell, widget, min_width, - minimum_size, natural_size); -} - -static void -gd_two_lines_renderer_get_aligned_area (GtkCellRenderer *cell, - GtkWidget *widget, - GtkCellRendererState flags, - const GdkRectangle *cell_area, - GdkRectangle *aligned_area) -{ - gint x_offset, x_offset_1, x_offset_2, y_offset; - - /* fetch common information */ - gd_two_lines_renderer_get_size (cell, widget, - NULL, NULL, - &aligned_area->width, &aligned_area->height, - cell_area, - &x_offset_1, &x_offset_2, &y_offset); - - x_offset = MIN (x_offset_1, x_offset_2); - - aligned_area->x = cell_area->x + x_offset; - aligned_area->y = cell_area->y + y_offset; -} - -static void -gd_two_lines_renderer_set_line_two (GdTwoLinesRenderer *self, - const gchar *line_two) -{ - GdTwoLinesRendererPrivate *priv; - - priv = gd_two_lines_renderer_get_instance_private (self); - - if (g_strcmp0 (priv->line_two, line_two) == 0) - return; - - g_free (priv->line_two); - priv->line_two = g_strdup (line_two); - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LINE_TWO]); -} - -static void -gd_two_lines_renderer_set_text_lines (GdTwoLinesRenderer *self, - gint text_lines) -{ - GdTwoLinesRendererPrivate *priv; - - priv = gd_two_lines_renderer_get_instance_private (self); - - if (priv->text_lines == text_lines) - return; - - priv->text_lines = text_lines; - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TEXT_LINES]); -} - -static void -gd_two_lines_renderer_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (object); - - switch (property_id) - { - case PROP_TEXT_LINES: - gd_two_lines_renderer_set_text_lines (self, g_value_get_int (value)); - break; - case PROP_LINE_TWO: - gd_two_lines_renderer_set_line_two (self, g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gd_two_lines_renderer_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (object); - GdTwoLinesRendererPrivate *priv; - - priv = gd_two_lines_renderer_get_instance_private (self); - - switch (property_id) - { - case PROP_TEXT_LINES: - g_value_set_int (value, priv->text_lines); - break; - case PROP_LINE_TWO: - g_value_set_string (value, priv->line_two); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gd_two_lines_renderer_finalize (GObject *object) -{ - GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (object); - GdTwoLinesRendererPrivate *priv; - - priv = gd_two_lines_renderer_get_instance_private (self); - - g_free (priv->line_two); - - G_OBJECT_CLASS (gd_two_lines_renderer_parent_class)->finalize (object); -} - -static void -gd_two_lines_renderer_class_init (GdTwoLinesRendererClass *klass) -{ - GtkCellRendererClass *cclass = GTK_CELL_RENDERER_CLASS (klass); - GObjectClass *oclass = G_OBJECT_CLASS (klass); - - cclass->render = gd_two_lines_renderer_render; - cclass->get_preferred_width = gd_two_lines_renderer_get_preferred_width; - cclass->get_preferred_height = gd_two_lines_renderer_get_preferred_height; - cclass->get_preferred_height_for_width = gd_two_lines_renderer_get_preferred_height_for_width; - cclass->get_aligned_area = gd_two_lines_renderer_get_aligned_area; - - oclass->set_property = gd_two_lines_renderer_set_property; - oclass->get_property = gd_two_lines_renderer_get_property; - oclass->finalize = gd_two_lines_renderer_finalize; - - properties[PROP_TEXT_LINES] = - g_param_spec_int ("text-lines", - "Lines of text", - "The total number of lines to be displayed", - 2, G_MAXINT, 2, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - properties[PROP_LINE_TWO] = - g_param_spec_string ("line-two", - "Second line", - "Second line", - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); -} - -static void -gd_two_lines_renderer_init (GdTwoLinesRenderer *self) -{ -} - -GtkCellRenderer * -gd_two_lines_renderer_new (void) -{ - return g_object_new (GD_TYPE_TWO_LINES_RENDERER, NULL); -} diff --git a/cut-n-paste/libgd/gd-two-lines-renderer.h b/cut-n-paste/libgd/gd-two-lines-renderer.h deleted file mode 100644 index b10ac8a43..000000000 --- a/cut-n-paste/libgd/gd-two-lines-renderer.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2011 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser 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 Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Author: Cosimo Cecchi - * - */ - -#ifndef _GD_TWO_LINES_RENDERER_H -#define _GD_TWO_LINES_RENDERER_H - -#include - -#include - -G_BEGIN_DECLS - -#define GD_TYPE_TWO_LINES_RENDERER gd_two_lines_renderer_get_type() -G_DECLARE_DERIVABLE_TYPE (GdTwoLinesRenderer, gd_two_lines_renderer, GD, TWO_LINES_RENDERER, GtkCellRendererText) - -struct _GdTwoLinesRendererClass -{ - GtkCellRendererTextClass parent_class; -}; - -GType gd_two_lines_renderer_get_type (void) G_GNUC_CONST; - -GtkCellRenderer *gd_two_lines_renderer_new (void); - -G_END_DECLS - -#endif /* _GD_TWO_LINES_RENDERER_H */ diff --git a/cut-n-paste/libgd/meson.build b/cut-n-paste/libgd/meson.build deleted file mode 100644 index efa50f6ab..000000000 --- a/cut-n-paste/libgd/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -sources = files( - 'gd-icon-utils.c', - 'gd-two-lines-renderer.c', -) - -deps = [ - cairo_dep, - gtk_dep, -] - -libgd = static_library( - 'gd', - sources: sources, - include_directories: top_inc, - dependencies: deps, -) - -libgd_dep = declare_dependency( - include_directories: include_directories('.'), - dependencies: deps, - link_with: libgd, -) diff --git a/cut-n-paste/meson.build b/cut-n-paste/meson.build index 279061d20..207500182 100644 --- a/cut-n-paste/meson.build +++ b/cut-n-paste/meson.build @@ -2,7 +2,6 @@ cut_n_paste_inc = include_directories('.') subdir('gimpcellrenderertoggle') subdir('libdazzle') -subdir('libgd') if not external_synctex subdir('synctex') diff --git a/shell/meson.build b/shell/meson.build index cc0464d88..74df0af3f 100644 --- a/shell/meson.build +++ b/shell/meson.build @@ -49,7 +49,6 @@ evince_deps = [ libevview_dep, libevproperties_dep, libdazzle_dep, - libgd_dep, libgimpcellrenderertoggle_dep, m_dep, ] -- GitLab From 785e82d2198d989c26c69e1eb92be566ad3048a3 Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Wed, 12 Jul 2023 15:31:20 +0800 Subject: [PATCH 04/50] cut-n-paste: Remove gimprenderertoggle Removed due to the same reason as libgd. Signed-off-by: Qiu Wenbo --- .../gimpcellrenderertoggle.c | 562 ------------------ .../gimpcellrenderertoggle.h | 83 --- .../gimpcellrenderertoggle/meson.build | 12 - cut-n-paste/meson.build | 1 - shell/meson.build | 1 - 5 files changed, 659 deletions(-) delete mode 100644 cut-n-paste/gimpcellrenderertoggle/gimpcellrenderertoggle.c delete mode 100644 cut-n-paste/gimpcellrenderertoggle/gimpcellrenderertoggle.h delete mode 100644 cut-n-paste/gimpcellrenderertoggle/meson.build diff --git a/cut-n-paste/gimpcellrenderertoggle/gimpcellrenderertoggle.c b/cut-n-paste/gimpcellrenderertoggle/gimpcellrenderertoggle.c deleted file mode 100644 index eafad6320..000000000 --- a/cut-n-paste/gimpcellrenderertoggle/gimpcellrenderertoggle.c +++ /dev/null @@ -1,562 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimpcellrenderertoggle.c - * Copyright (C) 2003-2004 Sven Neumann - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include - -#include "gimpcellrenderertoggle.h" - - -/** - * SECTION: gimpcellrenderertoggle - * @title: GimpCellRendererToggle - * @short_description: A #GtkCellRendererToggle that displays icons instead - * of a checkbox. - * - * A #GtkCellRendererToggle that displays icons instead of a checkbox. - **/ - - -#define DEFAULT_ICON_SIZE 16 - - -enum -{ - CLICKED, - LAST_SIGNAL -}; - -enum -{ - PROP_0, - PROP_ICON_NAME, - PROP_ICON_SIZE, - PROP_OVERRIDE_BACKGROUND -}; - - -struct _GimpCellRendererTogglePrivate -{ - gchar *icon_name; - gint icon_size; - gboolean override_background; - - GdkPixbuf *pixbuf; -}; - - -#define GET_PRIVATE(obj) (((GimpCellRendererToggle *) (obj))->priv) - - -static void gimp_cell_renderer_toggle_finalize (GObject *object); -static void gimp_cell_renderer_toggle_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void gimp_cell_renderer_toggle_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); -static void gimp_cell_renderer_toggle_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - const GdkRectangle *rectangle, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height); -static void gimp_cell_renderer_toggle_render (GtkCellRenderer *cell, - cairo_t *cr, - GtkWidget *widget, - const GdkRectangle *background_area, - const GdkRectangle *cell_area, - GtkCellRendererState flags); -static gboolean gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path, - const GdkRectangle *background_area, - const GdkRectangle *cell_area, - GtkCellRendererState flags); -static void gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle, - GtkWidget *widget); - - -G_DEFINE_TYPE_WITH_PRIVATE (GimpCellRendererToggle, gimp_cell_renderer_toggle, - GTK_TYPE_CELL_RENDERER_TOGGLE) - -#define parent_class gimp_cell_renderer_toggle_parent_class - -static guint toggle_cell_signals[LAST_SIGNAL] = { 0 }; - - -static void -gimp_cell_renderer_toggle_class_init (GimpCellRendererToggleClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass); - - toggle_cell_signals[CLICKED] = - g_signal_new ("clicked", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GimpCellRendererToggleClass, clicked), - NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, 2, - G_TYPE_STRING, - GDK_TYPE_MODIFIER_TYPE); - - object_class->finalize = gimp_cell_renderer_toggle_finalize; - object_class->get_property = gimp_cell_renderer_toggle_get_property; - object_class->set_property = gimp_cell_renderer_toggle_set_property; - - cell_class->get_size = gimp_cell_renderer_toggle_get_size; - cell_class->render = gimp_cell_renderer_toggle_render; - cell_class->activate = gimp_cell_renderer_toggle_activate; - - g_object_class_install_property (object_class, PROP_ICON_NAME, - g_param_spec_string ("icon-name", - "Icon Name", - "The icon to display", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property (object_class, PROP_ICON_SIZE, - g_param_spec_int ("icon-size", - "Icon Size", - "The desired icon size to use in pixel (before applying scaling factor)", - 0, G_MAXINT, - DEFAULT_ICON_SIZE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property (object_class, PROP_OVERRIDE_BACKGROUND, - g_param_spec_boolean ("override-background", - "Override Background", - "Draw the background if the row is selected", - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); -} - -static void -gimp_cell_renderer_toggle_init (GimpCellRendererToggle *toggle) -{ - toggle->priv = gimp_cell_renderer_toggle_get_instance_private (toggle); -} - -static void -gimp_cell_renderer_toggle_finalize (GObject *object) -{ - GimpCellRendererTogglePrivate *priv = GET_PRIVATE (object); - - g_clear_pointer (&priv->icon_name, g_free); - g_clear_object (&priv->pixbuf); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gimp_cell_renderer_toggle_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GimpCellRendererTogglePrivate *priv = GET_PRIVATE (object); - - switch (param_id) - { - case PROP_ICON_NAME: - g_value_set_string (value, priv->icon_name); - break; - - case PROP_ICON_SIZE: - g_value_set_int (value, priv->icon_size); - break; - - case PROP_OVERRIDE_BACKGROUND: - g_value_set_boolean (value, priv->override_background); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} - -static void -gimp_cell_renderer_toggle_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GimpCellRendererTogglePrivate *priv = GET_PRIVATE (object); - - switch (param_id) - { - case PROP_ICON_NAME: - if (priv->icon_name) - g_free (priv->icon_name); - priv->icon_name = g_value_dup_string (value); - break; - - case PROP_ICON_SIZE: - priv->icon_size = g_value_get_int (value); - break; - - case PROP_OVERRIDE_BACKGROUND: - priv->override_background = g_value_get_boolean (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } - - g_clear_object (&priv->pixbuf); -} - -static void -gimp_cell_renderer_toggle_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - const GdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height) -{ - GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (cell); - GimpCellRendererTogglePrivate *priv = GET_PRIVATE (cell); - GtkStyleContext *context = gtk_widget_get_style_context (widget); - GtkBorder border; - gint scale_factor; - gint calc_width; - gint calc_height; - gint pixbuf_width; - gint pixbuf_height; - gfloat xalign; - gfloat yalign; - gint xpad; - gint ypad; - - scale_factor = gtk_widget_get_scale_factor (widget); - - if (! priv->icon_name) - { - GTK_CELL_RENDERER_CLASS (parent_class)->get_size (cell, - widget, - cell_area, - x_offset, y_offset, - width, height); - return; - } - - gtk_style_context_save (context); - - gtk_cell_renderer_get_alignment (cell, &xalign, &yalign); - gtk_cell_renderer_get_padding (cell, &xpad, &ypad); - - if (! priv->pixbuf) - gimp_cell_renderer_toggle_create_pixbuf (toggle, widget); - - pixbuf_width = gdk_pixbuf_get_width (priv->pixbuf); - pixbuf_height = gdk_pixbuf_get_height (priv->pixbuf); - - /* The pixbuf size may be bigger than the logical size. */ - calc_width = pixbuf_width / scale_factor + (gint) xpad * 2; - calc_height = pixbuf_height / scale_factor + (gint) ypad * 2; - - gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON); - - gtk_style_context_get_border (context, 0, &border); - calc_width += border.left + border.right; - calc_height += border.top + border.bottom; - - if (width) - *width = calc_width; - - if (height) - *height = calc_height; - - if (cell_area) - { - if (x_offset) - { - *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ? - (1.0 - xalign) : xalign) * - (cell_area->width - calc_width)); - *x_offset = MAX (*x_offset, 0); - } - - if (y_offset) - { - *y_offset = yalign * (cell_area->height - calc_height); - *y_offset = MAX (*y_offset, 0); - } - } - - gtk_style_context_restore (context); -} - -static void -gimp_cell_renderer_toggle_render (GtkCellRenderer *cell, - cairo_t *cr, - GtkWidget *widget, - const GdkRectangle *background_area, - const GdkRectangle *cell_area, - GtkCellRendererState flags) -{ - GimpCellRendererTogglePrivate *priv = GET_PRIVATE (cell); - GtkStyleContext *context = gtk_widget_get_style_context (widget); - GdkRectangle toggle_rect; - GtkStateFlags state; - gboolean active; - gint scale_factor; - gint xpad; - gint ypad; - - scale_factor = gtk_widget_get_scale_factor (widget); - - if (! priv->icon_name) - { - GTK_CELL_RENDERER_CLASS (parent_class)->render (cell, cr, widget, - background_area, - cell_area, - flags); - return; - } - - if ((flags & GTK_CELL_RENDERER_SELECTED) && - priv->override_background) - { - gboolean background_set; - - g_object_get (cell, - "cell-background-set", &background_set, - NULL); - - if (background_set) - { - GdkRGBA *color; - - g_object_get (cell, - "cell-background-rgba", &color, - NULL); - - gdk_cairo_rectangle (cr, background_area); - gdk_cairo_set_source_rgba (cr, color); - cairo_fill (cr); - - gdk_rgba_free (color); - } - } - - gimp_cell_renderer_toggle_get_size (cell, widget, cell_area, - &toggle_rect.x, - &toggle_rect.y, - &toggle_rect.width, - &toggle_rect.height); - gtk_style_context_save (context); - - gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON); - - gtk_cell_renderer_get_padding (cell, &xpad, &ypad); - - toggle_rect.x += cell_area->x + xpad; - toggle_rect.y += cell_area->y + ypad; - toggle_rect.width -= xpad * 2; - toggle_rect.height -= ypad * 2; - - if (toggle_rect.width <= 0 || toggle_rect.height <= 0) - return; - - state = gtk_cell_renderer_get_state (cell, widget, flags); - - active = - gtk_cell_renderer_toggle_get_active (GTK_CELL_RENDERER_TOGGLE (cell)); - - if (active) - state |= GTK_STATE_FLAG_ACTIVE; - - if (! gtk_cell_renderer_toggle_get_activatable (GTK_CELL_RENDERER_TOGGLE (cell))) - state |= GTK_STATE_FLAG_INSENSITIVE; - - gtk_style_context_set_state (context, state); - - if (state & GTK_STATE_FLAG_PRELIGHT) - gtk_render_frame (context, cr, - toggle_rect.x, toggle_rect.y, - toggle_rect.width, toggle_rect.height); - - if (active) - { - GtkBorder border; - gboolean inconsistent; - - gtk_style_context_get_border (context, 0, &border); - toggle_rect.x += border.left; - toggle_rect.x *= scale_factor; - toggle_rect.y += border.top; - toggle_rect.y *= scale_factor; - toggle_rect.width -= border.left + border.right; - toggle_rect.height -= border.top + border.bottom; - - /* For high DPI displays, pixbuf size is bigger than logical size. */ - cairo_scale (cr, (gdouble) 1.0 / scale_factor, (gdouble) 1.0 / scale_factor); - gdk_cairo_set_source_pixbuf (cr, priv->pixbuf, - toggle_rect.x, toggle_rect.y); - cairo_paint (cr); - - g_object_get (cell, - "inconsistent", &inconsistent, - NULL); - - if (inconsistent) - { - GdkRGBA color; - - gtk_style_context_get_color (context, state, &color); - gdk_cairo_set_source_rgba (cr, &color); - cairo_set_line_width (cr, 1.5); - cairo_move_to (cr, - toggle_rect.x + toggle_rect.width - 1, - toggle_rect.y + 1); - cairo_line_to (cr, - toggle_rect.x + 1, - toggle_rect.y + toggle_rect.height - 1); - cairo_stroke (cr); - } - } - - gtk_style_context_restore (context); -} - -static gboolean -gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path, - const GdkRectangle *background_area, - const GdkRectangle *cell_area, - GtkCellRendererState flags) -{ - GtkCellRendererToggle *toggle = GTK_CELL_RENDERER_TOGGLE (cell); - - if (gtk_cell_renderer_toggle_get_activatable (toggle)) - { - GdkModifierType state = 0; - - if (event && ((GdkEventAny *) event)->type == GDK_BUTTON_PRESS) - state = ((GdkEventButton *) event)->state; - - gimp_cell_renderer_toggle_clicked (GIMP_CELL_RENDERER_TOGGLE (cell), - path, state); - - return TRUE; - } - - return FALSE; -} - -static void -gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle, - GtkWidget *widget) -{ - GimpCellRendererTogglePrivate *priv = GET_PRIVATE (toggle); - - g_clear_object (&priv->pixbuf); - - if (priv->icon_name) - { - GdkScreen *screen; - GtkIconTheme *icon_theme; - GtkIconInfo *icon_info; - gchar *icon_name; - gint scale_factor; - - scale_factor = gtk_widget_get_scale_factor (widget); - screen = gtk_widget_get_screen (widget); - icon_theme = gtk_icon_theme_get_for_screen (screen); - - /* Look for symbolic and fallback to color icon. */ - icon_name = g_strdup_printf ("%s-symbolic", priv->icon_name); - icon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name, - priv->icon_size, scale_factor, - GTK_ICON_LOOKUP_GENERIC_FALLBACK); - - g_free (icon_name); - if (icon_info) - { - GdkPixbuf *pixbuf; - - pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, - gtk_widget_get_style_context (widget), - NULL, NULL); - priv->pixbuf = pixbuf; - g_object_unref (icon_info); - } - } -} - - -/** - * gimp_cell_renderer_toggle_new: - * @icon_name: the icon name of the icon to use for the active state - * - * Creates a custom version of the #GtkCellRendererToggle. Instead of - * showing the standard toggle button, it shows a named icon if the - * cell is active and no icon otherwise. This cell renderer is for - * example used in the Layers treeview to indicate and control the - * layer's visibility by showing %GIMP_STOCK_VISIBLE. - * - * Return value: a new #GimpCellRendererToggle - * - * Since: GIMP 2.2 - **/ -GtkCellRenderer * -gimp_cell_renderer_toggle_new (const gchar *icon_name) -{ - return g_object_new (GIMP_TYPE_CELL_RENDERER_TOGGLE, - "icon-name", icon_name, - NULL); -} - -/** - * gimp_cell_renderer_toggle_clicked: - * @cell: a #GimpCellRendererToggle - * @path: the path to the clicked row - * @state: the modifier state - * - * Emits the "clicked" signal from a #GimpCellRendererToggle. - * - * Since: GIMP 2.2 - **/ -void -gimp_cell_renderer_toggle_clicked (GimpCellRendererToggle *cell, - const gchar *path, - GdkModifierType state) -{ - g_return_if_fail (GIMP_IS_CELL_RENDERER_TOGGLE (cell)); - g_return_if_fail (path != NULL); - - g_signal_emit (cell, toggle_cell_signals[CLICKED], 0, path, state); -} diff --git a/cut-n-paste/gimpcellrenderertoggle/gimpcellrenderertoggle.h b/cut-n-paste/gimpcellrenderertoggle/gimpcellrenderertoggle.h deleted file mode 100644 index e94d11248..000000000 --- a/cut-n-paste/gimpcellrenderertoggle/gimpcellrenderertoggle.h +++ /dev/null @@ -1,83 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimpcellrenderertoggle.h - * Copyright (C) 2003-2004 Sven Neumann - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __GIMP_CELL_RENDERER_TOGGLE_H__ -#define __GIMP_CELL_RENDERER_TOGGLE_H__ - -#include -#include - -G_BEGIN_DECLS - - -#define GIMP_TYPE_CELL_RENDERER_TOGGLE (gimp_cell_renderer_toggle_get_type ()) -#define GIMP_CELL_RENDERER_TOGGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CELL_RENDERER_TOGGLE, GimpCellRendererToggle)) -#define GIMP_CELL_RENDERER_TOGGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CELL_RENDERER_TOGGLE, GimpCellRendererToggleClass)) -#define GIMP_IS_CELL_RENDERER_TOGGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_CELL_RENDERER_TOGGLE)) -#define GIMP_IS_CELL_RENDERER_TOGGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_CELL_RENDERER_TOGGLE)) -#define GIMP_CELL_RENDERER_TOGGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CELL_RENDERER_TOGGLE, GimpCellRendererToggleClass)) - - -typedef struct _GimpCellRendererTogglePrivate GimpCellRendererTogglePrivate; -typedef struct _GimpCellRendererToggleClass GimpCellRendererToggleClass; - -struct _GimpCellRendererToggle -{ - GtkCellRendererToggle parent_instance; - - GimpCellRendererTogglePrivate *priv; -}; - -typedef struct _GimpCellRendererToggle GimpCellRendererToggle; - -struct _GimpCellRendererToggleClass -{ - GtkCellRendererToggleClass parent_class; - - void (* clicked) (GimpCellRendererToggle *cell, - const gchar *path, - GdkModifierType state); - - /* Padding for future expansion */ - void (* _gimp_reserved1) (void); - void (* _gimp_reserved2) (void); - void (* _gimp_reserved3) (void); - void (* _gimp_reserved4) (void); - void (* _gimp_reserved5) (void); - void (* _gimp_reserved6) (void); - void (* _gimp_reserved7) (void); - void (* _gimp_reserved8) (void); -}; - - -GType gimp_cell_renderer_toggle_get_type (void) G_GNUC_CONST; - -GtkCellRenderer * gimp_cell_renderer_toggle_new (const gchar *icon_name); - -void gimp_cell_renderer_toggle_clicked (GimpCellRendererToggle *cell, - const gchar *path, - GdkModifierType state); - - -G_END_DECLS - -#endif /* __GIMP_CELL_RENDERER_TOGGLE_H__ */ diff --git a/cut-n-paste/gimpcellrenderertoggle/meson.build b/cut-n-paste/gimpcellrenderertoggle/meson.build deleted file mode 100644 index b08e8b663..000000000 --- a/cut-n-paste/gimpcellrenderertoggle/meson.build +++ /dev/null @@ -1,12 +0,0 @@ -libgimpcellrenderertoggle = static_library( - 'gimpcellrenderertoggle', - sources: 'gimpcellrenderertoggle.c', - include_directories: top_inc, - dependencies: gtk_dep, -) - -libgimpcellrenderertoggle_dep = declare_dependency( - include_directories: include_directories('.'), - dependencies: gtk_dep, - link_with: libgimpcellrenderertoggle, -) diff --git a/cut-n-paste/meson.build b/cut-n-paste/meson.build index 207500182..0dc7bca8e 100644 --- a/cut-n-paste/meson.build +++ b/cut-n-paste/meson.build @@ -1,6 +1,5 @@ cut_n_paste_inc = include_directories('.') -subdir('gimpcellrenderertoggle') subdir('libdazzle') if not external_synctex diff --git a/shell/meson.build b/shell/meson.build index 74df0af3f..fcb90f892 100644 --- a/shell/meson.build +++ b/shell/meson.build @@ -49,7 +49,6 @@ evince_deps = [ libevview_dep, libevproperties_dep, libdazzle_dep, - libgimpcellrenderertoggle_dep, m_dep, ] -- GitLab From d63d12ceb391292fd6d03e09b851565666b3d74d Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Sun, 12 Nov 2023 15:46:26 +0800 Subject: [PATCH 05/50] libdocument: Port EvAttachment to gtk4 GdkScreen has been removed in GTK4. Signed-off-by: Qiu Wenbo --- libdocument/ev-attachment.c | 3 +-- libdocument/ev-attachment.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libdocument/ev-attachment.c b/libdocument/ev-attachment.c index 131a87d71..9a317be27 100644 --- a/libdocument/ev-attachment.c +++ b/libdocument/ev-attachment.c @@ -387,14 +387,13 @@ ev_attachment_launch_app (EvAttachment *attachment, gboolean ev_attachment_open (EvAttachment *attachment, - GdkScreen *screen, + GdkDisplay *display, guint32 timestamp, GError **error) { GAppInfo *app_info; gboolean retval = FALSE; EvAttachmentPrivate *priv; - GdkDisplay *display = gdk_screen_get_display (screen); g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), FALSE); diff --git a/libdocument/ev-attachment.h b/libdocument/ev-attachment.h index 8c63c5658..4177a8952 100644 --- a/libdocument/ev-attachment.h +++ b/libdocument/ev-attachment.h @@ -70,7 +70,7 @@ gboolean ev_attachment_save (EvAttachment *attachment, GError **error); EV_PUBLIC gboolean ev_attachment_open (EvAttachment *attachment, - GdkScreen *screen, + GdkDisplay *display, guint32 timestamp, GError **error); -- GitLab From 424c41b04aa972c024e7331efbceed093d890cdd Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Sun, 12 Nov 2023 15:47:08 +0800 Subject: [PATCH 06/50] libdocument: Port EvDocumentMisc to gtk4 Signed-off-by: Qiu Wenbo --- libdocument/ev-document-misc.c | 92 +++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/libdocument/ev-document-misc.c b/libdocument/ev-document-misc.c index c75572a58..bb7d50b8c 100644 --- a/libdocument/ev-document-misc.c +++ b/libdocument/ev-document-misc.c @@ -36,7 +36,6 @@ ev_document_misc_render_thumbnail_frame (GtkWidget *widget, cairo_surface_t *source_surface) { GtkStyleContext *context = gtk_widget_get_style_context (widget); - GtkStateFlags state = gtk_widget_get_state_flags (widget); double width_r, height_r; double width_f, height_f; cairo_surface_t *surface; @@ -70,7 +69,7 @@ ev_document_misc_render_thumbnail_frame (GtkWidget *widget, if (inverted_colors) gtk_style_context_add_class (context, "inverted"); - gtk_style_context_get_border (context, state, &border); + gtk_style_context_get_border (context, &border); width_f = width_r + border.left + border.right; height_f = height_r + border.top + border.bottom; @@ -261,20 +260,18 @@ ev_document_misc_invert_surface (cairo_surface_t *surface) { gdouble ev_document_misc_get_widget_dpi (GtkWidget *widget) { - GdkRectangle geometry; - GdkDisplay *display; - GdkMonitor *monitor; - GdkWindow *window; + GdkDisplay *display = gtk_widget_get_display (widget); + GtkNative *native = gtk_widget_get_native (widget); + GdkSurface *surface = NULL; + GdkMonitor *monitor = NULL; gboolean is_landscape; + GdkRectangle geometry; - display = gtk_widget_get_display (widget); - window = gtk_widget_get_window (widget); - if (window != NULL) { - monitor = gdk_display_get_monitor_at_window (display, window); - } else { - monitor = gdk_display_get_primary_monitor (display); - if (monitor == NULL) - monitor = gdk_display_get_monitor (display, 0); + if (native != NULL) + surface = gtk_native_get_surface (native); + + if (surface != NULL) { + monitor = gdk_display_get_monitor_at_surface (display, surface); } /* The only safe assumption you can make, on Unix-like/X11 and @@ -332,30 +329,45 @@ ev_document_misc_get_pointer_position (GtkWidget *widget, gint *x, gint *y) { - GdkSeat *seat; - GdkDevice *device_pointer; - GdkRectangle allocation; - - if (x) - *x = -1; - if (y) - *y = -1; - - if (!gtk_widget_get_realized (widget)) - return; - - seat = gdk_display_get_default_seat (gtk_widget_get_display (widget)); - device_pointer = gdk_seat_get_pointer (seat); - gdk_window_get_device_position (gtk_widget_get_window (widget), - device_pointer, - x, y, NULL); - - if (gtk_widget_get_has_window (widget)) - return; - - gtk_widget_get_allocation (widget, &allocation); - if (x) - *x -= allocation.x; - if (y) - *y -= allocation.y; + gdouble dx, dy; + GdkSeat *seat; + GtkNative *native; + GdkDevice *device_pointer; + GdkSurface *surface; + + if (x) + *x = -1; + if (y) + *y = -1; + + if (!gtk_widget_get_realized (widget)) + return; + + seat = gdk_display_get_default_seat (gtk_widget_get_display (widget)); + + device_pointer = gdk_seat_get_pointer (seat); + native = gtk_widget_get_native (widget); + + if (!native) + return; + + surface = gtk_native_get_surface (native); + if (!surface) + return; + + gdk_surface_get_device_position (surface, + device_pointer, + &dx, &dy, NULL); + + if (x) + *x = dx; + if (y) + *y = dy; + + gtk_widget_translate_coordinates (widget, GTK_WIDGET (native), 0, 0, &dx, &dy); + + if (x) + *x -= dx; + if (y) + *y -= dy; } -- GitLab From 0430677758b4a6df4edd6dbe694e0a6e25b53e98 Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Wed, 12 Jul 2023 16:25:08 +0800 Subject: [PATCH 07/50] properties: Port to new Nautilus extension API Signed-off-by: Qiu Wenbo --- properties/ev-properties-main.c | 130 ++++++++++++++++++++++++-------- properties/ev-properties-view.c | 68 +++-------------- properties/ev-properties-view.h | 46 +++++++++++ 3 files changed, 158 insertions(+), 86 deletions(-) diff --git a/properties/ev-properties-main.c b/properties/ev-properties-main.c index 7cc49da53..f415f9a80 100644 --- a/properties/ev-properties-main.c +++ b/properties/ev-properties-main.c @@ -41,9 +41,9 @@ static GType epp_type = 0; static void property_page_provider_iface_init - (NautilusPropertyPageProviderIface *iface); -static GList *ev_properties_get_pages - (NautilusPropertyPageProvider *provider, GList *files); + (NautilusPropertiesModelProviderInterface *iface); +static GList *ev_properties_get_models + (NautilusPropertiesModelProvider *provider, GList *files); static void ev_properties_plugin_register_type (GTypeModule *module) @@ -70,28 +70,109 @@ ev_properties_plugin_register_type (GTypeModule *module) &info, 0); g_type_module_add_interface (module, epp_type, - NAUTILUS_TYPE_PROPERTY_PAGE_PROVIDER, + NAUTILUS_TYPE_PROPERTIES_MODEL_PROVIDER, &property_page_provider_iface_info); } static void -property_page_provider_iface_init (NautilusPropertyPageProviderIface *iface) +property_page_provider_iface_init (NautilusPropertiesModelProviderInterface *iface) { - iface->get_pages = ev_properties_get_pages; + iface->get_models = ev_properties_get_models; +} + +static GListModel * +build_properties (EvDocument *document) +{ + EvDocumentInfo *info = ev_document_get_info (document); + GListStore *model = g_list_store_new (NAUTILUS_TYPE_PROPERTIES_ITEM); + const char *uri = ev_document_get_uri (document); + GDateTime *datetime = NULL; + char *text; + +#define SET_PROPERTY(p, value) do { \ + g_list_store_append (model, \ + nautilus_properties_item_new (_(properties_info[p##_PROPERTY].label), value)); \ + } while (0) + +#define FIELD_SET_PROPERTY(p, value) \ + if (info->fields_mask & EV_DOCUMENT_INFO_##p) { \ + SET_PROPERTY (p, value); \ + } + + FIELD_SET_PROPERTY (TITLE, info->title); + SET_PROPERTY (URI, uri); + FIELD_SET_PROPERTY (SUBJECT, info->subject); + FIELD_SET_PROPERTY (AUTHOR, info->author); + FIELD_SET_PROPERTY (KEYWORDS, info->keywords); + FIELD_SET_PROPERTY (PRODUCER, info->producer); + FIELD_SET_PROPERTY (CREATOR, info->creator); + + datetime = ev_document_info_get_created_datetime(info); + if (datetime != NULL) { + text = ev_document_misc_format_datetime(datetime); + SET_PROPERTY(CREATION_DATE, text); + g_free(text); + } else { + SET_PROPERTY(CREATION_DATE, NULL); + } + datetime = ev_document_info_get_modified_datetime(info); + if (datetime != NULL) { + text = ev_document_misc_format_datetime(datetime); + SET_PROPERTY(MOD_DATE, text); + g_free(text); + } else { + SET_PROPERTY(MOD_DATE, NULL); + } + + FIELD_SET_PROPERTY (FORMAT, info->format); + + if (info->fields_mask & EV_DOCUMENT_INFO_N_PAGES) { + text = g_strdup_printf ("%d", info->n_pages); + SET_PROPERTY (N_PAGES, text); + g_free (text); + } + FIELD_SET_PROPERTY (LINEARIZED, info->linearized); + FIELD_SET_PROPERTY (SECURITY, info->security); + + if (info->fields_mask & EV_DOCUMENT_INFO_PAPER_SIZE) { + text = ev_regular_paper_size (info); + SET_PROPERTY (PAPER_SIZE, text); + g_free (text); + } + + if (info->fields_mask & EV_DOCUMENT_INFO_CONTAINS_JS) { + if (info->contains_js == EV_DOCUMENT_CONTAINS_JS_YES) { + text = _("Yes"); + } else if (info->contains_js == EV_DOCUMENT_CONTAINS_JS_NO) { + text = _("No"); + } else { + text = _("Unknown"); + } + SET_PROPERTY (CONTAINS_JS, text); + } + + if (ev_document_get_size (document)) { + text = g_format_size (ev_document_get_size (document)); + SET_PROPERTY (FILE_SIZE, text); + g_free (text); + } + + return G_LIST_MODEL (model); +#undef SET_PROPERTY +#undef FIELD_SET_PROPERTY } static GList * -ev_properties_get_pages (NautilusPropertyPageProvider *provider, +ev_properties_get_models (NautilusPropertiesModelProvider *provider, GList *files) { GError *error = NULL; EvDocument *document = NULL; - GList *pages = NULL; + GList *models = NULL; NautilusFileInfo *file; gchar *uri = NULL; - GtkWidget *page, *label; - GtkWidget *scrolled; - NautilusPropertyPage *property_page; + gchar *mime_type = NULL; + NautilusPropertiesModel *properties_group; /* only add properties page if a single file is selected */ if (files == NULL || files->next != NULL) @@ -105,32 +186,21 @@ ev_properties_get_pages (NautilusPropertyPageProvider *provider, if (!document) goto end; - label = gtk_label_new (_("Document")); - page = ev_properties_view_new (document); - ev_properties_view_set_info (EV_PROPERTIES_VIEW (page), - ev_document_get_info (document)); - gtk_widget_show (page); - - scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), - GTK_POLICY_NEVER, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_propagate_natural_width (GTK_SCROLLED_WINDOW (scrolled), - TRUE); - gtk_container_add (GTK_CONTAINER (scrolled), page); - gtk_widget_show (scrolled); - - property_page = nautilus_property_page_new ("document-properties", - label, scrolled); + ev_document_load (document, uri, &error); + if (error) { + g_error_free (error); + goto end; + } - pages = g_list_prepend (pages, property_page); + properties_group = nautilus_properties_model_new (_("Document"), build_properties (document)); + models = g_list_prepend (models, properties_group); end: g_free (uri); g_clear_pointer (&error, g_error_free); g_clear_object (&document); - return pages; + return models; } /* --- extension interface --- */ diff --git a/properties/ev-properties-view.c b/properties/ev-properties-view.c index 04aa656f2..cb30722b9 100644 --- a/properties/ev-properties-view.c +++ b/properties/ev-properties-view.c @@ -33,49 +33,6 @@ #include "ev-properties-view.h" -typedef enum { - TITLE_PROPERTY, - URI_PROPERTY, - SUBJECT_PROPERTY, - AUTHOR_PROPERTY, - KEYWORDS_PROPERTY, - PRODUCER_PROPERTY, - CREATOR_PROPERTY, - CREATION_DATE_PROPERTY, - MOD_DATE_PROPERTY, - N_PAGES_PROPERTY, - LINEARIZED_PROPERTY, - FORMAT_PROPERTY, - SECURITY_PROPERTY, - CONTAINS_JS_PROPERTY, - PAPER_SIZE_PROPERTY, - FILE_SIZE_PROPERTY, - N_PROPERTIES, -} Property; - -typedef struct { - Property property; - const char *label; -} PropertyInfo; - -static const PropertyInfo properties_info[] = { - { TITLE_PROPERTY, N_("Title:") }, - { URI_PROPERTY, N_("Location:") }, - { SUBJECT_PROPERTY, N_("Subject:") }, - { AUTHOR_PROPERTY, N_("Author:") }, - { KEYWORDS_PROPERTY, N_("Keywords:") }, - { PRODUCER_PROPERTY, N_("Producer:") }, - { CREATOR_PROPERTY, N_("Creator:") }, - { CREATION_DATE_PROPERTY, N_("Created:") }, - { MOD_DATE_PROPERTY, N_("Modified:") }, - { N_PAGES_PROPERTY, N_("Number of Pages:") }, - { LINEARIZED_PROPERTY, N_("Optimized:") }, - { FORMAT_PROPERTY, N_("Format:") }, - { SECURITY_PROPERTY, N_("Security:") }, - { CONTAINS_JS_PROPERTY, N_("Contains Javascript:") }, - { PAPER_SIZE_PROPERTY, N_("Paper Size:") }, - { FILE_SIZE_PROPERTY, N_("Size:") } -}; struct _EvPropertiesView { GtkBox base_instance; @@ -242,12 +199,9 @@ set_property (EvPropertiesView *properties, } if (property_label && value_label) { - atk_object_add_relationship (gtk_widget_get_accessible (property_label), - ATK_RELATION_LABEL_FOR, - gtk_widget_get_accessible (value_label)); - atk_object_add_relationship (gtk_widget_get_accessible (value_label), - ATK_RELATION_LABELLED_BY, - gtk_widget_get_accessible (property_label)); + gtk_accessible_update_relation (GTK_ACCESSIBLE (value_label), + GTK_ACCESSIBLE_RELATION_LABELLED_BY, property_label, + NULL, -1); } gtk_widget_show (value_label); @@ -297,7 +251,7 @@ get_tolerance (gdouble size) return 3.0f; } -static char * +char * ev_regular_paper_size (const EvDocumentInfo *info) { GList *paper_sizes, *l; @@ -444,15 +398,17 @@ ev_properties_view_set_info (EvPropertiesView *properties, const EvDocumentInfo static void ev_properties_view_init (EvPropertiesView *properties) { + GtkWidget *widget = GTK_WIDGET (properties); + + gtk_widget_set_margin_bottom (widget, 12); + gtk_widget_set_margin_top (widget, 12); + gtk_widget_set_margin_start (widget, 12); + gtk_widget_set_margin_end (widget, 12); + properties->grid = gtk_grid_new (); gtk_grid_set_column_spacing (GTK_GRID (properties->grid), 12); gtk_grid_set_row_spacing (GTK_GRID (properties->grid), 6); - gtk_box_pack_start (GTK_BOX (properties), properties->grid, TRUE, TRUE, 0); - gtk_widget_show (properties->grid); - gtk_widget_set_margin_bottom (properties->grid, 12); - gtk_widget_set_margin_top (properties->grid, 12); - gtk_widget_set_margin_start (properties->grid, 12); - gtk_widget_set_margin_end (properties->grid, 12); + gtk_box_prepend (GTK_BOX (properties), properties->grid); } void diff --git a/properties/ev-properties-view.h b/properties/ev-properties-view.h index 8d27d5b50..f620147b9 100644 --- a/properties/ev-properties-view.h +++ b/properties/ev-properties-view.h @@ -26,6 +26,50 @@ G_BEGIN_DECLS +typedef enum { + TITLE_PROPERTY, + URI_PROPERTY, + SUBJECT_PROPERTY, + AUTHOR_PROPERTY, + KEYWORDS_PROPERTY, + PRODUCER_PROPERTY, + CREATOR_PROPERTY, + CREATION_DATE_PROPERTY, + MOD_DATE_PROPERTY, + N_PAGES_PROPERTY, + LINEARIZED_PROPERTY, + FORMAT_PROPERTY, + SECURITY_PROPERTY, + CONTAINS_JS_PROPERTY, + PAPER_SIZE_PROPERTY, + FILE_SIZE_PROPERTY, + N_PROPERTIES, +} Property; + +typedef struct { + Property property; + const char *label; +} PropertyInfo; + +static const PropertyInfo properties_info[] = { + { TITLE_PROPERTY, N_("Title:") }, + { URI_PROPERTY, N_("Location:") }, + { SUBJECT_PROPERTY, N_("Subject:") }, + { AUTHOR_PROPERTY, N_("Author:") }, + { KEYWORDS_PROPERTY, N_("Keywords:") }, + { PRODUCER_PROPERTY, N_("Producer:") }, + { CREATOR_PROPERTY, N_("Creator:") }, + { CREATION_DATE_PROPERTY, N_("Created:") }, + { MOD_DATE_PROPERTY, N_("Modified:") }, + { N_PAGES_PROPERTY, N_("Number of Pages:") }, + { LINEARIZED_PROPERTY, N_("Optimized:") }, + { FORMAT_PROPERTY, N_("Format:") }, + { SECURITY_PROPERTY, N_("Security:") }, + { CONTAINS_JS_PROPERTY, N_("Contains Javascript:") }, + { PAPER_SIZE_PROPERTY, N_("Paper Size:") }, + { FILE_SIZE_PROPERTY, N_("Size:") } +}; + typedef struct _EvPropertiesView EvPropertiesView; typedef struct _EvPropertiesViewClass EvPropertiesViewClass; typedef struct _EvPropertiesViewPrivate EvPropertiesViewPrivate; @@ -44,4 +88,6 @@ GtkWidget *ev_properties_view_new (EvDocument *document); void ev_properties_view_set_info (EvPropertiesView *properties, const EvDocumentInfo *info); +char * ev_regular_paper_size (const EvDocumentInfo *info); + G_END_DECLS -- GitLab From d9425708af0d1964914a08ec68ef485d90112335 Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Sun, 12 Nov 2023 17:48:25 +0800 Subject: [PATCH 08/50] meson: enable libdocument, backend, thumbnailer and properties Signed-off-by: Qiu Wenbo --- meson.build | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 0bed24bd7..b5de346c7 100644 --- a/meson.build +++ b/meson.build @@ -432,11 +432,11 @@ mime_types_conf.set('EVINCE_MIME_TYPES', ';'.join(evince_mime_types)) mime_types_conf.set('PACKAGE_ICON_NAME', app_id) subdir('cut-n-paste') -#subdir('libdocument') -#subdir('backend') +subdir('libdocument') +subdir('backend') #subdir('libview') #subdir('libmisc') -#subdir('properties') +subdir('properties') # *** Document Viewer *** enable_viewer = get_option('viewer') @@ -450,7 +450,7 @@ subdir('po') # *** Thumbnailer *** enable_thumbnailer = get_option('thumbnailer') if enable_thumbnailer - #subdir('thumbnailer') + subdir('thumbnailer') endif # Print Previewer -- GitLab From 0f4338165776c81e77de4549121e8935f7c4789d Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Sun, 12 Nov 2023 18:12:58 +0800 Subject: [PATCH 09/50] build: Disable flatpak build for CI Flatpak failed due to can't find evince command. We will enable it when the gtk4 port is finished. Signed-off-by: Qiu Wenbo --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4dafb13df..f82b8cbb1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -52,6 +52,7 @@ meson-internal-synctex: flatpak: extends: .flatpak stage: build + when: manual variables: MANIFEST_PATH: "build-aux/flatpak/org.gnome.Evince.json" -- GitLab From 41637a1271a849747b53a4516fc98d485ad079fe Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Wed, 8 Dec 2021 10:19:17 +0800 Subject: [PATCH 10/50] libview: Temporary remove a11y support The a11y support in GTK4 changed a lot. Eventually we should bring back a11y support. We simply remove a11y support for now. Signed-off-by: Qiu Wenbo --- libview/ev-form-field-accessible.h | 1 - libview/ev-image-accessible.h | 1 - libview/ev-link-accessible.h | 1 - libview/ev-page-accessible.h | 1 - libview/meson.build | 10 +++++----- 5 files changed, 5 insertions(+), 9 deletions(-) diff --git a/libview/ev-form-field-accessible.h b/libview/ev-form-field-accessible.h index fa003f592..4350d58ef 100644 --- a/libview/ev-form-field-accessible.h +++ b/libview/ev-form-field-accessible.h @@ -25,7 +25,6 @@ #error "This is a private header." #endif -#include #include "ev-page-accessible.h" #include "ev-form-field.h" diff --git a/libview/ev-image-accessible.h b/libview/ev-image-accessible.h index 9776d6413..ff937df87 100644 --- a/libview/ev-image-accessible.h +++ b/libview/ev-image-accessible.h @@ -25,7 +25,6 @@ #error "This is a private header." #endif -#include #include "ev-page-accessible.h" #include "ev-image.h" diff --git a/libview/ev-link-accessible.h b/libview/ev-link-accessible.h index 69540dd15..bbbce530a 100644 --- a/libview/ev-link-accessible.h +++ b/libview/ev-link-accessible.h @@ -24,7 +24,6 @@ #error "This is a private header." #endif -#include #include "ev-page-accessible.h" #include "ev-link.h" diff --git a/libview/ev-page-accessible.h b/libview/ev-page-accessible.h index 45edeeb68..58ba01406 100644 --- a/libview/ev-page-accessible.h +++ b/libview/ev-page-accessible.h @@ -26,7 +26,6 @@ #error "This is a private header." #endif -#include #include "ev-view-accessible.h" #include "ev-view.h" diff --git a/libview/meson.build b/libview/meson.build index 53fc3f351..d4abe4b3c 100644 --- a/libview/meson.build +++ b/libview/meson.build @@ -20,19 +20,19 @@ sources = files( 'ev-annotation-window.c', 'ev-color-contrast.c', 'ev-document-model.c', - 'ev-form-field-accessible.c', - 'ev-image-accessible.c', + #'ev-form-field-accessible.c', + #'ev-image-accessible.c', 'ev-jobs.c', 'ev-job-scheduler.c', - 'ev-link-accessible.c', - 'ev-page-accessible.c', + #'ev-link-accessible.c', + #'ev-page-accessible.c', 'ev-page-cache.c', 'ev-pixbuf-cache.c', 'ev-print-operation.c', 'ev-timeline.c', 'ev-transition-animation.c', 'ev-view.c', - 'ev-view-accessible.c', + #'ev-view-accessible.c', 'ev-view-cursor.c', 'ev-view-presentation.c', ) -- GitLab From e726471c8acb8ac18db7d18c30e7a7826fd7cfbb Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Sat, 7 Aug 2021 14:20:43 +0800 Subject: [PATCH 11/50] libview: Port cursor API to gtk4 For creating standard cursors, gdk_cursor_new_for_display() has been removed, you have to use cursor names instead of GdkCursorType. Callers will be updated in their corresponding port commits. Signed-off-by: Qiu Wenbo --- libview/ev-view-cursor.c | 47 ++++++++++++++-------------------------- libview/ev-view-cursor.h | 3 +-- 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/libview/ev-view-cursor.c b/libview/ev-view-cursor.c index 58d04a27d..bcdfc9306 100644 --- a/libview/ev-view-cursor.c +++ b/libview/ev-view-cursor.c @@ -19,37 +19,22 @@ #include "ev-view-cursor.h" -GdkCursor * -ev_view_cursor_new (GdkDisplay *display, - EvViewCursor new_cursor) -{ - GdkCursor *cursor = NULL; +static const gchar *cursors[] = { + [EV_VIEW_CURSOR_NORMAL] = NULL, + [EV_VIEW_CURSOR_IBEAM] = "text", + [EV_VIEW_CURSOR_LINK] = "pointer", + [EV_VIEW_CURSOR_WAIT] = "wait", + [EV_VIEW_CURSOR_HIDDEN] = "none", + [EV_VIEW_CURSOR_DRAG] = "grabbing", + [EV_VIEW_CURSOR_AUTOSCROLL] = "move", + [EV_VIEW_CURSOR_ADD] = "crosshair", +}; - switch (new_cursor) { - case EV_VIEW_CURSOR_NORMAL: - break; - case EV_VIEW_CURSOR_IBEAM: - cursor = gdk_cursor_new_for_display (display, GDK_XTERM); - break; - case EV_VIEW_CURSOR_LINK: - cursor = gdk_cursor_new_for_display (display, GDK_HAND2); - break; - case EV_VIEW_CURSOR_WAIT: - cursor = gdk_cursor_new_for_display (display, GDK_WATCH); - break; - case EV_VIEW_CURSOR_HIDDEN: - cursor = gdk_cursor_new_for_display (display, GDK_BLANK_CURSOR); - break; - case EV_VIEW_CURSOR_DRAG: - cursor = gdk_cursor_new_for_display (display, GDK_FLEUR); - break; - case EV_VIEW_CURSOR_AUTOSCROLL: - cursor = gdk_cursor_new_for_display (display, GDK_DOUBLE_ARROW); - break; - case EV_VIEW_CURSOR_ADD: - cursor = gdk_cursor_new_for_display (display, GDK_PLUS); - break; - } +const gchar * +ev_view_cursor_name (EvViewCursor cursor) +{ + if (cursor < G_N_ELEMENTS (cursors)) + return cursors[cursor]; - return cursor; + return NULL; } diff --git a/libview/ev-view-cursor.h b/libview/ev-view-cursor.h index 4e2e8c9ff..1a76252fd 100644 --- a/libview/ev-view-cursor.h +++ b/libview/ev-view-cursor.h @@ -38,7 +38,6 @@ typedef enum { EV_VIEW_CURSOR_ADD } EvViewCursor; -GdkCursor *ev_view_cursor_new (GdkDisplay *display, - EvViewCursor cursor); +const gchar *ev_view_cursor_name (EvViewCursor cursor); G_END_DECLS -- GitLab From d367e6cb7ee52fe3981728ee73d83f233b00c734 Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Sat, 16 Dec 2023 21:38:37 +0800 Subject: [PATCH 12/50] libview: Add EvJobRenderTexture and EvJobThumbnailTexture Signed-off-by: Qiu Wenbo --- libview/ev-jobs.c | 307 ++++++++++++++++++++++++++++++++++++++++++++++ libview/ev-jobs.h | 99 +++++++++++++++ 2 files changed, 406 insertions(+) diff --git a/libview/ev-jobs.c b/libview/ev-jobs.c index d5d366067..1e3754eaa 100644 --- a/libview/ev-jobs.c +++ b/libview/ev-jobs.c @@ -61,10 +61,14 @@ static void ev_job_annots_init (EvJobAnnots *job); static void ev_job_annots_class_init (EvJobAnnotsClass *class); static void ev_job_render_cairo_init (EvJobRenderCairo *job); static void ev_job_render_cairo_class_init (EvJobRenderCairoClass *class); +static void ev_job_render_texture_init (EvJobRenderTexture *job); +static void ev_job_render_texture_class_init (EvJobRenderTextureClass *class); static void ev_job_page_data_init (EvJobPageData *job); static void ev_job_page_data_class_init (EvJobPageDataClass *class); static void ev_job_thumbnail_cairo_init (EvJobThumbnailCairo *job); static void ev_job_thumbnail_cairo_class_init (EvJobThumbnailCairoClass *class); +static void ev_job_thumbnail_texture_init (EvJobThumbnailTexture *job); +static void ev_job_thumbnail_texture_class_init (EvJobThumbnailTextureClass *class); static void ev_job_load_init (EvJobLoad *job); static void ev_job_load_class_init (EvJobLoadClass *class); static void ev_job_save_init (EvJobSave *job); @@ -103,8 +107,10 @@ G_DEFINE_TYPE (EvJobLinks, ev_job_links, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobAttachments, ev_job_attachments, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobAnnots, ev_job_annots, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobRenderCairo, ev_job_render_cairo, EV_TYPE_JOB) +G_DEFINE_TYPE (EvJobRenderTexture, ev_job_render_texture, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobPageData, ev_job_page_data, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobThumbnailCairo, ev_job_thumbnail_cairo, EV_TYPE_JOB) +G_DEFINE_TYPE (EvJobThumbnailTexture, ev_job_thumbnail_texture, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobFonts, ev_job_fonts, EV_TYPE_JOB) G_DEFINE_TYPE (EvJobLoad, ev_job_load, EV_TYPE_JOB) G_DEFINE_TYPE_WITH_PRIVATE (EvJobLoadStream, ev_job_load_stream, EV_TYPE_JOB) @@ -723,6 +729,200 @@ ev_job_render_cairo_set_selection_info (EvJobRenderCairo *job, } G_GNUC_END_IGNORE_DEPRECATIONS +/* EvJobRenderTexture */ +static void +ev_job_render_texture_init (EvJobRenderTexture *job) +{ + EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD; +} + +static void +ev_job_render_texture_dispose (GObject *object) +{ + EvJobRenderTexture *job; + + job = EV_JOB_RENDER_TEXTURE (object); + + ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job->page, job); + + g_clear_object (&job->texture); + g_clear_object (&job->selection); + g_clear_pointer (&job->selection_region, cairo_region_destroy); + + (* G_OBJECT_CLASS (ev_job_render_texture_parent_class)->dispose) (object); +} + +static GdkTexture * +gdk_texture_new_for_surface (cairo_surface_t *surface) +{ + GdkTexture *texture; + GBytes *bytes; + + g_return_val_if_fail (surface != NULL, NULL); + g_return_val_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE, NULL); + g_return_val_if_fail (cairo_image_surface_get_width (surface) > 0, NULL); + g_return_val_if_fail (cairo_image_surface_get_height (surface) > 0, NULL); + + bytes = g_bytes_new_with_free_func (cairo_image_surface_get_data (surface), + cairo_image_surface_get_height (surface) * cairo_image_surface_get_stride (surface), + (GDestroyNotify)cairo_surface_destroy, + cairo_surface_reference (surface)); + + texture = gdk_memory_texture_new (cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface), + GDK_MEMORY_DEFAULT, + bytes, + cairo_image_surface_get_stride (surface)); + + g_bytes_unref (bytes); + + return texture; +} + +EvJob * +ev_job_render_texture_new (EvDocument *document, + gint page, + gint rotation, + gdouble scale, + gint width, + gint height) +{ + EvJobRenderTexture *job; + + ev_debug_message (DEBUG_JOBS, "page: %d", page); + + job = g_object_new (EV_TYPE_JOB_RENDER_TEXTURE, NULL); + + EV_JOB (job)->document = g_object_ref (document); + job->page = page; + job->rotation = rotation; + job->scale = scale; + job->target_width = width; + job->target_height = height; + + return EV_JOB (job); +} + +static gboolean +ev_job_render_texture_run (EvJob *job) +{ + EvJobRenderTexture *job_render = EV_JOB_RENDER_TEXTURE (job); + EvPage *ev_page; + EvRenderContext *rc; + cairo_surface_t *surface, *selection = NULL; + + ev_debug_message (DEBUG_JOBS, "page: %d (%p)", job_render->page, job); + ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); + + ev_document_doc_mutex_lock (); + + ev_profiler_start (EV_PROFILE_JOBS, "Rendering page %d", job_render->page); + + ev_document_fc_mutex_lock (); + + ev_page = ev_document_get_page (job->document, job_render->page); + rc = ev_render_context_new (ev_page, job_render->rotation, job_render->scale); + ev_render_context_set_target_size (rc, + job_render->target_width, job_render->target_height); + g_object_unref (ev_page); + + surface = ev_document_render (job->document, rc); + + if (surface == NULL || + cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) { + ev_document_fc_mutex_unlock (); + ev_document_doc_mutex_unlock (); + g_object_unref (rc); + + if (surface != NULL) { + cairo_status_t status = cairo_surface_status (surface); + ev_job_failed (job, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("Failed to render page %d: %s"), + job_render->page, + cairo_status_to_string (status)); + } else { + ev_job_failed (job, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("Failed to render page %d"), + job_render->page); + } + + job_render->texture = NULL; + return FALSE; + } + + job_render->texture = gdk_texture_new_for_surface (surface); + cairo_surface_destroy (surface); + + /* If job was cancelled during the page rendering, + * we return now, so that the thread is finished ASAP + */ + if (g_cancellable_is_cancelled (job->cancellable)) { + ev_document_fc_mutex_unlock (); + ev_document_doc_mutex_unlock (); + g_object_unref (rc); + + return FALSE; + } + + if (job_render->include_selection && EV_IS_SELECTION (job->document)) { + ev_selection_render_selection (EV_SELECTION (job->document), + rc, + &selection, + &(job_render->selection_points), + NULL, + job_render->selection_style, + &(job_render->text), &(job_render->base)); + job_render->selection_region = + ev_selection_get_selection_region (EV_SELECTION (job->document), + rc, + job_render->selection_style, + &(job_render->selection_points)); + + if (selection != NULL) { + job_render->selection = gdk_texture_new_for_surface (selection); + cairo_surface_destroy (selection); + } + } + + g_object_unref (rc); + + ev_document_fc_mutex_unlock (); + ev_document_doc_mutex_unlock (); + + ev_job_succeeded (job); + + return FALSE; +} + +static void +ev_job_render_texture_class_init (EvJobRenderTextureClass *class) +{ + GObjectClass *oclass = G_OBJECT_CLASS (class); + EvJobClass *job_class = EV_JOB_CLASS (class); + + oclass->dispose = ev_job_render_texture_dispose; + job_class->run = ev_job_render_texture_run; +} + +void +ev_job_render_texture_set_selection_info (EvJobRenderTexture *job, + EvRectangle *selection_points, + EvSelectionStyle selection_style, + GdkRGBA *text, + GdkRGBA *base) +{ + job->include_selection = TRUE; + + job->selection_points = *selection_points; + job->selection_style = selection_style; + job->text = *text; + job->base = *base; +} + /* EvJobPageData */ static void ev_job_page_data_init (EvJobPageData *job) @@ -923,6 +1123,113 @@ ev_job_thumbnail_cairo_new_with_target_size (EvDocument *document, } G_GNUC_END_IGNORE_DEPRECATIONS +/* EvJobThumbnailTexture */ +static void +ev_job_thumbnail_texture_init (EvJobThumbnailTexture *job) +{ + EV_JOB (job)->run_mode = EV_JOB_RUN_THREAD; +} + +static void +ev_job_thumbnail_texture_dispose (GObject *object) +{ + EvJobThumbnailTexture *job; + + job = EV_JOB_THUMBNAIL_TEXTURE (object); + + ev_debug_message (DEBUG_JOBS, "%d (%p)", job->page, job); + + g_clear_object (&job->thumbnail_texture); + + G_OBJECT_CLASS (ev_job_thumbnail_texture_parent_class)->dispose (object); +} + +static gboolean +ev_job_thumbnail_texture_run (EvJob *job) +{ + EvJobThumbnailTexture *job_thumb = EV_JOB_THUMBNAIL_TEXTURE(job); + EvRenderContext *rc; + EvPage *page; + cairo_surface_t *surface; + + ev_debug_message (DEBUG_JOBS, "%d (%p)", job_thumb->page, job); + ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); + + ev_document_doc_mutex_lock (); + + page = ev_document_get_page (job->document, job_thumb->page); + rc = ev_render_context_new (page, job_thumb->rotation, job_thumb->scale); + ev_render_context_set_target_size (rc, + job_thumb->target_width, job_thumb->target_height); + g_object_unref (page); + + surface = ev_document_get_thumbnail_surface (job->document, rc); + + job_thumb->thumbnail_texture = gdk_texture_new_for_surface (surface); + g_object_unref (rc); + ev_document_doc_mutex_unlock (); + + if (job_thumb->thumbnail_texture == NULL) { + ev_job_failed (job, + EV_DOCUMENT_ERROR, + EV_DOCUMENT_ERROR_INVALID, + _("Failed to create thumbnail for page %d"), + job_thumb->page); + } else { + ev_job_succeeded (job); + } + + return FALSE; +} + +static void +ev_job_thumbnail_texture_class_init (EvJobThumbnailTextureClass *class) +{ + GObjectClass *oclass = G_OBJECT_CLASS (class); + EvJobClass *job_class = EV_JOB_CLASS (class); + + oclass->dispose = ev_job_thumbnail_texture_dispose; + job_class->run = ev_job_thumbnail_texture_run; +} + +EvJob * +ev_job_thumbnail_texture_new (EvDocument *document, + gint page, + gint rotation, + gdouble scale) +{ + EvJobThumbnailTexture *job; + + ev_debug_message (DEBUG_JOBS, "%d", page); + + job = g_object_new (EV_TYPE_JOB_THUMBNAIL_TEXTURE, NULL); + + EV_JOB (job)->document = g_object_ref (document); + job->page = page; + job->rotation = rotation; + job->scale = scale; + job->target_width = -1; + job->target_height = -1; + + return EV_JOB (job); +} + +EvJob * +ev_job_thumbnail_texture_new_with_target_size (EvDocument *document, + gint page, + gint rotation, + gint target_width, + gint target_height) +{ + EvJob *job = ev_job_thumbnail_texture_new (document, page, rotation, 1.); + EvJobThumbnailTexture *job_thumb = EV_JOB_THUMBNAIL_TEXTURE(job); + + job_thumb->target_width = target_width; + job_thumb->target_height = target_height; + + return job; +} + /* EvJobFonts */ static void ev_job_fonts_init (EvJobFonts *job) diff --git a/libview/ev-jobs.h b/libview/ev-jobs.h index 2fbc3b6c6..8ce7b2089 100644 --- a/libview/ev-jobs.h +++ b/libview/ev-jobs.h @@ -38,12 +38,18 @@ typedef struct _EvJobClass EvJobClass; typedef struct _EvJobRenderCairo EvJobRenderCairo; typedef struct _EvJobRenderCairoClass EvJobRenderCairoClass; +typedef struct _EvJobRenderTexture EvJobRenderTexture; +typedef struct _EvJobRenderTextureClass EvJobRenderTextureClass; + typedef struct _EvJobPageData EvJobPageData; typedef struct _EvJobPageDataClass EvJobPageDataClass; typedef struct _EvJobThumbnailCairo EvJobThumbnailCairo; typedef struct _EvJobThumbnailCairoClass EvJobThumbnailCairoClass; +typedef struct _EvJobThumbnailTexture EvJobThumbnailTexture; +typedef struct _EvJobThumbnailTextureClass EvJobThumbnailTextureClass; + typedef struct _EvJobLinks EvJobLinks; typedef struct _EvJobLinksClass EvJobLinksClass; @@ -118,6 +124,13 @@ typedef struct _EvJobPrintClass EvJobPrintClass; #define EV_IS_JOB_RENDER_CAIRO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_JOB_RENDER_CAIRO)) #define EV_JOB_RENDER_CAIRO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_JOB_RENDER_CAIRO, EvJobRenderCairoClass)) +#define EV_TYPE_JOB_RENDER_TEXTURE (ev_job_render_texture_get_type()) +#define EV_JOB_RENDER_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_JOB_RENDER_TEXTURE, EvJobRenderTexture)) +#define EV_IS_JOB_RENDER_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_JOB_RENDER_TEXTURE)) +#define EV_JOB_RENDER_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_JOB_RENDER_TEXTURE, EvJobRenderTextureClass)) +#define EV_IS_JOB_RENDER_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_JOB_RENDER_TEXTURE)) +#define EV_JOB_RENDER_TEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_JOB_RENDER_TEXTURE, EvJobRenderTextureClass)) + #define EV_TYPE_JOB_PAGE_DATA (ev_job_page_data_get_type()) #define EV_JOB_PAGE_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_JOB_PAGE_DATA, EvJobPageData)) #define EV_IS_JOB_PAGE_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_JOB_PAGE_DATA)) @@ -132,6 +145,13 @@ typedef struct _EvJobPrintClass EvJobPrintClass; #define EV_IS_JOB_THUMBNAIL_CAIRO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_JOB_THUMBNAIL_CAIRO)) #define EV_JOB_THUMBNAIL_CAIRO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_JOB_THUMBNAIL_CAIRO, EvJobThumbnailCairoClass)) +#define EV_TYPE_JOB_THUMBNAIL_TEXTURE (ev_job_thumbnail_texture_get_type()) +#define EV_JOB_THUMBNAIL_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_JOB_THUMBNAIL_TEXTURE, EvJobThumbnailTexture)) +#define EV_IS_JOB_THUMBNAIL_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_JOB_THUMBNAIL_TEXTURE)) +#define EV_JOB_THUMBNAIL_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_JOB_THUMBNAIL_TEXTURE, EvJobThumbnailTextureClass)) +#define EV_IS_JOB_THUMBNAIL_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_JOB_THUMBNAIL_TEXTURE)) +#define EV_JOB_THUMBNAIL_TEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_JOB_THUMBNAIL_TEXTURE, EvJobThumbnailTextureClass)) + #define EV_TYPE_JOB_FONTS (ev_job_fonts_get_type()) #define EV_JOB_FONTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_JOB_FONTS, EvJobFonts)) #define EV_IS_JOB_FONTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_JOB_FONTS)) @@ -301,6 +321,33 @@ struct _EvJobRenderCairoClass EvJobClass parent_class; }; +struct _EvJobRenderTexture +{ + EvJob parent; + + gint page; + gint rotation; + gdouble scale; + + gboolean page_ready; + gint target_width; + gint target_height; + GdkTexture *texture; + + gboolean include_selection; + GdkTexture *selection; + cairo_region_t *selection_region; + EvRectangle selection_points; + EvSelectionStyle selection_style; + GdkRGBA base; + GdkRGBA text; +}; + +struct _EvJobRenderTextureClass +{ + EvJobClass parent_class; +}; + typedef enum { EV_PAGE_DATA_INCLUDE_NONE = 0, EV_PAGE_DATA_INCLUDE_LINKS = 1 << 0, @@ -360,6 +407,24 @@ struct _EvJobThumbnailCairoClass EvJobClass parent_class; }; +struct _EvJobThumbnailTexture +{ + EvJob parent; + + gint page; + gint rotation; + gdouble scale; + gint target_width; + gint target_height; + + GdkTexture *thumbnail_texture; +}; + +struct _EvJobThumbnailTextureClass +{ + EvJobClass parent_class; +}; + struct _EvJobFonts { EvJob parent; @@ -568,6 +633,24 @@ void ev_job_render_cairo_set_selection_info (EvJobRenderCairo *job, EvSelectionStyle selection_style, GdkRGBA *text, GdkRGBA *base); + +/* EvJobRenderTexture */ +EV_PUBLIC +GType ev_job_render_texture_get_type (void) G_GNUC_CONST; +EV_PUBLIC +EvJob *ev_job_render_texture_new (EvDocument *document, + gint page, + gint rotation, + gdouble scale, + gint width, + gint height); +EV_PUBLIC +void ev_job_render_texture_set_selection_info (EvJobRenderTexture *job, + EvRectangle *selection_points, + EvSelectionStyle selection_style, + GdkRGBA *text, + GdkRGBA *base); + /* EvJobPageData */ EV_PUBLIC GType ev_job_page_data_get_type (void) G_GNUC_CONST; @@ -590,6 +673,22 @@ EvJob *ev_job_thumbnail_cairo_new_with_target_size (EvDocument *documen gint rotation, gint target_width, gint target_height); + +/* EvJobThumbnailTexture */ +EV_PUBLIC +GType ev_job_thumbnail_texture_get_type (void) G_GNUC_CONST; +EV_PUBLIC +EvJob *ev_job_thumbnail_texture_new (EvDocument *document, + gint page, + gint rotation, + gdouble scale); +EV_PUBLIC +EvJob *ev_job_thumbnail_texture_new_with_target_size (EvDocument *document, + gint page, + gint rotation, + gint target_width, + gint target_height); + /* EvJobFonts */ EV_PUBLIC GType ev_job_fonts_get_type (void) G_GNUC_CONST; -- GitLab From 970afbe3b57fd8f045d87a2c8aea330ada84fde7 Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Wed, 8 Dec 2021 00:05:42 +0800 Subject: [PATCH 13/50] libview: Port EvPixbufCache to gtk4 We switch to GdkTexture based drawing model as GTK4 recommended. Signed-off-by: Qiu Wenbo --- libview/ev-pixbuf-cache.c | 168 ++++++++++++++++++-------------------- libview/ev-pixbuf-cache.h | 58 +++++++------ 2 files changed, 107 insertions(+), 119 deletions(-) diff --git a/libview/ev-pixbuf-cache.c b/libview/ev-pixbuf-cache.c index dcbba3061..f5b4110e8 100644 --- a/libview/ev-pixbuf-cache.c +++ b/libview/ev-pixbuf-cache.c @@ -15,9 +15,7 @@ typedef struct _CacheJobInfo /* Region of the page that needs to be drawn */ cairo_region_t *region; - - /* Data we get from rendering */ - cairo_surface_t *surface; + GdkTexture *texture; /* Device scale factor of target widget */ int device_scale; @@ -29,7 +27,7 @@ typedef struct _CacheJobInfo EvSelectionStyle selection_style; gboolean points_set; - cairo_surface_t *selection; + GdkTexture *selection_texture; gdouble selection_scale; EvRectangle selection_points; @@ -49,7 +47,6 @@ struct _EvPixbufCache int start_page; int end_page; ScrollDirection scroll_direction; - gboolean inverted_colors; gsize max_size; @@ -184,8 +181,8 @@ dispose_cache_job_info (CacheJobInfo *job_info, if (job_info->job) end_job (job_info, data); - g_clear_pointer (&job_info->surface, cairo_surface_destroy); - g_clear_pointer (&job_info->selection, cairo_surface_destroy); + g_clear_object (&job_info->texture); + g_clear_object (&job_info->selection_texture); g_clear_pointer (&job_info->region, cairo_region_destroy); g_clear_pointer (&job_info->selection_region, cairo_region_destroy); @@ -255,29 +252,48 @@ set_device_scale_on_surface (cairo_surface_t *surface, cairo_surface_set_device_scale (surface, device_scale, device_scale); } +static GdkTexture * +gdk_texture_new_for_surface (cairo_surface_t *surface) +{ + GdkTexture *texture; + GBytes *bytes; + + g_return_val_if_fail (surface != NULL, NULL); + g_return_val_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE, NULL); + g_return_val_if_fail (cairo_image_surface_get_width (surface) > 0, NULL); + g_return_val_if_fail (cairo_image_surface_get_height (surface) > 0, NULL); + + bytes = g_bytes_new_with_free_func (cairo_image_surface_get_data (surface), + cairo_image_surface_get_height (surface) * cairo_image_surface_get_stride (surface), + (GDestroyNotify)cairo_surface_destroy, + cairo_surface_reference (surface)); + + texture = gdk_memory_texture_new (cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface), + GDK_MEMORY_DEFAULT, + bytes, + cairo_image_surface_get_stride (surface)); + + g_bytes_unref (bytes); + + return texture; +} + static void -copy_job_to_job_info (EvJobRenderCairo *job_render, +copy_job_to_job_info (EvJobRenderTexture *job_render, CacheJobInfo *job_info, EvPixbufCache *pixbuf_cache) { - if (job_info->surface) { - cairo_surface_destroy (job_info->surface); - } - job_info->surface = cairo_surface_reference (job_render->surface); - set_device_scale_on_surface (job_info->surface, job_info->device_scale); - if (pixbuf_cache->inverted_colors) { - ev_document_misc_invert_surface (job_info->surface); - } + g_clear_object (&job_info->texture); + + job_info->texture = g_object_ref (job_render->texture); job_info->points_set = FALSE; if (job_render->include_selection) { - g_clear_pointer (&job_info->selection, cairo_surface_destroy); + g_clear_object (&job_info->selection_texture); g_clear_pointer (&job_info->selection_region, cairo_region_destroy); job_info->selection_points = job_render->selection_points; - job_info->selection = cairo_surface_reference (job_render->selection); - if (job_info->selection) - set_device_scale_on_surface (job_info->selection, job_info->device_scale); job_info->selection_scale = job_render->scale * job_info->device_scale; g_assert (job_info->selection_points.x1 >= 0); @@ -285,6 +301,7 @@ copy_job_to_job_info (EvJobRenderCairo *job_render, job_info->selection_region = cairo_region_reference (job_render->selection_region); job_info->selection_region_scale = job_render->scale; + job_info->selection_texture = g_object_ref (job_render->selection); job_info->points_set = TRUE; } @@ -299,7 +316,7 @@ job_finished_cb (EvJob *job, EvPixbufCache *pixbuf_cache) { CacheJobInfo *job_info; - EvJobRenderCairo *job_render = EV_JOB_RENDER_CAIRO (job); + EvJobRenderTexture *job_render = EV_JOB_RENDER_TEXTURE (job); /* If the job is outside of our interest, we silently discard it */ if ((job_render->page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size)) || @@ -338,12 +355,12 @@ check_job_size_and_unref (EvPixbufCache *pixbuf_cache, device_scale = get_device_scale (pixbuf_cache); if (job_info->device_scale == device_scale) { _get_page_size_for_scale_and_rotation (job_info->job->document, - EV_JOB_RENDER_CAIRO (job_info->job)->page, + EV_JOB_RENDER_TEXTURE (job_info->job)->page, scale, - EV_JOB_RENDER_CAIRO (job_info->job)->rotation, + EV_JOB_RENDER_TEXTURE (job_info->job)->rotation, &width, &height); - if (width * device_scale == EV_JOB_RENDER_CAIRO (job_info->job)->target_width && - height * device_scale == EV_JOB_RENDER_CAIRO (job_info->job)->target_height) + if (width * device_scale == EV_JOB_RENDER_TEXTURE (job_info->job)->target_width && + height * device_scale == EV_JOB_RENDER_TEXTURE (job_info->job)->target_height) return; } @@ -401,7 +418,7 @@ move_one_job (CacheJobInfo *job_info, *target_page = *job_info; job_info->job = NULL; job_info->region = NULL; - job_info->surface = NULL; + job_info->texture = NULL; if (new_priority != priority && target_page->job) { ev_job_scheduler_update_job (target_page->job, new_priority); @@ -642,7 +659,7 @@ add_job (EvPixbufCache *pixbuf_cache, if (job_info->job) end_job (job_info, pixbuf_cache); - job_info->job = ev_job_render_cairo_new (pixbuf_cache->document, + job_info->job = ev_job_render_texture_new (pixbuf_cache->document, page, rotation, scale * job_info->device_scale, width * job_info->device_scale, @@ -652,7 +669,7 @@ add_job (EvPixbufCache *pixbuf_cache, GdkRGBA text, base; _ev_view_get_selection_colors (EV_VIEW (pixbuf_cache->view), &base, &text); - ev_job_render_cairo_set_selection_info (EV_JOB_RENDER_CAIRO (job_info->job), + ev_job_render_texture_set_selection_info (EV_JOB_RENDER_TEXTURE (job_info->job), &(job_info->target_points), job_info->selection_style, &text, &base); @@ -682,16 +699,16 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache, page, scale, rotation, &width, &height); - if (job_info->surface && + if (job_info->texture && job_info->device_scale == device_scale && - cairo_image_surface_get_width (job_info->surface) == width * device_scale && - cairo_image_surface_get_height (job_info->surface) == height * device_scale) + gdk_texture_get_width (job_info->texture) == width * device_scale && + gdk_texture_get_height (job_info->texture) == height * device_scale) return; /* Free old surfaces for non visible pages */ if (priority == EV_JOB_PRIORITY_LOW) { - g_clear_pointer (&job_info->surface, cairo_surface_destroy); - g_clear_pointer (&job_info->selection, cairo_surface_destroy); + g_clear_object (&job_info->texture); + g_clear_object (&job_info->selection_texture); } add_job (pixbuf_cache, job_info, NULL, @@ -817,40 +834,8 @@ ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache, ev_pixbuf_cache_add_jobs_if_needed (pixbuf_cache, rotation, scale); } -void -ev_pixbuf_cache_set_inverted_colors (EvPixbufCache *pixbuf_cache, - gboolean inverted_colors) -{ - gint i; - - if (pixbuf_cache->inverted_colors == inverted_colors) - return; - - pixbuf_cache->inverted_colors = inverted_colors; - - for (i = 0; i < pixbuf_cache->preload_cache_size; i++) { - CacheJobInfo *job_info; - - job_info = pixbuf_cache->prev_job + i; - if (job_info && job_info->surface) - ev_document_misc_invert_surface (job_info->surface); - - job_info = pixbuf_cache->next_job + i; - if (job_info && job_info->surface) - ev_document_misc_invert_surface (job_info->surface); - } - - for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) { - CacheJobInfo *job_info; - - job_info = pixbuf_cache->job_list + i; - if (job_info && job_info->surface) - ev_document_misc_invert_surface (job_info->surface); - } -} - -cairo_surface_t * -ev_pixbuf_cache_get_surface (EvPixbufCache *pixbuf_cache, +GdkTexture * +ev_pixbuf_cache_get_texture (EvPixbufCache *pixbuf_cache, gint page) { CacheJobInfo *job_info; @@ -860,16 +845,16 @@ ev_pixbuf_cache_get_surface (EvPixbufCache *pixbuf_cache, return NULL; if (job_info->page_ready) - return job_info->surface; + return job_info->texture; /* We don't need to wait for the idle to handle the callback */ if (job_info->job && - EV_JOB_RENDER_CAIRO (job_info->job)->page_ready) { - copy_job_to_job_info (EV_JOB_RENDER_CAIRO (job_info->job), job_info, pixbuf_cache); + EV_JOB_RENDER_TEXTURE (job_info->job)->page_ready) { + copy_job_to_job_info (EV_JOB_RENDER_TEXTURE (job_info->job), job_info, pixbuf_cache); g_signal_emit (pixbuf_cache, signals[JOB_FINISHED], 0, job_info->region); } - return job_info->surface; + return job_info->texture; } static gboolean @@ -878,7 +863,7 @@ new_selection_surface_needed (EvPixbufCache *pixbuf_cache, gint page, gfloat scale) { - if (job_info->selection) + if (job_info->selection_texture) return job_info->selection_scale != scale; return job_info->points_set; } @@ -901,7 +886,7 @@ clear_selection_surface_if_needed (EvPixbufCache *pixbuf_cache, gfloat scale) { if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) { - g_clear_pointer (&job_info->selection, cairo_surface_destroy); + g_clear_object (&job_info->selection_texture); job_info->selection_points.x1 = -1; } } @@ -952,14 +937,15 @@ ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache) CacheJobInfo *job_info; job_info = pixbuf_cache->prev_job + i; - if (job_info->selection) { - g_clear_pointer (&job_info->selection, cairo_surface_destroy); + if (job_info->selection_texture) { + g_clear_object (&job_info->selection_texture); job_info->selection_points.x1 = -1; } job_info = pixbuf_cache->next_job + i; - if (job_info->selection) { - g_clear_pointer (&job_info->selection, cairo_surface_destroy); + + if (job_info->selection_texture) { + g_clear_object (&job_info->selection_texture); job_info->selection_points.x1 = -1; } } @@ -968,15 +954,16 @@ ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache) CacheJobInfo *job_info; job_info = pixbuf_cache->job_list + i; - if (job_info->selection) { - g_clear_pointer (&job_info->selection, cairo_surface_destroy); + + if (job_info->selection_texture) { + g_clear_object (&job_info->selection_texture); job_info->selection_points.x1 = -1; } } } -cairo_surface_t * -ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache, +GdkTexture * +ev_pixbuf_cache_get_selection_texture (EvPixbufCache *pixbuf_cache, gint page, gfloat scale) { @@ -997,8 +984,8 @@ ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache, /* If we have a running job, we just return what we have under the * assumption that it'll be updated later and we can scale it as need * be */ - if (job_info->job && EV_JOB_RENDER_CAIRO (job_info->job)->include_selection) - return job_info->selection; + if (job_info->job && EV_JOB_RENDER_TEXTURE (job_info->job)->include_selection) + return job_info->selection_texture; /* Now, lets see if we need to resize the image. If we do, we clear the * old one. */ @@ -1015,11 +1002,12 @@ ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache, EvRenderContext *rc; EvPage *ev_page; gint width, height; + cairo_surface_t *selection = NULL; /* we need to get a new selection pixbuf */ ev_document_doc_mutex_lock (); if (job_info->selection_points.x1 < 0) { - g_assert (job_info->selection == NULL); + g_assert (job_info->selection_texture == NULL); old_points = NULL; } else { old_points = &(job_info->selection_points); @@ -1037,19 +1025,21 @@ ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache, _ev_view_get_selection_colors (EV_VIEW (pixbuf_cache->view), &base, &text); ev_selection_render_selection (EV_SELECTION (pixbuf_cache->document), - rc, &(job_info->selection), + rc, &selection, &(job_info->target_points), old_points, job_info->selection_style, &text, &base); - if (job_info->selection) - set_device_scale_on_surface (job_info->selection, job_info->device_scale); + if (selection) + set_device_scale_on_surface (selection, job_info->device_scale); job_info->selection_points = job_info->target_points; job_info->selection_scale = scale * job_info->device_scale; + job_info->selection_texture = gdk_texture_new_for_surface (selection); + cairo_surface_destroy (selection); g_object_unref (rc); ev_document_doc_mutex_unlock (); } - return job_info->selection; + return job_info->selection_texture; } cairo_region_t * @@ -1131,7 +1121,7 @@ clear_job_selection (CacheJobInfo *job_info) job_info->points_set = FALSE; job_info->selection_points.x1 = -1; - g_clear_pointer (&job_info->selection, cairo_surface_destroy); + g_clear_object (&job_info->selection_texture); g_clear_pointer (&job_info->selection_region, cairo_region_destroy); } diff --git a/libview/ev-pixbuf-cache.h b/libview/ev-pixbuf-cache.h index b3aed18a8..43d37cdd9 100644 --- a/libview/ev-pixbuf-cache.h +++ b/libview/ev-pixbuf-cache.h @@ -55,36 +55,34 @@ struct _EvViewSelection { typedef struct _EvPixbufCache EvPixbufCache; typedef struct _EvPixbufCacheClass EvPixbufCacheClass; -GType ev_pixbuf_cache_get_type (void) G_GNUC_CONST; -EvPixbufCache *ev_pixbuf_cache_new (GtkWidget *view, - EvDocumentModel *model, - gsize max_size); -void ev_pixbuf_cache_set_max_size (EvPixbufCache *pixbuf_cache, - gsize max_size); -void ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache, - gint start_page, - gint end_page, - GList *selection_list); -cairo_surface_t *ev_pixbuf_cache_get_surface (EvPixbufCache *pixbuf_cache, - gint page); -void ev_pixbuf_cache_clear (EvPixbufCache *pixbuf_cache); -void ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache); -void ev_pixbuf_cache_reload_page (EvPixbufCache *pixbuf_cache, - cairo_region_t *region, - gint page, - gint rotation, - gdouble scale); -void ev_pixbuf_cache_set_inverted_colors (EvPixbufCache *pixbuf_cache, - gboolean inverted_colors); +GType ev_pixbuf_cache_get_type (void) G_GNUC_CONST; +EvPixbufCache *ev_pixbuf_cache_new (GtkWidget *view, + EvDocumentModel *model, + gsize max_size); +void ev_pixbuf_cache_set_max_size (EvPixbufCache *pixbuf_cache, + gsize max_size); +void ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache, + gint start_page, + gint end_page, + GList *selection_list); +GdkTexture *ev_pixbuf_cache_get_texture (EvPixbufCache *pixbuf_cache, + gint page); +void ev_pixbuf_cache_clear (EvPixbufCache *pixbuf_cache); +void ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache); +void ev_pixbuf_cache_reload_page (EvPixbufCache *pixbuf_cache, + cairo_region_t *region, + gint page, + gint rotation, + gdouble scale); /* Selection */ -cairo_surface_t *ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache, - gint page, - gfloat scale); -cairo_region_t *ev_pixbuf_cache_get_selection_region (EvPixbufCache *pixbuf_cache, - gint page, - gfloat scale); -void ev_pixbuf_cache_set_selection_list (EvPixbufCache *pixbuf_cache, - GList *selection_list); -GList *ev_pixbuf_cache_get_selection_list (EvPixbufCache *pixbuf_cache); +GdkTexture *ev_pixbuf_cache_get_selection_texture (EvPixbufCache *pixbuf_cache, + gint page, + gfloat scale); +cairo_region_t *ev_pixbuf_cache_get_selection_region (EvPixbufCache *pixbuf_cache, + gint page, + gfloat scale); +void ev_pixbuf_cache_set_selection_list (EvPixbufCache *pixbuf_cache, + GList *selection_list); +GList *ev_pixbuf_cache_get_selection_list (EvPixbufCache *pixbuf_cache); G_END_DECLS -- GitLab From 4de3ff42c2372d70f1a644ab871306d1996e239e Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Sun, 15 Aug 2021 21:20:32 +0800 Subject: [PATCH 14/50] libview: Port EvPrintOperation to gtk4 Signed-off-by: Qiu Wenbo --- libview/ev-print-operation.c | 65 ++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/libview/ev-print-operation.c b/libview/ev-print-operation.c index 27879afd6..392445a19 100644 --- a/libview/ev-print-operation.c +++ b/libview/ev-print-operation.c @@ -1349,10 +1349,10 @@ ev_print_operation_export_class_init (EvPrintOperationExportClass *klass) #include #ifdef GDK_WINDOWING_X11 -#include +#include #endif #ifdef GDK_WINDOWING_WAYLAND -#include +#include #endif #define EV_TYPE_PRINT_OPERATION_EXPORT_PORTAL (ev_print_operation_export_portal_get_type()) @@ -1396,22 +1396,22 @@ static gboolean ev_gtk_window_export_handle (GtkWindow *window #ifdef GDK_WINDOWING_WAYLAND -typedef void (*EvGdkWaylandWindowExported) (GdkWindow *window, - const char *handle, - gpointer user_data); +typedef void (*EvGdkWaylandToplevelExported) (GdkToplevel *toplevel, + const char *handle, + gpointer user_data); typedef struct { GtkWindow *window; EvGtkWindowHandleExported callback; gpointer user_data; -} WaylandWindowHandleExportedData; +} WaylandSurfaceHandleExportedData; static void -wayland_window_handle_exported_cb (GdkWindow *window, - const char *wayland_handle_str, - gpointer user_data) +wayland_window_handle_exported_cb (GdkToplevel *toplevel, + const char *wayland_handle_str, + gpointer user_data) { - WaylandWindowHandleExportedData *data = user_data; + WaylandSurfaceHandleExportedData *data = user_data; char *handle_str; handle_str = g_strdup_printf ("wayland:%s", wayland_handle_str); @@ -1425,11 +1425,11 @@ ev_gtk_window_export_handle (GtkWindow *window, EvGtkWindowHandleExported callback, gpointer user_data) { + GdkSurface *surface = gtk_native_get_surface (GTK_NATIVE (window)); #ifdef GDK_WINDOWING_X11 if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window)))) { - GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); char *handle_str; - guint32 xid = (guint32) gdk_x11_window_get_xid (gdk_window); + guint32 xid = (guint32) gdk_x11_surface_get_xid (surface); handle_str = g_strdup_printf ("x11:%x", xid); callback (window, handle_str, user_data); @@ -1440,17 +1440,16 @@ ev_gtk_window_export_handle (GtkWindow *window, #endif #ifdef GDK_WINDOWING_WAYLAND if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window)))) { - GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); - WaylandWindowHandleExportedData *data; - data = g_new0 (WaylandWindowHandleExportedData, 1); + WaylandSurfaceHandleExportedData *data; + data = g_new0 (WaylandSurfaceHandleExportedData, 1); data->window = window; data->callback = callback; data->user_data = user_data; - if (!gdk_wayland_window_export_handle (gdk_window, - wayland_window_handle_exported_cb, - data, - g_free)) { + if (!gdk_wayland_toplevel_export_handle (GDK_TOPLEVEL (surface), + wayland_window_handle_exported_cb, + data, + g_free)) { g_free (data); return FALSE; } @@ -1971,7 +1970,7 @@ export_unix_print_dialog_response_cb (GtkDialog *dialog, if (response != GTK_RESPONSE_OK && response != GTK_RESPONSE_APPLY) { - gtk_widget_destroy (GTK_WIDGET (dialog)); + gtk_window_destroy (GTK_WINDOW (dialog)); g_signal_emit (op, signals[DONE], 0, GTK_PRINT_OPERATION_RESULT_CANCEL); return; @@ -1993,7 +1992,7 @@ export_unix_print_dialog_response_cb (GtkDialog *dialog, if ((format == EV_FILE_FORMAT_PS && !gtk_printer_accepts_ps (export_unix->printer)) || (format == EV_FILE_FORMAT_PDF && !gtk_printer_accepts_pdf (export_unix->printer))) { - gtk_widget_destroy (GTK_WIDGET (dialog)); + gtk_window_destroy (GTK_WINDOW (dialog)); g_set_error_literal (&export->error, GTK_PRINT_ERROR, @@ -2005,7 +2004,7 @@ export_unix_print_dialog_response_cb (GtkDialog *dialog, } if (!ev_print_operation_export_mkstemp (export, format)) { - gtk_widget_destroy (GTK_WIDGET (dialog)); + gtk_window_destroy (GTK_WINDOW (dialog)); g_signal_emit (op, signals[DONE], 0, GTK_PRINT_OPERATION_RESULT_ERROR); return; @@ -2026,14 +2025,14 @@ export_unix_print_dialog_response_cb (GtkDialog *dialog, gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message_dialog), "%s", _("Your print range selection does not include any pages")); g_signal_connect (message_dialog, "response", - G_CALLBACK (gtk_widget_destroy), + G_CALLBACK (gtk_window_destroy), NULL); gtk_widget_show (message_dialog); return; } - gtk_widget_destroy (GTK_WIDGET (dialog)); + gtk_window_destroy (GTK_WINDOW (dialog)); ev_print_operation_export_prepare (export, format); } @@ -2155,7 +2154,6 @@ ev_print_operation_export_unix_run_previewer (EvPrintOperationExport *export, if (app != NULL) { ctx = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (export_unix->parent_window))); - gdk_app_launch_context_set_screen (ctx, gtk_window_get_screen (export_unix->parent_window)); g_app_info_launch (app, NULL, G_APP_LAUNCH_CONTEXT (ctx), &err); @@ -2679,7 +2677,10 @@ ev_print_operation_print_create_custom_widget (EvPrintOperationPrint *print, grid = gtk_grid_new (); gtk_grid_set_row_spacing (GTK_GRID (grid), 6); gtk_grid_set_column_spacing (GTK_GRID (grid), 12); - gtk_container_set_border_width (GTK_CONTAINER (grid), 12); + gtk_widget_set_margin_top (grid, 12); + gtk_widget_set_margin_bottom (grid, 12); + gtk_widget_set_margin_start (grid, 12); + gtk_widget_set_margin_end (grid, 12); label = gtk_label_new (_("Page Scaling:")); gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1); @@ -2705,7 +2706,7 @@ ev_print_operation_print_create_custom_widget (EvPrintOperationPrint *print, gtk_widget_show (print->scale_combo); print->autorotate_button = gtk_check_button_new_with_label (_("Auto Rotate and Center")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (print->autorotate_button), autorotate); + gtk_check_button_set_active (GTK_CHECK_BUTTON (print->autorotate_button), autorotate); gtk_widget_set_tooltip_text (print->autorotate_button, _("Rotate printer page orientation of each page to match orientation of each document page. " "Document pages will be centered within the printer page.")); @@ -2713,14 +2714,14 @@ ev_print_operation_print_create_custom_widget (EvPrintOperationPrint *print, gtk_widget_show (print->autorotate_button); print->source_button = gtk_check_button_new_with_label (_("Select page size using document page size")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (print->source_button), use_source_size); + gtk_check_button_set_active (GTK_CHECK_BUTTON (print->source_button), use_source_size); gtk_widget_set_tooltip_text (print->source_button, _("When enabled, each page will be printed on " "the same size paper as the document page.")); gtk_grid_attach (GTK_GRID (grid), print->source_button, 0, 2, 2, 1); gtk_widget_show (print->source_button); print->borders_button = gtk_check_button_new_with_label (_("Draw border around pages")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (print->borders_button), draw_borders); + gtk_check_button_set_active (GTK_CHECK_BUTTON (print->borders_button), draw_borders); gtk_widget_set_tooltip_text (print->borders_button, _("When enabled, a border will be drawn " "around each page.")); gtk_grid_attach (GTK_GRID (grid), print->borders_button, 0, 3, 2, 1); @@ -2736,9 +2737,9 @@ ev_print_operation_print_custom_widget_apply (EvPrintOperationPrint *print, GtkPrintSettings *settings; print->page_scale = gtk_combo_box_get_active (GTK_COMBO_BOX (print->scale_combo)); - print->autorotate = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (print->autorotate_button)); - print->use_source_size = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (print->source_button)); - print->draw_borders = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (print->borders_button)); + print->autorotate = gtk_check_button_get_active (GTK_CHECK_BUTTON (print->autorotate_button)); + print->use_source_size = gtk_check_button_get_active (GTK_CHECK_BUTTON (print->source_button)); + print->draw_borders = gtk_check_button_get_active (GTK_CHECK_BUTTON (print->borders_button)); settings = gtk_print_operation_get_print_settings (print->op); gtk_print_settings_set_int (settings, EV_PRINT_SETTING_PAGE_SCALE, print->page_scale); gtk_print_settings_set_bool (settings, EV_PRINT_SETTING_AUTOROTATE, print->autorotate); -- GitLab From 5369d333d8437e0df38fb3bb1f7b6e3e349293a2 Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Fri, 18 Aug 2023 10:53:50 +0800 Subject: [PATCH 15/50] libview: Port EvAnnotationWindow to gtk4 Signed-off-by: Qiu Wenbo --- libview/ev-annotation-window.c | 117 ++++++++++++++++----------------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/libview/ev-annotation-window.c b/libview/ev-annotation-window.c index bb6f77593..8ac8a8653 100644 --- a/libview/ev-annotation-window.c +++ b/libview/ev-annotation-window.c @@ -29,6 +29,10 @@ #include "ev-view-marshal.h" #include "ev-document-misc.h" +#ifdef GDK_WINDOWING_X11 +#include +#endif + enum { PROP_0, PROP_ANNOTATION, @@ -97,11 +101,12 @@ ev_annotation_window_set_color (EvAnnotationWindow *window, "button:active {background: darker(%1$s);}\n" "evannotationwindow.background { color: %2$s; }\n" "evannotationwindow.background:backdrop { color: alpha(%2$s, .75); }\n" - "evannotationwindow.background, button {background: %1$s}\n" - ".titlebar:not(headerbar) {background: %1$s}", + "evannotationwindow.background, button {background: %1$s;}\n" + ".titlebar:not(headerbar) {background: %1$s;}\n" + "evannotationwindow {padding-left: 2px; padding-right: 2px;}", rgba_str, icon_color_str); - gtk_css_provider_load_from_data (css_provider, css_data, strlen (css_data), &error); + gtk_css_provider_load_from_data (css_provider, css_data, strlen (css_data)); if (error != NULL) g_error ("%s", error->message); @@ -195,20 +200,22 @@ ev_annotation_window_close (EvAnnotationWindow *window) g_signal_emit (window, signals[CLOSED], 0); } -static gboolean -ev_annotation_window_button_press_event (GtkWidget *widget, - GdkEventButton *event) +static void +ev_annotation_window_button_press_event (GtkGestureClick *self, + gint n_press, + gdouble x, + gdouble y, + gpointer user_data) { - if (event->type == GDK_BUTTON_PRESS && event->button == 1) { - gtk_window_begin_move_drag (GTK_WINDOW (widget), - event->button, - event->x_root, - event->y_root, - event->time); - return TRUE; - } - - return FALSE; + EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (user_data); + GtkEventController *controller = GTK_EVENT_CONTROLLER (self); + GtkNative *native = gtk_widget_get_native (GTK_WIDGET (window)); + GdkSurface *toplevel = gtk_native_get_surface (native); + GdkDevice *device = gtk_event_controller_get_current_event_device (controller); + guint32 timestamp = gtk_event_controller_get_current_event_time (controller); + + gdk_toplevel_begin_move (GDK_TOPLEVEL (toplevel), device, GDK_BUTTON_PRIMARY, + x, y, timestamp); } static void @@ -224,9 +231,8 @@ static void ev_annotation_window_init (EvAnnotationWindow *window) { GtkWidget *vbox; - GtkWidget *icon; GtkWidget *swindow; - GtkWidget *header; + GtkEventController *controller; gtk_widget_set_can_focus (GTK_WIDGET (window), TRUE); @@ -236,62 +242,55 @@ ev_annotation_window_init (EvAnnotationWindow *window) window->titlebar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_window_set_titlebar (GTK_WINDOW (window), window->titlebar); - icon = gtk_image_new (); /* FIXME: use the annot icon */ - gtk_box_pack_start (GTK_BOX (window->titlebar), icon, FALSE, FALSE, 0); - gtk_widget_show (icon); - - header = gtk_event_box_new (); - gtk_widget_add_events (header, GDK_BUTTON_PRESS_MASK); - g_signal_connect_swapped (header, "button-press-event", - G_CALLBACK (ev_annotation_window_button_press_event), - window); - window->title = gtk_label_new (NULL); - gtk_container_add (GTK_CONTAINER (header), window->title); - gtk_widget_show (window->title); + gtk_widget_set_halign (window->title, GTK_ALIGN_FILL); + gtk_widget_set_hexpand (window->title, TRUE); - gtk_box_pack_start (GTK_BOX (window->titlebar), header, TRUE, TRUE, 0); - gtk_widget_show (header); + controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ()); + g_signal_connect (controller, "pressed", + G_CALLBACK (ev_annotation_window_button_press_event), + window); + gtk_widget_add_controller (window->title, controller); + gtk_box_append (GTK_BOX (window->titlebar), window->title); - window->close_button = gtk_button_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_BUTTON); + window->close_button = gtk_button_new_from_icon_name ("window-close-symbolic"); g_signal_connect_swapped (window->close_button, "clicked", G_CALLBACK (ev_annotation_window_close), window); gtk_widget_set_valign (GTK_WIDGET (window->close_button), GTK_ALIGN_CENTER); - - gtk_box_pack_start (GTK_BOX (window->titlebar), window->close_button, FALSE, FALSE, 0); - gtk_widget_show (window->close_button); - gtk_widget_show (window->titlebar); + gtk_box_append (GTK_BOX (window->titlebar), window->close_button); /* Contents */ - swindow = gtk_scrolled_window_new (NULL, NULL); + swindow = gtk_scrolled_window_new (); window->text_view = gtk_text_view_new (); - gtk_container_set_border_width (GTK_CONTAINER (window->text_view), 6); gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (window->text_view), TRUE); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (window->text_view), GTK_WRAP_WORD); - gtk_container_add (GTK_CONTAINER (swindow), window->text_view); - gtk_widget_show (window->text_view); + gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (swindow), window->text_view); + gtk_widget_set_valign (swindow, GTK_ALIGN_FILL); + gtk_widget_set_vexpand (swindow, TRUE); gtk_window_set_focus (GTK_WINDOW (window), window->text_view); g_signal_connect (window->text_view, "notify::has-focus", G_CALLBACK (ev_annotation_window_has_focus_changed), window); - gtk_box_pack_start (GTK_BOX (vbox), swindow, TRUE, TRUE, 0); - gtk_widget_show (swindow); + gtk_box_append (GTK_BOX (vbox), swindow); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); + gtk_window_set_child (GTK_WINDOW (window), vbox); - gtk_widget_add_events (GTK_WIDGET (window), - GDK_BUTTON_PRESS_MASK | - GDK_KEY_PRESS_MASK); +#ifdef GDK_WINDOWING_X11 + { + GtkNative *native = gtk_widget_get_native (GTK_WIDGET (window)); + GdkSurface *surface = gtk_native_get_surface (native); - gtk_container_set_border_width (GTK_CONTAINER (window), 2); + if (GDK_IS_X11_SURFACE (surface)) { + gdk_x11_surface_set_skip_taskbar_hint (GDK_X11_SURFACE (surface), TRUE); + gdk_x11_surface_set_skip_pager_hint (GDK_X11_SURFACE (surface), TRUE); + } + } +#endif gtk_window_set_decorated (GTK_WINDOW (window), TRUE); - gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE); - gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE); gtk_window_set_resizable (GTK_WINDOW (window), TRUE); } @@ -365,15 +364,12 @@ ev_annotation_window_constructor (GType type, } static gboolean -ev_annotation_window_key_press_event (GtkWidget *widget, - GdkEventKey *event) +ev_annotation_window_escape_pressed (GtkWidget *widget, + GVariant *args, + gpointer user_data) { - if (event->keyval == GDK_KEY_Escape) { - ev_annotation_window_close (EV_ANNOTATION_WINDOW (widget)); - return TRUE; - } - - return GTK_WIDGET_CLASS (ev_annotation_window_parent_class)->key_press_event (widget, event); + ev_annotation_window_close (EV_ANNOTATION_WINDOW (widget)); + return TRUE; } static void @@ -386,7 +382,8 @@ ev_annotation_window_class_init (EvAnnotationWindowClass *klass) g_object_class->set_property = ev_annotation_window_set_property; g_object_class->dispose = ev_annotation_window_dispose; - gtk_widget_class->key_press_event = ev_annotation_window_key_press_event; + gtk_widget_class_add_binding (gtk_widget_class, GDK_KEY_Escape, 0, + ev_annotation_window_escape_pressed, NULL); gtk_widget_class_set_css_name (gtk_widget_class, "evannotationwindow"); g_object_class_install_property (g_object_class, -- GitLab From 10b95ea07a017013126fa7aaec8698ed9ccb1db9 Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Sat, 7 Aug 2021 14:21:33 +0800 Subject: [PATCH 16/50] libview: Port EvViewPresentation to gtk4 * Ported transitions to OpenGL shaders. * Ported drawing to new GdkTexture interface. * Ported the window to change page to a popup dialog. This greatly simplifies the event and focus handling between the widgets, but unfortunately is completely unsupported in GTK3 * Ported event handling to modern GTK4 handlers. Signed-off-by: Qiu Wenbo --- libview/ev-view-presentation.c | 957 ++++++++++++++------------------- libview/libview.gresource.xml | 32 ++ libview/meson.build | 8 + libview/shader/blinds.glsl | 30 ++ libview/shader/box.glsl | 37 ++ libview/shader/cover.glsl | 33 ++ libview/shader/dissolve.glsl | 33 ++ libview/shader/fade.glsl | 28 + libview/shader/fly.glsl | 43 ++ libview/shader/glitter.glsl | 46 ++ libview/shader/push.glsl | 34 ++ libview/shader/split.glsl | 35 ++ libview/shader/uncover.glsl | 33 ++ libview/shader/wipe.glsl | 36 ++ 14 files changed, 846 insertions(+), 539 deletions(-) create mode 100644 libview/libview.gresource.xml create mode 100644 libview/shader/blinds.glsl create mode 100644 libview/shader/box.glsl create mode 100644 libview/shader/cover.glsl create mode 100644 libview/shader/dissolve.glsl create mode 100644 libview/shader/fade.glsl create mode 100644 libview/shader/fly.glsl create mode 100644 libview/shader/glitter.glsl create mode 100644 libview/shader/push.glsl create mode 100644 libview/shader/split.glsl create mode 100644 libview/shader/uncover.glsl create mode 100644 libview/shader/wipe.glsl diff --git a/libview/ev-view-presentation.c b/libview/ev-view-presentation.c index df7b02e95..4b7f338fc 100644 --- a/libview/ev-view-presentation.c +++ b/libview/ev-view-presentation.c @@ -27,12 +27,8 @@ #include "ev-view-presentation.h" #include "ev-jobs.h" #include "ev-job-scheduler.h" -#include "ev-transition-animation.h" #include "ev-view-cursor.h" #include "ev-page-cache.h" -#ifdef GDK_WINDOWING_WAYLAND -#include -#endif enum { PROP_0, @@ -45,7 +41,7 @@ enum { enum { CHANGE_PAGE, FINISHED, - SIGNAL_EXTERNAL_LINK, + SIGNAL_EXTERNAL_LINK, N_SIGNALS }; @@ -62,31 +58,30 @@ struct _EvViewPresentation guint is_constructing : 1; + gint64 start_time; + gdouble transition_time; + gint animation_tick_id; + guint current_page; - cairo_surface_t *current_surface; + guint previous_page; + GdkTexture *current_texture; + GdkTexture *previous_texture; EvDocument *document; guint rotation; gboolean inverted_colors; EvPresentationState state; - gint monitor_width; - gint monitor_height; /* Cursors */ EvViewCursor cursor; guint hide_cursor_timeout_id; /* Goto Window */ - GtkWidget *goto_window; + GtkWidget *goto_popup; GtkWidget *goto_entry; /* Page Transition */ guint trans_timeout_id; - /* Animations */ - gboolean enable_animations; - gboolean animation_finished; - EvTransitionAnimation *animation; - /* Links */ EvPageCache *page_cache; @@ -113,6 +108,9 @@ static void ev_view_presentation_set_cursor_for_location (EvViewPresentation *pv gdouble x, gdouble y); +static void ev_view_presentation_update_current_texture (EvViewPresentation *pview, + GdkTexture *surface); + #define HIDE_CURSOR_TIMEOUT 5000 G_DEFINE_TYPE (EvViewPresentation, ev_view_presentation, GTK_TYPE_WIDGET) @@ -177,6 +175,7 @@ ev_view_presentation_get_view_size (EvViewPresentation *pview, int *view_height) { gdouble width, height; + int widget_width, widget_height; ev_document_get_page_size (pview->document, page, &width, &height); if (pview->rotation == 90 || pview->rotation == 270) { @@ -187,12 +186,15 @@ ev_view_presentation_get_view_size (EvViewPresentation *pview, height = tmp; } - if (pview->monitor_width / width < pview->monitor_height / height) { - *view_width = pview->monitor_width; - *view_height = (int)((pview->monitor_width / width) * height + 0.5); + widget_width = gtk_widget_get_width (GTK_WIDGET (pview)); + widget_height = gtk_widget_get_width (GTK_WIDGET (pview)); + + if (widget_width / width < widget_height / height) { + *view_width = widget_width; + *view_height = (int)((widget_width / width) * height + 0.5); } else { - *view_width = (int)((pview->monitor_height / height) * width + 0.5); - *view_height = pview->monitor_height; + *view_width = (int)((widget_height / height) * width + 0.5); + *view_height = widget_height; } } @@ -201,16 +203,16 @@ ev_view_presentation_get_page_area (EvViewPresentation *pview, GdkRectangle *area) { GtkWidget *widget = GTK_WIDGET (pview); - GtkAllocation allocation; - gint view_width, view_height; + gint view_width, view_height, widget_width, widget_height; ev_view_presentation_get_view_size (pview, pview->current_page, &view_width, &view_height); - gtk_widget_get_allocation (widget, &allocation); + widget_width = gtk_widget_get_width (widget); + widget_height = gtk_widget_get_height (widget); - area->x = (MAX (0, allocation.width - view_width)) / 2; - area->y = (MAX (0, allocation.height - view_height)) / 2; + area->x = (MAX (0, widget_width - view_width)) / 2; + area->y = (MAX (0, widget_height - view_height)) / 2; area->width = view_width; area->height = view_height; } @@ -251,91 +253,68 @@ ev_view_presentation_transition_start (EvViewPresentation *pview) } } -/* Animations */ -static void -ev_view_presentation_animation_cancel (EvViewPresentation *pview) +static gboolean +animation_tick_cb (GtkWidget *widget, + GdkFrameClock *clock, + gpointer unused) { - g_clear_object (&pview->animation); + EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); + gint64 frame_time = gdk_frame_clock_get_frame_time (clock); + EvTransitionEffect *effect; + gdouble duration = 0; + + if (!EV_IS_DOCUMENT_TRANSITION (pview->document)) + return G_SOURCE_REMOVE; + + if (pview->start_time == 0) + pview->start_time = frame_time; + + pview->transition_time = (frame_time - pview->start_time) / (float)G_USEC_PER_SEC; + + gtk_widget_queue_draw (widget); + + effect = ev_document_transition_get_effect ( + EV_DOCUMENT_TRANSITION (pview->document), + pview->current_page); + g_object_get (effect, "duration-real", &duration, NULL); + + if (pview->transition_time >= duration) { + ev_view_presentation_transition_start (pview); + return G_SOURCE_REMOVE; + } + else { + return G_SOURCE_CONTINUE; + } } static void -ev_view_presentation_transition_animation_finish (EvViewPresentation *pview) +ev_view_presentation_animation_cancel (EvViewPresentation *pview) { - pview->animation_finished = TRUE; - ev_view_presentation_transition_start (pview); - gtk_widget_queue_draw (GTK_WIDGET (pview)); + if (pview->animation_tick_id) { + gtk_widget_remove_tick_callback (GTK_WIDGET (pview), pview->animation_tick_id); + pview->animation_tick_id = 0; + } } static void -ev_view_presentation_transition_animation_frame (EvViewPresentation *pview, - gdouble progress) +ev_view_presentation_animation_start (EvViewPresentation *pview) { - gtk_widget_queue_draw (GTK_WIDGET (pview)); + GtkWidget *widget = GTK_WIDGET (pview); + + pview->start_time = 0; + pview->animation_tick_id = gtk_widget_add_tick_callback (widget, + animation_tick_cb, pview, NULL); + gtk_widget_queue_draw (widget); } -static cairo_surface_t * -get_surface_from_job (EvViewPresentation *pview, +static GdkTexture * +get_texture_from_job (EvViewPresentation *pview, EvJob *job) { - cairo_surface_t *surface; - if (!job) return NULL; - surface = EV_JOB_RENDER_CAIRO(job)->surface; - if (!surface) - return NULL; - - int scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (pview)); - cairo_surface_set_device_scale (surface, scale_factor, scale_factor); - - return surface; -} - -static void -ev_view_presentation_animation_start (EvViewPresentation *pview, - gint new_page) -{ - EvTransitionEffect *effect = NULL; - EvJob *job; - cairo_surface_t *surface; - gint jump; - - if (!pview->enable_animations) - return; - - if (pview->current_page == new_page) - return; - - effect = ev_document_transition_get_effect (EV_DOCUMENT_TRANSITION (pview->document), - new_page); - if (!effect) - return; - - pview->animation = ev_transition_animation_new (effect); - - surface = pview->curr_job ? EV_JOB_RENDER_CAIRO (pview->curr_job)->surface : NULL; - ev_transition_animation_set_origin_surface (pview->animation, - surface != NULL ? - surface : pview->current_surface); - - jump = new_page - pview->current_page; - if (jump == -1) - job = pview->prev_job; - else if (jump == 1) - job = pview->next_job; - else - job = NULL; - surface = get_surface_from_job (pview, job); - if (surface) - ev_transition_animation_set_dest_surface (pview->animation, surface); - - g_signal_connect_swapped (pview->animation, "frame", - G_CALLBACK (ev_view_presentation_transition_animation_frame), - pview); - g_signal_connect_swapped (pview->animation, "finished", - G_CALLBACK (ev_view_presentation_transition_animation_finish), - pview); + return EV_JOB_RENDER_TEXTURE (job)->texture; } /* Page Navigation */ @@ -343,21 +322,13 @@ static void job_finished_cb (EvJob *job, EvViewPresentation *pview) { - EvJobRenderCairo *job_render = EV_JOB_RENDER_CAIRO (job); - - if (pview->inverted_colors) - ev_document_misc_invert_surface (job_render->surface); - if (job != pview->curr_job) return; - if (pview->animation) { - ev_transition_animation_set_dest_surface (pview->animation, - get_surface_from_job (pview, job)); - } else { - ev_view_presentation_transition_start (pview); - gtk_widget_queue_draw (GTK_WIDGET (pview)); - } + ev_view_presentation_update_current_texture (pview, + get_texture_from_job (pview, job)); + + ev_view_presentation_animation_start (pview); } static EvJob * @@ -405,6 +376,21 @@ ev_view_presentation_reset_jobs (EvViewPresentation *pview) ev_view_presentation_delete_job (pview, pview->next_job); } +static void +ev_view_presentation_update_current_texture (EvViewPresentation *pview, + GdkTexture *texture) +{ + if (!texture || pview->current_texture == texture) + return; + + g_object_ref (texture); + + g_clear_object (&pview->previous_texture); + + pview->previous_texture = pview->current_texture; + pview->current_texture = texture; +} + static void ev_view_presentation_update_current_page (EvViewPresentation *pview, guint page) @@ -415,7 +401,7 @@ ev_view_presentation_update_current_page (EvViewPresentation *pview, return; ev_view_presentation_animation_cancel (pview); - ev_view_presentation_animation_start (pview, page); + ev_view_presentation_transition_stop (pview); jump = page - pview->current_page; @@ -451,7 +437,9 @@ ev_view_presentation_update_current_page (EvViewPresentation *pview, else ev_job_scheduler_update_job (pview->curr_job, EV_JOB_PRIORITY_URGENT); pview->next_job = ev_view_presentation_schedule_new_job (pview, page + 1, EV_JOB_PRIORITY_HIGH); - ev_job_scheduler_update_job (pview->prev_job, EV_JOB_PRIORITY_LOW); + + if (pview->prev_job) + ev_job_scheduler_update_job (pview->prev_job, EV_JOB_PRIORITY_LOW); break; case -2: @@ -494,6 +482,7 @@ ev_view_presentation_update_current_page (EvViewPresentation *pview, } if (pview->current_page != page) { + pview->previous_page = pview->current_page; pview->current_page = page; g_object_notify (G_OBJECT (pview), "current-page"); } @@ -508,8 +497,12 @@ ev_view_presentation_update_current_page (EvViewPresentation *pview, ev_view_presentation_set_cursor_for_location (pview, x, y); } - if (EV_JOB_RENDER_CAIRO (pview->curr_job)->surface) - gtk_widget_queue_draw (GTK_WIDGET (pview)); + if (EV_JOB_RENDER_TEXTURE (pview->curr_job)->texture) { + ev_view_presentation_update_current_texture (pview, + EV_JOB_RENDER_TEXTURE (pview->curr_job)->texture); + + ev_view_presentation_animation_start (pview); + } } static void @@ -575,80 +568,22 @@ ev_view_presentation_previous_page (EvViewPresentation *pview) } /* Goto Window */ -#define KEY_IS_NUMERIC(keyval) \ - ((keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9) || (keyval >= GDK_KEY_KP_0 && keyval <= GDK_KEY_KP_9)) - -/* Cut and paste from gtkwindow.c */ -static void -send_focus_change (GtkWidget *widget, - gboolean in) +static int +key_to_digit (int keyval) { - GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE); - - fevent->focus_change.type = GDK_FOCUS_CHANGE; - fevent->focus_change.window = gtk_widget_get_window (widget); - fevent->focus_change.in = in; - if (fevent->focus_change.window) - g_object_ref (fevent->focus_change.window); + if (keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9) + return keyval - GDK_KEY_0; - gtk_widget_send_focus_change (widget, fevent); + if (keyval >= GDK_KEY_KP_0 && keyval <= GDK_KEY_KP_9) + return keyval - GDK_KEY_KP_0; - gdk_event_free (fevent); -} - -static void -ev_view_presentation_goto_window_hide (EvViewPresentation *pview) -{ - /* send focus-in event */ - send_focus_change (pview->goto_entry, FALSE); - gtk_widget_hide (pview->goto_window); - gtk_entry_set_text (GTK_ENTRY (pview->goto_entry), ""); + return -1; } static gboolean -ev_view_presentation_goto_window_delete_event (GtkWidget *widget, - GdkEventAny *event, - EvViewPresentation *pview) +key_is_numeric (int keyval) { - ev_view_presentation_goto_window_hide (pview); - - return TRUE; -} - -static gboolean -ev_view_presentation_goto_window_key_press_event (GtkWidget *widget, - GdkEventKey *event, - EvViewPresentation *pview) -{ - switch (event->keyval) { - case GDK_KEY_Escape: - case GDK_KEY_Tab: - case GDK_KEY_KP_Tab: - case GDK_KEY_ISO_Left_Tab: - ev_view_presentation_goto_window_hide (pview); - return TRUE; - case GDK_KEY_Return: - case GDK_KEY_KP_Enter: - case GDK_KEY_ISO_Enter: - case GDK_KEY_BackSpace: - case GDK_KEY_Delete: - return FALSE; - default: - if (!KEY_IS_NUMERIC (event->keyval)) - return TRUE; - } - - return FALSE; -} - -static gboolean -ev_view_presentation_goto_window_button_press_event (GtkWidget *widget, - GdkEventButton *event, - EvViewPresentation *pview) -{ - ev_view_presentation_goto_window_hide (pview); - - return TRUE; + return key_to_digit (keyval) >= 0; } static void @@ -658,101 +593,43 @@ ev_view_presentation_goto_entry_activate (GtkEntry *entry, const gchar *text; gint page; - text = gtk_entry_get_text (entry); + text = gtk_editable_get_text (GTK_EDITABLE (entry)); page = atoi (text) - 1; - ev_view_presentation_goto_window_hide (pview); + gtk_popover_popdown (GTK_POPOVER (pview->goto_popup)); ev_view_presentation_update_current_page (pview, page); } + static void ev_view_presentation_goto_window_create (EvViewPresentation *pview) { - GtkWidget *frame, *hbox, *label; - GtkWindow *toplevel, *goto_window; + GtkWidget *hbox, *label; - toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (pview))); - - if (pview->goto_window) { - goto_window = GTK_WINDOW (pview->goto_window); - if (gtk_window_has_group (toplevel)) - gtk_window_group_add_window (gtk_window_get_group (toplevel), goto_window); - else if (gtk_window_has_group (goto_window)) - gtk_window_group_remove_window (gtk_window_get_group (goto_window), goto_window); - - return; - } - - pview->goto_window = gtk_window_new (GTK_WINDOW_POPUP); - goto_window = GTK_WINDOW (pview->goto_window); - gtk_window_set_screen (goto_window, gtk_widget_get_screen (GTK_WIDGET (pview))); - gtk_window_set_transient_for (goto_window, toplevel); - - if (gtk_window_has_group (toplevel)) - gtk_window_group_add_window (gtk_window_get_group (toplevel), goto_window); - - gtk_window_set_modal (goto_window, TRUE); - - g_signal_connect (pview->goto_window, "delete_event", - G_CALLBACK (ev_view_presentation_goto_window_delete_event), - pview); - g_signal_connect (pview->goto_window, "key_press_event", - G_CALLBACK (ev_view_presentation_goto_window_key_press_event), - pview); - g_signal_connect (pview->goto_window, "button_press_event", - G_CALLBACK (ev_view_presentation_goto_window_button_press_event), - pview); - - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); - gtk_container_add (GTK_CONTAINER (pview->goto_window), frame); - gtk_widget_show (frame); + pview->goto_popup = gtk_popover_new (); + gtk_popover_set_position (GTK_POPOVER (pview->goto_popup), GTK_POS_BOTTOM); + gtk_popover_set_has_arrow (GTK_POPOVER (pview->goto_popup), FALSE); + gtk_widget_set_halign (pview->goto_popup, GTK_ALIGN_START); + gtk_widget_set_parent (pview->goto_popup, GTK_WIDGET (pview)); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 3); - gtk_container_add (GTK_CONTAINER (frame), hbox); - gtk_widget_show (hbox); + gtk_box_set_spacing (GTK_BOX (hbox), 3); + gtk_widget_set_margin_top (hbox, 3); + gtk_widget_set_margin_bottom (hbox, 3); + gtk_widget_set_margin_start (hbox, 3); + gtk_widget_set_margin_end (hbox, 3); + gtk_popover_set_child (GTK_POPOVER (pview->goto_popup), hbox); label = gtk_label_new (_("Jump to page:")); - gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 3); - gtk_widget_show (label); - gtk_widget_realize (label); + gtk_box_append (GTK_BOX (hbox), label); pview->goto_entry = gtk_entry_new (); + + gtk_box_append (GTK_BOX (hbox), pview->goto_entry); + g_signal_connect (pview->goto_entry, "activate", G_CALLBACK (ev_view_presentation_goto_entry_activate), pview); - gtk_box_pack_start (GTK_BOX (hbox), pview->goto_entry, TRUE, TRUE, 0); - gtk_widget_show (pview->goto_entry); - gtk_widget_realize (pview->goto_entry); -} - -static void -ev_view_presentation_goto_entry_grab_focus (EvViewPresentation *pview) -{ - GtkWidgetClass *entry_parent_class; - - entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (pview->goto_entry)); - (entry_parent_class->grab_focus) (pview->goto_entry); - - send_focus_change (pview->goto_entry, TRUE); -} - -static void -ev_view_presentation_goto_window_send_key_event (EvViewPresentation *pview, - GdkEvent *event) -{ - GdkEventKey *new_event; - - new_event = (GdkEventKey *) gdk_event_copy (event); - g_object_unref (new_event->window); - new_event->window = gtk_widget_get_window (pview->goto_window); - if (new_event->window) - g_object_ref (new_event->window); - gtk_widget_realize (pview->goto_window); - - gtk_widget_event (pview->goto_window, (GdkEvent *)new_event); - gdk_event_free ((GdkEvent *)new_event); } /* Links */ @@ -879,23 +756,18 @@ static void ev_view_presentation_set_cursor (EvViewPresentation *pview, EvViewCursor view_cursor) { - GtkWidget *widget; - GdkCursor *cursor; + GtkWidget *widget = GTK_WIDGET (pview); if (pview->cursor == view_cursor) return; - widget = GTK_WIDGET (pview); if (!gtk_widget_get_realized (widget)) gtk_widget_realize (widget); pview->cursor = view_cursor; - cursor = ev_view_cursor_new (gtk_widget_get_display (widget), view_cursor); - gdk_window_set_cursor (gtk_widget_get_window (widget), cursor); - gdk_display_flush (gtk_widget_get_display (widget)); - if (cursor) - g_object_unref (cursor); + gtk_widget_set_cursor_from_name (widget, + ev_view_cursor_name (view_cursor)); } static void @@ -934,19 +806,6 @@ ev_view_presentation_hide_cursor_timeout_start (EvViewPresentation *pview) pview); } -static void -ev_view_presentation_update_current_surface (EvViewPresentation *pview, - cairo_surface_t *surface) -{ - if (!surface || pview->current_surface == surface) - return; - - cairo_surface_reference (surface); - if (pview->current_surface) - cairo_surface_destroy (pview->current_surface); - pview->current_surface = surface; -} - static void ev_view_presentation_dispose (GObject *object) { @@ -954,41 +813,21 @@ ev_view_presentation_dispose (GObject *object) g_clear_object (&pview->document); - ev_view_presentation_animation_cancel (pview); ev_view_presentation_transition_stop (pview); ev_view_presentation_hide_cursor_timeout_stop (pview); ev_view_presentation_reset_jobs (pview); - g_clear_pointer (&pview->current_surface, cairo_surface_destroy); + g_clear_object (&pview->current_texture); g_clear_object (&pview->page_cache); + g_clear_object (&pview->previous_texture); - if (pview->goto_window) { - g_clear_pointer (&pview->goto_window, gtk_widget_destroy); - pview->goto_entry = NULL; - } + g_clear_pointer (&pview->goto_popup, gtk_widget_unparent); G_OBJECT_CLASS (ev_view_presentation_parent_class)->dispose (object); } static void -ev_view_presentation_get_preferred_width (GtkWidget *widget, - gint *minimum, - gint *natural) -{ - *minimum = *natural = 0; -} - -static void -ev_view_presentation_get_preferred_height (GtkWidget *widget, - gint *minimum, - gint *natural) -{ - *minimum = *natural = 0; -} - -static void -ev_view_presentation_draw_end_page (EvViewPresentation *pview, - cairo_t *cr) +ev_view_presentation_snapshot_end_page (EvViewPresentation *pview, GtkSnapshot *snapshot) { GtkWidget *widget = GTK_WIDGET (pview); PangoLayout *layout; @@ -1010,109 +849,208 @@ ev_view_presentation_draw_end_page (EvViewPresentation *pview, pango_layout_set_font_description (layout, font_desc); pango_layout_get_pixel_size (layout, &text_width, &text_height); x_center = gtk_widget_get_allocated_width (widget) / 2 - text_width / 2; - gtk_render_layout (gtk_widget_get_style_context (widget), cr, x_center, 15, layout); + + gtk_snapshot_render_layout (snapshot, gtk_widget_get_style_context (widget), + x_center, 15, layout); pango_font_description_free (font_desc); g_object_unref (layout); } -static gboolean -ev_view_presentation_draw (GtkWidget *widget, - cairo_t *cr) +static GskGLShader * +ev_view_presentation_load_shader (EvTransitionEffectType type) { - EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); - GdkRectangle page_area; - GdkRectangle overlap; - cairo_surface_t *surface; - GdkRectangle clip_rect; - GtkStyleContext *context; - - context = gtk_widget_get_style_context (GTK_WIDGET (pview)); - gtk_render_background (context, cr, - 0, 0, - gtk_widget_get_allocated_width (widget), - gtk_widget_get_allocated_height (widget)); - - if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect)) - return FALSE; + static const char *shader_resources[] = { + [EV_TRANSITION_EFFECT_REPLACE] = NULL, + [EV_TRANSITION_EFFECT_SPLIT] = "/org/gnome/evince/shader/split.glsl", + [EV_TRANSITION_EFFECT_WIPE] = "/org/gnome/evince/shader/wipe.glsl", + [EV_TRANSITION_EFFECT_COVER] = "/org/gnome/evince/shader/cover.glsl", + [EV_TRANSITION_EFFECT_UNCOVER] = "/org/gnome/evince/shader/uncover.glsl", + [EV_TRANSITION_EFFECT_DISSOLVE] = "/org/gnome/evince/shader/dissolve.glsl", + [EV_TRANSITION_EFFECT_PUSH] = "/org/gnome/evince/shader/push.glsl", + [EV_TRANSITION_EFFECT_BOX] = "/org/gnome/evince/shader/box.glsl", + [EV_TRANSITION_EFFECT_BLINDS] = "/org/gnome/evince/shader/blinds.glsl", + [EV_TRANSITION_EFFECT_FLY] = "/org/gnome/evince/shader/fly.glsl", + [EV_TRANSITION_EFFECT_GLITTER] = "/org/gnome/evince/shader/glitter.glsl", + [EV_TRANSITION_EFFECT_FADE] = "/org/gnome/evince/shader/fade.glsl", + }; - switch (pview->state) { - case EV_PRESENTATION_END: - ev_view_presentation_draw_end_page (pview, cr); - return FALSE; - case EV_PRESENTATION_BLACK: - case EV_PRESENTATION_WHITE: - return FALSE; - case EV_PRESENTATION_NORMAL: + static GskGLShader *shaders[G_N_ELEMENTS (shader_resources)] = {}; + + if (type >= G_N_ELEMENTS (shader_resources) || !shader_resources[type]) + return NULL; + + if (!shaders[type]) { + shaders[type] = gsk_gl_shader_new_from_resource (shader_resources[type]); + g_assert (shaders[type] != NULL); + } + + return shaders[type]; +} + +static GBytes * +ev_view_presentation_build_shader_args (GskGLShader *shader, + EvTransitionEffect *effect, + gdouble progress) +{ + GskShaderArgsBuilder *builder = gsk_shader_args_builder_new (shader, NULL); + EvTransitionEffectType type; + EvTransitionEffectAlignment alignment; + EvTransitionEffectDirection direction; + gint angle; + gdouble scale; + + g_object_get (effect, "type", &type, NULL); + + switch (type) { + case EV_TRANSITION_EFFECT_SPLIT: + g_object_get (effect, "direction", &direction, + "alignment", &alignment, NULL); + gsk_shader_args_builder_set_int (builder, 1, direction); + gsk_shader_args_builder_set_int (builder, 2, alignment); break; + case EV_TRANSITION_EFFECT_WIPE: + case EV_TRANSITION_EFFECT_PUSH: + case EV_TRANSITION_EFFECT_COVER: + case EV_TRANSITION_EFFECT_UNCOVER: + case EV_TRANSITION_EFFECT_GLITTER: + g_object_get (effect, "angle", &angle, NULL); + gsk_shader_args_builder_set_int (builder, 1, angle); + break; + case EV_TRANSITION_EFFECT_BOX: + g_object_get (effect, "direction", &direction, NULL); + gsk_shader_args_builder_set_int (builder, 1, direction); + break; + case EV_TRANSITION_EFFECT_BLINDS: + g_object_get (effect, "alignment", &alignment, NULL); + gsk_shader_args_builder_set_int (builder, 1, alignment); + break; + case EV_TRANSITION_EFFECT_FLY: + g_object_get (effect, "angle", &angle, + "scale", &scale, NULL); + gsk_shader_args_builder_set_int (builder, 1, angle); + gsk_shader_args_builder_set_float (builder, 2, scale); + break; + default: + g_assert_not_reached (); } - if (pview->animation) { - if (ev_transition_animation_ready (pview->animation)) { - ev_view_presentation_get_page_area (pview, &page_area); + gsk_shader_args_builder_set_float (builder, 0, progress); - cairo_save (cr); + return gsk_shader_args_builder_free_to_args (builder); +} - /* normalize to x=0, y=0 */ - cairo_translate (cr, page_area.x, page_area.y); - page_area.x = page_area.y = 0; +static void +ev_view_presentation_animation_snapshot (EvViewPresentation *pview, + GtkSnapshot *snapshot, + graphene_rect_t *area) +{ + GtkNative *native = gtk_widget_get_native (GTK_WIDGET (pview)); + GskRenderer *renderer = gtk_native_get_renderer (native); + GskGLShader *shader; + double duration; + EvTransitionEffectType type; + GError *error = NULL; - /* Try to fix rounding errors */ - page_area.width--; + int width = gtk_widget_get_width (GTK_WIDGET (pview)); + int height = gtk_widget_get_height (GTK_WIDGET (pview)); - ev_transition_animation_paint (pview->animation, cr, page_area); + EvTransitionEffect *effect = ev_document_transition_get_effect ( + EV_DOCUMENT_TRANSITION (pview->document), + pview->current_page); + g_object_get (effect, "duration-real", &duration, "type", &type, NULL); - cairo_restore (cr); - } + shader = ev_view_presentation_load_shader (type); - if (pview->animation_finished) { - ev_view_presentation_animation_cancel (pview); - pview->animation_finished = FALSE; - } + gdouble progress = pview->transition_time / duration; - return TRUE; - } + if (shader && gsk_gl_shader_compile (shader, renderer, &error)) { + gtk_snapshot_push_gl_shader (snapshot, shader, &GRAPHENE_RECT_INIT (0, 0, width, height), + ev_view_presentation_build_shader_args (shader, effect, progress)); + + // TODO: handle different page size + if (pview->previous_texture) + gtk_snapshot_append_texture (snapshot, pview->previous_texture, area); + else + gtk_snapshot_append_color (snapshot, &(GdkRGBA){0., 0., 0., 1.}, area); + + gtk_snapshot_gl_shader_pop_texture (snapshot); /* current child */ - surface = get_surface_from_job (pview, pview->curr_job); - if (surface) { - ev_view_presentation_update_current_surface (pview, surface); - } else if (pview->current_surface) { - surface = pview->current_surface; + gtk_snapshot_append_texture (snapshot, pview->current_texture, area); + gtk_snapshot_gl_shader_pop_texture (snapshot); /* next child */ + gtk_snapshot_pop(snapshot); } else { - return FALSE; + if (error) + g_warning ("failed to compile shader '%s'\n", error->message); + else if (type != EV_TRANSITION_EFFECT_REPLACE) + g_warning ("shader for type %d is not implemented\n", type); + + gtk_snapshot_append_texture (snapshot, pview->current_texture, area); } - ev_view_presentation_get_page_area (pview, &page_area); - if (gdk_rectangle_intersect (&page_area, &clip_rect, &overlap)) { - cairo_save (cr); + g_clear_pointer (&error, g_error_free); +} + +static void ev_view_presentation_snapshot(GtkWidget *widget, GtkSnapshot *snapshot) +{ + EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); + GtkStyleContext *context = gtk_widget_get_style_context (widget); + GdkRectangle page_area; + graphene_rect_t area; + + gtk_snapshot_render_background (snapshot, context, 0, 0, + gtk_widget_get_width (widget), + gtk_widget_get_height (widget)); + + switch (pview->state) { + case EV_PRESENTATION_END: + ev_view_presentation_snapshot_end_page (pview, snapshot); + return; + case EV_PRESENTATION_BLACK: + case EV_PRESENTATION_WHITE: + return; + case EV_PRESENTATION_NORMAL: + break; + } - /* Try to fix rounding errors. See bug #438760 */ - if (overlap.width == page_area.width) - overlap.width--; + if (!pview->curr_job) { + ev_view_presentation_update_current_page (pview, pview->current_page); + ev_view_presentation_hide_cursor_timeout_start (pview); + return; + } + + if (!pview->current_texture) + return; - cairo_rectangle (cr, overlap.x, overlap.y, overlap.width, overlap.height); - cairo_set_source_surface (cr, surface, page_area.x, page_area.y); - cairo_fill (cr); + ev_view_presentation_get_page_area (pview, &page_area); + area = GRAPHENE_RECT_INIT (page_area.x, page_area.y, + page_area.width, page_area.height); - cairo_restore (cr); + if (pview->inverted_colors) { + gtk_snapshot_push_blend (snapshot, GSK_BLEND_MODE_DIFFERENCE); + gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 1., 1., 1., 1.}, &area); + gtk_snapshot_pop (snapshot); } - return FALSE; + if (EV_IS_DOCUMENT_TRANSITION (pview->document)) + ev_view_presentation_animation_snapshot (pview, snapshot, &area); + else + gtk_snapshot_append_texture (snapshot, pview->current_texture, &area); + + if (pview->inverted_colors) + gtk_snapshot_pop (snapshot); } static gboolean -ev_view_presentation_key_press_event (GtkWidget *widget, - GdkEventKey *event) +ev_view_presentation_key_press_event (GtkEventControllerKey *self, + guint keyval, + guint keycode, + GdkModifierType state, + GtkWidget *widget) { EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); - if (pview->state == EV_PRESENTATION_END) - return gtk_bindings_activate_event (G_OBJECT (widget), event); - - if (event->state & GDK_CONTROL_MASK) - return gtk_bindings_activate_event (G_OBJECT (widget), event); - - switch (event->keyval) { + switch (keyval) { case GDK_KEY_b: case GDK_KEY_B: case GDK_KEY_period: @@ -1153,30 +1091,37 @@ ev_view_presentation_key_press_event (GtkWidget *widget, ev_view_presentation_set_normal (pview); - if (ev_document_get_n_pages (pview->document) > 1 && KEY_IS_NUMERIC (event->keyval)) { + if (ev_document_get_n_pages (pview->document) > 1 && key_is_numeric (keyval)) { gint x, y; + gchar *digit = g_strdup_printf ("%d", key_to_digit (keyval)); - ev_view_presentation_goto_window_create (pview); ev_document_misc_get_pointer_position (GTK_WIDGET (pview), &x, &y); - gtk_window_move (GTK_WINDOW (pview->goto_window), x, y); - gtk_widget_show (pview->goto_window); - ev_view_presentation_goto_window_send_key_event (pview, (GdkEvent *)event); - ev_view_presentation_goto_entry_grab_focus (pview); - + gtk_popover_set_pointing_to (GTK_POPOVER (pview->goto_popup), + &(GdkRectangle) {x, y, 1, 1}); + + gtk_editable_set_text (GTK_EDITABLE (pview->goto_entry), digit); + gtk_editable_set_position (GTK_EDITABLE (pview->goto_entry), -1); + gtk_entry_grab_focus_without_selecting (GTK_ENTRY (pview->goto_entry)); + gtk_popover_popup (GTK_POPOVER (pview->goto_popup)); + g_free (digit); return TRUE; } - return gtk_bindings_activate_event (G_OBJECT (widget), event); + return FALSE; } static gboolean -ev_view_presentation_button_release_event (GtkWidget *widget, - GdkEventButton *event) +ev_view_presentation_button_release_event (GtkGestureClick *self, + gint n_press, + gdouble x, + gdouble y, + GtkWidget *widget) { EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); + GdkEvent *event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (self)); - switch (event->button) { - case 1: { + switch (gdk_button_event_get_button (event)) { + case GDK_BUTTON_PRIMARY: { EvLink *link; if (pview->state == EV_PRESENTATION_END) { @@ -1185,16 +1130,14 @@ ev_view_presentation_button_release_event (GtkWidget *widget, return FALSE; } - link = ev_view_presentation_get_link_at_location (pview, - event->x, - event->y); + link = ev_view_presentation_get_link_at_location (pview, x, y); if (link) ev_view_presentation_handle_link (pview, link); else ev_view_presentation_next_page (pview); } break; - case 3: + case GDK_BUTTON_SECONDARY: ev_view_presentation_previous_page (pview); break; default: @@ -1204,104 +1147,16 @@ ev_view_presentation_button_release_event (GtkWidget *widget, return FALSE; } -static gint -ev_view_presentation_focus_out (GtkWidget *widget, - GdkEventFocus *event) -{ - EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); - - if (pview->goto_window) - ev_view_presentation_goto_window_hide (pview); - - return FALSE; -} - -static gboolean -ev_view_presentation_motion_notify_event (GtkWidget *widget, - GdkEventMotion *event) -{ - EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); - - ev_view_presentation_hide_cursor_timeout_start (pview); - ev_view_presentation_set_cursor_for_location (pview, event->x, event->y); - - return FALSE; -} - static void -ev_view_presentation_update_monitor_geometry (EvViewPresentation *pview) -{ - GdkDisplay *display; - GdkWindow *window; - GdkMonitor *monitor; - GdkRectangle geometry; - - display = gtk_widget_get_display (GTK_WIDGET (pview)); - window = gtk_widget_get_window (GTK_WIDGET (pview)); - monitor = gdk_display_get_monitor_at_window (display, window); - gdk_monitor_get_geometry (monitor, &geometry); - - pview->monitor_width = geometry.width; - pview->monitor_height = geometry.height; - -#if GTK_CHECK_VERSION(3, 24, 9) && defined (GDK_WINDOWING_WAYLAND) - if (GDK_IS_WAYLAND_DISPLAY (display)) { - /* See Evince issue #1365 and GTK regression gtk#2599 */ - int scale_factor = gdk_monitor_get_scale_factor (monitor); - pview->monitor_width = geometry.width / scale_factor; - pview->monitor_height = geometry.height / scale_factor; - } -#endif -} - -static void -init_presentation (GtkWidget *widget) +ev_view_presentation_motion_notify_event (GtkEventControllerMotion *self, + gdouble x, + gdouble y, + GtkWidget *widget) { EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); - ev_view_presentation_update_monitor_geometry (pview); - - ev_view_presentation_update_current_page (pview, pview->current_page); ev_view_presentation_hide_cursor_timeout_start (pview); -} - -static void -ev_view_presentation_realize (GtkWidget *widget) -{ - GdkWindow *window; - GdkWindowAttr attributes; - GtkAllocation allocation; - - gtk_widget_set_realized (widget, TRUE); - - attributes.window_type = GDK_WINDOW_CHILD; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual (widget); - - gtk_widget_get_allocation (widget, &allocation); - attributes.x = allocation.x; - attributes.y = allocation.y; - attributes.width = allocation.width; - attributes.height = allocation.height; - attributes.event_mask = GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_SCROLL_MASK | - GDK_KEY_PRESS_MASK | - GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK; - - window = gdk_window_new (gtk_widget_get_parent_window (widget), - &attributes, - GDK_WA_X | GDK_WA_Y | - GDK_WA_VISUAL); - - gdk_window_set_user_data (window, widget); - gtk_widget_set_window (widget, window); - - g_idle_add_once ((GSourceOnceFunc)init_presentation, widget); + ev_view_presentation_set_cursor_for_location (pview, x, y); } static void @@ -1321,17 +1176,19 @@ ev_view_presentation_change_page (EvViewPresentation *pview, } static gboolean -ev_view_presentation_scroll_event (GtkWidget *widget, - GdkEventScroll *event) -{ - EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); - guint state; - - state = event->state & gtk_accelerator_get_default_mod_mask (); +ev_view_presentation_scroll_event (GtkEventControllerScroll *self, + gdouble dx, + gdouble dy, + EvViewPresentation *pview) +{ + GtkEventController *controller = GTK_EVENT_CONTROLLER (self); + GdkEvent *event = gtk_event_controller_get_current_event (controller); + guint state = gtk_event_controller_get_current_event_state (controller) + & gtk_accelerator_get_default_mod_mask (); if (state != 0) return FALSE; - switch (event->direction) { + switch (gdk_scroll_event_get_direction (event)) { case GDK_SCROLL_DOWN: case GDK_SCROLL_RIGHT: ev_view_presentation_change_page (pview, GTK_SCROLL_PAGE_FORWARD); @@ -1349,19 +1206,17 @@ ev_view_presentation_scroll_event (GtkWidget *widget, static void -add_change_page_binding_keypad (GtkBindingSet *binding_set, +add_change_page_binding_keypad (GtkWidgetClass *widget_class, guint keyval, GdkModifierType modifiers, GtkScrollType scroll) { guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left; - gtk_binding_entry_add_signal (binding_set, keyval, modifiers, - "change_page", 1, - GTK_TYPE_SCROLL_TYPE, scroll); - gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers, - "change_page", 1, - GTK_TYPE_SCROLL_TYPE, scroll); + gtk_widget_class_add_binding_signal (widget_class, keyval, modifiers, + "change_page", "(i)", scroll); + gtk_widget_class_add_binding_signal (widget_class, keypad_keyval, modifiers, + "change_page", "(i)", scroll); } static void @@ -1375,7 +1230,6 @@ ev_view_presentation_set_property (GObject *object, switch (prop_id) { case PROP_DOCUMENT: pview->document = g_value_dup_object (value); - pview->enable_animations = EV_IS_DOCUMENT_TRANSITION (pview->document); break; case PROP_CURRENT_PAGE: ev_view_presentation_set_current_page (pview, g_value_get_uint (value)); @@ -1417,7 +1271,6 @@ ev_view_presentation_notify_scale_factor (EvViewPresentation *pview) if (!gtk_widget_get_realized (GTK_WIDGET (pview))) return; - ev_view_presentation_update_monitor_geometry (pview); ev_view_presentation_reset_jobs (pview); ev_view_presentation_update_current_page (pview, pview->current_page); } @@ -1447,26 +1300,33 @@ ev_view_presentation_constructor (GType type, return object; } +static void +ev_view_presentation_size_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + EvViewPresentation *pview = EV_VIEW_PRESENTATION (widget); + GtkWidgetClass *parent_class = GTK_WIDGET_CLASS ( + ev_view_presentation_parent_class); + parent_class->size_allocate (widget, width, height, baseline); + + if (pview->goto_popup) + gtk_popover_present (GTK_POPOVER (pview->goto_popup)); +} + static void ev_view_presentation_class_init (EvViewPresentationClass *klass) { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkBindingSet *binding_set; klass->change_page = ev_view_presentation_change_page; gobject_class->dispose = ev_view_presentation_dispose; - widget_class->get_preferred_width = ev_view_presentation_get_preferred_width; - widget_class->get_preferred_height = ev_view_presentation_get_preferred_height; - widget_class->realize = ev_view_presentation_realize; - widget_class->draw = ev_view_presentation_draw; - widget_class->key_press_event = ev_view_presentation_key_press_event; - widget_class->button_release_event = ev_view_presentation_button_release_event; - widget_class->focus_out_event = ev_view_presentation_focus_out; - widget_class->motion_notify_event = ev_view_presentation_motion_notify_event; - widget_class->scroll_event = ev_view_presentation_scroll_event; + widget_class->snapshot = ev_view_presentation_snapshot; + widget_class->size_allocate = ev_view_presentation_size_allocate; gtk_widget_class_set_css_name (widget_class, "evpresentationview"); @@ -1539,45 +1399,64 @@ ev_view_presentation_class_init (EvViewPresentationClass *klass) G_TYPE_NONE, 1, G_TYPE_OBJECT); - binding_set = gtk_binding_set_by_class (klass); - add_change_page_binding_keypad (binding_set, GDK_KEY_Left, 0, GTK_SCROLL_PAGE_BACKWARD); - add_change_page_binding_keypad (binding_set, GDK_KEY_Right, 0, GTK_SCROLL_PAGE_FORWARD); - add_change_page_binding_keypad (binding_set, GDK_KEY_Up, 0, GTK_SCROLL_PAGE_BACKWARD); - add_change_page_binding_keypad (binding_set, GDK_KEY_Down, 0, GTK_SCROLL_PAGE_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, - "change_page", 1, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, - "change_page", 1, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, - "change_page", 1, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Down, 0, - "change_page", 1, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Up, 0, - "change_page", 1, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_J, 0, - "change_page", 1, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_H, 0, - "change_page", 1, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_L, 0, - "change_page", 1, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_K, 0, - "change_page", 1, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD); + add_change_page_binding_keypad (widget_class, GDK_KEY_Left, 0, GTK_SCROLL_PAGE_BACKWARD); + add_change_page_binding_keypad (widget_class, GDK_KEY_Right, 0, GTK_SCROLL_PAGE_FORWARD); + add_change_page_binding_keypad (widget_class, GDK_KEY_Up, 0, GTK_SCROLL_PAGE_BACKWARD); + add_change_page_binding_keypad (widget_class, GDK_KEY_Down, 0, GTK_SCROLL_PAGE_FORWARD); + + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_space, 0, + "change_page", "(i)", GTK_SCROLL_PAGE_FORWARD); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_space, 0, + "change_page", "(i)", GTK_SCROLL_PAGE_FORWARD); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_space, GDK_SHIFT_MASK, + "change_page", "(i)", GTK_SCROLL_PAGE_BACKWARD); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_BackSpace, 0, + "change_page", "(i)", GTK_SCROLL_PAGE_BACKWARD); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Page_Down, 0, + "change_page", "(i)", GTK_SCROLL_PAGE_FORWARD); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Page_Up, 0, + "change_page", "(i)", GTK_SCROLL_PAGE_BACKWARD); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_J, 0, + "change_page", "(i)", GTK_SCROLL_PAGE_FORWARD); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_H, 0, + "change_page", "(i)", GTK_SCROLL_PAGE_BACKWARD); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_L, 0, + "change_page", "(i)", GTK_SCROLL_PAGE_FORWARD); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_K, 0, + "change_page", "(i)", GTK_SCROLL_PAGE_BACKWARD); } static void ev_view_presentation_init (EvViewPresentation *pview) { - gtk_widget_set_can_focus (GTK_WIDGET (pview), TRUE); - pview->is_constructing = TRUE; + GtkWidget *widget = GTK_WIDGET (pview); + GtkEventController *controller; + + gtk_widget_set_can_focus (widget, TRUE); + gtk_widget_set_focusable (widget, TRUE); + pview->is_constructing = TRUE; + + controller = gtk_event_controller_scroll_new (GTK_EVENT_CONTROLLER_SCROLL_VERTICAL); + g_signal_connect (G_OBJECT (controller), "scroll", + G_CALLBACK (ev_view_presentation_scroll_event), widget); + gtk_widget_add_controller (widget, controller); + + controller = gtk_event_controller_key_new (); + g_signal_connect (G_OBJECT (controller), "key-pressed", + G_CALLBACK (ev_view_presentation_key_press_event), widget); + gtk_widget_add_controller (widget, controller); + + controller = gtk_event_controller_motion_new (); + g_signal_connect (G_OBJECT (controller), "motion", + G_CALLBACK (ev_view_presentation_motion_notify_event), widget); + gtk_widget_add_controller (widget, controller); + + controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ()); + g_signal_connect (G_OBJECT (controller), "released", + G_CALLBACK (ev_view_presentation_button_release_event), widget); + gtk_widget_add_controller (widget, controller); + + ev_view_presentation_goto_window_create (pview); } GtkWidget * diff --git a/libview/libview.gresource.xml b/libview/libview.gresource.xml new file mode 100644 index 000000000..24e9d8afd --- /dev/null +++ b/libview/libview.gresource.xml @@ -0,0 +1,32 @@ + + + + + shader/fade.glsl + shader/split.glsl + shader/wipe.glsl + shader/box.glsl + shader/push.glsl + shader/cover.glsl + shader/uncover.glsl + shader/blinds.glsl + shader/dissolve.glsl + shader/fly.glsl + shader/glitter.glsl + + diff --git a/libview/meson.build b/libview/meson.build index d4abe4b3c..dfa33a94a 100644 --- a/libview/meson.build +++ b/libview/meson.build @@ -77,6 +77,14 @@ cflags = [ '-DEVINCE_COMPILATION' ] +sources += gnome.compile_resources( + 'ev-view-resources', + 'libview.gresource.xml', + source_dir: data_dir, + c_name: 'ev_view', +) + + libevview = shared_library( 'evview-' + ev_api_version, version: ev_view_version, diff --git a/libview/shader/blinds.glsl b/libview/shader/blinds.glsl new file mode 100644 index 000000000..92a4846a9 --- /dev/null +++ b/libview/shader/blinds.glsl @@ -0,0 +1,30 @@ +uniform float progress; +uniform int alignment; // 0 for horizontal, 1 for vertical +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; + +vec4 getFromColor (vec2 uv) { + return GskTexture(u_texture1, uv); +} + +vec4 getToColor (vec2 uv) { + return GskTexture(u_texture2, uv); +} + +// License: MIT +// Author: Qiu Wenbo + +const int count = 10; + +vec4 transition (vec2 uv) { + float s = sign(float(alignment)); + float axis = mix(uv.y, uv.x, s); + + return mix(getToColor(uv), getFromColor(uv), + step(progress, fract(((2. * s - 1.)) * count * axis))); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) +{ + fragColor = transition(uv); +} diff --git a/libview/shader/box.glsl b/libview/shader/box.glsl new file mode 100644 index 000000000..075f86ac3 --- /dev/null +++ b/libview/shader/box.glsl @@ -0,0 +1,37 @@ +uniform float progress; +uniform int direction; +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; + +vec4 getFromColor (vec2 uv) { + return GskTexture(u_texture1, uv); +} + +vec4 getToColor (vec2 uv) { + return GskTexture(u_texture2, uv); +} + +// License: MIT +// Author: Qiu Wenbo + +vec4 transition(vec2 uv) { + vec2 p=uv.xy/vec2(1.0).xy; + vec4 a=getFromColor(p); + vec4 b=getToColor(p); + float half_progress = progress / 2.0; + + float interpolate = mix( + 1.0 - step(half_progress, p.x) * step(p.x, 1.0 - half_progress) * + step(half_progress, p.y) * step(p.y, 1.0 - half_progress), + step(0.5 - half_progress, p.x) * step(p.x, 0.5 + half_progress) * + step(0.5 - half_progress, p.y) * step(p.y, 0.5 + half_progress), + float(direction) + ); + + return mix(a, b, interpolate); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) +{ + fragColor = transition(uv); +} diff --git a/libview/shader/cover.glsl b/libview/shader/cover.glsl new file mode 100644 index 000000000..21553128f --- /dev/null +++ b/libview/shader/cover.glsl @@ -0,0 +1,33 @@ +uniform float progress; +uniform int angle; +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; + +vec4 getFromColor (vec2 uv) { + return GskTexture(u_texture1, uv); +} + +vec4 getToColor (vec2 uv) { + return GskTexture(u_texture2, uv); +} + +// License: MIT +// Author: Qiu Wenbo + +vec4 transition (vec2 uv) { + float r = radians(float(angle)); + vec2 direction = vec2(cos(r), sin(r)); + vec2 p = uv - progress * sign(direction); + vec2 f = fract(p); + + return mix( + getToColor(f), + getFromColor(uv), + step(0.0, p.y) * step(p.y, 1.0) * step(0.0, p.x) * step(p.x, 1.0) + ); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) +{ + fragColor = transition(uv); +} diff --git a/libview/shader/dissolve.glsl b/libview/shader/dissolve.glsl new file mode 100644 index 000000000..6c4a428ae --- /dev/null +++ b/libview/shader/dissolve.glsl @@ -0,0 +1,33 @@ +uniform float progress; +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; + +vec4 getFromColor (vec2 uv) { + return GskTexture(u_texture1, uv); +} + +vec4 getToColor (vec2 uv) { + return GskTexture(u_texture2, uv); +} + +// Source: https://gl-transitions.com/editor/randomsquares +// License: MIT +// Author: gre + +const ivec2 size = ivec2(20, 20); +const float smoothness = 0.2; + +float rand (vec2 co) { + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +} + +vec4 transition(vec2 uv) { + float r = rand(floor(vec2(size) * uv)); + float m = smoothstep(0.0, -smoothness, r - (progress * (1.0 + smoothness))); + return mix(getFromColor(uv), getToColor(uv), m); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) +{ + fragColor = transition(uv); +} diff --git a/libview/shader/fade.glsl b/libview/shader/fade.glsl new file mode 100644 index 000000000..5fd6a182e --- /dev/null +++ b/libview/shader/fade.glsl @@ -0,0 +1,28 @@ +uniform float progress; +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; + +vec4 getFromColor (vec2 uv) { + return GskTexture(u_texture1, uv); +} + +vec4 getToColor (vec2 uv) { + return GskTexture(u_texture2, uv); +} + +// Source: https://gl-transitions.com/editor/fade +// License: MIT +// Author: gre + +vec4 transition (vec2 uv) { + return mix( + getFromColor(uv), + getToColor(uv), + progress + ); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) +{ + fragColor = transition(uv); +} diff --git a/libview/shader/fly.glsl b/libview/shader/fly.glsl new file mode 100644 index 000000000..fa17e69d3 --- /dev/null +++ b/libview/shader/fly.glsl @@ -0,0 +1,43 @@ +uniform float progress; +uniform int angle; +uniform float scale; +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; + +vec4 getFromColor (vec2 uv) { + return GskTexture(u_texture1, uv); +} + +vec4 getToColor (vec2 uv) { + return GskTexture(u_texture2, uv); +} + +// License: MIT +// Author: Qiu Wenbo +const vec2 center = vec2(0.5, 0.5); + +float r = radians(float(angle)); +vec2 direction = vec2(cos(r), sin(r)); +float size = (scale - 1.) * progress + 1.; + +vec2 box_coordinate(vec2 origin) +{ + return (origin - center) * size + center + direction * (1. + scale) / 2. * progress; +} + +vec4 transition (vec2 uv) { + vec2 f = (uv - (1. + scale) / 2. * progress * direction - center) / size + center; + + vec2 top_left = box_coordinate(vec2(0, 1)); + vec2 bottom_right = box_coordinate(vec2(1, 0)); + + float region = step(top_left.x, uv.x) * step(uv.x, bottom_right.x) * + step(uv.y, top_left.y) * step(bottom_right.y, uv.y); + + return mix(getToColor(uv), getFromColor(f), region); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) +{ + fragColor = transition(uv); +} diff --git a/libview/shader/glitter.glsl b/libview/shader/glitter.glsl new file mode 100644 index 000000000..0b8f548bd --- /dev/null +++ b/libview/shader/glitter.glsl @@ -0,0 +1,46 @@ +uniform float progress; +uniform int angle; +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; + +vec4 getFromColor (vec2 uv) { + return GskTexture(u_texture1, uv); +} + +vec4 getToColor (vec2 uv) { + return GskTexture(u_texture2, uv); +} + +// License: MIT +// Author: Qiu Wenbo, based on randomsquares from gre. See dissolve.glsl + +const float smoothness = 0.0; +const ivec2 size = ivec2(20, 20); + +float rand (vec2 co) { + return fract(sin(dot(co.xy ,vec2(12.9898,33.233))) * 43758.5453); +} + +vec4 transition(vec2 uv) { + float ra = radians(float(angle)); + vec2 direction = vec2(cos(ra), sin(ra)); + + vec2 rounded_uv = floor(uv * vec2(size)) / vec2(size); + + vec2 p = rounded_uv - progress * direction; + float should_speedup = 1.0 - step(0.0, p.y) * + step(p.y, 1.0) * + step(0.0, p.x) * + step(p.x, 1.0); + + float r = max(0., rand(rounded_uv) - 0.4 * should_speedup); + + float m = smoothstep(0.0, -smoothness, r - (progress * (1.0 + smoothness))); + + return mix(getFromColor(uv), getToColor(uv), m); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) +{ + fragColor = transition(uv); +} diff --git a/libview/shader/push.glsl b/libview/shader/push.glsl new file mode 100644 index 000000000..57e20e80d --- /dev/null +++ b/libview/shader/push.glsl @@ -0,0 +1,34 @@ +uniform float progress; +uniform int angle; +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; + +vec4 getFromColor (vec2 uv) { + return GskTexture(u_texture1, uv); +} + +vec4 getToColor (vec2 uv) { + return GskTexture(u_texture2, uv); +} + +// Source: https://gl-transitions.com/editor/Directional +// License: MIT +// Author: Gaëtan Renaudeau + +vec4 transition (vec2 uv) { + float r = radians(float(angle)); + vec2 direction = vec2(cos(r), sin(r)); + vec2 p = uv + progress * sign(direction); + vec2 f = fract(p); + + return mix( + getToColor(f), + getFromColor(f), + step(0.0, p.y) * step(p.y, 1.0) * step(0.0, p.x) * step(p.x, 1.0) + ); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) +{ + fragColor = transition(uv); +} diff --git a/libview/shader/split.glsl b/libview/shader/split.glsl new file mode 100644 index 000000000..36771473f --- /dev/null +++ b/libview/shader/split.glsl @@ -0,0 +1,35 @@ +uniform float progress; +uniform int direction; +uniform int alignment; +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; + +vec4 getFromColor (vec2 uv) { + return GskTexture(u_texture1, uv); +} + +vec4 getToColor (vec2 uv) { + return GskTexture(u_texture2, uv); +} + +// License: MIT +// Author: Qiu Wenbo + +vec4 transition(vec2 uv) { + vec2 p=uv.xy/vec2(1.0).xy; + vec4 a=getFromColor(p); + vec4 b=getToColor(p); + + float r = mix(p.x, p.y, float(alignment)); + float half_progress = progress / 2.0; + float interpolate = mix(1.0 - step(half_progress, r) * step(r, 1.0 - half_progress), + step(0.5 - half_progress, r) * step(r, 0.5 + half_progress), + float(direction)); + + return mix(a, b, interpolate); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) +{ + fragColor = transition(uv); +} diff --git a/libview/shader/uncover.glsl b/libview/shader/uncover.glsl new file mode 100644 index 000000000..eff7999a6 --- /dev/null +++ b/libview/shader/uncover.glsl @@ -0,0 +1,33 @@ +uniform float progress; +uniform int angle; +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; + +vec4 getFromColor (vec2 uv) { + return GskTexture(u_texture1, uv); +} + +vec4 getToColor (vec2 uv) { + return GskTexture(u_texture2, uv); +} + +// License: MIT +// Author: Qiu Wenbo + +vec4 transition (vec2 uv) { + float r = radians(float(angle)); + vec2 direction = vec2(cos(r), sin(r)); + vec2 p = uv - progress * sign(direction); + vec2 f = fract(p); + + return mix( + getToColor(uv), + getFromColor(f), + step(0.0, p.y) * step(p.y, 1.0) * step(0.0, p.x) * step(p.x, 1.0) + ); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) +{ + fragColor = transition(uv); +} diff --git a/libview/shader/wipe.glsl b/libview/shader/wipe.glsl new file mode 100644 index 000000000..9cca3f69c --- /dev/null +++ b/libview/shader/wipe.glsl @@ -0,0 +1,36 @@ +uniform float progress; +uniform int angle; +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; + +vec4 getFromColor (vec2 uv) { + return GskTexture(u_texture1, uv); +} + +vec4 getToColor (vec2 uv) { + return GskTexture(u_texture2, uv); +} + +// Source: https://gl-transitions.com/editor/directionalwipe +// License: MIT +// Author: gre + +const float smoothness = 0.0; +const vec2 center = vec2(0.5, 0.5); + +vec4 transition (vec2 uv) { + float r = radians(float(angle)); + vec2 direction = vec2(cos(r), sin(r)); + vec2 v = normalize(direction); + v /= abs(v.x)+abs(v.y); + float d = v.x * center.x + v.y * center.y; + float m = + (1.0-step(progress, 0.0)) * // there is something wrong with our formula that makes m not equals 0.0 with progress is 0.0 + (1.0 - smoothstep(-smoothness, 0.0, v.x * uv.x + v.y * uv.y - (d-0.5+progress*(1.+smoothness)))); + return mix(getFromColor(uv), getToColor(uv), m); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) +{ + fragColor = transition(uv); +} -- GitLab From 857ef9c0649df5d1cab70d332a9b38d60da1a333 Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Sat, 7 Aug 2021 14:22:39 +0800 Subject: [PATCH 17/50] libview: Port EvView to gtk4 Signed-off-by: Qiu Wenbo --- libview/ev-view-marshal.list | 3 +- libview/ev-view-private.h | 19 +- libview/ev-view.c | 2647 +++++++++++++-------------------- libview/evince-view.ui | 70 + libview/libview.gresource.xml | 3 + 5 files changed, 1148 insertions(+), 1594 deletions(-) create mode 100644 libview/evince-view.ui diff --git a/libview/ev-view-marshal.list b/libview/ev-view-marshal.list index 97bcc59f8..c0eb4ab8b 100644 --- a/libview/ev-view-marshal.list +++ b/libview/ev-view-marshal.list @@ -1,3 +1,4 @@ -VOID:ENUM,ENUM VOID:INT,INT +VOID:POINTER,DOUBLE,DOUBLE BOOLEAN:ENUM,INT,BOOLEAN +BOOLEAN:ENUM,ENUM diff --git a/libview/ev-view-private.h b/libview/ev-view-private.h index 010287125..298a05d81 100644 --- a/libview/ev-view-private.h +++ b/libview/ev-view-private.h @@ -36,6 +36,13 @@ #define DRAG_HISTORY 10 +struct GdkPoint { + gint x; + gint y; +}; + +typedef struct GdkPoint GdkPoint; + /* Information for middle clicking and moving around the doc */ typedef struct { gboolean in_drag; @@ -59,6 +66,7 @@ typedef struct { /* Information for handling selection */ typedef struct { + gboolean in_select; gboolean in_drag; GdkPoint start; GList *selections; @@ -128,10 +136,7 @@ typedef struct { } EvLinkPreview; struct _EvView { - GtkContainer layout; - - /* Container */ - GList *children; + GtkWidget parent; EvDocument *document; @@ -153,7 +158,6 @@ struct _EvView { EvViewCursor cursor; GtkRequisition requisition; - gboolean internal_size_request; /* Scrolling */ GtkAdjustment *hadjustment; @@ -235,9 +239,6 @@ struct _EvView { /* Synctex */ EvMapping *synctex_result; - /* Accessibility */ - AtkObject *accessible; - /* Caret navigation */ gboolean caret_enabled; gint cursor_offset; @@ -262,7 +263,7 @@ struct _EvView { }; struct _EvViewClass { - GtkContainerClass parent_class; + GtkWidgetClass parent_class; void (*scroll) (EvView *view, GtkScrollType scroll, diff --git a/libview/ev-view.c b/libview/ev-view.c index 093024429..63bad5e3b 100644 --- a/libview/ev-view.c +++ b/libview/ev-view.c @@ -35,15 +35,16 @@ #include "ev-document-layers.h" #include "ev-document-media.h" #include "ev-document-misc.h" + +#include "ev-view.h" +#include "ev-view-private.h" + #include "ev-form-field-private.h" #include "ev-pixbuf-cache.h" #include "ev-page-cache.h" #include "ev-view-marshal.h" #include "ev-document-annotations.h" #include "ev-annotation-window.h" -#include "ev-view.h" -#include "ev-view-accessible.h" -#include "ev-view-private.h" #include "ev-view-type-builtins.h" #include "ev-debug.h" @@ -65,12 +66,6 @@ enum { N_SIGNALS }; -enum { - TARGET_DND_URI, - TARGET_DND_TEXT, - TARGET_DND_IMAGE -}; - enum { PROP_0, PROP_IS_LOADING, @@ -90,8 +85,6 @@ typedef enum { } EvViewFindDirection; typedef struct { - GtkWidget *widget; - /* View coords */ gint x; gint y; @@ -156,12 +149,10 @@ static void get_link_area (EvView gint y, EvLink *link, GdkRectangle *area); -static void link_preview_show_thumbnail (cairo_surface_t *page_surface, +static void link_preview_show_thumbnail (GdkTexture *page_surface, + EvView *view); +static void link_preview_job_finished_cb (EvJobThumbnailCairo *job, EvView *view); -static void link_preview_job_finished_cb (EvJobThumbnailCairo *job, - EvView *view); -static gboolean link_preview_popover_motion_notify (EvView *view, - GdkEventMotion *event); static void link_preview_delayed_show (EvView *view); /*** Forms ***/ static EvFormField *ev_view_get_form_field_at_location (EvView *view, @@ -200,38 +191,22 @@ static void ev_view_size_request_single_page (EvView static void ev_view_size_request (GtkWidget *widget, GtkRequisition *requisition); static void ev_view_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static gboolean ev_view_scroll_event (GtkWidget *widget, - GdkEventScroll *event); -static gboolean ev_view_draw (GtkWidget *widget, - cairo_t *cr); -static gboolean ev_view_popup_menu (GtkWidget *widget); -static gboolean ev_view_button_press_event (GtkWidget *widget, - GdkEventButton *event); -static gboolean ev_view_motion_notify_event (GtkWidget *widget, - GdkEventMotion *event); -static gboolean ev_view_button_release_event (GtkWidget *widget, - GdkEventButton *event); -static gboolean ev_view_enter_notify_event (GtkWidget *widget, - GdkEventCrossing *event); -static gboolean ev_view_leave_notify_event (GtkWidget *widget, - GdkEventCrossing *event); -static void ev_view_style_updated (GtkWidget *widget); + int width, + int height, + int baseline); static void ev_view_remove_all (EvView *view); static void ev_view_remove_all_form_fields (EvView *view); -static AtkObject *ev_view_get_accessible (GtkWidget *widget); - /*** Drawing ***/ static void highlight_find_results (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, int page); static void highlight_forward_search_results (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, int page); static void draw_one_page (EvView *view, gint page, - cairo_t *cr, + GtkSnapshot *snapshot, GdkRectangle *page_area, GtkBorder *border, GdkRectangle *expose_area, @@ -249,7 +224,7 @@ static void ev_view_page_changed_cb (EvDocumentModel gint old_page, gint new_page, EvView *view); -static void on_adjustment_value_changed (GtkAdjustment *adjustment, +static void adjustment_value_changed_cb (GtkAdjustment *adjustment, EvView *view); /*** GObject ***/ static void ev_view_finalize (GObject *object); @@ -302,10 +277,12 @@ static void ev_view_set_cursor (EvView static void handle_cursor_over_link (EvView *view, EvLink *link, gint x, - gint y); + gint y, + gboolean from_motion); static void ev_view_handle_cursor_over_xy (EvView *view, gint x, - gint y); + gint y, + gboolean from_motion); /*** Find ***/ static gint ev_view_find_get_n_results (EvView *view, @@ -328,18 +305,12 @@ static void extend_selection (EvView static void clear_selection (EvView *view); static void selection_free (EvViewSelection *selection); static char* get_selected_text (EvView *ev_view); -static void ev_view_primary_get_cb (GtkClipboard *clipboard, - GtkSelectionData *selection_data, - guint info, - gpointer data); -static void ev_view_primary_clear_cb (GtkClipboard *clipboard, - gpointer data); -static void ev_view_update_primary_selection (EvView *ev_view); /*** Caret navigation ***/ static void ev_view_check_cursor_blink (EvView *ev_view); -G_DEFINE_TYPE_WITH_CODE (EvView, ev_view, GTK_TYPE_CONTAINER, + +G_DEFINE_TYPE_WITH_CODE (EvView, ev_view, GTK_TYPE_WIDGET, G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)) /* HeightToPage cache */ @@ -495,40 +466,6 @@ ev_view_get_height_to_page (EvView *view, } } -static gint -ev_view_get_scrollbar_size (EvView *view, - GtkOrientation orientation) -{ - GtkWidget *widget = GTK_WIDGET (view); - GtkWidget *sb; - GtkWidget *swindow = gtk_widget_get_parent (GTK_WIDGET (view)); - GtkAllocation allocation; - GtkRequisition req; - gint spacing; - - if (!GTK_IS_SCROLLED_WINDOW (swindow)) - return 0; - - gtk_widget_get_allocation (widget, &allocation); - - if (orientation == GTK_ORIENTATION_VERTICAL) { - if (allocation.height >= view->requisition.height) - sb = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (swindow)); - else - return 0; - } else { - if (allocation.width >= view->requisition.width) - sb = gtk_scrolled_window_get_hscrollbar (GTK_SCROLLED_WINDOW (swindow)); - else - return 0; - } - - gtk_widget_style_get (swindow, "scrollbar_spacing", &spacing, NULL); - gtk_widget_get_preferred_size (sb, &req, NULL); - - return (orientation == GTK_ORIENTATION_VERTICAL ? req.width : req.height) + spacing; -} - static gboolean is_dual_page (EvView *view, gboolean *odd_left_out) @@ -631,6 +568,9 @@ ev_view_scroll_to_page_position (EvView *view, GtkOrientation orientation) if (view->continuous && view->sizing_mode == EV_SIZING_FIT_PAGE) { y -= view->spacing + (border.top / 2); } + + if (view->current_page == 0) + y = 0.; } else { GdkPoint view_point; @@ -656,19 +596,15 @@ ev_view_set_loading (EvView *view, static void ev_view_set_adjustment_values (EvView *view, - GtkOrientation orientation) + GtkOrientation orientation, + int width, + int height) { GtkWidget *widget = GTK_WIDGET (view); GtkAdjustment *adjustment; GtkAllocation allocation; - int req_size; - int alloc_size; - gdouble page_size; - gdouble value; - gdouble upper; - double factor; - gint new_value; - gdouble zoom_center; + gint req_size, alloc_size, new_value; + gdouble page_size, value, upper, factor, zoom_center; gtk_widget_get_allocation (widget, &allocation); @@ -711,11 +647,8 @@ ev_view_set_adjustment_values (EvView *view, upper = MAX (alloc_size, req_size); page_size = alloc_size; - gtk_adjustment_set_page_size (adjustment, page_size); - gtk_adjustment_set_step_increment (adjustment, alloc_size * 0.1); - gtk_adjustment_set_page_increment (adjustment, alloc_size * 0.9); - gtk_adjustment_set_lower (adjustment, 0); - gtk_adjustment_set_upper (adjustment, upper); + gtk_adjustment_configure (adjustment, value, 0, upper, + alloc_size * 0.1, alloc_size * 0.9, page_size); /* * We add 0.5 to the values before to average out our rounding errors. @@ -724,7 +657,7 @@ ev_view_set_adjustment_values (EvView *view, case SCROLL_TO_KEEP_POSITION: case SCROLL_TO_FIND_LOCATION: new_value = CLAMP (upper * factor + 0.5, 0, upper - page_size); - gtk_adjustment_set_value (adjustment, (int)new_value); + gtk_adjustment_set_value (adjustment, new_value); break; case SCROLL_TO_PAGE_POSITION: ev_view_scroll_to_page_position (view, orientation); @@ -735,7 +668,7 @@ ev_view_set_adjustment_values (EvView *view, view->zoom_center_x = -1.0; else view->zoom_center_y = -1.0; - gtk_adjustment_set_value (adjustment, (int)new_value); + gtk_adjustment_set_value (adjustment, new_value); break; } } @@ -855,13 +788,15 @@ view_update_range_and_current_page (EvView *view) view->start_page, view->end_page, view->selection_info.selections); +#if 0 if (view->accessible) ev_view_accessible_set_page_range (EV_VIEW_ACCESSIBLE (view->accessible), view->start_page, view->end_page); +#endif - if (ev_pixbuf_cache_get_surface (view->pixbuf_cache, view->current_page)) - gtk_widget_queue_draw (GTK_WIDGET (view)); + if (ev_pixbuf_cache_get_texture (view->pixbuf_cache, view->current_page)) + gtk_widget_queue_draw (GTK_WIDGET (view)); } static void @@ -885,24 +820,24 @@ ev_view_set_scroll_adjustment (EvView *view, if (*to_set) { g_signal_handlers_disconnect_by_func (*to_set, - (gpointer) on_adjustment_value_changed, + (gpointer) adjustment_value_changed_cb, view); + g_object_unref (*to_set); } if (!adjustment) adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); - g_signal_connect (adjustment, "value_changed", - G_CALLBACK (on_adjustment_value_changed), + g_signal_connect (adjustment, "value-changed", + G_CALLBACK (adjustment_value_changed_cb), view); *to_set = g_object_ref_sink (adjustment); - ev_view_set_adjustment_values (view, orientation); g_object_notify (G_OBJECT (view), prop_name); } static void -add_scroll_binding_keypad (GtkBindingSet *binding_set, +add_scroll_binding_keypad (GtkWidgetClass *widget_class, guint keyval, GdkModifierType modifiers, GtkScrollType scroll, @@ -910,14 +845,10 @@ add_scroll_binding_keypad (GtkBindingSet *binding_set, { guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left; - gtk_binding_entry_add_signal (binding_set, keyval, modifiers, - "scroll", 2, - GTK_TYPE_SCROLL_TYPE, scroll, - GTK_TYPE_ORIENTATION, orientation); - gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers, - "scroll", 2, - GTK_TYPE_SCROLL_TYPE, scroll, - GTK_TYPE_ORIENTATION, orientation); + gtk_widget_class_add_binding_signal (widget_class, keyval, modifiers, + "scroll", "(ii)", scroll, orientation); + gtk_widget_class_add_binding_signal (widget_class, keypad_keyval, modifiers, + "scroll", "(ii)", scroll, orientation); } static gdouble @@ -1022,26 +953,20 @@ ev_view_last_page (EvView *view) } static void -ev_view_scroll (EvView *view, - GtkScrollType scroll, - GtkOrientation orientation) +ev_view_scroll (EvView *view, + GtkScrollType scroll, + GtkOrientation orientation) { GtkAdjustment *adjustment; - double value, increment; - gdouble upper, lower; - gdouble page_size; - gdouble step_increment; - gboolean first_page = FALSE; - gboolean last_page = FALSE; - gboolean horizontal = orientation == GTK_ORIENTATION_HORIZONTAL; + gdouble value, increment, upper, lower, page_size, step_increment; + gboolean first_page = FALSE, last_page = FALSE; - if (view->key_binding_handled) + if (view->key_binding_handled || view->caret_enabled) return; view->jump_to_find_result = FALSE; - if ((!horizontal && ev_view_page_fits (view, GTK_ORIENTATION_VERTICAL)) || - (horizontal && ev_view_page_fits (view, GTK_ORIENTATION_HORIZONTAL))) { + if (ev_view_page_fits (view, orientation)) { switch (scroll) { case GTK_SCROLL_PAGE_BACKWARD: case GTK_SCROLL_STEP_BACKWARD: @@ -1064,7 +989,8 @@ ev_view_scroll (EvView *view, } /* Assign values for increment and vertical adjustment */ - adjustment = horizontal ? view->hadjustment : view->vadjustment; + adjustment = orientation == GTK_ORIENTATION_HORIZONTAL ? + view->hadjustment : view->vadjustment; value = gtk_adjustment_get_value (adjustment); upper = gtk_adjustment_get_upper (adjustment); lower = gtk_adjustment_get_lower (adjustment); @@ -1186,11 +1112,10 @@ compute_border (EvView *view, GtkBorder *border) { GtkWidget *widget = GTK_WIDGET (view); GtkStyleContext *context = gtk_widget_get_style_context (widget); - GtkStateFlags state = gtk_widget_get_state_flags (widget); gtk_style_context_save (context); gtk_style_context_add_class (context, EV_STYLE_CLASS_DOCUMENT_PAGE); - gtk_style_context_get_border (context, state, border); + gtk_style_context_get_border (context, border); gtk_style_context_restore (context); } @@ -1752,6 +1677,12 @@ ev_view_get_area_from_mapping (EvView *view, area->y -= view->scroll_y; } +static void +ev_child_free (EvViewChild *child) +{ + g_slice_free (EvViewChild, child); +} + static void ev_view_put (EvView *view, GtkWidget *child_widget, @@ -1764,14 +1695,15 @@ ev_view_put (EvView *view, child = g_slice_new (EvViewChild); - child->widget = child_widget; child->x = x; child->y = y; child->page = page; child->doc_rect = *doc_rect; + g_object_set_data_full (G_OBJECT (child_widget), "ev-child", + child, (GDestroyNotify)ev_child_free); + gtk_widget_set_parent (child_widget, GTK_WIDGET (view)); - view->children = g_list_append (view->children, child); } static void @@ -2256,38 +2188,30 @@ tip_from_link (EvView *view, EvLink *link) return msg; } -gboolean -ev_view_current_event_is_type (EvView *view, GdkEventType type) +static gboolean +link_preview_popover_motion_notify (GtkEventControllerMotion *self, + gdouble x, + gdouble y, + EvView *view) { - GdkEvent *event; - gboolean ret = FALSE; - - event = gtk_get_current_event (); - if (event) { - if (event->type == type && - gdk_event_get_window (event) == gtk_widget_get_window (GTK_WIDGET (view))) { - ret = TRUE; - } - gdk_event_free (event); - } - return ret; + ev_view_link_preview_popover_cleanup (view); + return TRUE; } static void -handle_cursor_over_link (EvView *view, EvLink *link, gint x, gint y) +handle_cursor_over_link (EvView *view, EvLink *link, gint x, gint y, gboolean from_motion) { GdkRectangle link_area; EvLinkAction *action; EvLinkDest *dest; EvLinkDestType type; GtkWidget *popover, *spinner; - GdkEvent *event; - cairo_surface_t *page_surface = NULL; + GdkTexture *page_texture = NULL; guint link_dest_page; EvPoint link_dest_doc; GdkPoint link_dest_view; gint device_scale = 1; - gboolean from_motion = FALSE; + GtkEventController * controller; ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); @@ -2303,14 +2227,6 @@ handle_cursor_over_link (EvView *view, EvLink *link, gint x, gint y) if (!dest) return; - event = gtk_get_current_event (); - if (event) { - if (event->type == GDK_MOTION_NOTIFY && - gdk_event_get_window (event) == gtk_widget_get_window (GTK_WIDGET (view))) { - from_motion = TRUE; - } - gdk_event_free (event); - } /* Show preview popups only for motion events - Issue #1666 */ if (!from_motion) return; @@ -2324,18 +2240,21 @@ handle_cursor_over_link (EvView *view, EvLink *link, gint x, gint y) ev_view_link_preview_popover_cleanup (view); /* Init popover */ - view->link_preview.popover = popover = gtk_popover_new (GTK_WIDGET (view)); + view->link_preview.popover = popover = gtk_popover_new (); + gtk_popover_set_position (GTK_POPOVER (popover), GTK_POS_TOP); + gtk_widget_set_parent (popover, GTK_WIDGET (view)); get_link_area (view, x, y, link, &link_area); gtk_popover_set_pointing_to (GTK_POPOVER (popover), &link_area); - gtk_popover_set_modal (GTK_POPOVER (popover), FALSE); - g_signal_connect_swapped (popover, "motion-notify-event", + + controller = GTK_EVENT_CONTROLLER (gtk_event_controller_motion_new ()); + g_signal_connect (controller, "motion", G_CALLBACK (link_preview_popover_motion_notify), view); + gtk_widget_add_controller (popover, controller); spinner = gtk_spinner_new (); gtk_spinner_start (GTK_SPINNER (spinner)); - gtk_container_add (GTK_CONTAINER (popover) , spinner); - gtk_widget_show (spinner); + gtk_popover_set_child (GTK_POPOVER (popover) , spinner); /* Start thumbnailing job async */ link_dest_page = ev_link_dest_get_page (dest); @@ -2353,10 +2272,10 @@ handle_cursor_over_link (EvView *view, EvLink *link, gint x, gint y) view->link_preview.top = link_dest_view.y; view->link_preview.link = link; - page_surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, link_dest_page); + page_texture = ev_pixbuf_cache_get_texture (view->pixbuf_cache, link_dest_page); - if (page_surface) - link_preview_show_thumbnail (page_surface, view); + if (page_texture) + link_preview_show_thumbnail (page_texture, view); else { g_signal_connect (view->link_preview.job, "finished", G_CALLBACK (link_preview_job_finished_cb), @@ -2376,7 +2295,7 @@ handle_cursor_over_link (EvView *view, EvLink *link, gint x, gint y) } static void -ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y) +ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y, gboolean from_motion) { EvLink *link; EvFormField *field; @@ -2409,7 +2328,7 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y) link = ev_view_get_link_at_location (view, x, y); if (link) { - handle_cursor_over_link (view, link, x, y); + handle_cursor_over_link (view, link, x, y, from_motion); } else { ev_view_link_preview_popover_cleanup (view); view->link_preview.link = NULL; @@ -2497,8 +2416,10 @@ _ev_view_set_focused_element (EvView *view, GdkRectangle view_rect; cairo_region_t *region = NULL; +#if 0 if (view->accessible) ev_view_accessible_set_focused_element (EV_VIEW_ACCESSIBLE (view->accessible), element_mapping, page); +#endif if (ev_view_get_focused_area (view, &view_rect)) region = cairo_region_create_rectangle (&view_rect); @@ -2518,11 +2439,7 @@ _ev_view_set_focused_element (EvView *view, _ev_view_ensure_rectangle_is_visible (view, &view_rect); } - if (region) { - gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)), - region, TRUE); - cairo_region_destroy (region); - } + g_clear_pointer (®ion, cairo_region_destroy); } /*** Forms ***/ @@ -2637,10 +2554,12 @@ ev_view_form_field_button_toggle (EvView *view, !state); field_button->state = !state; +#if 0 if (view->accessible) ev_view_accessible_update_element_state (EV_VIEW_ACCESSIBLE (view->accessible), ev_mapping_list_find (forms_mapping, field), field->page->index); +#endif ev_view_reload_page (view, field->page->index, region); cairo_region_destroy (region); @@ -2698,7 +2617,7 @@ ev_view_form_field_text_changed (GtkWidget *widget, gchar *text = NULL; if (GTK_IS_ENTRY (widget)) { - text = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget))); + text = g_strdup (gtk_editable_get_text (GTK_EDITABLE (widget))); } else if (GTK_IS_TEXT_BUFFER (widget)) { GtkTextIter start, end; @@ -2715,22 +2634,22 @@ ev_view_form_field_text_changed (GtkWidget *widget, } } -static gboolean -ev_view_form_field_text_focus_out (GtkWidget *widget, - GdkEventFocus *event, - EvView *view) +static void +ev_view_form_field_text_focus_out (GtkEventControllerFocus *self, + EvView *view) { + GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (self)); ev_view_form_field_text_save (view, widget); - - return FALSE; } -static gboolean -ev_view_form_field_text_button_pressed (GtkWidget *widget, - GdkEventButton *event, - gpointer data) +static void +ev_view_form_field_text_button_pressed (GtkGestureClick *self, + gint n_press, + gdouble x, + gdouble y, + gpointer user_data) { - return GDK_EVENT_STOP; + gtk_gesture_set_state (GTK_GESTURE (self), GTK_EVENT_SEQUENCE_CLAIMED); } static GtkWidget * @@ -2741,6 +2660,7 @@ ev_view_form_field_text_create_widget (EvView *view, GtkWidget *text = NULL; gchar *txt; GtkStyleContext *context; + GtkEventController *controller; txt = ev_document_forms_form_field_text_get_text (EV_DOCUMENT_FORMS (view->document), field); @@ -2748,58 +2668,47 @@ ev_view_form_field_text_create_widget (EvView *view, switch (field_text->type) { case EV_FORM_FIELD_TEXT_FILE_SELECT: /* TODO */ + return NULL; case EV_FORM_FIELD_TEXT_NORMAL: text = gtk_entry_new (); gtk_entry_set_has_frame (GTK_ENTRY (text), FALSE); /* Remove '.flat' style added by previous call * gtk_entry_set_has_frame(FALSE) which caused bug #687 */ context = gtk_widget_get_style_context (text); - gtk_style_context_remove_class (context, GTK_STYLE_CLASS_FLAT); + gtk_style_context_remove_class (context, "flat"); gtk_entry_set_max_length (GTK_ENTRY (text), field_text->max_len); gtk_entry_set_visibility (GTK_ENTRY (text), !field_text->is_password); - if (txt) { - gtk_entry_set_text (GTK_ENTRY (text), txt); - g_free (txt); - } - - g_signal_connect (text, "focus-out-event", - G_CALLBACK (ev_view_form_field_text_focus_out), - view); - g_signal_connect (text, "changed", - G_CALLBACK (ev_view_form_field_text_changed), - field); g_signal_connect_after (text, "activate", G_CALLBACK (ev_view_form_field_destroy), view); - g_signal_connect_after (text, "button-press-event", - G_CALLBACK (ev_view_form_field_text_button_pressed), - NULL); break; case EV_FORM_FIELD_TEXT_MULTILINE: { - GtkTextBuffer *buffer; - text = gtk_text_view_new (); - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); - - if (txt) { - gtk_text_buffer_set_text (buffer, txt, -1); - g_free (txt); - } - - g_signal_connect (text, "focus-out-event", - G_CALLBACK (ev_view_form_field_text_focus_out), - view); - g_signal_connect (buffer, "changed", - G_CALLBACK (ev_view_form_field_text_changed), - field); - g_signal_connect_after (text, "button-press-event", - G_CALLBACK (ev_view_form_field_text_button_pressed), - NULL); } break; } + if (txt) { + gtk_editable_set_text (GTK_EDITABLE (text), txt); + g_free (txt); + } + + g_signal_connect (text, "changed", + G_CALLBACK (ev_view_form_field_text_changed), + field); + + controller = GTK_EVENT_CONTROLLER (gtk_event_controller_focus_new ()); + g_signal_connect (controller, "leave", + G_CALLBACK (ev_view_form_field_text_focus_out), + view); + gtk_widget_add_controller (text, controller); + + controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ()); + g_signal_connect (controller, "pressed", + G_CALLBACK (ev_view_form_field_text_button_pressed), NULL); + gtk_widget_add_controller (text, controller); + g_object_weak_ref (G_OBJECT (text), (GWeakNotify)ev_view_form_field_text_save, view); @@ -2863,7 +2772,7 @@ ev_view_form_field_choice_changed (GtkWidget *widget, if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (widget))) { const gchar *text; - text = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (widget)))); + text = gtk_editable_get_text (GTK_EDITABLE (gtk_combo_box_get_child (GTK_COMBO_BOX (widget)))); if (!field_choice->text || (field_choice->text && g_ascii_strcasecmp (field_choice->text, text) != 0)) { g_free (field_choice->text); @@ -3002,8 +2911,8 @@ ev_view_form_field_choice_create_widget (EvView *view, "text", 0, NULL); - choice = gtk_scrolled_window_new (NULL, NULL); - gtk_container_add (GTK_CONTAINER (choice), tree_view); + choice = gtk_scrolled_window_new (); + gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (choice), tree_view); gtk_widget_show (tree_view); g_signal_connect (selection, "changed", @@ -3017,22 +2926,22 @@ ev_view_form_field_choice_create_widget (EvView *view, gchar *text; choice = gtk_combo_box_new_with_model_and_entry (model); - combo_entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (choice))); + combo_entry = GTK_ENTRY (gtk_combo_box_get_child (GTK_COMBO_BOX (choice))); /* This sets GtkEntry's minimum-width to be 1 char long, short enough * to workaround gtk issue gtk#1422 . Evince issue #1002 */ - gtk_entry_set_width_chars (combo_entry, 1); + gtk_editable_set_width_chars (GTK_EDITABLE (combo_entry), 1); gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (choice), 0); text = ev_document_forms_form_field_choice_get_text (EV_DOCUMENT_FORMS (view->document), field); if (text) { - gtk_entry_set_text (combo_entry, text); + gtk_editable_set_text (GTK_EDITABLE (combo_entry), text); g_free (text); } g_signal_connect (choice, "changed", G_CALLBACK (ev_view_form_field_choice_changed), field); - g_signal_connect_after (gtk_bin_get_child (GTK_BIN (choice)), + g_signal_connect_after (gtk_combo_box_get_child (GTK_COMBO_BOX (choice)), "activate", G_CALLBACK (ev_view_form_field_destroy), view); @@ -3132,7 +3041,18 @@ get_media_mapping_at_location (EvView *view, gdouble y, gint *page) { - return NULL; + gint x_new = 0, y_new = 0; + EvMappingList *media_mapping; + + if (!EV_IS_DOCUMENT_MEDIA (view->document)) + return NULL; + + if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new)) + return NULL; + + media_mapping = ev_page_cache_get_media_mapping (view->page_cache, *page); + + return media_mapping ? ev_mapping_list_get (media_mapping, x_new, y_new) : NULL; } static EvMedia * @@ -3152,6 +3072,17 @@ static gboolean ev_view_find_player_for_media (EvView *view, EvMedia *media) { + for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (view)); + child != NULL; + child = gtk_widget_get_next_sibling (child)) + { + if (!GTK_IS_VIDEO (child)) + continue; + + if (g_object_get_data (G_OBJECT(child), "media") == media) + return TRUE; + } + return FALSE; } @@ -3159,6 +3090,36 @@ static void ev_view_handle_media (EvView *view, EvMedia *media) { + GtkWidget *player; + EvMappingList *media_mapping; + EvMapping *mapping; + GdkRectangle render_area; + guint page; + GFile *uri; + + page = ev_media_get_page_index (media); + media_mapping = ev_page_cache_get_media_mapping (view->page_cache, page); + + /* TODO: focus? */ + + if (ev_view_find_player_for_media (view, media)) + return; + + uri = g_file_new_for_uri (ev_media_get_uri (media)); + player = gtk_video_new_for_file (uri); + gtk_video_set_autoplay (GTK_VIDEO (player), TRUE); + g_object_unref (uri); + + g_object_set_data_full (G_OBJECT (player), "media", + g_object_ref (media), + (GDestroyNotify)g_object_unref); + + mapping = ev_mapping_list_find (media_mapping, media); + _ev_view_transform_doc_rect_to_view_rect (view, page, &mapping->area, &render_area); + render_area.x -= view->scroll_x; + render_area.y -= view->scroll_y; + + ev_view_put (view, player, render_area.x, render_area.y, page, &mapping->area); } /* Annotations */ @@ -3241,7 +3202,7 @@ ev_view_remove_window_child_for_annot (EvView *view, } wannot = ev_annotation_window_get_annotation (EV_ANNOTATION_WINDOW (child->window)); if (ev_annotation_equal (wannot, annot)) { - gtk_widget_destroy (child->window); + gtk_window_destroy (GTK_WINDOW (child->window)); view->window_children = g_list_delete_link (view->window_children, children); break; } @@ -3261,7 +3222,7 @@ ev_view_window_children_free (EvView *view) EvViewWindowChild *child; child = (EvViewWindowChild *)l->data; - gtk_widget_destroy (GTK_WIDGET (child->window)); + gtk_window_destroy (GTK_WINDOW (child->window)); g_free (child); } g_clear_pointer (&view->window_children, g_list_free); @@ -3312,7 +3273,9 @@ ev_view_create_annotation_window (EvView *view, page = ev_annotation_get_page_index (annot); ev_view_window_child_put (view, window, page); + ev_annotation_window_set_enable_spellchecking (EV_ANNOTATION_WINDOW (window), ev_view_get_enable_spellchecking (view)); + return window; } @@ -3324,7 +3287,7 @@ show_annotation_windows (EvView *view, GList *l; GtkWindow *parent; - parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))); + parent = GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (view))); annots = ev_page_cache_get_annot_mapping (view->page_cache, page); @@ -3492,7 +3455,7 @@ ev_view_annotation_create_show_popup_window (EvView *view, GtkWidget *window = get_window_for_annot (view, annot); if (!window) { - parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))); + parent = GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (view))); window = ev_view_create_annotation_window (view, annot, parent); } @@ -3530,7 +3493,7 @@ ev_view_handle_annotation (EvView *view, "popup_is_open", TRUE, NULL); - parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))); + parent = GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (view))); window = ev_view_create_annotation_window (view, annot, parent); } else if (window && ev_annotation_markup_has_popup (EV_ANNOTATION_MARKUP (annot))) { EvMappingList *annots; @@ -3563,7 +3526,7 @@ ev_view_handle_annotation (EvView *view, GError *error = NULL; ev_attachment_open (attachment, - gtk_widget_get_screen (GTK_WIDGET (view)), + gtk_widget_get_display (GTK_WIDGET (view)), timestamp, &error); @@ -3788,7 +3751,7 @@ ev_view_cancel_add_annotation (EvView *view) view->adding_annot_info.adding_annot = FALSE; g_assert(!view->adding_annot_info.annot); ev_document_misc_get_pointer_position (GTK_WIDGET (view), &x, &y); - ev_view_handle_cursor_over_xy (view, x, y); + ev_view_handle_cursor_over_xy (view, x, y, FALSE); } void @@ -3917,7 +3880,7 @@ get_caret_cursor_area (EvView *view, EvRectangle *areas = NULL; EvRectangle *doc_rect; guint n_areas = 0; - gfloat cursor_aspect_ratio; + gdouble cursor_aspect_ratio; gint stem_width; if (!view->caret_enabled || view->rotation != 0) @@ -3957,9 +3920,11 @@ get_caret_cursor_area (EvView *view, area->x -= view->scroll_x; area->y -= view->scroll_y; - gtk_style_context_get_style (gtk_widget_get_style_context (GTK_WIDGET (view)), - "cursor-aspect-ratio", &cursor_aspect_ratio, - NULL); + g_object_get (gtk_settings_get_for_display ( + gtk_style_context_get_display (gtk_widget_get_style_context (GTK_WIDGET (view)))), + "gtk-cursor-aspect-ratio", &cursor_aspect_ratio, + NULL); + stem_width = area->height * cursor_aspect_ratio + 1; area->x -= (stem_width / 2); area->width = stem_width; @@ -3980,9 +3945,7 @@ show_cursor (EvView *view) view->cursor_visible = TRUE; if (gtk_widget_has_focus (widget) && get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &view_rect)) { - gtk_widget_queue_draw_area (widget, - view_rect.x, view_rect.y, - view_rect.width, view_rect.height); + gtk_widget_queue_draw (widget); } } @@ -3999,9 +3962,7 @@ hide_cursor (EvView *view) view->cursor_visible = FALSE; if (gtk_widget_has_focus (widget) && get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &view_rect)) { - gtk_widget_queue_draw_area (widget, - view_rect.x, view_rect.y, - view_rect.width, view_rect.height); + gtk_widget_queue_draw (widget); } } @@ -4030,7 +3991,7 @@ blink_cb (EvView *view) blink_time *= CURSOR_ON_MULTIPLIER; } - view->cursor_blink_timeout_id = gdk_threads_add_timeout (blink_time / CURSOR_DIVIDER, (GSourceFunc)blink_cb, view); + view->cursor_blink_timeout_id = g_timeout_add (blink_time / CURSOR_DIVIDER, (GSourceFunc)blink_cb, view); return G_SOURCE_REMOVE; } @@ -4041,7 +4002,7 @@ ev_view_check_cursor_blink (EvView *view) if (cursor_should_blink (view)) { if (view->cursor_blink_timeout_id == 0) { show_cursor (view); - view->cursor_blink_timeout_id = gdk_threads_add_timeout (get_cursor_blink_time (view) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER, + view->cursor_blink_timeout_id = g_timeout_add (get_cursor_blink_time (view) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER, (GSourceFunc)blink_cb, view); } @@ -4067,7 +4028,7 @@ ev_view_pend_cursor_blink (EvView *view) g_source_remove (view->cursor_blink_timeout_id); show_cursor (view); - view->cursor_blink_timeout_id = gdk_threads_add_timeout (get_cursor_blink_time (view) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER, + view->cursor_blink_timeout_id = g_timeout_add (get_cursor_blink_time (view) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER, (GSourceFunc)blink_cb, view); } @@ -4317,79 +4278,49 @@ ev_view_size_request (GtkWidget *widget, if (view->document == NULL) { view->requisition.width = 1; view->requisition.height = 1; - - *requisition = view->requisition; - - return; - } - - /* Get zoom for size here when not called from - * ev_view_size_allocate() - */ - if (!view->internal_size_request && - (view->sizing_mode == EV_SIZING_FIT_WIDTH || - view->sizing_mode == EV_SIZING_FIT_PAGE || - view->sizing_mode == EV_SIZING_AUTOMATIC)) { - GtkAllocation allocation; - - gtk_widget_get_allocation (widget, &allocation); - ev_view_zoom_for_size (view, - allocation.width, - allocation.height); + } else { + dual_page = is_dual_page(view, NULL); + if (view->continuous && dual_page) + ev_view_size_request_continuous_dual_page(view, &view->requisition); + else if (view->continuous) + ev_view_size_request_continuous(view, &view->requisition); + else if (dual_page) + ev_view_size_request_dual_page(view, &view->requisition); + else + ev_view_size_request_single_page(view, &view->requisition); } - dual_page = is_dual_page (view, NULL); - if (view->continuous && dual_page) - ev_view_size_request_continuous_dual_page (view, &view->requisition); - else if (view->continuous) - ev_view_size_request_continuous (view, &view->requisition); - else if (dual_page) - ev_view_size_request_dual_page (view, &view->requisition); - else - ev_view_size_request_single_page (view, &view->requisition); - - *requisition = view->requisition; + if (requisition) + *requisition = view->requisition; } static void -ev_view_get_preferred_width (GtkWidget *widget, - gint *minimum, - gint *natural) +ev_view_measure (GtkWidget* widget, + GtkOrientation orientation, + int for_size, + int* minimum, + int* natural, + int* minimum_baseline, + int* natural_baseline) { - GtkRequisition requisition; - - ev_view_size_request (widget, &requisition); - - *minimum = *natural = requisition.width; -} + GtkRequisition requisition; -static void -ev_view_get_preferred_height (GtkWidget *widget, - gint *minimum, - gint *natural) -{ - GtkRequisition requisition; + ev_view_size_request (widget, &requisition); - ev_view_size_request (widget, &requisition); + if (orientation == GTK_ORIENTATION_HORIZONTAL) + *minimum = *natural = requisition.width; - *minimum = *natural = requisition.height; + if (orientation == GTK_ORIENTATION_VERTICAL) + *minimum = *natural = requisition.height; } static void ev_view_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) + int width, + int height, + int baseline) { EvView *view = EV_VIEW (widget); - GList *l; - - gtk_widget_set_allocation (widget, allocation); - - if (gtk_widget_get_realized (widget)) - gdk_window_move_resize (gtk_widget_get_window (widget), - allocation->x, - allocation->y, - allocation->width, - allocation->height); if (!view->document) return; @@ -4397,60 +4328,68 @@ ev_view_size_allocate (GtkWidget *widget, if (view->sizing_mode == EV_SIZING_FIT_WIDTH || view->sizing_mode == EV_SIZING_FIT_PAGE || view->sizing_mode == EV_SIZING_AUTOMATIC) { - GtkRequisition req; - - ev_view_zoom_for_size (view, - allocation->width, - allocation->height); - view->internal_size_request = TRUE; - ev_view_size_request (widget, &req); - view->internal_size_request = FALSE; + ev_view_zoom_for_size (view, width, height); + ev_view_size_request (widget, NULL); } - ev_view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL); - ev_view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL); + ev_view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL, width, height); + ev_view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL, width, height); - if (view->document) - view_update_range_and_current_page (view); + view_update_range_and_current_page (view); view->pending_scroll = SCROLL_TO_KEEP_POSITION; view->pending_resize = FALSE; view->pending_point.x = 0; view->pending_point.y = 0; - for (l = view->children; l && l->data; l = g_list_next (l)) { + for (GtkWidget *child = gtk_widget_get_first_child (widget); + child != NULL; + child = gtk_widget_get_next_sibling (child)) { + EvViewChild *data = g_object_get_data (G_OBJECT (child), "ev-child"); GdkRectangle view_area; - EvViewChild *child = (EvViewChild *)l->data; - if (!gtk_widget_get_visible (child->widget)) + if (!data || !gtk_widget_get_visible (child)) continue; - _ev_view_transform_doc_rect_to_view_rect (view, child->page, &child->doc_rect, &view_area); + _ev_view_transform_doc_rect_to_view_rect (view, data->page, &data->doc_rect, &view_area); view_area.x -= view->scroll_x; view_area.y -= view->scroll_y; - gtk_widget_set_size_request (child->widget, view_area.width, view_area.height); - gtk_widget_size_allocate (child->widget, &view_area); + gtk_widget_set_size_request (child, view_area.width, view_area.height); + // TODO: this is a temporary solution to eliminate the warning + gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, view_area.width, NULL, NULL, NULL, NULL); + gtk_widget_size_allocate (child, &view_area, baseline); } + + if (view->link_preview.popover) + gtk_popover_present (GTK_POPOVER (view->link_preview.popover)); } static gboolean -ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event) +ev_view_scroll_event (GtkEventControllerScroll *self, gdouble dx, gdouble dy, GtkWidget *widget) { EvView *view = EV_VIEW (widget); + GdkEvent *event; guint state; - gboolean fit_width, fit_height; + GdkScrollDirection direction; + double x, y; ev_view_link_preview_popover_cleanup (view); - state = event->state & gtk_accelerator_get_default_mod_mask (); + event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (self)); + state = gtk_event_controller_get_current_event_state (GTK_EVENT_CONTROLLER (self)) + & gtk_accelerator_get_default_mod_mask (); + direction = gdk_scroll_event_get_direction (event); + gdk_event_get_axis (GDK_EVENT (event), GDK_AXIS_X, &x); + gdk_event_get_axis (GDK_EVENT (event), GDK_AXIS_Y, &y); + if (state == GDK_CONTROL_MASK) { ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE); - view->zoom_center_x = event->x; - view->zoom_center_y = event->y; + view->zoom_center_x = x; + view->zoom_center_y = y; - switch (event->direction) { + switch (direction) { case GDK_SCROLL_DOWN: case GDK_SCROLL_RIGHT: if (ev_view_can_zoom_out (view)) @@ -4462,7 +4401,7 @@ ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event) ev_view_zoom_in (view); break; case GDK_SCROLL_SMOOTH: { - gdouble delta = event->delta_x + event->delta_y; + gdouble delta = dx + dy; gdouble factor = pow (delta < 0 ? ZOOM_IN_FACTOR : ZOOM_OUT_FACTOR, fabs (delta)); if (ev_view_can_zoom (view, factor)) @@ -4476,6 +4415,8 @@ ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event) view->jump_to_find_result = FALSE; +#if 0 + /* TODO: implement this in GTK4 */ /* Shift+Wheel scrolls the in the perpendicular direction */ if (state & GDK_SHIFT_MASK) { if (event->direction == GDK_SCROLL_UP) @@ -4563,6 +4504,7 @@ ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event) else if (abs_x > abs_y) event->delta_y = 0.0; } +#endif return FALSE; } @@ -4585,79 +4527,30 @@ find_selection_for_page (EvView *view, return NULL; } -static void -ev_view_realize (GtkWidget *widget) -{ - GtkAllocation allocation; - GdkWindow *window; - GdkWindowAttr attributes; - gint attributes_mask; - - gtk_widget_set_realized (widget, TRUE); - - gtk_widget_get_allocation (widget, &allocation); - - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = allocation.x; - attributes.y = allocation.y; - attributes.width = allocation.width; - attributes.height = allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual (widget); - attributes.event_mask = gtk_widget_get_events (widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; - - window = gdk_window_new (gtk_widget_get_parent_window (widget), - &attributes, attributes_mask); - gtk_widget_set_window (widget, window); - gdk_window_set_user_data (window, widget); -} - -static void -get_cursor_color (GtkStyleContext *context, - GdkRGBA *color) -{ - GdkRGBA *caret_color; - - gtk_style_context_get (context, - gtk_style_context_get_state (context), - "caret-color", - &caret_color, - NULL); - - if (caret_color) { - color->red = caret_color->red; - color->green = caret_color->green; - color->blue = caret_color->blue; - color->alpha = caret_color->alpha; - - gdk_rgba_free (caret_color); - } else { - gtk_style_context_save (context); - gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, color); - gtk_style_context_restore (context); - } -} - /* This is based on the deprecated function gtk_draw_insertion_cursor. */ static void -draw_caret_cursor (EvView *view, - cairo_t *cr) +draw_caret_cursor (EvView *view, + GtkSnapshot *snapshot) { GdkRectangle view_rect; GdkRGBA cursor_color; + GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (view)); if (!get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &view_rect)) return; - get_cursor_color (gtk_widget_get_style_context (GTK_WIDGET (view)), &cursor_color); + gtk_style_context_get_color (context, &cursor_color); + + gtk_snapshot_save (snapshot); - cairo_save (cr); - gdk_cairo_set_source_rgba (cr, &cursor_color); - cairo_rectangle (cr, view_rect.x, view_rect.y, view_rect.width, view_rect.height); - cairo_fill (cr); - cairo_restore (cr); + gtk_snapshot_append_color (snapshot, &cursor_color, + &GRAPHENE_RECT_INIT ( + view_rect.x, + view_rect.y, + view_rect.width, + view_rect.height)); + + gtk_snapshot_restore (snapshot); } static gboolean @@ -4673,7 +4566,7 @@ should_draw_caret_cursor (EvView *view, static void draw_focus (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, gint page, GdkRectangle *clip) { @@ -4684,15 +4577,15 @@ draw_focus (EvView *view, if (view->focused_element_page != page) return; - if (!gtk_widget_has_focus (GTK_WIDGET (view))) + if (!gtk_widget_has_focus (widget)) return; if (!ev_view_get_focused_area (view, &rect)) return; if (gdk_rectangle_intersect (&rect, clip, &intersect)) { - gtk_render_focus (gtk_widget_get_style_context (widget), - cr, + gtk_snapshot_render_focus (snapshot, + gtk_widget_get_style_context (widget), intersect.x, intersect.y, intersect.width, @@ -4702,23 +4595,27 @@ draw_focus (EvView *view, #ifdef EV_ENABLE_DEBUG static void -stroke_view_rect (cairo_t *cr, +stroke_view_rect (GtkSnapshot *snapshot, GdkRectangle *clip, + GdkRGBA *color, GdkRectangle *view_rect) { GdkRectangle intersect; + GdkRGBA border_color[4] = { *color, *color, *color, *color }; + float border_width[4] = { 1, 1, 1, 1 }; if (gdk_rectangle_intersect (view_rect, clip, &intersect)) { - cairo_rectangle (cr, - intersect.x, intersect.y, - intersect.width, intersect.height); - cairo_stroke (cr); + gtk_snapshot_append_border (snapshot, + &GSK_ROUNDED_RECT_INIT (intersect.x, intersect.y, + intersect.width, intersect.height), + border_width, border_color); } } static void stroke_doc_rect (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, + GdkRGBA *color, gint page, GdkRectangle *clip, EvRectangle *doc_rect) @@ -4728,35 +4625,35 @@ stroke_doc_rect (EvView *view, _ev_view_transform_doc_rect_to_view_rect (view, page, doc_rect, &view_rect); view_rect.x -= view->scroll_x; view_rect.y -= view->scroll_y; - stroke_view_rect (cr, clip, &view_rect); + stroke_view_rect (snapshot, clip, color, &view_rect); } static void show_chars_border (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, gint page, GdkRectangle *clip) { EvRectangle *areas = NULL; guint n_areas = 0; guint i; + GdkRGBA color = { 1, 0, 0, 1 }; ev_page_cache_get_text_layout (view->page_cache, page, &areas, &n_areas); if (!areas) return; - cairo_set_source_rgb (cr, 1., 0., 0.); - for (i = 0; i < n_areas; i++) { EvRectangle *doc_rect = areas + i; - stroke_doc_rect (view, cr, page, clip, doc_rect); + stroke_doc_rect (view, snapshot, &color, page, clip, doc_rect); } } static void show_mapping_list_border (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, + GdkRGBA *color, gint page, GdkRectangle *clip, EvMappingList *mapping_list) @@ -4766,81 +4663,80 @@ show_mapping_list_border (EvView *view, for (l = ev_mapping_list_get_list (mapping_list); l; l = g_list_next (l)) { EvMapping *mapping = (EvMapping *)l->data; - stroke_doc_rect (view, cr, page, clip, &mapping->area); + stroke_doc_rect (view, snapshot, color, page, clip, &mapping->area); } } static void show_links_border (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, gint page, GdkRectangle *clip) { - cairo_set_source_rgb (cr, 0., 0., 1.); - show_mapping_list_border (view,cr, page, clip, + GdkRGBA color = { 0, 0, 1, 1 }; + show_mapping_list_border (view, snapshot, &color, page, clip, ev_page_cache_get_link_mapping (view->page_cache, page)); } static void show_forms_border (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, gint page, GdkRectangle *clip) { - cairo_set_source_rgb (cr, 0., 1., 0.); - show_mapping_list_border (view, cr, page, clip, + GdkRGBA color = { 0, 1, 0, 1 }; + show_mapping_list_border (view, snapshot, &color, page, clip, ev_page_cache_get_form_field_mapping (view->page_cache, page)); } static void show_annots_border (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, gint page, GdkRectangle *clip) { - cairo_set_source_rgb (cr, 0., 1., 1.); - show_mapping_list_border (view, cr, page, clip, + GdkRGBA color = { 0, 1, 1, 1 }; + show_mapping_list_border (view, snapshot, &color, page, clip, ev_page_cache_get_annot_mapping (view->page_cache, page)); } static void show_images_border (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, gint page, GdkRectangle *clip) { - cairo_set_source_rgb (cr, 1., 0., 1.); - show_mapping_list_border (view, cr, page, clip, + GdkRGBA color = { 1, 0, 1, 1 }; + show_mapping_list_border (view, snapshot, &color, page, clip, ev_page_cache_get_image_mapping (view->page_cache, page)); } static void show_media_border (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, gint page, GdkRectangle *clip) { - cairo_set_source_rgb (cr, 1., 1., 0.); - show_mapping_list_border (view, cr, page, clip, + GdkRGBA color = { 1, 1, 0, 1 }; + show_mapping_list_border (view, snapshot, &color, page, clip, ev_page_cache_get_media_mapping (view->page_cache, page)); } static void show_selections_border (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, gint page, GdkRectangle *clip) { cairo_region_t *region; guint i, n_rects; + GdkRGBA color = { 0.75, 0.50, 0.25, 1 }; region = ev_page_cache_get_text_mapping (view->page_cache, page); if (!region) return; - cairo_set_source_rgb (cr, 0.75, 0.50, 0.25); - region = cairo_region_copy (region); n_rects = cairo_region_num_rectangles (region); for (i = 0; i < n_rects; i++) { @@ -4855,61 +4751,59 @@ show_selections_border (EvView *view, doc_rect_float.x2 = doc_rect_int.x + doc_rect_int.width; doc_rect_float.y2 = doc_rect_int.y + doc_rect_int.height; - stroke_doc_rect (view, cr, page, clip, &doc_rect_float); + stroke_doc_rect (view, snapshot, &color, page, clip, &doc_rect_float); } cairo_region_destroy (region); } static void draw_debug_borders (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, gint page, GdkRectangle *clip) { EvDebugBorders borders = ev_debug_get_debug_borders(); - cairo_save (cr); - cairo_set_line_width (cr, 0.5); - if (borders & EV_DEBUG_BORDER_CHARS) - show_chars_border (view, cr, page, clip); + show_chars_border (view, snapshot, page, clip); if (borders & EV_DEBUG_BORDER_LINKS) - show_links_border (view, cr, page, clip); + show_links_border (view, snapshot, page, clip); if (borders & EV_DEBUG_BORDER_FORMS) - show_forms_border (view, cr, page, clip); + show_forms_border (view, snapshot, page, clip); if (borders & EV_DEBUG_BORDER_ANNOTS) - show_annots_border (view, cr, page, clip); + show_annots_border (view, snapshot, page, clip); if (borders & EV_DEBUG_BORDER_IMAGES) - show_images_border (view, cr, page, clip); + show_images_border (view, snapshot, page, clip); if (borders & EV_DEBUG_BORDER_MEDIA) - show_media_border (view, cr, page, clip); + show_media_border (view, snapshot, page, clip); if (borders & EV_DEBUG_BORDER_SELECTIONS) - show_selections_border (view, cr, page, clip); - - cairo_restore (cr); + show_selections_border (view, snapshot, page, clip); } #endif -static gboolean -ev_view_draw (GtkWidget *widget, - cairo_t *cr) +static void ev_view_snapshot(GtkWidget *widget, GtkSnapshot *snapshot) { - EvView *view = EV_VIEW (widget); + int width, height; + EvView *view = EV_VIEW (widget); gint i; GdkRectangle clip_rect; GtkBorder border; - gtk_render_background (gtk_widget_get_style_context (widget), - cr, - 0, 0, - gtk_widget_get_allocated_width (widget), - gtk_widget_get_allocated_height (widget)); + width = gtk_widget_get_width(widget); + height = gtk_widget_get_height(widget); + + gtk_snapshot_render_background (snapshot, gtk_widget_get_style_context (widget), + 0, 0, width, height); + + clip_rect.x = 0; + clip_rect.y = 0; + clip_rect.width = width; + clip_rect.height = height; if (view->document == NULL) - return FALSE; + return; - if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect)) - return FALSE; + gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height)); compute_border (view, &border); for (i = view->start_page; i >= 0 && i <= view->end_page; i++) { @@ -4922,28 +4816,28 @@ ev_view_draw (GtkWidget *widget, page_area.x -= view->scroll_x; page_area.y -= view->scroll_y; - draw_one_page (view, i, cr, &page_area, &border, &clip_rect, &page_ready); + draw_one_page (view, i, snapshot, &page_area, &border, &clip_rect, &page_ready); if (page_ready && should_draw_caret_cursor (view, i)) - draw_caret_cursor (view, cr); + draw_caret_cursor (view, snapshot); if (page_ready && view->find_pages && view->highlight_find_results) - highlight_find_results (view, cr, i); + highlight_find_results (view, snapshot, i); if (page_ready && EV_IS_DOCUMENT_ANNOTATIONS (view->document)) show_annotation_windows (view, i); if (page_ready && view->focused_element) - draw_focus (view, cr, i, &clip_rect); + draw_focus (view, snapshot, i, &clip_rect); if (page_ready && view->synctex_result) - highlight_forward_search_results (view, cr, i); + highlight_forward_search_results (view, snapshot, i); #ifdef EV_ENABLE_DEBUG if (page_ready) - draw_debug_borders (view, cr, i, &clip_rect); + draw_debug_borders (view, snapshot, i, &clip_rect); #endif } - if (GTK_WIDGET_CLASS (ev_view_parent_class)->draw) - GTK_WIDGET_CLASS (ev_view_parent_class)->draw (widget, cr); + /* snapshot child widgets */ + GTK_WIDGET_CLASS (ev_view_parent_class)->snapshot (widget, snapshot); - return FALSE; + gtk_snapshot_pop (snapshot); } static void @@ -4998,22 +4892,13 @@ ev_view_do_popup_menu (EvView *view, if (annot) items = g_list_prepend (items, annot); - g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, items); + g_signal_emit (view, signals[SIGNAL_POPUP_MENU], 0, items, x, y); g_list_free (items); return TRUE; } -static gboolean -ev_view_popup_menu (GtkWidget *widget) -{ - gint x, y; - - ev_document_misc_get_pointer_position (widget, &x, &y); - return ev_view_do_popup_menu (EV_VIEW (widget), x, y); -} - static void get_link_area (EvView *view, gint x, @@ -5078,27 +4963,25 @@ get_field_area (EvView *view, ev_view_get_area_from_mapping (view, page, field_mapping, field, area); } + static void -link_preview_show_thumbnail (cairo_surface_t *page_surface, +link_preview_show_thumbnail (GdkTexture *page_texture, EvView *view) { GtkWidget *popover = view->link_preview.popover; - GtkWidget *image_view; + GtkWidget *picture; + GtkSnapshot *snapshot; gdouble x, y; /* position of the link on destination page */ gint pwidth, pheight; /* dimensions of destination page */ gint vwidth, vheight; /* dimensions of main view */ gint width, height; /* dimensions of popup */ gint left, top; - gdouble device_scale_x = 1, device_scale_y = 1; - cairo_surface_t *thumbnail_slice; - cairo_t *cr; x = view->link_preview.left; y = view->link_preview.top; - cairo_surface_get_device_scale (page_surface, &device_scale_x, &device_scale_y); - pwidth = cairo_image_surface_get_width (page_surface) / device_scale_x; - pheight = cairo_image_surface_get_height (page_surface) / device_scale_y; + pwidth = gdk_texture_get_width (page_texture); + pheight = gdk_texture_get_height (page_texture); vwidth = gtk_widget_get_allocated_width (GTK_WIDGET (view)); vheight = gtk_widget_get_allocated_height (GTK_WIDGET (view)); @@ -5131,63 +5014,68 @@ link_preview_show_thumbnail (cairo_surface_t *page_surface, left = MIN (MAX (0, left), pwidth - width); top = MIN (MAX (0, top), pheight - height); - /* paint out the part of the page we want to a separate cairo_surface_t */ - thumbnail_slice = cairo_surface_create_similar (page_surface, CAIRO_CONTENT_COLOR, width, height); - cr = cairo_create (thumbnail_slice); - cairo_set_source_surface (cr, page_surface, -left, -top); - cairo_rectangle (cr, 0, 0, width, height); - cairo_fill (cr); - - image_view = gtk_image_new_from_surface (thumbnail_slice); + snapshot = gtk_snapshot_new (); + gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height)); + gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (-left, -top)); + gtk_snapshot_append_texture (snapshot, page_texture, &GRAPHENE_RECT_INIT (0, 0, pwidth, pheight)); + gtk_snapshot_pop (snapshot); - gtk_widget_destroy (gtk_bin_get_child (GTK_BIN (popover))); - gtk_container_add (GTK_CONTAINER (popover), image_view); - gtk_widget_show (image_view); - - cairo_destroy (cr); - cairo_surface_destroy (thumbnail_slice); -} - -static gboolean -link_preview_popover_motion_notify (EvView *view, - GdkEventMotion *event) -{ - ev_view_link_preview_popover_cleanup (view); - return TRUE; + picture = gtk_picture_new_for_paintable (gtk_snapshot_free_to_paintable (snapshot, NULL)); + gtk_widget_set_size_request (popover, width, height); + gtk_popover_set_child (GTK_POPOVER (popover), picture); } static void link_preview_delayed_show (EvView *view) { GtkWidget *popover = view->link_preview.popover; - gtk_widget_show (popover); + + gtk_popover_present (GTK_POPOVER (popover)); + gtk_popover_popup (GTK_POPOVER (popover)); view->link_preview.delay_timeout_id = 0; } +static GdkTexture * +gdk_texture_new_for_surface(cairo_surface_t *surface) +{ + GdkTexture *texture; + GBytes *bytes; + + g_return_val_if_fail(surface != NULL, NULL); + g_return_val_if_fail(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE, NULL); + g_return_val_if_fail(cairo_image_surface_get_width(surface) > 0, NULL); + g_return_val_if_fail(cairo_image_surface_get_height(surface) > 0, NULL); + + bytes = g_bytes_new_with_free_func(cairo_image_surface_get_data(surface), + cairo_image_surface_get_height(surface) * cairo_image_surface_get_stride(surface), + (GDestroyNotify)cairo_surface_destroy, + cairo_surface_reference(surface)); + + texture = gdk_memory_texture_new(cairo_image_surface_get_width(surface), + cairo_image_surface_get_height(surface), + GDK_MEMORY_DEFAULT, + bytes, + cairo_image_surface_get_stride(surface)); + + g_bytes_unref(bytes); + + return texture; +} + static void link_preview_job_finished_cb (EvJobThumbnailCairo *job, EvView *view) { - GtkWidget *popover = view->link_preview.popover; - gint device_scale = 1; - if (ev_job_is_failed (EV_JOB (job))) { - gtk_widget_destroy (popover); + gtk_widget_unparent (view->link_preview.popover); view->link_preview.popover = NULL; g_object_unref (job); view->link_preview.job = NULL; - return; } - device_scale = gtk_widget_get_scale_factor (GTK_WIDGET (view)); - cairo_surface_set_device_scale (job->thumbnail_surface, device_scale, device_scale); - - if (ev_document_model_get_inverted_colors (view->model)) - ev_document_misc_invert_surface (job->thumbnail_surface); - - link_preview_show_thumbnail (job->thumbnail_surface, view); + link_preview_show_thumbnail (gdk_texture_new_for_surface (job->thumbnail_surface), view); g_object_unref (job); view->link_preview.job = NULL; @@ -5200,7 +5088,10 @@ ev_view_link_preview_popover_cleanup (EvView *view) { g_clear_object (&view->link_preview.job); } - g_clear_pointer (&view->link_preview.popover, gtk_widget_destroy); + if (view->link_preview.popover) { + gtk_popover_popdown (GTK_POPOVER (view->link_preview.popover)); + g_clear_pointer (&view->link_preview.popover, gtk_widget_unparent); + } if (view->link_preview.delay_timeout_id) { g_source_remove (view->link_preview.delay_timeout_id); @@ -5273,19 +5164,22 @@ ev_view_query_tooltip (GtkWidget *widget, } static void -start_selection_for_event (EvView *view, - GdkEventButton *event) +start_selection_for_event (EvView *view, + gdouble x, + gdouble y, + gint n_press) { clear_selection (view); - view->selection_info.start.x = event->x + view->scroll_x; - view->selection_info.start.y = event->y + view->scroll_y; + view->selection_info.in_select = TRUE; + view->selection_info.start.x = x + view->scroll_x; + view->selection_info.start.y = y + view->scroll_y; - switch (event->type) { - case GDK_2BUTTON_PRESS: + switch (n_press) { + case 2: view->selection_info.style = EV_SELECTION_STYLE_WORD; break; - case GDK_3BUTTON_PRESS: + case 3: view->selection_info.style = EV_SELECTION_STYLE_LINE; break; default: @@ -5425,7 +5319,8 @@ position_caret_cursor_at_location (EvView *view, static gboolean position_caret_cursor_for_event (EvView *view, - GdkEventButton *event, + gdouble x, + gdouble y, gboolean redraw) { GdkRectangle area; @@ -5434,7 +5329,7 @@ position_caret_cursor_for_event (EvView *view, if (redraw) get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &prev_area); - if (!position_caret_cursor_at_location (view, event->x, event->y)) + if (!position_caret_cursor_at_location (view, x, y)) return FALSE; if (!get_caret_cursor_area (view, view->cursor_page, view->cursor_offset, &area)) @@ -5445,56 +5340,66 @@ position_caret_cursor_for_event (EvView *view, g_signal_emit (view, signals[SIGNAL_CURSOR_MOVED], 0, view->cursor_page, view->cursor_offset); if (redraw) { - cairo_region_t *damage_region; - - damage_region = cairo_region_create_rectangle (&prev_area); - cairo_region_union_rectangle (damage_region, &area); - gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)), - damage_region, TRUE); - cairo_region_destroy (damage_region); + gtk_widget_queue_draw (GTK_WIDGET (view)); } return TRUE; } -static gboolean -ev_view_button_press_event (GtkWidget *widget, - GdkEventButton *event) +static void +ev_view_button_press_event (GtkGestureClick *gesture, + int n_press, + double x, + double y, + gpointer user_data) { + GtkEventController *controller = GTK_EVENT_CONTROLLER (gesture); + GtkWidget *widget = gtk_event_controller_get_widget (controller); + GdkEvent *event = gtk_event_controller_get_current_event (controller); + guint button; + GdkModifierType state = gtk_event_controller_get_current_event_state (controller); + + EvView *view = EV_VIEW (widget); ev_view_link_preview_popover_cleanup (view); if (!view->document || ev_document_get_n_pages (view->document) <= 0) - return FALSE; + return; if (gtk_gesture_is_recognized (view->zoom_gesture)) - return TRUE; + return; + + if (gtk_gesture_is_recognized (view->pan_gesture)) + return; if (!gtk_widget_has_focus (widget)) { gtk_widget_grab_focus (widget); } - view->pressed_button = event->button; + button = gdk_button_event_get_button (event); + + view->pressed_button = button; view->selection_info.in_drag = FALSE; + view->selection_info.in_select = FALSE; if (view->scroll_info.autoscrolling) - return TRUE; + return; if (view->adding_annot_info.adding_annot && !view->adding_annot_info.annot) { - if (event->button != 1) - return TRUE; + if (button != GDK_BUTTON_PRIMARY) + return; - view->adding_annot_info.start.x = event->x + view->scroll_x; - view->adding_annot_info.start.y = event->y + view->scroll_y; + view->adding_annot_info.start.x = x + view->scroll_x; + view->adding_annot_info.start.y = y + view->scroll_y; view->adding_annot_info.stop = view->adding_annot_info.start; ev_view_create_annotation (view); - return TRUE; + return; } - switch (event->button) { - case 1: { + switch (button) { + case GDK_BUTTON_PRIMARY: { EvImage *image; EvAnnotation *annot; EvFormField *field; @@ -5502,32 +5407,34 @@ ev_view_button_press_event (GtkWidget *widget, EvMedia *media; gint page; - if (event->state & GDK_CONTROL_MASK) - return ev_view_synctex_backward_search (view, event->x , event->y); + if (state & GDK_CONTROL_MASK) { + ev_view_synctex_backward_search (view, x , y); + return; + } if (EV_IS_SELECTION (view->document) && view->selection_info.selections) { - if (event->type == GDK_3BUTTON_PRESS) { - start_selection_for_event (view, event); - } else if (event->state & GDK_SHIFT_MASK) { + if (n_press == 3) { + start_selection_for_event (view, x, y, n_press); + } else if (state & GDK_SHIFT_MASK) { GdkPoint end_point; - end_point.x = event->x + view->scroll_x; - end_point.y = event->y + view->scroll_y; + end_point.x = x + view->scroll_x; + end_point.y = y + view->scroll_y; extend_selection (view, &view->selection_info.start, &end_point); } else if (location_in_selected_text (view, - event->x + view->scroll_x, - event->y + view->scroll_y)) { + x + view->scroll_x, + y + view->scroll_y)) { view->selection_info.in_drag = TRUE; } else { - start_selection_for_event (view, event); - if (position_caret_cursor_for_event (view, event, TRUE)) { + start_selection_for_event (view, x, y, n_press); + if (position_caret_cursor_for_event (view, x, y, TRUE)) { view->cursor_blink_time = 0; ev_view_pend_cursor_blink (view); } } - } else if ((media = ev_view_get_media_at_location (view, event->x, event->y))) { + } else if ((media = ev_view_get_media_at_location (view, x, y))) { ev_view_handle_media (view, media); - } else if ((annot = ev_view_get_annotation_at_location (view, event->x, event->y))) { + } else if ((annot = ev_view_get_annotation_at_location (view, x, y))) { if (EV_IS_ANNOTATION_TEXT (annot)) { EvRectangle current_area; GdkPoint view_point; @@ -5545,8 +5452,8 @@ ev_view_button_press_event (GtkWidget *widget, view->moving_annot_info.annot = annot; ev_annotation_get_area (annot, ¤t_area); - view_point.x = event->x + view->scroll_x; - view_point.y = event->y + view->scroll_y; + view_point.x = x + view->scroll_x; + view_point.y = y + view->scroll_y; /* Remember the coordinates of the button press event * in order to implement a minimum threshold for moving @@ -5564,20 +5471,20 @@ ev_view_button_press_event (GtkWidget *widget, view->moving_annot_info.cursor_offset.x = doc_point.x - current_area.x1; view->moving_annot_info.cursor_offset.y = doc_point.y - current_area.y1; } - } else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) { + } else if ((field = ev_view_get_form_field_at_location (view, x, y))) { ev_view_remove_all_form_fields (view); ev_view_handle_form_field (view, field); - } else if ((link = get_link_mapping_at_location (view, event->x, event->y, &page))){ + } else if ((link = get_link_mapping_at_location (view, x, y, &page))){ _ev_view_set_focused_element (view, link, page); - } else if (!location_in_text (view, event->x + view->scroll_x, event->y + view->scroll_y) && - (image = ev_view_get_image_at_location (view, event->x, event->y))) { + } else if (!location_in_text (view, x + view->scroll_x, y + view->scroll_y) && + (image = ev_view_get_image_at_location (view, x, y))) { if (view->image_dnd_info.image) g_object_unref (view->image_dnd_info.image); view->image_dnd_info.image = g_object_ref (image); view->image_dnd_info.in_drag = TRUE; - view->image_dnd_info.start.x = event->x + view->scroll_x; - view->image_dnd_info.start.y = event->y + view->scroll_y; + view->image_dnd_info.start.x = x + view->scroll_x; + view->image_dnd_info.start.y = y + view->scroll_y; } else { ev_view_remove_all_form_fields (view); _ev_view_set_focused_element (view, NULL, -1); @@ -5588,181 +5495,31 @@ ev_view_button_press_event (GtkWidget *widget, } if (EV_IS_SELECTION (view->document)) - start_selection_for_event (view, event); + start_selection_for_event (view, x, y, n_press); - if (position_caret_cursor_for_event (view, event, TRUE)) { + if (position_caret_cursor_for_event (view, x, y, TRUE)) { view->cursor_blink_time = 0; ev_view_pend_cursor_blink (view); } } } - return TRUE; - case 2: - /* use root coordinates as reference point because - * scrolling changes window relative coordinates */ - view->drag_info.start.x = event->x_root; - view->drag_info.start.y = event->y_root; - view->drag_info.hadj = gtk_adjustment_get_value (view->hadjustment); - view->drag_info.vadj = gtk_adjustment_get_value (view->vadjustment); - - ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG); - ev_view_set_focused_element_at_location (view, event->x, event->y); - return TRUE; - case 3: - view->scroll_info.start_y = event->y; - ev_view_set_focused_element_at_location (view, event->x, event->y); - return ev_view_do_popup_menu (view, event->x, event->y); + return; + case GDK_BUTTON_MIDDLE: + ev_view_set_focused_element_at_location (view, x, y); + return; + case GDK_BUTTON_SECONDARY: + view->scroll_info.start_y = y; + ev_view_set_focused_element_at_location (view, x, y); + ev_view_do_popup_menu (view, x, y); } - - return FALSE; } -static void -ev_view_remove_all (EvView *view) +static gboolean +ev_view_drag_update_momentum (EvView *view) { - gtk_container_foreach (GTK_CONTAINER (view), (GtkCallback) gtk_widget_destroy, NULL); -} - -static void -destroy_child_if_form_widget (GtkWidget *widget) -{ - if (g_object_get_data (G_OBJECT (widget), "form-field")) - gtk_widget_destroy (widget); -} - -static void -ev_view_remove_all_form_fields (EvView *view) -{ - gtk_container_foreach (GTK_CONTAINER (view), (GtkCallback)destroy_child_if_form_widget, NULL); -} - -/*** Drag and Drop ***/ -static void -ev_view_drag_data_get (GtkWidget *widget, - GdkDragContext *context, - GtkSelectionData *selection_data, - guint info, - guint time) -{ - EvView *view = EV_VIEW (widget); - - switch (info) { - case TARGET_DND_TEXT: - if (EV_IS_SELECTION (view->document) && - view->selection_info.selections) { - gchar *text; - - text = get_selected_text (view); - gtk_selection_data_set_text (selection_data, - text, - strlen (text)); - g_free (text); - } - break; - case TARGET_DND_IMAGE: - if (view->image_dnd_info.image) { - GdkPixbuf *pixbuf; - - ev_document_doc_mutex_lock (); - pixbuf = ev_document_images_get_image (EV_DOCUMENT_IMAGES (view->document), - view->image_dnd_info.image); - ev_document_doc_mutex_unlock (); - - gtk_selection_data_set_pixbuf (selection_data, pixbuf); - g_object_unref (pixbuf); - } - break; - case TARGET_DND_URI: - if (view->image_dnd_info.image) { - GdkPixbuf *pixbuf; - const gchar *tmp_uri; - gchar *uris[2]; - - ev_document_doc_mutex_lock (); - pixbuf = ev_document_images_get_image (EV_DOCUMENT_IMAGES (view->document), - view->image_dnd_info.image); - ev_document_doc_mutex_unlock (); - - tmp_uri = ev_image_save_tmp (view->image_dnd_info.image, pixbuf); - g_object_unref (pixbuf); - - uris[0] = (gchar *)tmp_uri; - uris[1] = NULL; - gtk_selection_data_set_uris (selection_data, uris); - } - } -} - -static gboolean -ev_view_drag_motion (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time) -{ - if (gtk_drag_get_source_widget (context) == widget) - gdk_drag_status (context, 0, time); - else - gdk_drag_status (context, gdk_drag_context_get_suggested_action (context), time); - - return TRUE; -} - -static void -selection_update_idle_cb (EvView *view) -{ - compute_selections (view, - view->selection_info.style, - &view->selection_info.start, - &view->motion); - view->selection_update_id = 0; -} - -static gboolean -selection_scroll_timeout_cb (EvView *view) -{ - gint x, y, shift = 0; - GtkWidget *widget = GTK_WIDGET (view); - GtkAllocation allocation; - - gtk_widget_get_allocation (widget, &allocation); - ev_document_misc_get_pointer_position (widget, &x, &y); - - if (y > allocation.height) { - shift = (y - allocation.height) / 2; - } else if (y < 0) { - shift = y / 2; - } - - if (shift) - gtk_adjustment_set_value (view->vadjustment, - CLAMP (gtk_adjustment_get_value (view->vadjustment) + shift, - gtk_adjustment_get_lower (view->vadjustment), - gtk_adjustment_get_upper (view->vadjustment) - - gtk_adjustment_get_page_size (view->vadjustment))); - - if (x > allocation.width) { - shift = (x - allocation.width) / 2; - } else if (x < 0) { - shift = x / 2; - } - - if (shift) - gtk_adjustment_set_value (view->hadjustment, - CLAMP (gtk_adjustment_get_value (view->hadjustment) + shift, - gtk_adjustment_get_lower (view->hadjustment), - gtk_adjustment_get_upper (view->hadjustment) - - gtk_adjustment_get_page_size (view->hadjustment))); - - return G_SOURCE_CONTINUE; -} - -static gboolean -ev_view_drag_update_momentum (EvView *view) -{ - int i; - if (!view->drag_info.in_drag) - return G_SOURCE_REMOVE; + int i; + if (!view->drag_info.in_drag) + return G_SOURCE_REMOVE; for (i = DRAG_HISTORY - 1; i > 0; i--) { view->drag_info.buffer[i].x = view->drag_info.buffer[i-1].x; @@ -5830,87 +5587,235 @@ ev_view_scroll_drag_release (EvView *view) return G_SOURCE_CONTINUE; } -static gboolean -ev_view_motion_notify_event (GtkWidget *widget, - GdkEventMotion *event) +static void +middle_clicked_drag_begin_cb (GtkGestureDrag *self, + gdouble start_x, + gdouble start_y, + EvView *view) { - EvView *view = EV_VIEW (widget); - GdkWindow *window; - gint x, y; + /* use root coordinates as reference point because + * scrolling changes window relative coordinates */ + view->drag_info.hadj = gtk_adjustment_get_value (view->hadjustment); + view->drag_info.vadj = gtk_adjustment_get_value (view->vadjustment); - if (!view->document) - return FALSE; + ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG); - if (gtk_gesture_is_recognized (view->zoom_gesture)) - return TRUE; + view->drag_info.drag_timeout_id = g_timeout_add (10, + (GSourceFunc)ev_view_drag_update_momentum, view); + /* Set 100 to choose how long it takes to build up momentum */ + /* Clear out previous momentum info: */ + for (int i = 0; i < DRAG_HISTORY; i++) { + view->drag_info.buffer[i].x = start_x; + view->drag_info.buffer[i].y = start_y; + } + view->drag_info.momentum.x = 0; + view->drag_info.momentum.y = 0; - window = gtk_widget_get_window (widget); + view->drag_info.in_drag = TRUE; +} - if (event->is_hint || event->window != window) { - ev_document_misc_get_pointer_position (widget, &x, &y); - } else { - x = event->x; - y = event->y; +static void +middle_clicked_drag_end_cb (GtkGestureDrag *self, + gdouble offset_x, + gdouble offset_y, + EvView *view) +{ + view->drag_info.release_timeout_id = + g_timeout_add (20, (GSourceFunc)ev_view_scroll_drag_release, view); + + view->drag_info.in_drag = FALSE; +} + +static void +middle_clicked_drag_update_cb (GtkGestureDrag *self, + gdouble offset_x, + gdouble offset_y, + EvView *view) +{ + GdkEvent *event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (self)); + gdouble dhadj_value, dvadj_value; + GtkAllocation allocation; + + gtk_widget_get_allocation (GTK_WIDGET (view), &allocation); + + dhadj_value = gtk_adjustment_get_page_size (view->hadjustment) * + offset_x / allocation.width; + dvadj_value = gtk_adjustment_get_page_size (view->vadjustment) * + offset_y / allocation.height; + + /* We will update the drag event's start position if + * the adjustment value is changed, but only if the + * change was not caused by this function. */ + + view->drag_info.in_notify = TRUE; + + /* clamp scrolling to visible area */ + gtk_adjustment_set_value (view->hadjustment, MIN (view->drag_info.hadj - dhadj_value, + gtk_adjustment_get_upper (view->hadjustment) - + gtk_adjustment_get_page_size (view->hadjustment))); + gtk_adjustment_set_value (view->vadjustment, MIN (view->drag_info.vadj - dvadj_value, + gtk_adjustment_get_upper (view->vadjustment) - + gtk_adjustment_get_page_size (view->vadjustment))); + + view->drag_info.in_notify = FALSE; + + gdouble x, y; + + gdk_event_get_axis (event, GDK_AXIS_X, &x); + gdk_event_get_axis (event, GDK_AXIS_Y, &y); + + view->drag_info.buffer[0].x = x; + view->drag_info.buffer[0].y = y; +} + +static void +ev_view_remove_all_form_fields (EvView *view) +{ + GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (view)); + + while (child != NULL) { + GtkWidget *next = gtk_widget_get_next_sibling (child); + + if (g_object_get_data (G_OBJECT (child), "form-field")) + gtk_widget_unparent (child); + + child = next; } +} - if (view->scroll_info.autoscrolling) { - if (y >= 0) - view->scroll_info.last_y = y; - return TRUE; +static void +ev_view_remove_all (EvView *view) +{ + GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (view)); + + while (child != NULL) { + GtkWidget *next = gtk_widget_get_next_sibling (child); + + gtk_widget_unparent (child); + + child = next; } +} - if (view->selection_info.in_drag) { - if (gtk_drag_check_threshold (widget, - view->selection_info.start.x, - view->selection_info.start.y, - x, y)) { - GtkTargetList *target_list = gtk_target_list_new (NULL, 0); +/*** Drag and Drop ***/ +static GdkContentProvider * +drag_prepare_cb (GtkDragSource *self, + gdouble x, + gdouble y, + EvView *view) +{ + EvImage *image; + GdkPixbuf *pixbuf; + const char *tmp_uri; + GFile *file; + + if (view->selection_info.in_select) + return NULL; - gtk_target_list_add_text_targets (target_list, TARGET_DND_TEXT); + if (EV_IS_SELECTION (view->document) && view->selection_info.in_drag && + location_in_selected_text (view, x + view->scroll_x, y + view->scroll_y)) { + gchar *text = get_selected_text (view); - gtk_drag_begin_with_coordinates (widget, target_list, - GDK_ACTION_COPY, - 1, (GdkEvent *)event, - -1, -1); + return gdk_content_provider_new_for_bytes ("text/plain", + g_bytes_new_take (text, strlen (text))); + } - view->selection_info.in_drag = FALSE; - view->pressed_button = -1; + if (!location_in_text (view, x + view->scroll_x, y + view->scroll_y) && + (image = ev_view_get_image_at_location (view, x, y))) { + ev_document_doc_mutex_lock (); + pixbuf = ev_document_images_get_image (EV_DOCUMENT_IMAGES (view->document), image); + ev_document_doc_mutex_unlock (); - gtk_target_list_unref (target_list); + tmp_uri = ev_image_save_tmp (image, pixbuf); + file = g_file_new_for_uri (tmp_uri); - return TRUE; - } - } else if (view->image_dnd_info.in_drag) { - if (gtk_drag_check_threshold (widget, - view->selection_info.start.x, - view->selection_info.start.y, - x, y)) { - GtkTargetList *target_list = gtk_target_list_new (NULL, 0); + return gdk_content_provider_new_union ((GdkContentProvider *[2]) { + gdk_content_provider_new_typed (G_TYPE_FILE, file), + gdk_content_provider_new_typed (GDK_TYPE_PIXBUF, pixbuf), + }, 2); + } - gtk_target_list_add_uri_targets (target_list, TARGET_DND_URI); - gtk_target_list_add_image_targets (target_list, TARGET_DND_IMAGE, TRUE); + return NULL; +} - gtk_drag_begin_with_coordinates (widget, target_list, - GDK_ACTION_COPY, - 1, (GdkEvent *)event, - -1, -1); +static void +selection_update_idle_cb (EvView *view) +{ + compute_selections (view, + view->selection_info.style, + &view->selection_info.start, + &view->motion); + view->selection_update_id = 0; +} - view->image_dnd_info.in_drag = FALSE; - view->pressed_button = -1; +static gboolean +selection_scroll_timeout_cb (EvView *view) +{ + gint x, y, shift = 0; + GtkWidget *widget = GTK_WIDGET (view); + GtkAllocation allocation; - gtk_target_list_unref (target_list); + gtk_widget_get_allocation (widget, &allocation); + ev_document_misc_get_pointer_position (widget, &x, &y); - return TRUE; - } + if (y > allocation.height) { + shift = (y - allocation.height) / 2; + } else if (y < 0) { + shift = y / 2; + } + + if (shift) + gtk_adjustment_set_value (view->vadjustment, + CLAMP (gtk_adjustment_get_value (view->vadjustment) + shift, + gtk_adjustment_get_lower (view->vadjustment), + gtk_adjustment_get_upper (view->vadjustment) - + gtk_adjustment_get_page_size (view->vadjustment))); + + if (x > allocation.width) { + shift = (x - allocation.width) / 2; + } else if (x < 0) { + shift = x / 2; + } + + if (shift) + gtk_adjustment_set_value (view->hadjustment, + CLAMP (gtk_adjustment_get_value (view->hadjustment) + shift, + gtk_adjustment_get_lower (view->hadjustment), + gtk_adjustment_get_upper (view->hadjustment) - + gtk_adjustment_get_page_size (view->hadjustment))); + + return TRUE; +} + +static void +ev_view_motion_notify_event (GtkEventControllerMotion *self, + gdouble x, + gdouble y, + gpointer user_data) +{ + EvView *view = EV_VIEW (user_data); + GtkWidget *widget = GTK_WIDGET (view); + GdkModifierType state = gtk_event_controller_get_current_event_state (GTK_EVENT_CONTROLLER (self)); + + if (!view->document) + return; + + if (gtk_gesture_is_recognized (view->zoom_gesture)) + return; + + if (view->scroll_info.autoscrolling) { + if (y >= 0) + view->scroll_info.last_y = y; + return; } switch (view->pressed_button) { - case 1: + case GDK_BUTTON_PRIMARY: /* For the Evince 0.4.x release, we limit selection to un-rotated * documents only. */ if (view->rotation != 0) - return FALSE; + return; if (view->adding_annot_info.adding_annot) { EvRectangle rect; @@ -5922,12 +5827,12 @@ ev_view_motion_notify_event (GtkWidget *widget, guint annot_page; if (!view->adding_annot_info.annot) - return TRUE; + return; ev_annotation_get_area (view->adding_annot_info.annot, ¤t_area); - view->adding_annot_info.stop.x = event->x + view->scroll_x; - view->adding_annot_info.stop.y = event->y + view->scroll_y; + view->adding_annot_info.stop.x = x + view->scroll_x; + view->adding_annot_info.stop.y = y + view->scroll_y; annot_page = ev_annotation_get_page_index (view->adding_annot_info.annot); ev_view_get_page_extents (view, annot_page, &page_area, &border); _ev_view_transform_view_point_to_doc_point (view, &view->adding_annot_info.start, &page_area, &border, @@ -5977,10 +5882,10 @@ ev_view_motion_notify_event (GtkWidget *widget, double page_height; if (!view->moving_annot_info.annot) - return TRUE; + return; - view_point.x = event->x + view->scroll_x; - view_point.y = event->y + view->scroll_y; + view_point.x = x + view->scroll_x; + view_point.y = y + view->scroll_y; if (!view->moving_annot_info.moving_annot) { /* Only move the annotation if the threshold is exceeded */ @@ -5989,7 +5894,7 @@ ev_view_motion_notify_event (GtkWidget *widget, view->moving_annot_info.start.y, view_point.x, view_point.y)) - return TRUE; + return; view->moving_annot_info.moving_annot = TRUE; } @@ -6028,10 +5933,10 @@ ev_view_motion_notify_event (GtkWidget *widget, /* FIXME: reload only annotation area */ ev_view_reload_page (view, annot_page, NULL); - } else if (ev_document_has_synctex (view->document) && (event->state & GDK_CONTROL_MASK)) { + } else if (ev_document_has_synctex (view->document) && (state & GDK_CONTROL_MASK)) { /* Ignore spurious motion event triggered by slightly moving mouse * while clicking for launching synctex. Issue #951 */ - return TRUE; + return; } else { /* Schedule timeout to scroll during selection and additionally * scroll once to allow arbitrary speed. */ @@ -6050,81 +5955,20 @@ ev_view_motion_notify_event (GtkWidget *widget, * than new motion events reach us. We always put it in the * idle to make sure we catch up and don't visibly lag the * mouse. */ - if (!view->selection_update_id) + if (view->selection_info.in_select && !view->selection_update_id) view->selection_update_id = g_idle_add_once ((GSourceOnceFunc)selection_update_idle_cb, view); } - return TRUE; - case 2: - if (!view->drag_info.in_drag) { - gboolean start; - int i; - - start = gtk_drag_check_threshold (widget, - view->drag_info.start.x, - view->drag_info.start.y, - event->x_root, - event->y_root); - view->drag_info.in_drag = start; - view->drag_info.drag_timeout_id = g_timeout_add (10, - (GSourceFunc)ev_view_drag_update_momentum, view); - /* Set 100 to choose how long it takes to build up momentum */ - /* Clear out previous momentum info: */ - for (i = 0; i < DRAG_HISTORY; i++) { - view->drag_info.buffer[i].x = event->x; - view->drag_info.buffer[i].y = event->y; - } - view->drag_info.momentum.x = 0; - view->drag_info.momentum.y = 0; - } - - if (view->drag_info.in_drag) { - int dx, dy; - gdouble dhadj_value, dvadj_value; - GtkAllocation allocation; - - view->drag_info.buffer[0].x = event->x; - view->drag_info.buffer[0].y = event->y; - - dx = event->x_root - view->drag_info.start.x; - dy = event->y_root - view->drag_info.start.y; - - gtk_widget_get_allocation (widget, &allocation); - - dhadj_value = gtk_adjustment_get_page_size (view->hadjustment) * - (gdouble)dx / allocation.width; - dvadj_value = gtk_adjustment_get_page_size (view->vadjustment) * - (gdouble)dy / allocation.height; - - /* We will update the drag event's start position if - * the adjustment value is changed, but only if the - * change was not caused by this function. */ - view->drag_info.in_notify = TRUE; - - /* clamp scrolling to visible area */ - gtk_adjustment_set_value (view->hadjustment, - MIN (view->drag_info.hadj - dhadj_value, - gtk_adjustment_get_upper (view->hadjustment) - - gtk_adjustment_get_page_size (view->hadjustment))); - gtk_adjustment_set_value (view->vadjustment, - MIN (view->drag_info.vadj - dvadj_value, - gtk_adjustment_get_upper (view->vadjustment) - - gtk_adjustment_get_page_size (view->vadjustment))); - - view->drag_info.in_notify = FALSE; - - return TRUE; - } - + return; + case GDK_BUTTON_MIDDLE: break; default: - ev_view_handle_cursor_over_xy (view, x, y); + ev_view_handle_cursor_over_xy (view, x, y, TRUE); } - - return FALSE; } + /** * ev_view_get_selected_text: * @view: #EvView instance @@ -6232,40 +6076,45 @@ ev_view_get_enable_spellchecking (EvView *view) return FALSE; } -static gboolean -ev_view_button_release_event (GtkWidget *widget, - GdkEventButton *event) +static void +ev_view_button_release_event(GtkGestureClick *self, + gint n_press, + gdouble x, + gdouble y, + gpointer user_data) { - EvView *view = EV_VIEW (widget); + EvView *view = EV_VIEW (user_data); + GtkEventController *controller = GTK_EVENT_CONTROLLER (self); + GdkEvent *event = gtk_event_controller_get_current_event (controller); + GdkModifierType state = gtk_event_controller_get_current_event_state (controller); + guint32 time = gtk_event_controller_get_current_event_time (controller); EvLink *link = NULL; view->image_dnd_info.in_drag = FALSE; + view->selection_info.in_select = FALSE; if (gtk_gesture_is_recognized (view->zoom_gesture)) - return TRUE; + return; + + if (gtk_gesture_is_recognized (view->pan_gesture)) + return; if (view->scroll_info.autoscrolling) { ev_view_autoscroll_stop (view); view->pressed_button = -1; - return TRUE; + return; } - if (view->pressed_button == 1 && event->state & GDK_CONTROL_MASK) { + if (view->pressed_button == GDK_BUTTON_PRIMARY && state & GDK_CONTROL_MASK) { view->pressed_button = -1; - return TRUE; - } - - if (view->drag_info.in_drag) { - view->drag_info.release_timeout_id = - g_timeout_add (20, - (GSourceFunc)ev_view_scroll_drag_release, view); + return; } if (view->document && !view->drag_info.in_drag && (view->pressed_button == GDK_BUTTON_PRIMARY || view->pressed_button == GDK_BUTTON_MIDDLE)) { - link = ev_view_get_link_at_location (view, event->x, event->y); + link = ev_view_get_link_at_location (view, x, y); } view->drag_info.in_drag = FALSE; @@ -6274,8 +6123,8 @@ ev_view_button_release_event (GtkWidget *widget, gboolean annot_added = TRUE; /* We ignore right-click buttons while in annotation add mode */ - if (view->pressed_button != 1) - return FALSE; + if (view->pressed_button != GDK_BUTTON_PRIMARY) + return; g_assert (view->adding_annot_info.annot); if (EV_IS_ANNOTATION_MARKUP (view->adding_annot_info.annot)) { @@ -6316,8 +6165,8 @@ ev_view_button_release_event (GtkWidget *widget, if (view->adding_annot_info.type == EV_ANNOTATION_TYPE_TEXT) ev_view_annotation_create_show_popup_window (view, view->adding_annot_info.annot); - view->adding_annot_info.stop.x = event->x + view->scroll_x; - view->adding_annot_info.stop.y = event->y + view->scroll_y; + view->adding_annot_info.stop.x = x + view->scroll_x; + view->adding_annot_info.stop.y = y + view->scroll_y; if (annot_added) g_signal_emit (view, signals[SIGNAL_ANNOT_ADDED], 0, view->adding_annot_info.annot); else @@ -6325,35 +6174,35 @@ ev_view_button_release_event (GtkWidget *widget, view->adding_annot_info.adding_annot = FALSE; view->adding_annot_info.annot = NULL; - ev_view_handle_cursor_over_xy (view, event->x, event->y); + ev_view_handle_cursor_over_xy (view, x, y, FALSE); view->pressed_button = -1; - return FALSE; + return; } if (view->moving_annot_info.annot_clicked) { if (view->moving_annot_info.moving_annot) - ev_view_handle_cursor_over_xy (view, event->x, event->y); + ev_view_handle_cursor_over_xy (view, x, y, FALSE); else - ev_view_handle_annotation (view, view->moving_annot_info.annot, event->x, event->y, event->time); + ev_view_handle_annotation (view, view->moving_annot_info.annot, x, y, time); view->moving_annot_info.annot_clicked = FALSE; view->moving_annot_info.moving_annot = FALSE; view->moving_annot_info.annot = NULL; view->pressed_button = -1; - return FALSE; + return; } - if (view->pressed_button == 1) { - EvAnnotation *annot = ev_view_get_annotation_at_location (view, event->x, event->y); + if (view->pressed_button == GDK_BUTTON_PRIMARY) { + EvAnnotation *annot = ev_view_get_annotation_at_location (view, x, y); if (annot) - ev_view_handle_annotation (view, annot, event->x, event->y, event->time); + ev_view_handle_annotation (view, annot, x, y, time); } - if (view->pressed_button == 2) { - ev_view_handle_cursor_over_xy (view, event->x, event->y); + if (view->pressed_button == GDK_BUTTON_MIDDLE) { + ev_view_handle_cursor_over_xy (view, x, y, FALSE); } view->pressed_button = -1; @@ -6369,21 +6218,20 @@ ev_view_button_release_event (GtkWidget *widget, if (view->selection_info.selections) { g_clear_object (&view->link_selected); - ev_view_update_primary_selection (view); - position_caret_cursor_for_event (view, event, FALSE); + position_caret_cursor_for_event (view, x, y, FALSE); if (view->selection_info.in_drag) clear_selection (view); view->selection_info.in_drag = FALSE; } else if (link) { - if (event->button == 2) { + if (gdk_button_event_get_button (event) == GDK_BUTTON_MIDDLE) { EvLinkAction *action; EvLinkActionType type; action = ev_link_get_action (link); if (!action) - return FALSE; + return; type = ev_link_action_get_action_type (action); if (type == EV_LINK_ACTION_TYPE_GOTO_DEST) { @@ -6395,35 +6243,6 @@ ev_view_button_release_event (GtkWidget *widget, ev_view_handle_link (view, link); } } - - return FALSE; -} - -static gboolean -ev_view_forward_key_event_to_focused_child (EvView *view, - GdkEventKey *event) -{ - GtkWidget *child_widget = NULL; - GdkEventKey *new_event; - gboolean handled; - - if (view->children) { - EvViewChild *child = (EvViewChild *)view->children->data; - child_widget = child->widget; - } else { - return FALSE; - } - - new_event = (GdkEventKey *) gdk_event_copy ((GdkEvent *)event); - g_object_unref (new_event->window); - new_event->window = gtk_widget_get_window (child_widget); - if (new_event->window) - g_object_ref (new_event->window); - gtk_widget_realize (child_widget); - handled = gtk_widget_event (child_widget, (GdkEvent *)new_event); - gdk_event_free ((GdkEvent *)new_event); - - return handled; } static gint @@ -6835,7 +6654,6 @@ ev_view_move_cursor (EvView *view, GdkRectangle select_start_rect; gint select_start_offset = 0; gint select_start_page = 0; - cairo_region_t *damage_region; gboolean changed_page; gboolean clear_selections = FALSE; const gboolean forward = count >= 0; @@ -6982,9 +6800,7 @@ ev_view_move_cursor (EvView *view, view->cursor_line_offset = rect.x; } - damage_region = cairo_region_create_rectangle (&rect); - if (get_caret_cursor_area (view, prev_page, prev_offset, &prev_rect)) - cairo_region_union_rectangle (damage_region, &prev_rect); + get_caret_cursor_area (view, prev_page, prev_offset, &prev_rect); rect.x += view->scroll_x; rect.y += view->scroll_y; @@ -6994,9 +6810,7 @@ ev_view_move_cursor (EvView *view, g_signal_emit (view, signals[SIGNAL_CURSOR_MOVED], 0, view->cursor_page, view->cursor_offset); - gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)), - damage_region, TRUE); - cairo_region_destroy (damage_region); + gtk_widget_queue_draw (GTK_WIDGET (view)); /* Select text */ if (extend_selections && EV_IS_SELECTION (view->document)) { @@ -7018,31 +6832,6 @@ ev_view_move_cursor (EvView *view, return TRUE; } -static gboolean -ev_view_key_press_event (GtkWidget *widget, - GdkEventKey *event) -{ - EvView *view = EV_VIEW (widget); - gboolean retval; - - ev_view_link_preview_popover_cleanup (view); - - if (!view->document) - return FALSE; - - if (!gtk_widget_has_focus (widget)) - return ev_view_forward_key_event_to_focused_child (view, event); - - /* I expected GTK+ do this for me, but it doesn't cancel - * the propagation of bindings handled for the same binding set - */ - view->key_binding_handled = FALSE; - retval = gtk_bindings_activate_event (G_OBJECT (widget), event); - view->key_binding_handled = FALSE; - - return retval; -} - static gboolean ev_view_activate_form_field (EvView *view, EvFormField *field) @@ -7065,6 +6854,7 @@ ev_view_activate_form_field (EvView *view, return handled; } +#if 0 static gboolean current_event_is_space_key_press (void) { @@ -7083,17 +6873,19 @@ current_event_is_space_key_press (void) return is_space_key_press; } +#endif static gboolean ev_view_activate_link (EvView *view, EvLink *link) { +#if 0 /* Most of the GtkWidgets emit activate on both Space and Return key press, * but we don't want to activate links on Space for consistency with the Web. */ if (current_event_is_space_key_press ()) return FALSE; - +#endif ev_view_handle_link (view, link); return TRUE; @@ -7177,11 +6969,11 @@ ev_view_autoscroll_pause (EvView *view) view->scroll_info.timeout_id = 0; } -static gint -ev_view_focus_in (GtkWidget *widget, - GdkEventFocus *event) +static void +ev_view_focus_in (GtkEventControllerFocus *self, + gpointer user_data) { - EvView *view = EV_VIEW (widget); + EvView *view = EV_VIEW (user_data); if (view->pixbuf_cache) ev_pixbuf_cache_style_changed (view->pixbuf_cache); @@ -7189,16 +6981,14 @@ ev_view_focus_in (GtkWidget *widget, ev_view_autoscroll_resume (view); ev_view_check_cursor_blink (view); - gtk_widget_queue_draw (widget); - - return FALSE; + gtk_widget_queue_draw (GTK_WIDGET (view)); } -static gint -ev_view_focus_out (GtkWidget *widget, - GdkEventFocus *event) +static void +ev_view_focus_out (GtkEventControllerFocus *self, + gpointer user_data) { - EvView *view = EV_VIEW (widget); + EvView *view = EV_VIEW (user_data); if (view->pixbuf_cache) ev_pixbuf_cache_style_changed (view->pixbuf_cache); @@ -7206,46 +6996,33 @@ ev_view_focus_out (GtkWidget *widget, ev_view_autoscroll_pause (view); ev_view_check_cursor_blink (view); - gtk_widget_queue_draw (widget); - - return FALSE; + gtk_widget_queue_draw (GTK_WIDGET (view)); } -static gboolean -ev_view_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event) +static void +ev_view_leave_notify_event (GtkEventControllerMotion *self, + gpointer user_data) { - EvView *view = EV_VIEW (widget); + EvView *view = EV_VIEW (user_data); if (view->cursor != EV_VIEW_CURSOR_NORMAL) ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL); - - return FALSE; -} - -static gboolean -ev_view_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event) -{ - EvView *view = EV_VIEW (widget); - - ev_view_handle_cursor_over_xy (view, event->x, event->y); - - return FALSE; } static void -ev_view_style_updated (GtkWidget *widget) +ev_view_enter_notify_event (GtkEventControllerMotion *self, + gdouble x, + gdouble y, + gpointer user_data) { - if (EV_VIEW (widget)->pixbuf_cache) - ev_pixbuf_cache_style_changed (EV_VIEW (widget)->pixbuf_cache); - - GTK_WIDGET_CLASS (ev_view_parent_class)->style_updated (widget); + ev_view_handle_cursor_over_xy (EV_VIEW (user_data), x, y, FALSE); } /*** Drawing ***/ static void draw_rubberband (EvView *view, - cairo_t *cr, + GtkSnapshot *snapshot, const GdkRectangle *rect, gboolean active) { @@ -7259,7 +7036,7 @@ draw_rubberband (EvView *view, else gtk_style_context_set_state (context, GTK_STATE_FLAG_SELECTED); - gtk_render_background (context, cr, + gtk_snapshot_render_background (snapshot, context, rect->x - view->scroll_x, rect->y - view->scroll_y, rect->width, rect->height); @@ -7268,9 +7045,9 @@ draw_rubberband (EvView *view, static void -highlight_find_results (EvView *view, - cairo_t *cr, - int page) +highlight_find_results (EvView *view, + GtkSnapshot *snapshot, + int page) { EvRectangle *ev_rect; gint i, n_results = 0; @@ -7291,7 +7068,7 @@ highlight_find_results (EvView *view, active = page == view->find_page && i == view->find_result; _ev_view_transform_doc_rect_to_view_rect (view, page, ev_rect, &view_rectangle); - draw_rubberband (view, cr, &view_rectangle, active); + draw_rubberband (view, snapshot, &view_rectangle, active); if (active && find_rect->next_line) { /* Draw now next result (which is second part of multi-line match) */ @@ -7302,7 +7079,7 @@ highlight_find_results (EvView *view, ev_rect->y1 = find_rect->y1; ev_rect->y2 = find_rect->y2; _ev_view_transform_doc_rect_to_view_rect (view, page, ev_rect, &view_rectangle); - draw_rubberband (view, cr, &view_rectangle, TRUE); + draw_rubberband (view, snapshot, &view_rectangle, TRUE); } } @@ -7310,64 +7087,48 @@ highlight_find_results (EvView *view, } static void -highlight_forward_search_results (EvView *view, - cairo_t *cr, - int page) +highlight_forward_search_results (EvView *view, + GtkSnapshot *snapshot, + int page) { GdkRectangle rect; EvMapping *mapping = view->synctex_result; + GdkRGBA color = { 1.0, 0.0, 0.0, 0.3 }; if (GPOINTER_TO_INT (mapping->data) != page) return; _ev_view_transform_doc_rect_to_view_rect (view, page, &mapping->area, &rect); - cairo_save (cr); - cairo_set_source_rgb (cr, 1., 0., 0.); - cairo_rectangle (cr, + gtk_snapshot_append_color (snapshot, &color, + &GRAPHENE_RECT_INIT ( rect.x - view->scroll_x, rect.y - view->scroll_y, - rect.width, rect.height); - cairo_stroke (cr); - cairo_restore (cr); + rect.width, rect.height)); } static void -draw_surface (cairo_t *cr, - cairo_surface_t *surface, - gint x, - gint y, - gint offset_x, - gint offset_y, - gint target_width, - gint target_height) +draw_surface (GtkSnapshot *snapshot, + GdkTexture *texture, + const graphene_point_t *point, + const graphene_rect_t *area, + gboolean inverted) { - gdouble width, height; - gdouble device_scale_x = 1, device_scale_y = 1; - - cairo_surface_get_device_scale (surface, &device_scale_x, &device_scale_y); - width = cairo_image_surface_get_width (surface) / device_scale_x; - height = cairo_image_surface_get_height (surface) / device_scale_y; + gtk_snapshot_save (snapshot); + gtk_snapshot_translate (snapshot, point); - cairo_save (cr); - cairo_translate (cr, x, y); - - if (width != target_width || height != target_height) { - gdouble scale_x, scale_y; + if (inverted) { + gtk_snapshot_push_blend (snapshot, GSK_BLEND_MODE_DIFFERENCE); + gtk_snapshot_append_color (snapshot, &(GdkRGBA) {1., 1., 1., 1.}, area); + gtk_snapshot_pop (snapshot); + } - scale_x = (gdouble)target_width / width; - scale_y = (gdouble)target_height / height; - cairo_pattern_set_filter (cairo_get_source (cr), - CAIRO_FILTER_NEAREST); - cairo_scale (cr, scale_x, scale_y); + gtk_snapshot_append_texture (snapshot, texture, area); - offset_x /= scale_x; - offset_y /= scale_y; - } + if (inverted) + gtk_snapshot_pop (snapshot); - cairo_set_source_surface (cr, surface, -offset_x, -offset_y); - cairo_paint (cr); - cairo_restore (cr); + gtk_snapshot_restore (snapshot); } void @@ -7376,32 +7137,35 @@ _ev_view_get_selection_colors (EvView *view, GdkRGBA *fg_color) { GtkWidget *widget = GTK_WIDGET (view); - GtkStateFlags state; - GtkStyleContext *context; - - context = gtk_widget_get_style_context (widget); - gtk_style_context_save (context); - gtk_style_context_add_class (context, EV_STYLE_CLASS_FIND_RESULTS); - state = gtk_style_context_get_state (context) | - (gtk_widget_has_focus (widget) ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_ACTIVE); - gtk_style_context_set_state (context, state); + GtkStyleContext *context = gtk_widget_get_style_context (widget); - if (bg_color) { - g_autoptr (GdkRGBA) color = NULL; - gtk_style_context_get (context, state, - GTK_STYLE_PROPERTY_BACKGROUND_COLOR, - &color, NULL); - *bg_color = *color; + if (bg_color && + !gtk_style_context_lookup_color (context, "accent_bg_color", bg_color) && + !gtk_style_context_lookup_color (context, "theme_selected_bg_color", bg_color)) { + bg_color->red = 0; + bg_color->green = 0.623; + bg_color->blue = 1.; + bg_color->alpha = 1.; } - if (fg_color) - gtk_style_context_get_color (context, state, fg_color); + if (gtk_widget_has_focus (widget)) + bg_color->alpha = 0.3; + else + bg_color->alpha = 0.6; - gtk_style_context_restore (context); + if (fg_color && + !gtk_style_context_lookup_color (context, "accent_fg_color", fg_color) && + !gtk_style_context_lookup_color (context, "theme_selected_fg_color", fg_color)) { + fg_color->red = 1.; + fg_color->green = 1.; + fg_color->blue = 1.; + fg_color->alpha = 1.; + } } static void -draw_selection_region (cairo_t *cr, +draw_selection_region (GtkSnapshot *snapshot, + GtkWidget *widget, cairo_region_t *region, GdkRGBA *color, gint x, @@ -7409,21 +7173,38 @@ draw_selection_region (cairo_t *cr, gdouble scale_x, gdouble scale_y) { - cairo_save (cr); - cairo_translate (cr, x, y); - cairo_scale (cr, scale_x, scale_y); - gdk_cairo_region (cr, region); - cairo_set_source_rgb (cr, color->red, color->green, color->blue); - cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY); - cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); - cairo_fill (cr); - cairo_restore (cr); + cairo_rectangle_int_t box; + gint n_boxes, i; + guint state; + GtkStyleContext *context; + + context = gtk_widget_get_style_context (widget); + gtk_style_context_save (context); + gtk_style_context_add_class (context, EV_STYLE_CLASS_FIND_RESULTS); + state = gtk_style_context_get_state (context) | + (gtk_widget_has_focus (widget) ? GTK_STATE_FLAG_SELECTED : GTK_STATE_FLAG_ACTIVE); + gtk_style_context_set_state (context, state); + + gtk_snapshot_save (snapshot); + gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y)); + + n_boxes = cairo_region_num_rectangles (region); + + for (i = 0; i < n_boxes; i++) { + cairo_region_get_rectangle (region, i, &box); + + gtk_snapshot_render_background (snapshot, context, + box.x, box.y, box.width, box.height); + } + + gtk_snapshot_restore (snapshot); + gtk_style_context_restore (context); } static void draw_one_page (EvView *view, gint page, - cairo_t *cr, + GtkSnapshot *snapshot, GdkRectangle *page_area, GtkBorder *border, GdkRectangle *expose_area, @@ -7433,8 +7214,7 @@ draw_one_page (EvView *view, GdkRectangle overlap; GdkRectangle real_page_area; gint current_page; - - g_assert (view->document); + GtkWidget *widget = GTK_WIDGET (view); if (! gdk_rectangle_intersect (page_area, expose_area, &overlap)) return; @@ -7459,20 +7239,21 @@ draw_one_page (EvView *view, if (view->continuous && page == current_page) gtk_style_context_set_state (context, GTK_STATE_FLAG_ACTIVE); - gtk_render_background (context, cr, page_area->x, page_area->y, page_area->width, page_area->height); - gtk_render_frame (context, cr, page_area->x, page_area->y, page_area->width, page_area->height); + gtk_snapshot_render_background (snapshot, context, page_area->x, page_area->y, page_area->width, page_area->height); + gtk_snapshot_render_frame (snapshot, context, page_area->x, page_area->y, page_area->width, page_area->height); gtk_style_context_restore (context); if (gdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) { gint width, height; - cairo_surface_t *page_surface = NULL; - cairo_surface_t *selection_surface = NULL; - gint offset_x, offset_y; + GdkTexture *page_texture = NULL, *selection_texture = NULL; + graphene_point_t point; + graphene_rect_t area; cairo_region_t *region = NULL; + gboolean inverted = ev_document_model_get_inverted_colors (view->model); - page_surface = ev_pixbuf_cache_get_surface (view->pixbuf_cache, page); + page_texture = ev_pixbuf_cache_get_texture (view->pixbuf_cache, page); - if (!page_surface) { + if (!page_texture) { if (page == current_page) ev_view_set_loading (view, TRUE); @@ -7485,21 +7266,23 @@ draw_one_page (EvView *view, ev_view_set_loading (view, FALSE); ev_view_get_page_size (view, page, &width, &height); - offset_x = overlap.x - real_page_area.x; - offset_y = overlap.y - real_page_area.y; - draw_surface (cr, page_surface, overlap.x, overlap.y, offset_x, offset_y, width, height); + area = GRAPHENE_RECT_INIT (real_page_area.x - overlap.x, + real_page_area.y - overlap.y, + width, height); + point = GRAPHENE_POINT_INIT (overlap.x, overlap.y); + + draw_surface (snapshot, page_texture, &point, &area, inverted); /* Get the selection pixbuf iff we have something to draw */ if (!find_selection_for_page (view, page)) return; - selection_surface = ev_pixbuf_cache_get_selection_surface (view->pixbuf_cache, + selection_texture = ev_pixbuf_cache_get_selection_texture (view->pixbuf_cache, page, view->scale); - if (selection_surface) { - draw_surface (cr, selection_surface, overlap.x, overlap.y, offset_x, offset_y, - width, height); + if (selection_texture) { + draw_surface (snapshot, selection_texture, &point, &area, false); return; } @@ -7509,18 +7292,12 @@ draw_one_page (EvView *view, if (region) { double scale_x, scale_y; GdkRGBA color; - double device_scale_x = 1, device_scale_y = 1; - - scale_x = (gdouble)width / cairo_image_surface_get_width (page_surface); - scale_y = (gdouble)height / cairo_image_surface_get_height (page_surface); - cairo_surface_get_device_scale (page_surface, &device_scale_x, &device_scale_y); - - scale_x *= device_scale_x; - scale_y *= device_scale_y; + scale_x = (gdouble)width / gdk_texture_get_width (page_texture); + scale_y = (gdouble)height / gdk_texture_get_height (page_texture); _ev_view_get_selection_colors (view, &color, NULL); - draw_selection_region (cr, region, &color, real_page_area.x, real_page_area.y, + draw_selection_region (snapshot, widget, region, &color, real_page_area.x, real_page_area.y, scale_x, scale_y); } } @@ -7541,8 +7318,6 @@ ev_view_finalize (GObject *object) g_clear_object (&view->image_dnd_info.image); g_clear_pointer (&view->annot_window_map, g_hash_table_destroy); - g_object_unref (view->zoom_gesture); - G_OBJECT_CLASS (ev_view_parent_class)->finalize (object); } @@ -7612,8 +7387,6 @@ ev_view_dispose (GObject *object) gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (view), NULL); gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (view), NULL); - g_clear_object(&view->accessible); - G_OBJECT_CLASS (ev_view_parent_class)->dispose (object); } @@ -7687,61 +7460,6 @@ ev_view_set_property (GObject *object, } } -/* Accessibility */ -static AtkObject * -ev_view_get_accessible (GtkWidget *widget) -{ - EvView *view = EV_VIEW (widget); - - if (!view->accessible) - view->accessible = ev_view_accessible_new (widget); - return view->accessible; -} - -/* GtkContainer */ -static void -ev_view_remove (GtkContainer *container, - GtkWidget *widget) -{ - EvView *view = EV_VIEW (container); - GList *tmp_list = view->children; - EvViewChild *child; - - while (tmp_list) { - child = tmp_list->data; - - if (child->widget == widget) { - gtk_widget_unparent (widget); - - view->children = g_list_remove_link (view->children, tmp_list); - g_list_free_1 (tmp_list); - g_slice_free (EvViewChild, child); - - return; - } - - tmp_list = tmp_list->next; - } -} - -static void -ev_view_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data) -{ - EvView *view = EV_VIEW (container); - GList *tmp_list = view->children; - EvViewChild *child; - - while (tmp_list) { - child = tmp_list->data; - tmp_list = tmp_list->next; - - (* callback) (child->widget, callback_data); - } -} - static void view_update_scale_limits (EvView *view) { @@ -7767,24 +7485,6 @@ view_update_scale_limits (EvView *view) ev_document_model_set_max_scale (view->model, max_scale * dpi); } -static void -ev_view_screen_changed (GtkWidget *widget, - GdkScreen *old_screen) -{ - EvView *view = EV_VIEW (widget); - GdkScreen *screen; - - screen = gtk_widget_get_screen (widget); - if (screen == old_screen) - return; - - view_update_scale_limits (view); - - if (GTK_WIDGET_CLASS (ev_view_parent_class)->screen_changed) { - GTK_WIDGET_CLASS (ev_view_parent_class)->screen_changed (widget, old_screen); - } -} - static void pan_gesture_pan_cb (GtkGesturePan *gesture, GtkPanDirection direction, @@ -7834,30 +7534,7 @@ pan_gesture_end_cb (GtkGesture *gesture, } static void -ev_view_hierarchy_changed (GtkWidget *widget, - GtkWidget *previous_toplevel) -{ - GtkWidget *parent = gtk_widget_get_parent (widget); - EvView *view = EV_VIEW (widget); - - if (parent && !view->pan_gesture) { - view->pan_gesture = - gtk_gesture_pan_new (parent, GTK_ORIENTATION_HORIZONTAL); - g_signal_connect (view->pan_gesture, "pan", - G_CALLBACK (pan_gesture_pan_cb), widget); - g_signal_connect (view->pan_gesture, "end", - G_CALLBACK (pan_gesture_end_cb), widget); - - gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (view->pan_gesture), TRUE); - gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (view->pan_gesture), - GTK_PHASE_CAPTURE); - } else if (!parent && view->pan_gesture) { - g_clear_object (&view->pan_gesture); - } -} - -static void -add_move_binding_keypad (GtkBindingSet *binding_set, +add_move_binding_keypad (GtkWidgetClass *widget_class, guint keyval, GdkModifierType modifiers, GtkMovementStep step, @@ -7865,28 +7542,21 @@ add_move_binding_keypad (GtkBindingSet *binding_set, { guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left; - gtk_binding_entry_add_signal (binding_set, keyval, modifiers, - "move-cursor", 3, - GTK_TYPE_MOVEMENT_STEP, step, - G_TYPE_INT, count, - G_TYPE_BOOLEAN, FALSE); - gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers, - "move-cursor", 3, - GTK_TYPE_MOVEMENT_STEP, step, - G_TYPE_INT, count, - G_TYPE_BOOLEAN, FALSE); + gtk_widget_class_add_binding_signal (widget_class, keyval, modifiers, + "move-cursor", "(iib)", + step, count, FALSE); + + gtk_widget_class_add_binding_signal (widget_class, keypad_keyval, modifiers, + "move-cursor", "(iib)", + step, count, FALSE); /* Selection-extending version */ - gtk_binding_entry_add_signal (binding_set, keyval, modifiers | GDK_SHIFT_MASK, - "move-cursor", 3, - GTK_TYPE_MOVEMENT_STEP, step, - G_TYPE_INT, count, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers | GDK_SHIFT_MASK, - "move-cursor", 3, - GTK_TYPE_MOVEMENT_STEP, step, - G_TYPE_INT, count, - G_TYPE_BOOLEAN, TRUE); + gtk_widget_class_add_binding_signal (widget_class, keyval, modifiers | GDK_SHIFT_MASK, + "move-cursor", "(iib)", + step, count, TRUE); + gtk_widget_class_add_binding_signal (widget_class, keypad_keyval, modifiers | GDK_SHIFT_MASK, + "move-cursor", "(iib)", + step, count, TRUE); } static gint @@ -8048,13 +7718,40 @@ ev_view_focus (GtkWidget *widget, } static void -ev_view_parent_set (GtkWidget *widget, - GtkWidget *previous_parent) +notify_scale_factor_cb (EvView *view, + GParamSpec *pspec) +{ + if (view->document) + view_update_range_and_current_page (view); +} + +static void +zoom_gesture_begin_cb (GtkGesture *gesture, + GdkEventSequence *sequence, + EvView *view) +{ + view->prev_zoom_gesture_scale = 1; +} + +static void +zoom_gesture_scale_changed_cb (GtkGestureZoom *gesture, + gdouble scale, + EvView *view) { - GtkWidget *parent; + gdouble factor; + + view->drag_info.in_drag = FALSE; + view->image_dnd_info.in_drag = FALSE; + + factor = scale - view->prev_zoom_gesture_scale + 1; + view->prev_zoom_gesture_scale = scale; + ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE); + + gtk_gesture_get_bounding_box_center (GTK_GESTURE (gesture), &view->zoom_center_x, &view->zoom_center_y); - parent = gtk_widget_get_parent (widget); - g_assert (!parent || GTK_IS_SCROLLED_WINDOW (parent)); + if ((factor < 1.0 && ev_view_can_zoom_out (view)) || + (factor >= 1.0 && ev_view_can_zoom_in (view))) + ev_view_zoom (view, factor); } static void @@ -8062,48 +7759,48 @@ ev_view_class_init (EvViewClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); - GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class); - GtkBindingSet *binding_set; object_class->get_property = ev_view_get_property; object_class->set_property = ev_view_set_property; object_class->dispose = ev_view_dispose; object_class->finalize = ev_view_finalize; - widget_class->realize = ev_view_realize; - widget_class->draw = ev_view_draw; - widget_class->button_press_event = ev_view_button_press_event; - widget_class->motion_notify_event = ev_view_motion_notify_event; - widget_class->button_release_event = ev_view_button_release_event; - widget_class->key_press_event = ev_view_key_press_event; - widget_class->focus_in_event = ev_view_focus_in; - widget_class->focus_out_event = ev_view_focus_out; - widget_class->get_accessible = ev_view_get_accessible; - widget_class->get_preferred_width = ev_view_get_preferred_width; - widget_class->get_preferred_height = ev_view_get_preferred_height; + widget_class->snapshot = ev_view_snapshot; + widget_class->measure = ev_view_measure; widget_class->size_allocate = ev_view_size_allocate; - widget_class->scroll_event = ev_view_scroll_event; - widget_class->enter_notify_event = ev_view_enter_notify_event; - widget_class->leave_notify_event = ev_view_leave_notify_event; - widget_class->style_updated = ev_view_style_updated; - widget_class->drag_data_get = ev_view_drag_data_get; - widget_class->drag_motion = ev_view_drag_motion; - widget_class->popup_menu = ev_view_popup_menu; widget_class->query_tooltip = ev_view_query_tooltip; - widget_class->screen_changed = ev_view_screen_changed; widget_class->focus = ev_view_focus; - widget_class->parent_set = ev_view_parent_set; - widget_class->hierarchy_changed = ev_view_hierarchy_changed; gtk_widget_class_set_css_name (widget_class, "evview"); - container_class->remove = ev_view_remove; - container_class->forall = ev_view_forall; - class->scroll = ev_view_scroll; class->move_cursor = ev_view_move_cursor; class->activate = ev_view_activate; + gtk_widget_class_set_template_from_resource (widget_class, + "/org/gnome/evince/ui/view.ui"); + + gtk_widget_class_bind_template_child (widget_class, EvView, zoom_gesture); + gtk_widget_class_bind_template_child (widget_class, EvView, pan_gesture); + + gtk_widget_class_bind_template_callback (widget_class, ev_view_button_press_event); + gtk_widget_class_bind_template_callback (widget_class, ev_view_button_release_event); + gtk_widget_class_bind_template_callback (widget_class, ev_view_motion_notify_event); + gtk_widget_class_bind_template_callback (widget_class, ev_view_enter_notify_event); + gtk_widget_class_bind_template_callback (widget_class, ev_view_leave_notify_event); + gtk_widget_class_bind_template_callback (widget_class, zoom_gesture_begin_cb); + gtk_widget_class_bind_template_callback (widget_class, zoom_gesture_scale_changed_cb); + gtk_widget_class_bind_template_callback (widget_class, notify_scale_factor_cb); + gtk_widget_class_bind_template_callback (widget_class, ev_view_focus_in); + gtk_widget_class_bind_template_callback (widget_class, ev_view_focus_out); + gtk_widget_class_bind_template_callback (widget_class, middle_clicked_drag_begin_cb); + gtk_widget_class_bind_template_callback (widget_class, middle_clicked_drag_end_cb); + gtk_widget_class_bind_template_callback (widget_class, middle_clicked_drag_update_cb); + gtk_widget_class_bind_template_callback (widget_class, ev_view_scroll_event); + gtk_widget_class_bind_template_callback (widget_class, drag_prepare_cb); + gtk_widget_class_bind_template_callback (widget_class, pan_gesture_pan_cb); + gtk_widget_class_bind_template_callback (widget_class, pan_gesture_end_cb); + /** * EvView:is-loading: * @@ -8157,8 +7854,8 @@ ev_view_class_init (EvViewClass *class) G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EvViewClass, scroll), NULL, NULL, - ev_view_marshal_VOID__ENUM_ENUM, - G_TYPE_NONE, 2, + ev_view_marshal_BOOLEAN__ENUM_ENUM, + G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, GTK_TYPE_ORIENTATION); signals[SIGNAL_HANDLE_LINK] = g_signal_new ("handle-link", @@ -8182,9 +7879,11 @@ ev_view_class_init (EvViewClass *class) G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EvViewClass, popup_menu), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); + ev_view_marshal_VOID__POINTER_DOUBLE_DOUBLE, + G_TYPE_NONE, 3, + G_TYPE_POINTER, + G_TYPE_DOUBLE, + G_TYPE_DOUBLE); signals[SIGNAL_SELECTION_CHANGED] = g_signal_new ("selection-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, @@ -8268,149 +7967,78 @@ ev_view_class_init (EvViewClass *class) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); - widget_class->activate_signal = signals[SIGNAL_ACTIVATE]; - - binding_set = gtk_binding_set_by_class (class); - - add_move_binding_keypad (binding_set, GDK_KEY_Left, 0, GTK_MOVEMENT_VISUAL_POSITIONS, -1); - add_move_binding_keypad (binding_set, GDK_KEY_Right, 0, GTK_MOVEMENT_VISUAL_POSITIONS, 1); - add_move_binding_keypad (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, -1); - add_move_binding_keypad (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, 1); - add_move_binding_keypad (binding_set, GDK_KEY_Up, 0, GTK_MOVEMENT_DISPLAY_LINES, -1); - add_move_binding_keypad (binding_set, GDK_KEY_Down, 0, GTK_MOVEMENT_DISPLAY_LINES, 1); - add_move_binding_keypad (binding_set, GDK_KEY_Home, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); - add_move_binding_keypad (binding_set, GDK_KEY_End, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); - add_move_binding_keypad (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, -1); - add_move_binding_keypad (binding_set, GDK_KEY_End, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, 1); - - add_scroll_binding_keypad (binding_set, GDK_KEY_Left, 0, GTK_SCROLL_STEP_BACKWARD, GTK_ORIENTATION_HORIZONTAL); - add_scroll_binding_keypad (binding_set, GDK_KEY_Right, 0, GTK_SCROLL_STEP_FORWARD, GTK_ORIENTATION_HORIZONTAL); - add_scroll_binding_keypad (binding_set, GDK_KEY_Left, GDK_MOD1_MASK, GTK_SCROLL_STEP_DOWN, GTK_ORIENTATION_HORIZONTAL); - add_scroll_binding_keypad (binding_set, GDK_KEY_Right, GDK_MOD1_MASK, GTK_SCROLL_STEP_UP, GTK_ORIENTATION_HORIZONTAL); - add_scroll_binding_keypad (binding_set, GDK_KEY_Up, 0, GTK_SCROLL_STEP_BACKWARD, GTK_ORIENTATION_VERTICAL); - add_scroll_binding_keypad (binding_set, GDK_KEY_Down, 0, GTK_SCROLL_STEP_FORWARD, GTK_ORIENTATION_VERTICAL); - add_scroll_binding_keypad (binding_set, GDK_KEY_Up, GDK_MOD1_MASK, GTK_SCROLL_STEP_DOWN, GTK_ORIENTATION_VERTICAL); - add_scroll_binding_keypad (binding_set, GDK_KEY_Down, GDK_MOD1_MASK, GTK_SCROLL_STEP_UP, GTK_ORIENTATION_VERTICAL); - add_scroll_binding_keypad (binding_set, GDK_KEY_Page_Up, 0, GTK_SCROLL_PAGE_BACKWARD, GTK_ORIENTATION_VERTICAL); - add_scroll_binding_keypad (binding_set, GDK_KEY_Page_Down, 0, GTK_SCROLL_PAGE_FORWARD, GTK_ORIENTATION_VERTICAL); - add_scroll_binding_keypad (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK, GTK_SCROLL_START, GTK_ORIENTATION_VERTICAL); - add_scroll_binding_keypad (binding_set, GDK_KEY_End, GDK_CONTROL_MASK, GTK_SCROLL_END, GTK_ORIENTATION_VERTICAL); + + + gtk_widget_class_set_activate_signal (widget_class, signals[SIGNAL_ACTIVATE]); + + add_move_binding_keypad (widget_class, GDK_KEY_Left, 0, GTK_MOVEMENT_VISUAL_POSITIONS, -1); + add_move_binding_keypad (widget_class, GDK_KEY_Right, 0, GTK_MOVEMENT_VISUAL_POSITIONS, 1); + add_move_binding_keypad (widget_class, GDK_KEY_Left, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, -1); + add_move_binding_keypad (widget_class, GDK_KEY_Right, GDK_CONTROL_MASK, GTK_MOVEMENT_WORDS, 1); + add_move_binding_keypad (widget_class, GDK_KEY_Up, 0, GTK_MOVEMENT_DISPLAY_LINES, -1); + add_move_binding_keypad (widget_class, GDK_KEY_Down, 0, GTK_MOVEMENT_DISPLAY_LINES, 1); + add_move_binding_keypad (widget_class, GDK_KEY_Home, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); + add_move_binding_keypad (widget_class, GDK_KEY_End, 0, GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); + add_move_binding_keypad (widget_class, GDK_KEY_Home, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, -1); + add_move_binding_keypad (widget_class, GDK_KEY_End, GDK_CONTROL_MASK, GTK_MOVEMENT_BUFFER_ENDS, 1); + + add_scroll_binding_keypad (widget_class, GDK_KEY_Left, 0, GTK_SCROLL_STEP_BACKWARD, GTK_ORIENTATION_HORIZONTAL); + add_scroll_binding_keypad (widget_class, GDK_KEY_Right, 0, GTK_SCROLL_STEP_FORWARD, GTK_ORIENTATION_HORIZONTAL); + add_scroll_binding_keypad (widget_class, GDK_KEY_Left, GDK_ALT_MASK, GTK_SCROLL_STEP_DOWN, GTK_ORIENTATION_HORIZONTAL); + add_scroll_binding_keypad (widget_class, GDK_KEY_Right, GDK_ALT_MASK, GTK_SCROLL_STEP_UP, GTK_ORIENTATION_HORIZONTAL); + add_scroll_binding_keypad (widget_class, GDK_KEY_Up, 0, GTK_SCROLL_STEP_BACKWARD, GTK_ORIENTATION_VERTICAL); + add_scroll_binding_keypad (widget_class, GDK_KEY_Down, 0, GTK_SCROLL_STEP_FORWARD, GTK_ORIENTATION_VERTICAL); + add_scroll_binding_keypad (widget_class, GDK_KEY_Up, GDK_ALT_MASK, GTK_SCROLL_STEP_DOWN, GTK_ORIENTATION_VERTICAL); + add_scroll_binding_keypad (widget_class, GDK_KEY_Down, GDK_ALT_MASK, GTK_SCROLL_STEP_UP, GTK_ORIENTATION_VERTICAL); + add_scroll_binding_keypad (widget_class, GDK_KEY_Page_Up, 0, GTK_SCROLL_PAGE_BACKWARD, GTK_ORIENTATION_VERTICAL); + add_scroll_binding_keypad (widget_class, GDK_KEY_Page_Down, 0, GTK_SCROLL_PAGE_FORWARD, GTK_ORIENTATION_VERTICAL); + add_scroll_binding_keypad (widget_class, GDK_KEY_Home, GDK_CONTROL_MASK, GTK_SCROLL_START, GTK_ORIENTATION_VERTICAL); + add_scroll_binding_keypad (widget_class, GDK_KEY_End, GDK_CONTROL_MASK, GTK_SCROLL_END, GTK_ORIENTATION_VERTICAL); /* We can't use the bindings defined in GtkWindow for Space and Return, * because we also have those bindings for scrolling. */ - gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, - "activate", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, - "activate", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, - "activate", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, - "activate", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, - "activate", 0); - - gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "scroll", 2, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD, - GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, GDK_SHIFT_MASK, "scroll", 2, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD, - GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_H, 0, "scroll", 2, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD, - GTK_TYPE_ORIENTATION, GTK_ORIENTATION_HORIZONTAL); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_J, 0, "scroll", 2, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD, - GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_K, 0, "scroll", 2, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD, - GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_L, 0, "scroll", 2, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD, - GTK_TYPE_ORIENTATION, GTK_ORIENTATION_HORIZONTAL); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "scroll", 2, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD, - GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "scroll", 2, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD, - GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "scroll", 2, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD, - GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_SHIFT_MASK, "scroll", 2, - GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD, - GTK_TYPE_ORIENTATION, GTK_ORIENTATION_VERTICAL); -} - -static void -on_notify_scale_factor (EvView *view, - GParamSpec *pspec) -{ - if (view->document) - view_update_range_and_current_page (view); -} - -static void -zoom_gesture_begin_cb (GtkGesture *gesture, - GdkEventSequence *sequence, - EvView *view) -{ - view->prev_zoom_gesture_scale = 1; -} - -static void -zoom_gesture_scale_changed_cb (GtkGestureZoom *gesture, - gdouble scale, - EvView *view) -{ - gdouble factor; - - view->drag_info.in_drag = FALSE; - view->image_dnd_info.in_drag = FALSE; - - factor = scale - view->prev_zoom_gesture_scale + 1; - view->prev_zoom_gesture_scale = scale; - ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE); - - gtk_gesture_get_bounding_box_center (GTK_GESTURE (gesture), &view->zoom_center_x, &view->zoom_center_y); - - if ((factor < 1.0 && ev_view_can_zoom_out (view)) || - (factor >= 1.0 && ev_view_can_zoom_in (view))) - ev_view_zoom (view, factor); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_space, 0, + "activate", NULL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Space, 0, + "activate", NULL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Return, 0, + "activate", NULL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_ISO_Enter, 0, + "activate", NULL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Enter, 0, + "activate", NULL); + + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Return, 0, "scroll", + "(ii)", GTK_SCROLL_PAGE_FORWARD, GTK_ORIENTATION_VERTICAL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Return, GDK_SHIFT_MASK, "scroll", + "(ii)", GTK_SCROLL_PAGE_BACKWARD, GTK_ORIENTATION_VERTICAL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_H, 0, "scroll", + "(ii)", GTK_SCROLL_STEP_BACKWARD, GTK_ORIENTATION_HORIZONTAL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_J, 0, "scroll", + "(ii)", GTK_SCROLL_STEP_FORWARD, GTK_ORIENTATION_VERTICAL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_K, 0, "scroll", + "(ii)", GTK_SCROLL_STEP_BACKWARD, GTK_ORIENTATION_VERTICAL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_L, 0, "scroll", + "(ii)", GTK_SCROLL_STEP_FORWARD, GTK_ORIENTATION_HORIZONTAL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_space, 0, "scroll", + "(ii)", GTK_SCROLL_PAGE_FORWARD, GTK_ORIENTATION_VERTICAL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_space, GDK_SHIFT_MASK, "scroll", + "(ii)", GTK_SCROLL_PAGE_BACKWARD, GTK_ORIENTATION_VERTICAL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_BackSpace, 0, "scroll", + "(ii)", GTK_SCROLL_PAGE_BACKWARD, GTK_ORIENTATION_VERTICAL); + gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_BackSpace, GDK_SHIFT_MASK, "scroll", + "(ii)", GTK_SCROLL_PAGE_FORWARD, GTK_ORIENTATION_VERTICAL); } static void ev_view_init (EvView *view) { - GtkStyleContext *context; - - gtk_widget_set_has_window (GTK_WIDGET (view), TRUE); - gtk_widget_set_can_focus (GTK_WIDGET (view), TRUE); - gtk_widget_set_redraw_on_allocate (GTK_WIDGET (view), FALSE); - gtk_widget_set_has_tooltip (GTK_WIDGET (view), TRUE); - - context = gtk_widget_get_style_context (GTK_WIDGET (view)); - gtk_style_context_add_class (context, "content-view"); - gtk_style_context_add_class (context, "view"); - - gtk_widget_set_events (GTK_WIDGET (view), - GDK_TOUCH_MASK | - GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_SCROLL_MASK | - GDK_SMOOTH_SCROLL_MASK | - GDK_KEY_PRESS_MASK | - GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); - view->start_page = -1; view->end_page = -1; view->spacing = 14; view->scale = 1.0; - view->current_page = 0; + view->current_page = -1; view->pressed_button = -1; view->cursor = EV_VIEW_CURSOR_NORMAL; view->drag_info.in_drag = FALSE; @@ -8421,7 +8049,9 @@ ev_view_init (EvView *view) view->dual_even_left = TRUE; view->sizing_mode = EV_SIZING_FIT_WIDTH; view->page_layout = EV_PAGE_LAYOUT_SINGLE; - view->pending_scroll = SCROLL_TO_KEEP_POSITION; + view->pending_scroll = SCROLL_TO_PAGE_POSITION; + view->pending_point.x = 0; + view->pending_point.y = 0; view->find_page = -1; view->jump_to_find_result = TRUE; view->highlight_find_results = FALSE; @@ -8433,17 +8063,7 @@ ev_view_init (EvView *view) view->zoom_center_x = -1; view->zoom_center_y = -1; - g_signal_connect (view, "notify::scale-factor", - G_CALLBACK (on_notify_scale_factor), NULL); - - view->zoom_gesture = gtk_gesture_zoom_new (GTK_WIDGET (view)); - gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (view->zoom_gesture), - GTK_PHASE_CAPTURE); - - g_signal_connect (view->zoom_gesture, "begin", - G_CALLBACK (zoom_gesture_begin_cb), view); - g_signal_connect (view->zoom_gesture, "scale-changed", - G_CALLBACK (zoom_gesture_scale_changed_cb), view); + gtk_widget_init_template (GTK_WIDGET (view)); } /*** Callbacks ***/ @@ -8460,7 +8080,7 @@ ev_view_change_page (EvView *view, ev_view_set_loading (view, FALSE); ev_document_misc_get_pointer_position (GTK_WIDGET (view), &x, &y); - ev_view_handle_cursor_over_xy (view, x, y); + ev_view_handle_cursor_over_xy (view, x, y, FALSE); gtk_widget_queue_resize (GTK_WIDGET (view)); } @@ -8470,11 +8090,7 @@ job_finished_cb (EvPixbufCache *pixbuf_cache, cairo_region_t *region, EvView *view) { - if (region) { - gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)), region, TRUE); - } else { - gtk_widget_queue_draw (GTK_WIDGET (view)); - } + gtk_widget_queue_draw (GTK_WIDGET (view)); } static void @@ -8493,6 +8109,7 @@ ev_view_page_changed_cb (EvDocumentModel *model, } } +#if 0 static gboolean cursor_scroll_update (gpointer data) { @@ -8501,7 +8118,7 @@ cursor_scroll_update (gpointer data) view->update_cursor_idle_id = 0; ev_document_misc_get_pointer_position (GTK_WIDGET (view), &x, &y); - ev_view_handle_cursor_over_xy (view, x, y); + ev_view_handle_cursor_over_xy (view, x, y, FALSE); return FALSE; } @@ -8515,18 +8132,15 @@ schedule_scroll_cursor_update (EvView *view) view->update_cursor_idle_id = g_idle_add (cursor_scroll_update, view); } +#endif static void -on_adjustment_value_changed (GtkAdjustment *adjustment, +adjustment_value_changed_cb (GtkAdjustment *adjustment, EvView *view) { GtkWidget *widget = GTK_WIDGET (view); int dx = 0, dy = 0; - gdouble x, y; gint value; - GList *l; - GdkEvent *event; - gboolean cursor_updated; if (!gtk_widget_get_realized (widget)) return; @@ -8554,21 +8168,25 @@ on_adjustment_value_changed (GtkAdjustment *adjustment, view->scroll_y = 0; } - for (l = view->children; l && l->data; l = g_list_next (l)) { - EvViewChild *child = (EvViewChild *)l->data; + for (GtkWidget *child = gtk_widget_get_first_child (widget); + child != NULL; + child = gtk_widget_get_next_sibling (child)) { + EvViewChild *data = g_object_get_data (G_OBJECT (child), "ev-child"); - child->x += dx; - child->y += dy; - if (gtk_widget_get_visible (child->widget) && gtk_widget_get_visible (widget)) + if (!data) + continue; + + data->x += dx; + data->y += dy; + if (gtk_widget_get_visible (child) && gtk_widget_get_visible (widget)) gtk_widget_queue_resize (widget); } if (view->pending_resize) { gtk_widget_queue_draw (widget); - } else { - gdk_window_scroll (gtk_widget_get_window (widget), dx, dy); } +#if 0 cursor_updated = FALSE; event = gtk_get_current_event (); if (event) { @@ -8583,6 +8201,7 @@ on_adjustment_value_changed (GtkAdjustment *adjustment, if (!cursor_updated) schedule_scroll_cursor_update (view); +#endif if (view->document) view_update_range_and_current_page (view); @@ -8601,8 +8220,6 @@ ev_view_new (void) static void setup_caches (EvView *view) { - gboolean inverted_colors; - view->height_to_page_cache = ev_view_get_height_to_page_cache (view); view->pixbuf_cache = ev_pixbuf_cache_new (GTK_WIDGET (view), view->model, view->pixbuf_cache_size); view->page_cache = ev_page_cache_new (view->document); @@ -8614,8 +8231,6 @@ setup_caches (EvView *view) EV_PAGE_DATA_INCLUDE_TEXT_ATTRS | EV_PAGE_DATA_INCLUDE_TEXT_LOG_ATTRS); - inverted_colors = ev_document_model_get_inverted_colors (view->model); - ev_pixbuf_cache_set_inverted_colors (view->pixbuf_cache, inverted_colors); g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view); } @@ -8681,7 +8296,7 @@ ev_view_autoscroll_start (EvView *view) ev_view_autoscroll_resume (view); ev_document_misc_get_pointer_position (GTK_WIDGET (view), &x, &y); - ev_view_handle_cursor_over_xy (view, x, y); + ev_view_handle_cursor_over_xy (view, x, y, FALSE); } void @@ -8698,7 +8313,7 @@ ev_view_autoscroll_stop (EvView *view) ev_view_autoscroll_pause (view); ev_document_misc_get_pointer_position (GTK_WIDGET (view), &x, &y); - ev_view_handle_cursor_over_xy (view, x, y); + ev_view_handle_cursor_over_xy (view, x, y, FALSE); } static void @@ -8741,6 +8356,7 @@ ev_view_document_changed_cb (EvDocumentModel *model, view->pending_scroll = SCROLL_TO_KEEP_POSITION; gtk_widget_queue_resize (GTK_WIDGET (view)); } + view_update_scale_limits (view); } } @@ -8773,13 +8389,7 @@ ev_view_inverted_colors_changed_cb (EvDocumentModel *model, GParamSpec *pspec, EvView *view) { - if (view->pixbuf_cache) { - gboolean inverted_colors; - - inverted_colors = ev_document_model_get_inverted_colors (model); - ev_pixbuf_cache_set_inverted_colors (view->pixbuf_cache, inverted_colors); - gtk_widget_queue_draw (GTK_WIDGET (view)); - } + gtk_widget_queue_draw (GTK_WIDGET (view)); } static void @@ -8982,10 +8592,11 @@ ev_view_set_model (EvView *view, g_signal_connect (view->model, "page-changed", G_CALLBACK (ev_view_page_changed_cb), view); - +#if 0 if (view->accessible) ev_view_accessible_set_model (EV_VIEW_ACCESSIBLE (view->accessible), view->model); +#endif } static void @@ -9126,7 +8737,6 @@ ev_view_zoom_for_size_continuous_and_dual_page (EvView *view, gdouble doc_width, doc_height; GtkBorder border; gdouble scale; - gint sb_size; ev_document_get_max_page_size (view->document, &doc_width, &doc_height); if (view->rotation == 90 || view->rotation == 270) { @@ -9143,18 +8753,16 @@ ev_view_zoom_for_size_continuous_and_dual_page (EvView *view, width -= (2 * (border.left + border.right) + 3 * view->spacing); height -= (border.top + border.bottom + 2 * view->spacing); - sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL); - switch (view->sizing_mode) { case EV_SIZING_FIT_WIDTH: - scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height); + scale = zoom_for_size_fit_width (doc_width, doc_height, width, height); break; case EV_SIZING_FIT_PAGE: - scale = zoom_for_size_fit_page (doc_width, doc_height, width - sb_size, height); + scale = zoom_for_size_fit_page (doc_width, doc_height, width, height); break; case EV_SIZING_AUTOMATIC: scale = zoom_for_size_automatic (GTK_WIDGET (view), - doc_width, doc_height, width - sb_size, height); + doc_width, doc_height, width, height); break; default: g_assert_not_reached (); @@ -9171,7 +8779,6 @@ ev_view_zoom_for_size_continuous (EvView *view, gdouble doc_width, doc_height; GtkBorder border; gdouble scale; - gint sb_size; ev_document_get_max_page_size (view->document, &doc_width, &doc_height); if (view->rotation == 90 || view->rotation == 270) { @@ -9187,18 +8794,16 @@ ev_view_zoom_for_size_continuous (EvView *view, width -= (border.left + border.right + 2 * view->spacing); height -= (border.top + border.bottom + 2 * view->spacing); - sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL); - switch (view->sizing_mode) { case EV_SIZING_FIT_WIDTH: - scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height); + scale = zoom_for_size_fit_width (doc_width, doc_height, width, height); break; case EV_SIZING_FIT_PAGE: - scale = zoom_for_size_fit_page (doc_width, doc_height, width - sb_size, height); + scale = zoom_for_size_fit_page (doc_width, doc_height, width, height); break; case EV_SIZING_AUTOMATIC: scale = zoom_for_size_automatic (GTK_WIDGET (view), - doc_width, doc_height, width - sb_size, height); + doc_width, doc_height, width, height); break; default: g_assert_not_reached (); @@ -9216,7 +8821,6 @@ ev_view_zoom_for_size_dual_page (EvView *view, gdouble doc_width, doc_height; gdouble scale; gint other_page; - gint sb_size; other_page = view->current_page ^ 1; @@ -9239,16 +8843,14 @@ ev_view_zoom_for_size_dual_page (EvView *view, switch (view->sizing_mode) { case EV_SIZING_FIT_WIDTH: - sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL); - scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height); + scale = zoom_for_size_fit_width (doc_width, doc_height, width, height); break; case EV_SIZING_FIT_PAGE: scale = zoom_for_size_fit_page (doc_width, doc_height, width, height); break; case EV_SIZING_AUTOMATIC: - sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL); scale = zoom_for_size_automatic (GTK_WIDGET (view), - doc_width, doc_height, width - sb_size, height); + doc_width, doc_height, width, height); break; default: g_assert_not_reached (); @@ -9265,7 +8867,6 @@ ev_view_zoom_for_size_single_page (EvView *view, gdouble doc_width, doc_height; GtkBorder border; gdouble scale; - gint sb_size; get_doc_page_size (view, view->current_page, &doc_width, &doc_height); @@ -9277,16 +8878,14 @@ ev_view_zoom_for_size_single_page (EvView *view, switch (view->sizing_mode) { case EV_SIZING_FIT_WIDTH: - sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL); - scale = zoom_for_size_fit_width (doc_width, doc_height, width - sb_size, height); + scale = zoom_for_size_fit_width (doc_width, doc_height, width, height); break; case EV_SIZING_FIT_PAGE: scale = zoom_for_size_fit_page (doc_width, doc_height, width, height); break; case EV_SIZING_AUTOMATIC: - sb_size = ev_view_get_scrollbar_size (view, GTK_ORIENTATION_VERTICAL); scale = zoom_for_size_automatic (GTK_WIDGET (view), - doc_width, doc_height, width - sb_size, height); + doc_width, doc_height, width, height); break; default: g_assert_not_reached (); @@ -9795,7 +9394,6 @@ merge_selection_region (EvView *view, { GList *old_list; GList *new_list_ptr, *old_list_ptr; - GtkBorder border; /* Update the selection */ old_list = ev_pixbuf_cache_get_selection_list (view->pixbuf_cache); @@ -9807,11 +9405,10 @@ merge_selection_region (EvView *view, new_list_ptr = new_list; old_list_ptr = old_list; - compute_border (view, &border); while (new_list_ptr || old_list_ptr) { EvViewSelection *old_sel, *new_sel; int cur_page; - cairo_region_t *region = NULL; + gboolean need_redraw = FALSE; new_sel = (new_list_ptr) ? (new_list_ptr->data) : NULL; old_sel = (old_list_ptr) ? (old_list_ptr->data) : NULL; @@ -9856,61 +9453,19 @@ merge_selection_region (EvView *view, } /* Now we figure out what needs redrawing */ - if (old_sel && new_sel) { - if (old_sel->covered_region && new_sel->covered_region) { - if (!cairo_region_equal (old_sel->covered_region, new_sel->covered_region)) { - /* Anything that was previously or currently selected may - * have changed */ - region = cairo_region_copy (old_sel->covered_region); - cairo_region_union (region, new_sel->covered_region); - } - } else if (old_sel->covered_region) { - region = cairo_region_reference (old_sel->covered_region); - } else if (new_sel->covered_region) { - region = cairo_region_reference (new_sel->covered_region); - } - } else if (old_sel && !new_sel) { - if (old_sel->covered_region && !cairo_region_is_empty (old_sel->covered_region)) { - region = cairo_region_reference (old_sel->covered_region); - } - } else if (!old_sel && new_sel) { - if (new_sel->covered_region && !cairo_region_is_empty (new_sel->covered_region)) { - region = cairo_region_reference (new_sel->covered_region); - } - } else { - g_assert_not_reached (); - } - - /* Redraw the damaged region! */ - if (region) { - GdkRectangle page_area; - cairo_region_t *damage_region; - gint i, n_rects; - - ev_view_get_page_extents_for_border (view, cur_page, &border, &page_area); - - damage_region = cairo_region_create (); - /* Translate the region and grow it 2 pixels because for some zoom levels - * the area actually drawn by cairo is larger than the selected region, due - * to rounding errors or pixel alignment. - */ - n_rects = cairo_region_num_rectangles (region); - for (i = 0; i < n_rects; i++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (region, i, &rect); - rect.x += page_area.x + border.left - view->scroll_x - 2; - rect.y += page_area.y + border.top - view->scroll_y - 2; - rect.width += 4; - rect.height += 4; - cairo_region_union_rectangle (damage_region, &rect); - } - cairo_region_destroy (region); - - gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)), - damage_region, TRUE); - cairo_region_destroy (damage_region); - } + if (old_sel && new_sel && (old_sel->covered_region || new_sel->covered_region)) + need_redraw = TRUE; + else if (old_sel && !new_sel && + old_sel->covered_region && + !cairo_region_is_empty (old_sel->covered_region)) + need_redraw = TRUE; + else if (!old_sel && new_sel && + new_sel->covered_region && + !cairo_region_is_empty (new_sel->covered_region)) + need_redraw = TRUE; + + if (need_redraw) + gtk_widget_queue_draw (GTK_WIDGET (view)); } ev_view_check_cursor_blink (view); @@ -10033,11 +9588,10 @@ static void ev_view_clipboard_copy (EvView *view, const gchar *text) { - GtkClipboard *clipboard; + GdkClipboard *clipboard; - clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view), - GDK_SELECTION_CLIPBOARD); - gtk_clipboard_set_text (clipboard, text, -1); + clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view)); + gdk_clipboard_set_text (clipboard, text); } void @@ -10053,71 +9607,6 @@ ev_view_copy (EvView *ev_view) g_free (text); } -static void -ev_view_primary_get_cb (GtkClipboard *clipboard, - GtkSelectionData *selection_data, - guint info, - gpointer data) -{ - EvView *ev_view = EV_VIEW (data); - - if (ev_view->link_selected) { - gtk_selection_data_set_text (selection_data, - ev_link_action_get_uri (ev_view->link_selected), - -1); - } else if (EV_IS_SELECTION (ev_view->document) && - ev_view->selection_info.selections) { - gchar *text; - - text = get_selected_text (ev_view); - if (text) { - gtk_selection_data_set_text (selection_data, text, -1); - g_free (text); - } - } -} - -static void -ev_view_primary_clear_cb (GtkClipboard *clipboard, - gpointer data) -{ - EvView *view = EV_VIEW (data); - - clear_selection (view); - g_clear_object (&view->link_selected); -} - -static void -ev_view_update_primary_selection (EvView *ev_view) -{ - GtkClipboard *clipboard; - - clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view), - GDK_SELECTION_PRIMARY); - - if (ev_view->selection_info.selections || ev_view->link_selected) { - GtkTargetList *target_list; - GtkTargetEntry *targets; - int n_targets; - - target_list = gtk_target_list_new (NULL, 0); - gtk_target_list_add_text_targets (target_list, 0); - targets = gtk_target_table_new_from_list (target_list, &n_targets); - gtk_target_list_unref (target_list); - - gtk_clipboard_set_with_owner (clipboard, - targets, n_targets, - ev_view_primary_get_cb, - ev_view_primary_clear_cb, - G_OBJECT (ev_view)); - - gtk_target_table_free (targets, n_targets); - } else { - if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (ev_view)) - gtk_clipboard_clear (clipboard); - } -} - void ev_view_copy_link_address (EvView *view, EvLinkAction *action) @@ -10127,30 +9616,20 @@ ev_view_copy_link_address (EvView *view, ev_view_clipboard_copy (view, ev_link_action_get_uri (action)); view->link_selected = g_object_ref (action); - ev_view_update_primary_selection (view); } /*** Cursor operations ***/ static void ev_view_set_cursor (EvView *view, EvViewCursor new_cursor) { - GdkCursor *cursor = NULL; - GtkWidget *widget; - GdkWindow *window; - if (view->cursor == new_cursor) { return; } view->cursor = new_cursor; - window = gtk_widget_get_window (GTK_WIDGET (view)); - widget = gtk_widget_get_toplevel (GTK_WIDGET (view)); - cursor = ev_view_cursor_new (gtk_widget_get_display (widget), new_cursor); - gdk_window_set_cursor (window, cursor); - gdk_display_flush (gtk_widget_get_display (widget)); - if (cursor) - g_object_unref (cursor); + gtk_widget_set_cursor_from_name (GTK_WIDGET (view), + ev_view_cursor_name (new_cursor)); } void diff --git a/libview/evince-view.ui b/libview/evince-view.ui new file mode 100644 index 000000000..899aec4ef --- /dev/null +++ b/libview/evince-view.ui @@ -0,0 +1,70 @@ + + + + diff --git a/libview/libview.gresource.xml b/libview/libview.gresource.xml index 24e9d8afd..db21da7cf 100644 --- a/libview/libview.gresource.xml +++ b/libview/libview.gresource.xml @@ -29,4 +29,7 @@ shader/fly.glsl shader/glitter.glsl + + evince-view.ui + -- GitLab From 13c4048d6a1bd4cd431e56399fa74b5746f18015 Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Wed, 22 Sep 2021 14:39:59 +0800 Subject: [PATCH 18/50] libview: Remove EvTransitionAnimation and EvTimeline Since we implement it through GLSL shaders now. Signed-off-by: Qiu Wenbo --- libview/ev-timeline.c | 446 -------------------- libview/ev-timeline.h | 87 ---- libview/ev-transition-animation.c | 677 ------------------------------ libview/ev-transition-animation.h | 69 --- libview/meson.build | 2 - 5 files changed, 1281 deletions(-) delete mode 100644 libview/ev-timeline.c delete mode 100644 libview/ev-timeline.h delete mode 100644 libview/ev-transition-animation.c delete mode 100644 libview/ev-transition-animation.h diff --git a/libview/ev-timeline.c b/libview/ev-timeline.c deleted file mode 100644 index b79d663bf..000000000 --- a/libview/ev-timeline.c +++ /dev/null @@ -1,446 +0,0 @@ -/* ev-timeline.c - * this file is part of evince, a gnome document viewer - * - * Copyright (C) 2007 Carlos Garnacho - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include "ev-timeline.h" - -#define MSECS_PER_SEC 1000 -#define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes) -#define DEFAULT_FPS 30 - -typedef struct EvTimelinePrivate EvTimelinePrivate; - -struct EvTimelinePrivate { - guint duration; - guint fps; - guint source_id; - - GTimer *timer; - - guint loop : 1; -}; - -enum { - PROP_0, - PROP_FPS, - PROP_DURATION, - PROP_LOOP -}; - -enum { - STARTED, - PAUSED, - FINISHED, - FRAME, - LAST_SIGNAL -}; - -static guint signals [LAST_SIGNAL] = { 0, }; - - -G_DEFINE_TYPE_WITH_PRIVATE (EvTimeline, ev_timeline, G_TYPE_OBJECT) - - -static void -ev_timeline_init (EvTimeline *timeline) -{ - EvTimelinePrivate *priv; - - priv = ev_timeline_get_instance_private (timeline); - - priv->fps = DEFAULT_FPS; - priv->duration = 0; -} - -static void -ev_timeline_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - EvTimeline *timeline; - - timeline = EV_TIMELINE (object); - - switch (prop_id) { - case PROP_FPS: - ev_timeline_set_fps (timeline, g_value_get_uint (value)); - break; - case PROP_DURATION: - ev_timeline_set_duration (timeline, g_value_get_uint (value)); - break; - case PROP_LOOP: - ev_timeline_set_loop (timeline, g_value_get_boolean (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -ev_timeline_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - EvTimeline *timeline; - EvTimelinePrivate *priv; - - timeline = EV_TIMELINE (object); - priv = ev_timeline_get_instance_private (timeline); - - switch (prop_id) { - case PROP_FPS: - g_value_set_uint (value, priv->fps); - break; - case PROP_DURATION: - g_value_set_uint (value, priv->duration); - break; - case PROP_LOOP: - g_value_set_boolean (value, priv->loop); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -ev_timeline_finalize (GObject *object) -{ - EvTimelinePrivate *priv; - - priv = ev_timeline_get_instance_private (EV_TIMELINE (object)); - - if (priv->source_id) { - g_source_remove (priv->source_id); - priv->source_id = 0; - } - - if (priv->timer) - g_timer_destroy (priv->timer); - - G_OBJECT_CLASS (ev_timeline_parent_class)->finalize (object); -} - -static gboolean -ev_timeline_run_frame (EvTimeline *timeline) -{ - EvTimelinePrivate *priv; - gdouble progress; - guint elapsed_time; - - priv = ev_timeline_get_instance_private (timeline); - - elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); - progress = (gdouble) elapsed_time / priv->duration; - progress = CLAMP (progress, 0., 1.); - - g_signal_emit (timeline, signals [FRAME], 0, progress); - - if (progress >= 1.0) { - if (!priv->loop) { - if (priv->source_id) { - g_source_remove (priv->source_id); - priv->source_id = 0; - } - - g_signal_emit (timeline, signals [FINISHED], 0); - return G_SOURCE_REMOVE; - } else { - ev_timeline_rewind (timeline); - } - } - - return G_SOURCE_CONTINUE; -} - -static void -ev_timeline_real_start (EvTimeline *timeline) -{ - EvTimelinePrivate *priv; - - priv = ev_timeline_get_instance_private (timeline); - - if (!priv->source_id) { - if (priv->timer) - g_timer_continue (priv->timer); - else - priv->timer = g_timer_new (); - - /* sanity check */ - g_assert (priv->fps > 0); - - g_signal_emit (timeline, signals [STARTED], 0); - - priv->source_id = g_timeout_add (FRAME_INTERVAL (priv->fps), - (GSourceFunc) ev_timeline_run_frame, - timeline); - } -} - -static void -ev_timeline_class_init (EvTimelineClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - - object_class->set_property = ev_timeline_set_property; - object_class->get_property = ev_timeline_get_property; - object_class->finalize = ev_timeline_finalize; - - class->start = ev_timeline_real_start; - - g_object_class_install_property (object_class, - PROP_FPS, - g_param_spec_uint ("fps", - "FPS", - "Frames per second for the timeline", - 1, - G_MAXUINT, - DEFAULT_FPS, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (object_class, - PROP_DURATION, - g_param_spec_uint ("duration", - "Animation Duration", - "Animation Duration", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (object_class, - PROP_LOOP, - g_param_spec_boolean ("loop", - "Loop", - "Whether the timeline loops or not", - FALSE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - signals[STARTED] = - g_signal_new ("started", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EvTimelineClass, started), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[PAUSED] = - g_signal_new ("paused", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EvTimelineClass, paused), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[FINISHED] = - g_signal_new ("finished", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EvTimelineClass, finished), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[FRAME] = - g_signal_new ("frame", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EvTimelineClass, frame), - NULL, NULL, - g_cclosure_marshal_VOID__DOUBLE, - G_TYPE_NONE, 1, - G_TYPE_DOUBLE); -} - -EvTimeline * -ev_timeline_new (guint duration) -{ - return g_object_new (EV_TYPE_TIMELINE, - "duration", duration, - NULL); -} - -void -ev_timeline_start (EvTimeline *timeline) -{ - g_return_if_fail (EV_IS_TIMELINE (timeline)); - - EV_TIMELINE_GET_CLASS (timeline)->start (timeline); -} - -void -ev_timeline_pause (EvTimeline *timeline) -{ - EvTimelinePrivate *priv; - - g_return_if_fail (EV_IS_TIMELINE (timeline)); - - priv = ev_timeline_get_instance_private (timeline); - - if (priv->source_id) { - g_source_remove (priv->source_id); - priv->source_id = 0; - g_timer_stop (priv->timer); - g_signal_emit (timeline, signals [PAUSED], 0); - } -} - -void -ev_timeline_rewind (EvTimeline *timeline) -{ - EvTimelinePrivate *priv; - - g_return_if_fail (EV_IS_TIMELINE (timeline)); - - priv = ev_timeline_get_instance_private (timeline); - - /* destroy and re-create timer if neccesary */ - if (priv->timer) { - g_timer_destroy (priv->timer); - - if (ev_timeline_is_running (timeline)) - priv->timer = g_timer_new (); - else - priv->timer = NULL; - } -} - -gboolean -ev_timeline_is_running (EvTimeline *timeline) -{ - EvTimelinePrivate *priv; - - g_return_val_if_fail (EV_IS_TIMELINE (timeline), FALSE); - - priv = ev_timeline_get_instance_private (timeline); - - return (priv->source_id != 0); -} - -guint -ev_timeline_get_fps (EvTimeline *timeline) -{ - EvTimelinePrivate *priv; - - g_return_val_if_fail (EV_IS_TIMELINE (timeline), 1); - - priv = ev_timeline_get_instance_private (timeline); - return priv->fps; -} - -void -ev_timeline_set_fps (EvTimeline *timeline, - guint fps) -{ - EvTimelinePrivate *priv; - - g_return_if_fail (EV_IS_TIMELINE (timeline)); - - priv = ev_timeline_get_instance_private (timeline); - - priv->fps = fps; - - if (ev_timeline_is_running (timeline)) { - g_source_remove (priv->source_id); - priv->source_id = g_timeout_add (FRAME_INTERVAL (priv->fps), - (GSourceFunc) ev_timeline_run_frame, - timeline); - } - - g_object_notify (G_OBJECT (timeline), "fps"); -} - -gboolean -ev_timeline_get_loop (EvTimeline *timeline) -{ - EvTimelinePrivate *priv; - - g_return_val_if_fail (EV_IS_TIMELINE (timeline), FALSE); - - priv = ev_timeline_get_instance_private (timeline); - return priv->loop; -} - -void -ev_timeline_set_loop (EvTimeline *timeline, - gboolean loop) -{ - EvTimelinePrivate *priv; - - g_return_if_fail (EV_IS_TIMELINE (timeline)); - - priv = ev_timeline_get_instance_private (timeline); - priv->loop = loop; - - g_object_notify (G_OBJECT (timeline), "loop"); -} - -void -ev_timeline_set_duration (EvTimeline *timeline, - guint duration) -{ - EvTimelinePrivate *priv; - - g_return_if_fail (EV_IS_TIMELINE (timeline)); - - priv = ev_timeline_get_instance_private (timeline); - - priv->duration = duration; - - g_object_notify (G_OBJECT (timeline), "duration"); -} - -guint -ev_timeline_get_duration (EvTimeline *timeline) -{ - EvTimelinePrivate *priv; - - g_return_val_if_fail (EV_IS_TIMELINE (timeline), 0); - - priv = ev_timeline_get_instance_private (timeline); - - return priv->duration; -} - -gdouble -ev_timeline_get_progress (EvTimeline *timeline) -{ - EvTimelinePrivate *priv; - gdouble progress; - guint elapsed_time; - - g_return_val_if_fail (EV_IS_TIMELINE (timeline), 0.0); - - priv = ev_timeline_get_instance_private (timeline); - - if (!priv->timer) - return 0.; - - elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); - progress = (gdouble) elapsed_time / priv->duration; - - return CLAMP (progress, 0., 1.); -} diff --git a/libview/ev-timeline.h b/libview/ev-timeline.h deleted file mode 100644 index 568b5a702..000000000 --- a/libview/ev-timeline.h +++ /dev/null @@ -1,87 +0,0 @@ -/* ev-timeline.h - * this file is part of evince, a gnome document viewer - * - * Copyright (C) 2007 Carlos Garnacho - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#if !defined (EVINCE_COMPILATION) -#error "This is a private header." -#endif - -#include - -G_BEGIN_DECLS - -#define EV_TYPE_TIMELINE (ev_timeline_get_type ()) -#define EV_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_TIMELINE, EvTimeline)) -#define EV_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_TIMELINE, EvTimelineClass)) -#define EV_IS_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_TIMELINE)) -#define EV_IS_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_TIMELINE)) -#define EV_TIMELINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_TIMELINE, EvTimelineClass)) - -typedef struct _EvTimeline EvTimeline; -typedef struct _EvTimelineClass EvTimelineClass; - -struct _EvTimeline { - GObject parent_instance; -}; - -struct _EvTimelineClass { - GObjectClass parent_class; - - /* vmethods */ - void (* start) (EvTimeline *timeline); - - /* signals */ - void (* started) (EvTimeline *timeline); - void (* finished) (EvTimeline *timeline); - void (* paused) (EvTimeline *timeline); - - void (* frame) (EvTimeline *timeline, - gdouble progress); -}; - - -GType ev_timeline_get_type (void) G_GNUC_CONST; - -EvTimeline *ev_timeline_new (guint duration); - -void ev_timeline_start (EvTimeline *timeline); -void ev_timeline_pause (EvTimeline *timeline); -void ev_timeline_rewind (EvTimeline *timeline); - -gboolean ev_timeline_is_running (EvTimeline *timeline); - -guint ev_timeline_get_fps (EvTimeline *timeline); -void ev_timeline_set_fps (EvTimeline *timeline, - guint fps); - -gboolean ev_timeline_get_loop (EvTimeline *timeline); -void ev_timeline_set_loop (EvTimeline *timeline, - gboolean loop); - -guint ev_timeline_get_duration (EvTimeline *timeline); -void ev_timeline_set_duration (EvTimeline *timeline, - guint duration); - -gdouble ev_timeline_get_progress (EvTimeline *timeline); - - -G_END_DECLS diff --git a/libview/ev-transition-animation.c b/libview/ev-transition-animation.c deleted file mode 100644 index f1741df02..000000000 --- a/libview/ev-transition-animation.c +++ /dev/null @@ -1,677 +0,0 @@ -/* ev-transition-animation.c - * this file is part of evince, a gnome document viewer - * - * Copyright (C) 2007 Carlos Garnacho - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include "ev-transition-animation.h" -#include "ev-timeline.h" - -#define N_BLINDS 6 - -typedef struct EvTransitionAnimationPrivate EvTransitionAnimationPrivate; - -struct EvTransitionAnimationPrivate { - EvTransitionEffect *effect; - cairo_surface_t *origin_surface; - cairo_surface_t *dest_surface; -}; - -enum { - PROP_0, - PROP_EFFECT, - PROP_ORIGIN_SURFACE, - PROP_DEST_SURFACE -}; - - -G_DEFINE_TYPE_WITH_PRIVATE (EvTransitionAnimation, ev_transition_animation, EV_TYPE_TIMELINE) - - -static void -ev_transition_animation_init (EvTransitionAnimation *animation) -{ -} - -static void -ev_transition_animation_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - EvTransitionAnimationPrivate *priv; - - priv = ev_transition_animation_get_instance_private (EV_TRANSITION_ANIMATION (object)); - - switch (prop_id) { - case PROP_EFFECT: - if (priv->effect) - g_object_unref (priv->effect); - - priv->effect = g_value_dup_object (value); - break; - case PROP_ORIGIN_SURFACE: - ev_transition_animation_set_origin_surface (EV_TRANSITION_ANIMATION (object), - g_value_get_pointer (value)); - break; - case PROP_DEST_SURFACE: - ev_transition_animation_set_dest_surface (EV_TRANSITION_ANIMATION (object), - g_value_get_pointer (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -ev_transition_animation_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - EvTransitionAnimationPrivate *priv; - - priv = ev_transition_animation_get_instance_private (EV_TRANSITION_ANIMATION (object)); - - switch (prop_id) { - case PROP_EFFECT: - g_value_set_object (value, priv->effect); - break; - case PROP_ORIGIN_SURFACE: - g_value_set_pointer (value, priv->origin_surface); - break; - case PROP_DEST_SURFACE: - g_value_set_pointer (value, priv->dest_surface); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -ev_transition_animation_finalize (GObject *object) -{ - EvTransitionAnimationPrivate *priv; - - priv = ev_transition_animation_get_instance_private (EV_TRANSITION_ANIMATION (object)); - - if (priv->effect) - g_object_unref (priv->effect); - - if (priv->origin_surface) - cairo_surface_destroy (priv->origin_surface); - - if (priv->dest_surface) - cairo_surface_destroy (priv->dest_surface); - - G_OBJECT_CLASS (ev_transition_animation_parent_class)->finalize (object); -} - -static GObject * -ev_transition_animation_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_params) -{ - GObject *object; - EvTransitionAnimationPrivate *priv; - EvTransitionEffect *effect; - gdouble duration; - - object = G_OBJECT_CLASS (ev_transition_animation_parent_class)->constructor (type, - n_construct_properties, - construct_params); - - priv = ev_transition_animation_get_instance_private (EV_TRANSITION_ANIMATION (object)); - effect = priv->effect; - - g_object_get (effect, "duration-real", &duration, NULL); - ev_timeline_set_duration (EV_TIMELINE (object), duration * 1000); - - return object; -} - -static void -ev_transition_animation_class_init (EvTransitionAnimationClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->set_property = ev_transition_animation_set_property; - object_class->get_property = ev_transition_animation_get_property; - object_class->finalize = ev_transition_animation_finalize; - object_class->constructor = ev_transition_animation_constructor; - - g_object_class_install_property (object_class, - PROP_EFFECT, - g_param_spec_object ("effect", - "Effect", - "Transition effect description", - EV_TYPE_TRANSITION_EFFECT, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (object_class, - PROP_ORIGIN_SURFACE, - g_param_spec_pointer ("origin-surface", - "Origin surface", - "Cairo surface from which the animation will happen", - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (object_class, - PROP_DEST_SURFACE, - g_param_spec_pointer ("dest-surface", - "Destination surface", - "Cairo surface to which the animation will happen", - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); -} - -static void -paint_surface (cairo_t *cr, - cairo_surface_t *surface, - gdouble x_offset, - gdouble y_offset, - gdouble alpha, - GdkRectangle page_area) -{ - cairo_save (cr); - - gdk_cairo_rectangle (cr, &page_area); - cairo_clip (cr); - cairo_surface_set_device_offset (surface, x_offset, y_offset); - cairo_set_source_surface (cr, surface, 0, 0); - - if (alpha == 1.) - cairo_paint (cr); - else - cairo_paint_with_alpha (cr, alpha); - - cairo_restore (cr); -} - -/* animations */ -static void -ev_transition_animation_split (cairo_t *cr, - EvTransitionAnimation *animation, - EvTransitionEffect *effect, - gdouble progress, - GdkRectangle page_area) -{ - EvTransitionAnimationPrivate *priv; - EvTransitionEffectAlignment alignment; - EvTransitionEffectDirection direction; - gint width, height; - - priv = ev_transition_animation_get_instance_private (animation); - width = page_area.width; - height = page_area.height; - - g_object_get (effect, - "alignment", &alignment, - "direction", &direction, - NULL); - - if (direction == EV_TRANSITION_DIRECTION_INWARD) { - paint_surface (cr, priv->dest_surface, 0, 0, 1., page_area); - - if (alignment == EV_TRANSITION_ALIGNMENT_HORIZONTAL) { - cairo_rectangle (cr, - 0, - height * progress / 2, - width, - height * (1 - progress)); - } else { - cairo_rectangle (cr, - width * progress / 2, - 0, - width * (1 - progress), - height); - } - - cairo_clip (cr); - - paint_surface (cr, priv->origin_surface, 0, 0, 1., page_area); - } else { - paint_surface (cr, priv->origin_surface, 0, 0, 1., page_area); - - if (alignment == EV_TRANSITION_ALIGNMENT_HORIZONTAL) { - cairo_rectangle (cr, - 0, - (height / 2) - (height * progress / 2), - width, - height * progress); - } else { - cairo_rectangle (cr, - (width / 2) - (width * progress / 2), - 0, - width * progress, - height); - } - - cairo_clip (cr); - - paint_surface (cr, priv->dest_surface, 0, 0, 1., page_area); - } -} - -static void -ev_transition_animation_blinds (cairo_t *cr, - EvTransitionAnimation *animation, - EvTransitionEffect *effect, - gdouble progress, - GdkRectangle page_area) -{ - EvTransitionAnimationPrivate *priv; - EvTransitionEffectAlignment alignment; - gint width, height, i; - - priv = ev_transition_animation_get_instance_private (animation); - width = page_area.width; - height = page_area.height; - - g_object_get (effect, - "alignment", &alignment, - NULL); - - paint_surface (cr, priv->origin_surface, 0, 0, 1., page_area); - - for (i = 0; i < N_BLINDS; i++) { - cairo_save (cr); - - if (alignment == EV_TRANSITION_ALIGNMENT_HORIZONTAL) { - cairo_rectangle (cr, - 0, - height / N_BLINDS * i, - width, - height / N_BLINDS * progress); - } else { - cairo_rectangle (cr, - width / N_BLINDS * i, - 0, - width / N_BLINDS * progress, - height); - } - - cairo_clip (cr); - paint_surface (cr, priv->dest_surface, 0, 0, 1., page_area); - cairo_restore (cr); - } -} - -static void -ev_transition_animation_box (cairo_t *cr, - EvTransitionAnimation *animation, - EvTransitionEffect *effect, - gdouble progress, - GdkRectangle page_area) -{ - EvTransitionAnimationPrivate *priv; - EvTransitionEffectDirection direction; - gint width, height; - - priv = ev_transition_animation_get_instance_private (animation); - width = page_area.width; - height = page_area.height; - - g_object_get (effect, - "direction", &direction, - NULL); - - if (direction == EV_TRANSITION_DIRECTION_INWARD) { - paint_surface (cr, priv->dest_surface, 0, 0, 1., page_area); - - cairo_rectangle (cr, - width * progress / 2, - height * progress / 2, - width * (1 - progress), - height * (1 - progress)); - cairo_clip (cr); - - paint_surface (cr, priv->origin_surface, 0, 0, 1., page_area); - } else { - paint_surface (cr, priv->origin_surface, 0, 0, 1., page_area); - - cairo_rectangle (cr, - (width / 2) - (width * progress / 2), - (height / 2) - (height * progress / 2), - width * progress, - height * progress); - cairo_clip (cr); - - paint_surface (cr, priv->dest_surface, 0, 0, 1., page_area); - } -} - -static void -ev_transition_animation_wipe (cairo_t *cr, - EvTransitionAnimation *animation, - EvTransitionEffect *effect, - gdouble progress, - GdkRectangle page_area) -{ - EvTransitionAnimationPrivate *priv; - gint width, height; - gint angle; - - priv = ev_transition_animation_get_instance_private (animation); - width = page_area.width; - height = page_area.height; - - g_object_get (effect, - "angle", &angle, - NULL); - - paint_surface (cr, priv->origin_surface, 0, 0, 1., page_area); - - if (angle == 0) { - /* left to right */ - cairo_rectangle (cr, - 0, 0, - width * progress, - height); - } else if (angle <= 90) { - /* bottom to top */ - cairo_rectangle (cr, - 0, - height * (1 - progress), - width, - height * progress); - } else if (angle <= 180) { - /* right to left */ - cairo_rectangle (cr, - width * (1 - progress), - 0, - width * progress, - height); - } else if (angle <= 270) { - /* top to bottom */ - cairo_rectangle (cr, - 0, 0, - width, - height * progress); - } - - cairo_clip (cr); - - paint_surface (cr, priv->dest_surface, 0, 0, 1., page_area); -} - -static void -ev_transition_animation_dissolve (cairo_t *cr, - EvTransitionAnimation *animation, - EvTransitionEffect *effect, - gdouble progress, - GdkRectangle page_area) -{ - EvTransitionAnimationPrivate *priv; - - priv = ev_transition_animation_get_instance_private (animation); - - paint_surface (cr, priv->dest_surface, 0, 0, 1., page_area); - paint_surface (cr, priv->origin_surface, 0, 0, 1 - progress, page_area); -} - -static void -ev_transition_animation_push (cairo_t *cr, - EvTransitionAnimation *animation, - EvTransitionEffect *effect, - gdouble progress, - GdkRectangle page_area) -{ - EvTransitionAnimationPrivate *priv; - gint width, height; - gint angle; - - priv = ev_transition_animation_get_instance_private (animation); - width = page_area.width; - height = page_area.height; - - g_object_get (effect, - "angle", &angle, - NULL); - - if (angle == 0) { - /* left to right */ - paint_surface (cr, priv->origin_surface, - (width * progress), 0, 1., page_area); - paint_surface (cr, priv->dest_surface, width * (1 - progress), 0, 1., page_area); - } else { - /* top to bottom */ - paint_surface (cr, priv->origin_surface, 0, - (height * progress), 1., page_area); - paint_surface (cr, priv->dest_surface, 0, height * (1 - progress), 1., page_area); - } -} - -static void -ev_transition_animation_cover (cairo_t *cr, - EvTransitionAnimation *animation, - EvTransitionEffect *effect, - gdouble progress, - GdkRectangle page_area) -{ - EvTransitionAnimationPrivate *priv; - gint width, height; - gint angle; - - priv = ev_transition_animation_get_instance_private (animation); - width = page_area.width; - height = page_area.height; - - g_object_get (effect, - "angle", &angle, - NULL); - - paint_surface (cr, priv->origin_surface, 0, 0, 1., page_area); - - if (angle == 0) { - /* left to right */ - paint_surface (cr, priv->dest_surface, width * (1 - progress), 0, 1., page_area); - } else { - /* top to bottom */ - paint_surface (cr, priv->dest_surface, 0, height * (1 - progress), 1., page_area); - } -} - -static void -ev_transition_animation_uncover (cairo_t *cr, - EvTransitionAnimation *animation, - EvTransitionEffect *effect, - gdouble progress, - GdkRectangle page_area) -{ - EvTransitionAnimationPrivate *priv; - gint width, height; - gint angle; - - priv = ev_transition_animation_get_instance_private (animation); - width = page_area.width; - height = page_area.height; - - g_object_get (effect, - "angle", &angle, - NULL); - - paint_surface (cr, priv->dest_surface, 0, 0, 1., page_area); - - if (angle == 0) { - /* left to right */ - paint_surface (cr, priv->origin_surface, - (width * progress), 0, 1., page_area); - } else { - /* top to bottom */ - paint_surface (cr, priv->origin_surface, 0, - (height * progress), 1., page_area); - } -} - -static void -ev_transition_animation_fade (cairo_t *cr, - EvTransitionAnimation *animation, - EvTransitionEffect *effect, - gdouble progress, - GdkRectangle page_area) -{ - EvTransitionAnimationPrivate *priv; - - priv = ev_transition_animation_get_instance_private (animation); - - paint_surface (cr, priv->origin_surface, 0, 0, 1., page_area); - paint_surface (cr, priv->dest_surface, 0, 0, progress, page_area); -} - -void -ev_transition_animation_paint (EvTransitionAnimation *animation, - cairo_t *cr, - GdkRectangle page_area) -{ - EvTransitionAnimationPrivate *priv; - EvTransitionEffectType type; - gdouble progress; - - g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation)); - - priv = ev_transition_animation_get_instance_private (animation); - - if (!priv->dest_surface) { - /* animation is still not ready, paint the origin surface */ - paint_surface (cr, priv->origin_surface, 0, 0, 1., page_area); - return; - } - - g_object_get (priv->effect, "type", &type, NULL); - progress = ev_timeline_get_progress (EV_TIMELINE (animation)); - - switch (type) { - case EV_TRANSITION_EFFECT_REPLACE: - /* just paint the destination slide */ - paint_surface (cr, priv->dest_surface, 0, 0, 1., page_area); - break; - case EV_TRANSITION_EFFECT_SPLIT: - ev_transition_animation_split (cr, animation, priv->effect, progress, page_area); - break; - case EV_TRANSITION_EFFECT_BLINDS: - ev_transition_animation_blinds (cr, animation, priv->effect, progress, page_area); - break; - case EV_TRANSITION_EFFECT_BOX: - ev_transition_animation_box (cr, animation, priv->effect, progress, page_area); - break; - case EV_TRANSITION_EFFECT_WIPE: - ev_transition_animation_wipe (cr, animation, priv->effect, progress, page_area); - break; - case EV_TRANSITION_EFFECT_DISSOLVE: - ev_transition_animation_dissolve (cr, animation, priv->effect, progress, page_area); - break; - case EV_TRANSITION_EFFECT_PUSH: - ev_transition_animation_push (cr, animation, priv->effect, progress, page_area); - break; - case EV_TRANSITION_EFFECT_COVER: - ev_transition_animation_cover (cr, animation, priv->effect, progress, page_area); - break; - case EV_TRANSITION_EFFECT_UNCOVER: - ev_transition_animation_uncover (cr, animation, priv->effect, progress, page_area); - break; - case EV_TRANSITION_EFFECT_FADE: - ev_transition_animation_fade (cr, animation, priv->effect, progress, page_area); - break; - default: { - GEnumValue *enum_value; - - enum_value = g_enum_get_value (g_type_class_peek (EV_TYPE_TRANSITION_EFFECT_TYPE), type); - - g_warning ("Unimplemented transition animation: '%s', " - "please post a bug report in the issue tracker " - "(https://gitlab.gnome.org/GNOME/evince/issues/) " - "with a testcase.", - enum_value->value_nick); - - /* just paint the destination slide */ - paint_surface (cr, priv->dest_surface, 0, 0, 1., page_area); - } - } -} - -EvTransitionAnimation * -ev_transition_animation_new (EvTransitionEffect *effect) -{ - g_return_val_if_fail (EV_IS_TRANSITION_EFFECT (effect), NULL); - - return g_object_new (EV_TYPE_TRANSITION_ANIMATION, - "effect", effect, - NULL); -} - -void -ev_transition_animation_set_origin_surface (EvTransitionAnimation *animation, - cairo_surface_t *origin_surface) -{ - EvTransitionAnimationPrivate *priv; - cairo_surface_t *surface; - - g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation)); - - priv = ev_transition_animation_get_instance_private (animation); - - if (priv->origin_surface == origin_surface) - return; - - surface = cairo_surface_reference (origin_surface); - - if (priv->origin_surface) - cairo_surface_destroy (priv->origin_surface); - - priv->origin_surface = surface; - g_object_notify (G_OBJECT (animation), "origin-surface"); - - if (priv->origin_surface && priv->dest_surface) - ev_timeline_start (EV_TIMELINE (animation)); -} - -void -ev_transition_animation_set_dest_surface (EvTransitionAnimation *animation, - cairo_surface_t *dest_surface) -{ - EvTransitionAnimationPrivate *priv; - cairo_surface_t *surface; - - g_return_if_fail (EV_IS_TRANSITION_ANIMATION (animation)); - - priv = ev_transition_animation_get_instance_private (animation); - - if (priv->dest_surface == dest_surface) - return; - - surface = cairo_surface_reference (dest_surface); - - if (priv->dest_surface) - cairo_surface_destroy (priv->dest_surface); - - priv->dest_surface = surface; - g_object_notify (G_OBJECT (animation), "dest-surface"); - - if (priv->origin_surface && priv->dest_surface) - ev_timeline_start (EV_TIMELINE (animation)); -} - -gboolean -ev_transition_animation_ready (EvTransitionAnimation *animation) -{ - EvTransitionAnimationPrivate *priv; - - g_return_val_if_fail (EV_IS_TRANSITION_ANIMATION (animation), FALSE); - - priv = ev_transition_animation_get_instance_private (animation); - - return (priv->origin_surface != NULL); -} diff --git a/libview/ev-transition-animation.h b/libview/ev-transition-animation.h deleted file mode 100644 index 332574f59..000000000 --- a/libview/ev-transition-animation.h +++ /dev/null @@ -1,69 +0,0 @@ -/* ev-transition-animation.h - * this file is part of evince, a gnome document viewer - * - * Copyright (C) 2007 Carlos Garnacho - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#if !defined (EVINCE_COMPILATION) -#error "This is a private header." -#endif - -#include -#include "ev-timeline.h" -#include "ev-transition-effect.h" - -G_BEGIN_DECLS - -#define EV_TYPE_TRANSITION_ANIMATION (ev_transition_animation_get_type ()) -#define EV_TRANSITION_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_TRANSITION_ANIMATION, EvTransitionAnimation)) -#define EV_TRANSITION_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_TRANSITION_ANIMATION, EvTransitionAnimationClass)) -#define EV_IS_TRANSITION_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_TRANSITION_ANIMATION)) -#define EV_IS_TRANSITION_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_TRANSITION_ANIMATION)) -#define EV_TRANSITION_ANIMATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_TRANSITION_ANIMATION, EvTransitionAnimationClass)) - -typedef struct _EvTransitionAnimation EvTransitionAnimation; -typedef struct _EvTransitionAnimationClass EvTransitionAnimationClass; - -struct _EvTransitionAnimation { - EvTimeline parent_instance; -}; - -struct _EvTransitionAnimationClass { - EvTimelineClass parent_class; -}; - - -GType ev_transition_animation_get_type (void) G_GNUC_CONST; - -EvTransitionAnimation * ev_transition_animation_new (EvTransitionEffect *effect); - -void ev_transition_animation_set_origin_surface (EvTransitionAnimation *animation, - cairo_surface_t *origin_surface); -void ev_transition_animation_set_dest_surface (EvTransitionAnimation *animation, - cairo_surface_t *origin_surface); -gint ev_transition_animation_get_page_from (EvTransitionAnimation *animation); -gint ev_transition_animation_get_page_to (EvTransitionAnimation *animation); - -void ev_transition_animation_paint (EvTransitionAnimation *animation, - cairo_t *cr, - GdkRectangle page_area); -gboolean ev_transition_animation_ready (EvTransitionAnimation *animation); - -G_END_DECLS diff --git a/libview/meson.build b/libview/meson.build index dfa33a94a..fb3c8db0e 100644 --- a/libview/meson.build +++ b/libview/meson.build @@ -29,8 +29,6 @@ sources = files( 'ev-page-cache.c', 'ev-pixbuf-cache.c', 'ev-print-operation.c', - 'ev-timeline.c', - 'ev-transition-animation.c', 'ev-view.c', #'ev-view-accessible.c', 'ev-view-cursor.c', -- GitLab From a9d197b48c44725d49a903a87b65a4836941fe9b Mon Sep 17 00:00:00 2001 From: Qiu Wenbo Date: Sun, 12 Nov 2023 17:15:08 +0800 Subject: [PATCH 19/50] libmisc: Port EvPageAction to gtk4 * Move to focus event controller Signed-off-by: Qiu Wenbo --- libmisc/ev-page-action-widget.c | 40 ++++++++++++++++++-------------- libmisc/ev-page-action-widget.ui | 32 ++++++++++++++----------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/libmisc/ev-page-action-widget.c b/libmisc/ev-page-action-widget.c index 4c3b4d1d6..d244fbd0e 100644 --- a/libmisc/ev-page-action-widget.c +++ b/libmisc/ev-page-action-widget.c @@ -70,7 +70,7 @@ show_page_number_in_pages_label (EvPageActionWidget *action_widget, return FALSE; page_label = g_strdup_printf ("%d", page + 1); - retval = g_strcmp0 (page_label, gtk_entry_get_text (GTK_ENTRY (action_widget->entry))) != 0; + retval = g_strcmp0 (page_label, gtk_editable_get_text (GTK_EDITABLE (action_widget->entry))) != 0; g_free (page_label); return retval; @@ -88,7 +88,7 @@ update_pages_label (EvPageActionWidget *action_widget, label_text = g_strdup_printf (_("(%d of %d)"), page + 1, n_pages); else label_text = g_strdup_printf (_("of %d"), n_pages); - gtk_entry_set_text (GTK_ENTRY (action_widget->label), label_text); + gtk_editable_set_text (GTK_EDITABLE (action_widget->label), label_text); g_free (label_text); } @@ -100,11 +100,11 @@ ev_page_action_widget_set_current_page (EvPageActionWidget *action_widget, gchar *page_label; page_label = ev_document_get_page_label (action_widget->document, page); - gtk_entry_set_text (GTK_ENTRY (action_widget->entry), page_label); + gtk_editable_set_text (GTK_EDITABLE (action_widget->entry), page_label); gtk_editable_set_position (GTK_EDITABLE (action_widget->entry), -1); g_free (page_label); } else { - gtk_entry_set_text (GTK_ENTRY (action_widget->entry), ""); + gtk_editable_set_text (GTK_EDITABLE (action_widget->entry), ""); } update_pages_label (action_widget, page); @@ -133,11 +133,11 @@ ev_page_action_widget_update_max_width (EvPageActionWidget *action_widget) } g_free (max_page_label); - gtk_entry_set_width_chars (GTK_ENTRY (action_widget->label), max_label_len); + gtk_editable_set_width_chars (GTK_EDITABLE (action_widget->label), max_label_len); g_free (max_label); max_label_len = ev_document_get_max_label_len (action_widget->document); - gtk_entry_set_width_chars (GTK_ENTRY (action_widget->entry), + gtk_editable_set_width_chars (GTK_EDITABLE (action_widget->entry), CLAMP (max_label_len, strlen (max_page_numeric_label) + 1, 12)); g_free (max_page_numeric_label); } @@ -152,16 +152,22 @@ page_changed_cb (EvDocumentModel *model, } static gboolean -page_scroll_cb (EvPageActionWidget *action_widget, GdkEventScroll *event) +page_scroll_cb (GtkEventControllerScroll *self, + gdouble dx, + gdouble dy, + gpointer user_data) { + EvPageActionWidget *action_widget = EV_PAGE_ACTION_WIDGET (user_data); EvDocumentModel *model = action_widget->doc_model; - gint pageno; + GdkEvent *event = gtk_event_controller_get_current_event ( + GTK_EVENT_CONTROLLER (self)); + GdkScrollDirection direction = gdk_scroll_event_get_direction (event); + gint pageno = ev_document_model_get_page (model); - pageno = ev_document_model_get_page (model); - if ((event->direction == GDK_SCROLL_DOWN) && + if ((direction == GDK_SCROLL_DOWN) && (pageno < ev_document_get_n_pages (action_widget->document) - 1)) pageno++; - if ((event->direction == GDK_SCROLL_UP) && (pageno > 0)) + if ((direction == GDK_SCROLL_UP) && (pageno > 0)) pageno--; ev_document_model_set_page (model, pageno); @@ -183,14 +189,14 @@ activate_cb (EvPageActionWidget *action_widget) model = action_widget->doc_model; current_page = ev_document_model_get_page (model); - text = gtk_entry_get_text (GTK_ENTRY (action_widget->entry)); + text = gtk_editable_get_text (GTK_EDITABLE (action_widget->entry)); /* If we are not in search mode, i.e. we are entering a page number */ if (!ev_page_action_widget_completion_search_is_enabled (action_widget)) { /* Convert utf8 fullwidth numbers (eg. japanese) to halfwidth - fixes #1518 */ new_text = g_utf8_normalize (text, -1, G_NORMALIZE_ALL); - gtk_entry_set_text (GTK_ENTRY (action_widget->entry), new_text); - text = gtk_entry_get_text (GTK_ENTRY (action_widget->entry)); + gtk_editable_set_text (GTK_EDITABLE (action_widget->entry), new_text); + text = gtk_editable_get_text (GTK_EDITABLE (action_widget->entry)); g_free (new_text); } @@ -317,7 +323,7 @@ static void ev_page_action_widget_class_init (EvPageActionWidgetClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->finalize = ev_page_action_widget_finalize; @@ -557,7 +563,7 @@ ev_page_action_widget_grab_focus (EvPageActionWidget *proxy) void ev_page_action_widget_clear (EvPageActionWidget *proxy) { - gtk_entry_set_text (GTK_ENTRY (proxy->entry), ""); + gtk_editable_set_text (GTK_EDITABLE (proxy->entry), ""); } /* Sets width of the text entry, width will be restablished @@ -567,7 +573,7 @@ ev_page_action_widget_clear (EvPageActionWidget *proxy) void ev_page_action_widget_set_temporary_entry_width (EvPageActionWidget *proxy, gint width) { - gtk_entry_set_width_chars (GTK_ENTRY (proxy->entry), width); + gtk_editable_set_width_chars (GTK_EDITABLE (proxy->entry), width); /* xalign will also be restablished on focus_out */ g_object_set (proxy->entry, "xalign", 0., NULL); } diff --git a/libmisc/ev-page-action-widget.ui b/libmisc/ev-page-action-widget.ui index 909cdddfb..92361141a 100644 --- a/libmisc/ev-page-action-widget.ui +++ b/libmisc/ev-page-action-widget.ui @@ -1,31 +1,37 @@