Blame src/dh-web-view.c

Packit 116408
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
Packit 116408
/*
Packit 116408
 * Copyright (C) 2018 Sébastien Wilmet <swilmet@gnome.org>
Packit 116408
 *
Packit 116408
 * This program is free software; you can redistribute it and/or
Packit 116408
 * modify it under the terms of the GNU General Public License as
Packit 116408
 * published by the Free Software Foundation; either version 2 of the
Packit 116408
 * License, or (at your option) any later version.
Packit 116408
 *
Packit 116408
 * This program is distributed in the hope that it will be useful,
Packit 116408
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 116408
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 116408
 * General Public License for more details.
Packit 116408
 *
Packit 116408
 * You should have received a copy of the GNU General Public License
Packit 116408
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Packit 116408
 */
Packit 116408
Packit 116408
#include "dh-web-view.h"
Packit 116408
#include <math.h>
Packit 116408
#include <glib/gi18n.h>
Packit 116408
Packit 116408
struct _DhWebViewPrivate {
Packit 116408
        gchar *search_text;
Packit 116408
        gdouble total_scroll_delta_y;
Packit 116408
};
Packit 116408
Packit 116408
static const gdouble zoom_levels[] = {
Packit 116408
        0.5,            /* 50% */
Packit 116408
        0.8408964152,   /* 75% */
Packit 116408
        1.0,            /* 100% */
Packit 116408
        1.1892071149,   /* 125% */
Packit 116408
        1.4142135623,   /* 150% */
Packit 116408
        1.6817928304,   /* 175% */
Packit 116408
        2.0,            /* 200% */
Packit 116408
        2.8284271247,   /* 300% */
Packit 116408
        4.0             /* 400% */
Packit 116408
};
Packit 116408
Packit 116408
static const guint n_zoom_levels = G_N_ELEMENTS (zoom_levels);
Packit 116408
Packit 116408
#define ZOOM_DEFAULT (zoom_levels[2])
Packit 116408
Packit 116408
G_DEFINE_TYPE_WITH_PRIVATE (DhWebView, dh_web_view, WEBKIT_TYPE_WEB_VIEW)
Packit 116408
Packit 116408
static gint
Packit 116408
get_current_zoom_level_index (DhWebView *view)
Packit 116408
{
Packit 116408
        gdouble zoom_level;
Packit 116408
        gdouble previous;
Packit 116408
        guint i;
Packit 116408
Packit 116408
        zoom_level = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (view));
Packit 116408
Packit 116408
        previous = zoom_levels[0];
Packit 116408
        for (i = 1; i < n_zoom_levels; i++) {
Packit 116408
                gdouble current = zoom_levels[i];
Packit 116408
                gdouble mean = sqrt (previous * current);
Packit 116408
Packit 116408
                if (zoom_level <= mean)
Packit 116408
                        return i - 1;
Packit 116408
Packit 116408
                previous = current;
Packit 116408
        }
Packit 116408
Packit 116408
        return n_zoom_levels - 1;
Packit 116408
}
Packit 116408
Packit 116408
static void
Packit 116408
bump_zoom_level (DhWebView *view,
Packit 116408
                 gint       bump_amount)
Packit 116408
{
Packit 116408
        gint zoom_level_index;
Packit 116408
        gdouble new_zoom_level;
Packit 116408
Packit 116408
        if (bump_amount == 0)
Packit 116408
                return;
Packit 116408
Packit 116408
        zoom_level_index = get_current_zoom_level_index (view) + bump_amount;
Packit 116408
        zoom_level_index = CLAMP (zoom_level_index, 0, (gint)n_zoom_levels - 1);
Packit 116408
        new_zoom_level = zoom_levels[zoom_level_index];
Packit 116408
Packit 116408
        webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (view), new_zoom_level);
Packit 116408
}
Packit 116408
Packit 116408
static gboolean
Packit 116408
dh_web_view_scroll_event (GtkWidget      *widget,
Packit 116408
                          GdkEventScroll *scroll_event)
Packit 116408
{
Packit 116408
        DhWebView *view = DH_WEB_VIEW (widget);
Packit 116408
        gdouble delta_y;
Packit 116408
Packit 116408
        if ((scroll_event->state & GDK_CONTROL_MASK) == 0)
Packit 116408
                goto chain_up;
Packit 116408
Packit 116408
        switch (scroll_event->direction) {
Packit 116408
                case GDK_SCROLL_UP:
Packit 116408
                        bump_zoom_level (view, 1);
Packit 116408
                        return GDK_EVENT_STOP;
Packit 116408
Packit 116408
                case GDK_SCROLL_DOWN:
Packit 116408
                        bump_zoom_level (view, -1);
Packit 116408
                        return GDK_EVENT_STOP;
Packit 116408
Packit 116408
                case GDK_SCROLL_LEFT:
Packit 116408
                case GDK_SCROLL_RIGHT:
Packit 116408
                        break;
Packit 116408
Packit 116408
                case GDK_SCROLL_SMOOTH:
Packit 116408
                        gdk_event_get_scroll_deltas ((GdkEvent *)scroll_event, NULL, &delta_y);
Packit 116408
                        view->priv->total_scroll_delta_y += delta_y;
Packit 116408
Packit 116408
                        /* Avoiding direct float comparison.
Packit 116408
                         * -1 and 1 are the thresholds for bumping the zoom level,
Packit 116408
                         * which can be adjusted for taste.
Packit 116408
                         */
Packit 116408
                        if ((gint)view->priv->total_scroll_delta_y <= -1) {
Packit 116408
                                view->priv->total_scroll_delta_y = 0.f;
Packit 116408
                                bump_zoom_level (view, 1);
Packit 116408
                        } else if ((gint)view->priv->total_scroll_delta_y >= 1) {
Packit 116408
                                view->priv->total_scroll_delta_y = 0.f;
Packit 116408
                                bump_zoom_level (view, -1);
Packit 116408
                        }
Packit 116408
                        return GDK_EVENT_STOP;
Packit 116408
Packit 116408
                default:
Packit 116408
                        g_warn_if_reached ();
Packit 116408
        }
Packit 116408
Packit 116408
chain_up:
Packit 116408
        if (GTK_WIDGET_CLASS (dh_web_view_parent_class)->scroll_event == NULL)
Packit 116408
                return GDK_EVENT_PROPAGATE;
Packit 116408
Packit 116408
        return GTK_WIDGET_CLASS (dh_web_view_parent_class)->scroll_event (widget, scroll_event);
Packit 116408
}
Packit 116408
Packit 116408
static void
Packit 116408
dh_web_view_constructed (GObject *object)
Packit 116408
{
Packit 116408
        WebKitWebView *view = WEBKIT_WEB_VIEW (object);
Packit 116408
        WebKitSettings *settings;
Packit 116408
Packit 116408
        if (G_OBJECT_CLASS (dh_web_view_parent_class)->constructed != NULL)
Packit 116408
                G_OBJECT_CLASS (dh_web_view_parent_class)->constructed (object);
Packit 116408
Packit 116408
        /* Disable some things we have no need for. */
Packit 116408
        settings = webkit_web_view_get_settings (view);
Packit 116408
        webkit_settings_set_enable_html5_database (settings, FALSE);
Packit 116408
        webkit_settings_set_enable_html5_local_storage (settings, FALSE);
Packit 116408
        webkit_settings_set_enable_plugins (settings, FALSE);
Packit 116408
}
Packit 116408
Packit 116408
static void
Packit 116408
dh_web_view_finalize (GObject *object)
Packit 116408
{
Packit 116408
        DhWebView *view = DH_WEB_VIEW (object);
Packit 116408
Packit 116408
        g_free (view->priv->search_text);
Packit 116408
Packit 116408
        G_OBJECT_CLASS (dh_web_view_parent_class)->finalize (object);
Packit 116408
}
Packit 116408
Packit 116408
static void
Packit 116408
dh_web_view_class_init (DhWebViewClass *klass)
Packit 116408
{
Packit 116408
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit 116408
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
Packit 116408
Packit 116408
        object_class->constructed = dh_web_view_constructed;
Packit 116408
        object_class->finalize = dh_web_view_finalize;
Packit 116408
Packit 116408
        widget_class->scroll_event = dh_web_view_scroll_event;
Packit 116408
}
Packit 116408
Packit 116408
static void
Packit 116408
dh_web_view_init (DhWebView *view)
Packit 116408
{
Packit 116408
        view->priv = dh_web_view_get_instance_private (view);
Packit 116408
        view->priv->total_scroll_delta_y = 0.f;
Packit 116408
Packit 116408
        gtk_widget_set_hexpand (GTK_WIDGET (view), TRUE);
Packit 116408
        gtk_widget_set_vexpand (GTK_WIDGET (view), TRUE);
Packit 116408
}
Packit 116408
Packit 116408
DhWebView *
Packit 116408
dh_web_view_new (void)
Packit 116408
{
Packit 116408
        return g_object_new (DH_TYPE_WEB_VIEW, NULL);
Packit 116408
}
Packit 116408
Packit 116408
const gchar *
Packit 116408
dh_web_view_get_devhelp_title (DhWebView *view)
Packit 116408
{
Packit 116408
        const gchar *title;
Packit 116408
Packit 116408
        g_return_val_if_fail (DH_IS_WEB_VIEW (view), NULL);
Packit 116408
Packit 116408
        title = webkit_web_view_get_title (WEBKIT_WEB_VIEW (view));
Packit 116408
Packit 116408
        if (title == NULL || title[0] == '\0')
Packit 116408
                title = _("Empty Page");
Packit 116408
Packit 116408
        return title;
Packit 116408
}
Packit 116408
Packit 116408
/*
Packit 116408
 * dh_web_view_set_search_text:
Packit 116408
 * @view: a #DhWebView.
Packit 116408
 * @search_text: (nullable): the search string, or %NULL.
Packit 116408
 *
Packit 116408
 * A more convenient API (for Devhelp needs) than #WebKitFindController. If
Packit 116408
 * @search_text is not empty, it calls webkit_find_controller_search() if not
Packit 116408
 * already done. If @search_text is empty or %NULL, it calls
Packit 116408
 * webkit_find_controller_search_finish().
Packit 116408
 */
Packit 116408
void
Packit 116408
dh_web_view_set_search_text (DhWebView   *view,
Packit 116408
                             const gchar *search_text)
Packit 116408
{
Packit 116408
        WebKitFindController *find_controller;
Packit 116408
Packit 116408
        g_return_if_fail (DH_IS_WEB_VIEW (view));
Packit 116408
Packit 116408
        if (g_strcmp0 (view->priv->search_text, search_text) == 0)
Packit 116408
                return;
Packit 116408
Packit 116408
        g_free (view->priv->search_text);
Packit 116408
        view->priv->search_text = g_strdup (search_text);
Packit 116408
Packit 116408
        find_controller = webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (view));
Packit 116408
Packit 116408
        if (search_text != NULL && search_text[0] != '\0') {
Packit 116408
                /* If webkit_find_controller_search() is called a second time
Packit 116408
                 * with the same parameters it's not a NOP, it launches a new
Packit 116408
                 * search, apparently, which screws up search_next() and
Packit 116408
                 * search_previous(). So we must call it only once for the same
Packit 116408
                 * search string.
Packit 116408
                 */
Packit 116408
                webkit_find_controller_search (find_controller,
Packit 116408
                                               search_text,
Packit 116408
                                               WEBKIT_FIND_OPTIONS_WRAP_AROUND |
Packit 116408
                                               WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE,
Packit 116408
                                               G_MAXUINT);
Packit 116408
        } else {
Packit 116408
                /* It's fine to call it several times. But unfortunately it
Packit 116408
                 * doesn't change the WebKitFindController:text property. So we
Packit 116408
                 * must store our own search_text.
Packit 116408
                 */
Packit 116408
                webkit_find_controller_search_finish (find_controller);
Packit 116408
        }
Packit 116408
}
Packit 116408
Packit 116408
void
Packit 116408
dh_web_view_search_next (DhWebView *view)
Packit 116408
{
Packit 116408
        WebKitFindController *find_controller;
Packit 116408
Packit 116408
        g_return_if_fail (DH_IS_WEB_VIEW (view));
Packit 116408
Packit 116408
        if (view->priv->search_text == NULL || view->priv->search_text[0] == '\0')
Packit 116408
                return;
Packit 116408
Packit 116408
        find_controller = webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (view));
Packit 116408
        webkit_find_controller_search_next (find_controller);
Packit 116408
}
Packit 116408
Packit 116408
void
Packit 116408
dh_web_view_search_previous (DhWebView *view)
Packit 116408
{
Packit 116408
        WebKitFindController *find_controller;
Packit 116408
Packit 116408
        g_return_if_fail (DH_IS_WEB_VIEW (view));
Packit 116408
Packit 116408
        if (view->priv->search_text == NULL || view->priv->search_text[0] == '\0')
Packit 116408
                return;
Packit 116408
Packit 116408
        find_controller = webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (view));
Packit 116408
        webkit_find_controller_search_previous (find_controller);
Packit 116408
}
Packit 116408
Packit 116408
gboolean
Packit 116408
dh_web_view_can_zoom_in (DhWebView *view)
Packit 116408
{
Packit 116408
        gint zoom_level_index;
Packit 116408
Packit 116408
        g_return_val_if_fail (DH_IS_WEB_VIEW (view), FALSE);
Packit 116408
Packit 116408
        zoom_level_index = get_current_zoom_level_index (view);
Packit 116408
        return zoom_level_index < ((gint)n_zoom_levels - 1);
Packit 116408
}
Packit 116408
Packit 116408
gboolean
Packit 116408
dh_web_view_can_zoom_out (DhWebView *view)
Packit 116408
{
Packit 116408
        gint zoom_level_index;
Packit 116408
Packit 116408
        g_return_val_if_fail (DH_IS_WEB_VIEW (view), FALSE);
Packit 116408
Packit 116408
        zoom_level_index = get_current_zoom_level_index (view);
Packit 116408
        return zoom_level_index > 0;
Packit 116408
}
Packit 116408
Packit 116408
gboolean
Packit 116408
dh_web_view_can_reset_zoom (DhWebView *view)
Packit 116408
{
Packit 116408
        gint zoom_level_index;
Packit 116408
Packit 116408
        g_return_val_if_fail (DH_IS_WEB_VIEW (view), FALSE);
Packit 116408
Packit 116408
        zoom_level_index = get_current_zoom_level_index (view);
Packit 116408
        return zoom_levels[zoom_level_index] != ZOOM_DEFAULT;
Packit 116408
}
Packit 116408
Packit 116408
void
Packit 116408
dh_web_view_zoom_in (DhWebView *view)
Packit 116408
{
Packit 116408
        g_return_if_fail (DH_IS_WEB_VIEW (view));
Packit 116408
Packit 116408
        bump_zoom_level (view, 1);
Packit 116408
}
Packit 116408
Packit 116408
void
Packit 116408
dh_web_view_zoom_out (DhWebView *view)
Packit 116408
{
Packit 116408
        g_return_if_fail (DH_IS_WEB_VIEW (view));
Packit 116408
Packit 116408
        bump_zoom_level (view, -1);
Packit 116408
}
Packit 116408
Packit 116408
void
Packit 116408
dh_web_view_reset_zoom (DhWebView *view)
Packit 116408
{
Packit 116408
        g_return_if_fail (DH_IS_WEB_VIEW (view));
Packit 116408
Packit 116408
        webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (view), ZOOM_DEFAULT);
Packit 116408
}