[evince] Use GMenu for the zoom selector instead of GtkAction



commit 55b21fe75eb910992af06a23fdd11d3073c06f6e
Author: Carlos Garcia Campos <carlosgc gnome org>
Date:   Sat Jun 21 11:33:24 2014 +0200

    Use GMenu for the zoom selector instead of GtkAction
    
    Merge EvZoomAction and EvZoomActionWidget into a single widget
    derived from GtkBox that uses GAction.

 po/POTFILES.in                |    1 +
 shell/Makefile.am             |    2 -
 shell/ev-toolbar.c            |   28 ++-
 shell/ev-window.c             |  230 +++----------------
 shell/ev-window.h             |    4 +-
 shell/ev-zoom-action-widget.c |  429 ----------------------------------
 shell/ev-zoom-action-widget.h |   63 -----
 shell/ev-zoom-action.c        |  506 ++++++++++++++++++++++++++++++++++++-----
 shell/ev-zoom-action.h        |   36 +---
 shell/evince-menus.ui         |   24 ++
 shell/evince-ui.xml           |    8 -
 11 files changed, 529 insertions(+), 802 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 86c7443..d94d468 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -52,6 +52,7 @@ shell/ev-toolbar.c
 shell/ev-utils.c
 shell/ev-window.c
 shell/ev-window-title.c
+shell/ev-zoom-action.c
 shell/main.c
 [type: gettext/glade]shell/evince-menus.ui
 evince.appdata.xml.in
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 5024554..63dc48d 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -55,8 +55,6 @@ evince_SOURCES=                               \
        ev-window-title.h               \
        ev-zoom-action.c                \
        ev-zoom-action.h                \
-       ev-zoom-action-widget.c         \
-       ev-zoom-action-widget.h         \
        ev-sidebar.c                    \
        ev-sidebar.h                    \
        ev-sidebar-annotations.c        \
diff --git a/shell/ev-toolbar.c b/shell/ev-toolbar.c
index 5e7278c..6b68dee 100644
--- a/shell/ev-toolbar.c
+++ b/shell/ev-toolbar.c
@@ -45,6 +45,7 @@ struct _EvToolbarPrivate {
         GtkWidget *view_menu_button;
         GtkWidget *action_menu_button;
         GtkWidget *history_action;
+        GtkWidget *zoom_action;
         GMenu *bookmarks_section;
 };
 
@@ -182,13 +183,20 @@ ev_toolbar_bookmarks_menu_model_changed (GMenuModel *model,
 }
 
 static void
+zoom_selector_activated (GtkWidget *zoom_action,
+                         EvToolbar *toolbar)
+{
+        ev_window_focus_view (toolbar->priv->window);
+}
+
+static void
 ev_toolbar_constructed (GObject *object)
 {
         EvToolbar      *ev_toolbar = EV_TOOLBAR (object);
         GtkBuilder     *builder;
         GtkActionGroup *action_group;
         GtkWidget      *tool_item;
-        GtkWidget      *hbox;
+        GtkWidget      *hbox, *vbox;
         GtkAction      *action;
         GtkWidget      *button;
         gboolean        rtl;
@@ -277,12 +285,20 @@ ev_toolbar_constructed (GObject *object)
         gtk_widget_show (tool_item);
 
         /* Zoom selector */
-        action = gtk_action_group_get_action (action_group, "ViewZoom");
-        tool_item = gtk_action_create_tool_item (action);
+        vbox = ev_zoom_action_new (ev_window_get_document_model (ev_toolbar->priv->window),
+                                   G_MENU (gtk_builder_get_object (builder, "zoom-menu")));
+        ev_toolbar->priv->zoom_action = vbox;
+        g_signal_connect (vbox, "activated",
+                          G_CALLBACK (zoom_selector_activated),
+                          ev_toolbar);
+        tool_item = GTK_WIDGET (gtk_tool_item_new ());
         if (rtl)
                 gtk_widget_set_margin_left (tool_item, 12);
         else
                 gtk_widget_set_margin_right (tool_item, 12);
+        gtk_container_add (GTK_CONTAINER (tool_item), vbox);
+        gtk_widget_show (vbox);
+
         gtk_container_add (GTK_CONTAINER (ev_toolbar), tool_item);
         gtk_widget_show (tool_item);
 
@@ -374,8 +390,6 @@ ev_toolbar_new (EvWindow *window)
 gboolean
 ev_toolbar_has_visible_popups (EvToolbar *ev_toolbar)
 {
-        GtkAction        *action;
-        GtkActionGroup   *action_group;
         GtkMenu          *popup_menu;
         EvToolbarPrivate *priv;
 
@@ -391,9 +405,7 @@ ev_toolbar_has_visible_popups (EvToolbar *ev_toolbar)
         if (gtk_widget_get_visible (GTK_WIDGET (popup_menu)))
                 return TRUE;
 
-        action_group = ev_window_get_main_action_group (ev_toolbar->priv->window);
-        action = gtk_action_group_get_action (action_group, "ViewZoom");
-        if (ev_zoom_action_get_popup_shown (EV_ZOOM_ACTION (action)))
+        if (ev_zoom_action_get_popup_shown (EV_ZOOM_ACTION (ev_toolbar->priv->zoom_action)))
                 return TRUE;
 
         if (ev_history_action_get_popup_shown (EV_HISTORY_ACTION (ev_toolbar->priv->history_action)))
diff --git a/shell/ev-window.c b/shell/ev-window.c
index ac9868a..9355e61 100644
--- a/shell/ev-window.c
+++ b/shell/ev-window.c
@@ -171,7 +171,6 @@ struct _EvWindowPrivate {
        GtkActionGroup   *action_group;
        GtkActionGroup   *view_popup_action_group;
        GtkActionGroup   *attachment_popup_action_group;
-       GtkActionGroup   *zoom_selector_popup_action_group;
        GtkRecentManager *recent_manager;
        guint             bookmarks_ui_id;
        GtkUIManager     *ui_manager;
@@ -241,7 +240,6 @@ struct _EvWindowPrivate {
 #define EV_WINDOW_IS_PRESENTATION(w) (w->priv->presentation_view != NULL)
 
 #define PAGE_SELECTOR_ACTION   "PageSelector"
-#define ZOOM_CONTROL_ACTION    "ViewZoom"
 
 #define GS_LOCKDOWN_SCHEMA_NAME  "org.gnome.desktop.lockdown"
 #define GS_LOCKDOWN_SAVE         "disable-save-to-disk"
@@ -341,12 +339,6 @@ static void        ev_attachment_popup_cmd_open_attachment (GtkAction        *action,
                                                         EvWindow         *window);
 static void    ev_attachment_popup_cmd_save_attachment_as (GtkAction     *action, 
                                                         EvWindow         *window);
-static void    ev_window_cmd_view_fit_page             (GtkAction        *action,
-                                                        EvWindow         *ev_window);
-static void    ev_window_cmd_view_fit_width            (GtkAction        *action,
-                                                        EvWindow         *ev_window);
-static void     ev_window_cmd_view_zoom_automatic       (GtkAction        *action,
-                                                        EvWindow         *ev_window);
 static void    view_handle_link_cb                     (EvView           *view, 
                                                         EvLink           *link, 
                                                         EvWindow         *window);
@@ -492,7 +484,6 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window)
 
        /* Toolbar-specific actions: */
        ev_window_set_action_sensitive (ev_window, PAGE_SELECTOR_ACTION, has_pages);
-       ev_window_set_action_sensitive (ev_window, ZOOM_CONTROL_ACTION,  has_pages);
 
         ev_window_update_actions_sensitivity (ev_window);
 }
@@ -610,46 +601,27 @@ update_chrome_flag (EvWindow *window, EvChrome flag, gboolean active)
 static void
 update_sizing_buttons (EvWindow *window)
 {
-       GtkActionGroup *action_group = window->priv->zoom_selector_popup_action_group;
-       GtkAction      *action;
-       gboolean        fit_page = FALSE;
-       gboolean        fit_width = FALSE;
-       gboolean        automatic = FALSE;
+       GAction     *action;
+       const gchar *mode = NULL;
+
+       action = g_action_map_lookup_action (G_ACTION_MAP (window), "sizing-mode");
 
        switch (ev_document_model_get_sizing_mode (window->priv->model)) {
        case EV_SIZING_FIT_PAGE:
-               fit_page = TRUE;
+               mode = "fit-page";
                break;
        case EV_SIZING_FIT_WIDTH:
-               fit_width = TRUE;
+               mode = "fit-width";
                break;
        case EV_SIZING_AUTOMATIC:
-               automatic = TRUE;
+               mode = "automatic";
                break;
        case EV_SIZING_FREE:
+               mode = "free";
                break;
        }
 
-       action = gtk_action_group_get_action (action_group, "ViewFitPage");
-       g_signal_handlers_block_by_func
-               (action, G_CALLBACK (ev_window_cmd_view_fit_page), window);
-       gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), fit_page);
-       g_signal_handlers_unblock_by_func
-               (action, G_CALLBACK (ev_window_cmd_view_fit_page), window);
-
-       action = gtk_action_group_get_action (action_group, "ViewFitWidth");
-       g_signal_handlers_block_by_func
-               (action, G_CALLBACK (ev_window_cmd_view_fit_width), window);
-       gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), fit_width);
-       g_signal_handlers_unblock_by_func
-               (action, G_CALLBACK (ev_window_cmd_view_fit_width), window);
-
-       action = gtk_action_group_get_action (action_group, "ViewZoomAutomatic");
-       g_signal_handlers_block_by_func
-               (action, G_CALLBACK (ev_window_cmd_view_zoom_automatic), window);
-       gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), automatic);
-       g_signal_handlers_unblock_by_func
-               (action, G_CALLBACK (ev_window_cmd_view_zoom_automatic), window);
+       g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_string (mode));
 }
 
 /**
@@ -3747,19 +3719,6 @@ ev_window_cmd_dual_odd_pages_left (GSimpleAction *action,
 }
 
 static void
-ev_window_cmd_view_fit_page (GtkAction *action, EvWindow *ev_window)
-{
-       ev_window_stop_presentation (ev_window, TRUE);
-
-       if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
-               ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FIT_PAGE);
-       } else {
-               ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
-       }
-       ev_window_update_actions_sensitivity (ev_window);
-}
-
-static void
 ev_window_change_sizing_mode_action_state (GSimpleAction *action,
                                           GVariant      *state,
                                           gpointer       user_data)
@@ -3784,47 +3743,12 @@ ev_window_change_sizing_mode_action_state (GSimpleAction *action,
 }
 
 static void
-ev_window_cmd_view_fit_width (GtkAction *action, EvWindow *ev_window)
-{
-       ev_window_stop_presentation (ev_window, TRUE);
-
-       if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
-               ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FIT_WIDTH);
-       } else {
-               ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
-       }
-       ev_window_update_actions_sensitivity (ev_window);
-}
-
-static void
-ev_window_cmd_view_zoom_automatic (GtkAction *action,
-                                  EvWindow  *ev_window)
-{
-       ev_window_stop_presentation (ev_window, TRUE);
-
-       if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
-               ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_AUTOMATIC);
-       } else {
-               ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
-       }
-       ev_window_update_actions_sensitivity (ev_window);
-}
-
-static void
-ev_window_cmd_view_zoom_activate (GtkAction *action,
-                                 EvWindow  *ev_window)
+ev_window_cmd_view_zoom (GSimpleAction *action,
+                        GVariant      *parameter,
+                        gpointer       user_data)
 {
-       const char *action_name = gtk_action_get_name (action);
-       gdouble     zoom = 0;
-       guint       i;
-
-       for (i = 0; i < G_N_ELEMENTS (zoom_levels); i++) {
-               if (strcmp (action_name, zoom_levels[i].name) == 0) {
-                       zoom = zoom_levels[i].level;
-                       break;
-               }
-       }
-       g_assert (zoom > 0);
+       EvWindow *ev_window = user_data;
+       gdouble zoom = g_variant_get_double (parameter);
 
        ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
        ev_document_model_set_scale (ev_window->priv->model,
@@ -4764,27 +4688,6 @@ ev_window_zoom_changed_cb (EvDocumentModel *model, GParamSpec *pspec, EvWindow *
 }
 
 static void
-ev_window_setup_zoom_actions_visibility (EvWindow *window,
-                                        gdouble   max_scale)
-{
-       GtkActionGroup *action_group = window->priv->zoom_selector_popup_action_group;
-       guint           i;
-
-       for (i = 0; i < G_N_ELEMENTS (zoom_levels); i++) {
-               GtkAction *action;
-
-               action = gtk_action_group_get_action (action_group, zoom_levels[i].name);
-               gtk_action_set_visible (action, zoom_levels[i].level <= max_scale);
-       }
-}
-
-static void
-ev_window_max_zoom_changed_cb (EvDocumentModel *model, GParamSpec *pspec, EvWindow *window)
-{
-       ev_window_setup_zoom_actions_visibility (window, ev_document_model_get_max_scale (model));
-}
-
-static void
 ev_window_continuous_changed_cb (EvDocumentModel *model,
                                 GParamSpec      *pspec,
                                 EvWindow        *ev_window)
@@ -5565,8 +5468,6 @@ ev_window_dispose (GObject *object)
                priv->attachment_popup_action_group = NULL;
        }
 
-       g_clear_object (&priv->zoom_selector_popup_action_group);
-
        g_clear_object (&priv->bookmarks_menu);
 
        if (priv->recent_manager) {
@@ -5804,6 +5705,7 @@ static const GActionEntry actions[] = {
        { "scroll-forward", ev_window_cmd_scroll_forward },
        { "scroll-backwards", ev_window_cmd_scroll_backwards },
        { "sizing-mode", NULL, "s", "'free'", ev_window_change_sizing_mode_action_state },
+       { "zoom", ev_window_cmd_view_zoom, "d" },
        { "escape", ev_window_cmd_escape },
        { "open-menu", ev_window_cmd_action_menu },
        { "caret-navigation", NULL, NULL, "false", ev_window_cmd_view_toggle_caret_navigation },
@@ -5835,17 +5737,6 @@ static const GtkActionEntry attachment_popup_entries [] = {
          NULL, G_CALLBACK (ev_attachment_popup_cmd_save_attachment_as) },
 };
 
-static const GtkToggleActionEntry zoom_selector_popup_actions[] = {
-       { "ViewFitPage", EV_STOCK_ZOOM_PAGE, N_("Fit Pa_ge"), NULL,
-         N_("Make the current document fill the window"),
-         G_CALLBACK (ev_window_cmd_view_fit_page) },
-       { "ViewFitWidth", EV_STOCK_ZOOM_WIDTH, N_("Fit _Width"), NULL,
-         N_("Make the current document fill the window width"),
-         G_CALLBACK (ev_window_cmd_view_fit_width) },
-       { "ViewZoomAutomatic", NULL, N_("_Automatic"), NULL, NULL,
-         G_CALLBACK (ev_window_cmd_view_zoom_automatic) }
-};
-
 static void
 sidebar_links_link_activated_cb (EvSidebarLinks *sidebar_links, EvLink *link, EvWindow *window)
 {
@@ -5909,43 +5800,6 @@ sidebar_annots_annot_add_cancelled (EvSidebarAnnotations *sidebar_annots,
 }
 
 static void
-zoom_action_activated_cb (EvZoomAction *action,
-                         EvWindow     *window)
-{
-       gtk_widget_grab_focus (window->priv->view);
-}
-
-static void
-ev_window_register_zoom_selector_popup_actions (EvWindow *window)
-{
-       GtkActionGroup *action_group = window->priv->zoom_selector_popup_action_group;
-       guint           i, new_ui_id;
-
-       new_ui_id = gtk_ui_manager_new_merge_id (window->priv->ui_manager);
-
-       for (i = 0; i < G_N_ELEMENTS (zoom_levels); i++) {
-               GtkAction *action;
-
-               action = gtk_action_new (zoom_levels[i].name,
-                                        _(zoom_levels[i].name),
-                                        NULL, NULL);
-               g_signal_connect (action, "activate",
-                                 G_CALLBACK (ev_window_cmd_view_zoom_activate),
-                                 window);
-               gtk_action_group_add_action (action_group, action);
-               g_object_unref (action);
-
-               gtk_ui_manager_add_ui (window->priv->ui_manager,
-                                      new_ui_id,
-                                      "/ZoomSelectorPopup/ViewZoomItems",
-                                      _(zoom_levels[i].name),
-                                      zoom_levels[i].name,
-                                      GTK_UI_MANAGER_MENUITEM,
-                                      FALSE);
-       }
-}
-
-static void
 register_custom_actions (EvWindow *window, GtkActionGroup *group)
 {
        GtkAction *action;
@@ -5963,21 +5817,6 @@ register_custom_actions (EvWindow *window, GtkActionGroup *group)
                          G_CALLBACK (activate_link_cb), window);
        gtk_action_group_add_action (group, action);
        g_object_unref (action);
-
-       action = g_object_new (EV_TYPE_ZOOM_ACTION,
-                              "name", ZOOM_CONTROL_ACTION,
-                              "label", _("Zoom"),
-                              "stock_id", EV_STOCK_ZOOM,
-                              "tooltip", _("Adjust the zoom level"),
-                              NULL);
-       ev_zoom_action_set_model (EV_ZOOM_ACTION (action),
-                                 window->priv->model);
-       ev_zoom_action_set_window (EV_ZOOM_ACTION (action),
-                                  window);
-       g_signal_connect (action, "activated",
-                         G_CALLBACK (zoom_action_activated_cb), window);
-       gtk_action_group_add_action (group, action);
-       g_object_unref (action);
 }
 
 static void
@@ -6958,22 +6797,11 @@ ev_window_init (EvWindow *ev_window)
        gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
                                            action_group, 0);
 
-       action_group = gtk_action_group_new ("ZoomSelectorPopupActions");
-       ev_window->priv->zoom_selector_popup_action_group = action_group;
-       gtk_action_group_set_translation_domain (action_group, NULL);
-       gtk_action_group_add_toggle_actions (action_group, zoom_selector_popup_actions,
-                                            G_N_ELEMENTS (zoom_selector_popup_actions),
-                                            ev_window);
-       gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
-                                           action_group, 0);
-
         gtk_ui_manager_add_ui_from_resource (ev_window->priv->ui_manager,
                                              "/org/gnome/evince/shell/ui/evince.xml",
                                              &error);
         g_assert_no_error (error);
 
-       ev_window_register_zoom_selector_popup_actions (ev_window);
-
        css_provider = gtk_css_provider_new ();
        _gtk_css_provider_load_from_resource (css_provider,
                                              "/org/gnome/evince/shell/ui/evince.css",
@@ -7195,10 +7023,6 @@ ev_window_init (EvWindow *ev_window)
                          G_CALLBACK (ev_window_zoom_changed_cb),
                          ev_window);
        g_signal_connect (ev_window->priv->model,
-                         "notify::max-scale",
-                         G_CALLBACK (ev_window_max_zoom_changed_cb),
-                         ev_window);
-       g_signal_connect (ev_window->priv->model,
                          "notify::sizing-mode",
                          G_CALLBACK (ev_window_sizing_mode_changed_cb),
                          ev_window);
@@ -7348,14 +7172,6 @@ ev_window_get_main_action_group (EvWindow *ev_window)
        return ev_window->priv->action_group;
 }
 
-GtkActionGroup *
-ev_window_get_zoom_selector_action_group (EvWindow *ev_window)
-{
-       g_return_val_if_fail (EV_WINDOW (ev_window), NULL);
-
-       return ev_window->priv->zoom_selector_popup_action_group;
-}
-
 GMenuModel *
 ev_window_get_bookmarks_menu (EvWindow *ev_window)
 {
@@ -7371,3 +7187,19 @@ ev_window_get_history (EvWindow *ev_window)
 
        return ev_window->priv->history;
 }
+
+EvDocumentModel *
+ev_window_get_document_model (EvWindow *ev_window)
+{
+       g_return_val_if_fail (EV_WINDOW (ev_window), NULL);
+
+       return ev_window->priv->model;
+}
+
+void
+ev_window_focus_view (EvWindow *ev_window)
+{
+       g_return_if_fail (EV_WINDOW (ev_window));
+
+       gtk_widget_grab_focus (ev_window->priv->view);
+}
diff --git a/shell/ev-window.h b/shell/ev-window.h
index d074073..cabd9c9 100644
--- a/shell/ev-window.h
+++ b/shell/ev-window.h
@@ -28,6 +28,7 @@
 
 #include "ev-link.h"
 #include "ev-history.h"
+#include "ev-document-model.h"
 
 G_BEGIN_DECLS
 
@@ -89,9 +90,10 @@ void         ev_window_print_range                    (EvWindow       *ev_window,
 const gchar    *ev_window_get_dbus_object_path           (EvWindow       *ev_window);
 GtkUIManager   *ev_window_get_ui_manager                 (EvWindow       *ev_window);
 GtkActionGroup *ev_window_get_main_action_group          (EvWindow       *ev_window);
-GtkActionGroup *ev_window_get_zoom_selector_action_group (EvWindow       *ev_window);
 GMenuModel     *ev_window_get_bookmarks_menu             (EvWindow       *ev_window);
 EvHistory      *ev_window_get_history                    (EvWindow       *ev_window);
+EvDocumentModel *ev_window_get_document_model            (EvWindow       *ev_window);
+void            ev_window_focus_view                     (EvWindow       *ev_window);
 
 G_END_DECLS
 
diff --git a/shell/ev-zoom-action.c b/shell/ev-zoom-action.c
index 2e974d7..86b1929 100644
--- a/shell/ev-zoom-action.c
+++ b/shell/ev-zoom-action.c
@@ -19,70 +19,458 @@
  */
 
 #include "config.h"
-
 #include "ev-zoom-action.h"
-#include "ev-zoom-action-widget.h"
+
+#include <glib/gi18n.h>
 
 enum {
         ACTIVATED,
         LAST_SIGNAL
 };
 
+enum
+{
+        PROP_0,
+
+        PROP_DOCUMENT_MODEL,
+        PROP_MENU
+};
+
+enum {
+        ZOOM_MODES_SECTION,
+        ZOOM_FREE_SECTION
+};
+
+static const struct {
+        const gchar *name;
+        float        level;
+} zoom_levels[] = {
+        { N_("50%"), 0.5 },
+        { N_("70%"), 0.7071067811 },
+        { N_("85%"), 0.8408964152 },
+        { N_("100%"), 1.0 },
+        { N_("125%"), 1.1892071149 },
+        { N_("150%"), 1.4142135623 },
+        { N_("175%"), 1.6817928304 },
+        { N_("200%"), 2.0 },
+        { N_("300%"), 2.8284271247 },
+        { N_("400%"), 4.0 },
+        { N_("800%"), 8.0 },
+        { N_("1600%"), 16.0 },
+        { N_("3200%"), 32.0 },
+        { N_("6400%"), 64.0 }
+};
 
 struct _EvZoomActionPrivate {
+        GtkWidget       *entry;
+
         EvDocumentModel *model;
-        EvWindow        *window;
+        GMenu           *menu;
+
+        GMenuModel      *zoom_free_section;
+        GtkWidget       *popup;
         gboolean         popup_shown;
 };
 
-G_DEFINE_TYPE (EvZoomAction, ev_zoom_action, GTK_TYPE_ACTION)
+G_DEFINE_TYPE (EvZoomAction, ev_zoom_action, GTK_TYPE_BOX)
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
+#define EPSILON 0.000001
+
+static void
+ev_zoom_action_set_zoom_level (EvZoomAction *zoom_action,
+                               float         zoom)
+{
+        gchar *zoom_str;
+        float  zoom_perc;
+        guint  i;
+
+        for (i = 3; i < G_N_ELEMENTS (zoom_levels); i++) {
+                if (ABS (zoom - zoom_levels[i].level) < EPSILON) {
+                        gtk_entry_set_text (GTK_ENTRY (zoom_action->priv->entry),
+                                            zoom_levels[i].name);
+                        return;
+                }
+        }
+
+        zoom_perc = zoom * 100.;
+        if (ABS ((gint)zoom_perc - zoom_perc) < 0.001)
+                zoom_str = g_strdup_printf ("%d%%", (gint)zoom_perc);
+        else
+                zoom_str = g_strdup_printf ("%.2f%%", zoom_perc);
+        gtk_entry_set_text (GTK_ENTRY (zoom_action->priv->entry), zoom_str);
+        g_free (zoom_str);
+}
+
+static void
+ev_zoom_action_update_zoom_level (EvZoomAction *zoom_action)
+{
+        float      zoom = ev_document_model_get_scale (zoom_action->priv->model);
+        GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (zoom_action));
+
+        zoom *= 72.0 / ev_document_misc_get_screen_dpi (screen);
+        ev_zoom_action_set_zoom_level (zoom_action, zoom);
+}
+
+static void
+zoom_changed_cb (EvDocumentModel *model,
+                 GParamSpec      *pspec,
+                 EvZoomAction    *zoom_action)
+{
+        ev_zoom_action_update_zoom_level (zoom_action);
+}
+
+static void
+document_changed_cb (EvDocumentModel *model,
+                     GParamSpec      *pspec,
+                     EvZoomAction    *zoom_action)
+{
+        EvDocument *document = ev_document_model_get_document (model);
+
+        if (!document) {
+                gtk_widget_set_sensitive (GTK_WIDGET (zoom_action), FALSE);
+                return;
+        }
+        gtk_widget_set_sensitive (GTK_WIDGET (zoom_action), ev_document_get_n_pages (document) > 0);
+
+        ev_zoom_action_update_zoom_level (zoom_action);
+}
+
+static void
+ev_zoom_action_populate_free_zoom_section (EvZoomAction *zoom_action)
+{
+        gdouble max_scale;
+        guint   i;
+
+        max_scale = ev_document_model_get_max_scale (zoom_action->priv->model);
+
+        for (i = 0; i < G_N_ELEMENTS (zoom_levels); i++) {
+                GMenuItem *item;
+
+                if (zoom_levels[i].level > max_scale)
+                        break;
+
+                item = g_menu_item_new (zoom_levels[i].name, NULL);
+                g_menu_item_set_action_and_target (item, "win.zoom",
+                                                   "d", zoom_levels[i].level);
+                g_menu_append_item (G_MENU (zoom_action->priv->zoom_free_section), item);
+                g_object_unref (item);
+        }
+}
+
 static void
-popup_shown_cb (GObject      *zoom_widget,
-                GParamSpec   *pspec,
-                EvZoomAction *zoom_action)
+max_zoom_changed_cb (EvDocumentModel *model,
+                     GParamSpec      *pspec,
+                     EvZoomAction    *zoom_action)
 {
-        g_object_get (zoom_widget, "popup-shown", &zoom_action->priv->popup_shown, NULL);
+        g_menu_remove_all (G_MENU (zoom_action->priv->zoom_free_section));
+        g_clear_pointer (&zoom_action->priv->popup, (GDestroyNotify)gtk_widget_destroy);
+        ev_zoom_action_populate_free_zoom_section (zoom_action);
 }
 
 static void
-zoom_widget_activated_cb (GtkEntry     *entry,
-                          EvZoomAction *zoom_action)
+entry_activated_cb (GtkEntry     *entry,
+                    EvZoomAction *zoom_action)
 {
+        GdkScreen   *screen;
+        double       zoom_perc;
+        float        zoom;
+        const gchar *text = gtk_entry_get_text (entry);
+        gchar       *end_ptr = NULL;
+
+        if (!text || text[0] == '\0') {
+                ev_zoom_action_update_zoom_level (zoom_action);
+                g_signal_emit (zoom_action, signals[ACTIVATED], 0, NULL);
+                return;
+        }
+
+        zoom_perc = g_strtod (text, &end_ptr);
+        if (end_ptr && end_ptr[0] != '\0' && end_ptr[0] != '%') {
+                ev_zoom_action_update_zoom_level (zoom_action);
+                g_signal_emit (zoom_action, signals[ACTIVATED], 0, NULL);
+                return;
+        }
+
+        screen = gtk_widget_get_screen (GTK_WIDGET (zoom_action));
+        zoom = zoom_perc / 100.;
+        ev_document_model_set_sizing_mode (zoom_action->priv->model, EV_SIZING_FREE);
+        ev_document_model_set_scale (zoom_action->priv->model,
+                                     zoom * ev_document_misc_get_screen_dpi (screen) / 72.0);
         g_signal_emit (zoom_action, signals[ACTIVATED], 0, NULL);
 }
 
+static gboolean
+focus_out_cb (EvZoomAction *zoom_action)
+{
+        ev_zoom_action_update_zoom_level (zoom_action);
+
+        return FALSE;
+}
+
+static void
+popup_menu_show_cb (GtkWidget    *widget,
+                    EvZoomAction *zoom_action)
+{
+        zoom_action->priv->popup_shown = TRUE;
+}
+
+static void
+popup_menu_hide_cb (GtkWidget    *widget,
+                    EvZoomAction *zoom_action)
+{
+        zoom_action->priv->popup_shown = FALSE;
+}
+
+static void
+popup_menu_detached (EvZoomAction *zoom_action,
+                     GtkWidget    *popup)
+{
+        GtkWidget *toplevel;
+
+        if (zoom_action->priv->popup != popup)
+                return;
+
+        toplevel = gtk_widget_get_toplevel (zoom_action->priv->popup);
+        g_signal_handlers_disconnect_by_func (toplevel,
+                                              popup_menu_show_cb,
+                                              zoom_action);
+        g_signal_handlers_disconnect_by_func (toplevel,
+                                              popup_menu_hide_cb,
+                                              zoom_action);
+
+        zoom_action->priv->popup = NULL;
+}
+
+static GtkWidget *
+get_popup (EvZoomAction *zoom_action)
+{
+        GtkWidget *toplevel;
+
+        if (zoom_action->priv->popup)
+                return zoom_action->priv->popup;
+
+        zoom_action->priv->popup = gtk_menu_new_from_model (G_MENU_MODEL (zoom_action->priv->menu));
+        gtk_menu_attach_to_widget (GTK_MENU (zoom_action->priv->popup),
+                                   GTK_WIDGET (zoom_action),
+                                   (GtkMenuDetachFunc)popup_menu_detached);
+        toplevel = gtk_widget_get_toplevel (zoom_action->priv->popup);
+        g_signal_connect (toplevel, "show",
+                          G_CALLBACK (popup_menu_show_cb),
+                          zoom_action);
+        g_signal_connect (toplevel, "hide",
+                          G_CALLBACK (popup_menu_hide_cb),
+                          zoom_action);
+
+        return zoom_action->priv->popup;
+}
+
+
+static void
+menu_position_below (GtkMenu  *menu,
+                     gint     *x,
+                     gint     *y,
+                     gint     *push_in,
+                     gpointer  user_data)
+{
+        EvZoomAction  *zoom_action;
+        GtkWidget     *widget;
+        GtkAllocation  child_allocation;
+        GtkRequisition req;
+        GdkScreen     *screen;
+        gint           monitor_num;
+        GdkRectangle   monitor;
+        gint           sx = 0, sy = 0;
+
+        zoom_action = EV_ZOOM_ACTION (user_data);
+        widget = GTK_WIDGET (zoom_action);
+
+        gtk_widget_get_allocation (zoom_action->priv->entry, &child_allocation);
+
+        if (!gtk_widget_get_has_window (zoom_action->priv->entry)) {
+                sx += child_allocation.x;
+                sy += child_allocation.y;
+        }
+
+        gdk_window_get_root_coords (gtk_widget_get_window (zoom_action->priv->entry),
+                                    sx, sy, &sx, &sy);
+
+        gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
+
+        if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+                *x = sx;
+        else
+                *x = sx + child_allocation.width - req.width;
+        *y = sy;
+
+        screen = gtk_widget_get_screen (widget);
+        monitor_num = gdk_screen_get_monitor_at_window (screen,
+                                                        gtk_widget_get_window (widget));
+        gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+        if (*x < monitor.x)
+                *x = monitor.x;
+        else if (*x + req.width > monitor.x + monitor.width)
+                *x = monitor.x + monitor.width - req.width;
+
+        if (monitor.y + monitor.height - *y - child_allocation.height >= req.height)
+                *y += child_allocation.height;
+        else if (*y - monitor.y >= req.height)
+                *y -= req.height;
+        else if (monitor.y + monitor.height - *y - child_allocation.height > *y - monitor.y)
+                *y += child_allocation.height;
+        else
+                *y -= req.height;
+
+        *push_in = FALSE;
+}
+
+static void
+entry_icon_press_callback (GtkEntry            *entry,
+                           GtkEntryIconPosition icon_pos,
+                           GdkEventButton      *event,
+                           EvZoomAction        *zoom_action)
+{
+        GtkWidget *menu;
+
+        if (event->button != GDK_BUTTON_PRIMARY)
+                return;
+
+        menu = get_popup (zoom_action);
+        gtk_widget_set_size_request (menu,
+                                     gtk_widget_get_allocated_width (GTK_WIDGET (zoom_action)),
+                                     -1);
+
+        gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+                        menu_position_below, zoom_action,
+                        event->button, event->time);
+}
+
+static void
+ev_zoom_action_finalize (GObject *object)
+{
+        EvZoomAction *zoom_action = EV_ZOOM_ACTION (object);
+
+        if (zoom_action->priv->model) {
+                g_object_remove_weak_pointer (G_OBJECT (zoom_action->priv->model),
+                                              (gpointer)&zoom_action->priv->model);
+        }
+
+        g_clear_object (&zoom_action->priv->zoom_free_section);
+
+        G_OBJECT_CLASS (ev_zoom_action_parent_class)->finalize (object);
+}
+
+static void
+ev_zoom_action_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+        EvZoomAction *zoom_action = EV_ZOOM_ACTION (object);
+
+        switch (prop_id) {
+        case PROP_DOCUMENT_MODEL:
+                zoom_action->priv->model = g_value_get_object (value);
+                break;
+        case PROP_MENU:
+                zoom_action->priv->menu = g_value_get_object (value);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        }
+}
+
 static void
-connect_proxy (GtkAction *action,
-               GtkWidget *proxy)
+setup_initial_entry_size (EvZoomAction *zoom_action)
 {
-        if (EV_IS_ZOOM_ACTION_WIDGET (proxy))   {
-                EvZoomAction *zoom_action = EV_ZOOM_ACTION (action);
-                EvZoomActionWidget* zoom_widget = EV_ZOOM_ACTION_WIDGET (proxy);
+        GMenuModel *menu;
+        guint       i;
+        gint        n_items;
+        gint        width = 0;
+
+        menu = g_menu_model_get_item_link (G_MENU_MODEL (zoom_action->priv->menu),
+                                           ZOOM_MODES_SECTION, G_MENU_LINK_SECTION);
+
+        n_items = g_menu_model_get_n_items (menu);
+        for (i = 0; i < n_items; i++) {
+                GVariant *value;
+                gint      length;
 
-                ev_zoom_action_widget_set_model (zoom_widget, zoom_action->priv->model);
-                ev_zoom_action_widget_set_window (zoom_widget, zoom_action->priv->window);
-                g_signal_connect (zoom_widget, "notify::popup-shown",
-                                  G_CALLBACK (popup_shown_cb),
-                                  action);
-                g_signal_connect (ev_zoom_action_widget_get_entry (zoom_widget), "activate",
-                                  G_CALLBACK (zoom_widget_activated_cb),
-                                  action);
+                value = g_menu_model_get_item_attribute_value (menu, i, G_MENU_ATTRIBUTE_LABEL, NULL);
+                length = g_utf8_strlen (g_variant_get_string (value, NULL), -1);
+                if (length > width)
+                        width = length;
+                g_variant_unref (value);
         }
+        g_object_unref (menu);
 
-        GTK_ACTION_CLASS (ev_zoom_action_parent_class)->connect_proxy (action, proxy);
+        /* Count the toggle size as one character more */
+        gtk_entry_set_width_chars (GTK_ENTRY (zoom_action->priv->entry), width + 1);
+}
+
+static void
+ev_zoom_action_constructed (GObject *object)
+{
+        EvZoomAction *zoom_action = EV_ZOOM_ACTION (object);
+
+        G_OBJECT_CLASS (ev_zoom_action_parent_class)->constructed (object);
+
+        zoom_action->priv->zoom_free_section =
+                g_menu_model_get_item_link (G_MENU_MODEL (zoom_action->priv->menu),
+                                            ZOOM_FREE_SECTION, G_MENU_LINK_SECTION);
+        ev_zoom_action_populate_free_zoom_section (zoom_action);
+
+        g_object_add_weak_pointer (G_OBJECT (zoom_action->priv->model),
+                                   (gpointer)&zoom_action->priv->model);
+        if (ev_document_model_get_document (zoom_action->priv->model)) {
+                ev_zoom_action_update_zoom_level (zoom_action);
+        } else {
+                ev_zoom_action_set_zoom_level (zoom_action, 1.);
+                gtk_widget_set_sensitive (GTK_WIDGET (zoom_action), FALSE);
+        }
+
+        g_signal_connect (zoom_action->priv->model, "notify::document",
+                          G_CALLBACK (document_changed_cb),
+                          zoom_action);
+        g_signal_connect (zoom_action->priv->model, "notify::scale",
+                          G_CALLBACK (zoom_changed_cb),
+                          zoom_action);
+        g_signal_connect (zoom_action->priv->model, "notify::max-scale",
+                          G_CALLBACK (max_zoom_changed_cb),
+                          zoom_action);
+
+        setup_initial_entry_size (zoom_action);
 }
 
 static void
 ev_zoom_action_class_init (EvZoomActionClass *class)
 {
         GObjectClass *object_class = G_OBJECT_CLASS (class);
-        GtkActionClass *action_class = GTK_ACTION_CLASS (class);
 
-        action_class->toolbar_item_type = EV_TYPE_ZOOM_ACTION_WIDGET;
-        action_class->connect_proxy = connect_proxy;
+        object_class->finalize = ev_zoom_action_finalize;
+        object_class->constructed = ev_zoom_action_constructed;
+        object_class->set_property = ev_zoom_action_set_property;
+
+        g_object_class_install_property (object_class,
+                                         PROP_DOCUMENT_MODEL,
+                                         g_param_spec_object ("document-model",
+                                                              "DocumentModel",
+                                                              "The document model",
+                                                              EV_TYPE_DOCUMENT_MODEL,
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT_ONLY |
+                                                              G_PARAM_STATIC_STRINGS));
+
+        g_object_class_install_property (object_class,
+                                         PROP_MENU,
+                                         g_param_spec_object ("menu",
+                                                              "Menu",
+                                                              "The zoom popup menu",
+                                                              G_TYPE_MENU,
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT_ONLY |
+                                                              G_PARAM_STATIC_STRINGS));
 
         signals[ACTIVATED] =
                 g_signal_new ("activated",
@@ -96,50 +484,44 @@ ev_zoom_action_class_init (EvZoomActionClass *class)
 }
 
 static void
-ev_zoom_action_init (EvZoomAction *action)
+ev_zoom_action_init (EvZoomAction *zoom_action)
 {
-        action->priv = G_TYPE_INSTANCE_GET_PRIVATE (action, EV_TYPE_ZOOM_ACTION, EvZoomActionPrivate);
-}
+        EvZoomActionPrivate *priv;
 
-void
-ev_zoom_action_set_model (EvZoomAction    *action,
-                          EvDocumentModel *model)
-{
-        GSList *proxies, *l;
+        zoom_action->priv = G_TYPE_INSTANCE_GET_PRIVATE (zoom_action, EV_TYPE_ZOOM_ACTION, 
EvZoomActionPrivate);
+        priv = zoom_action->priv;
 
-        g_return_if_fail (EV_IS_ZOOM_ACTION (action));
-        g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+        gtk_orientable_set_orientation (GTK_ORIENTABLE (zoom_action), GTK_ORIENTATION_VERTICAL);
 
-        if (action->priv->model == model)
-                return;
+        priv->entry = gtk_entry_new ();
+        gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv->entry),
+                                           GTK_ENTRY_ICON_SECONDARY,
+                                           "go-down-symbolic");
+        gtk_box_pack_start (GTK_BOX (zoom_action), priv->entry, TRUE, FALSE, 0);
+        gtk_widget_show (priv->entry);
 
-        action->priv->model = model;
-        proxies = gtk_action_get_proxies (GTK_ACTION (action));
-        for (l = proxies; l && l->data; l = g_slist_next (l)) {
-                if (EV_IS_ZOOM_ACTION_WIDGET (l->data))
-                        ev_zoom_action_widget_set_model (EV_ZOOM_ACTION_WIDGET (l->data), model);
-        }
+        g_signal_connect (priv->entry, "icon-press",
+                          G_CALLBACK (entry_icon_press_callback),
+                          zoom_action);
+        g_signal_connect (priv->entry, "activate",
+                          G_CALLBACK (entry_activated_cb),
+                          zoom_action);
+        g_signal_connect_swapped (priv->entry, "focus-out-event",
+                                  G_CALLBACK (focus_out_cb),
+                                  zoom_action);
 }
 
-void
-ev_zoom_action_set_window (EvZoomAction *action,
-                           EvWindow     *window)
+GtkWidget *
+ev_zoom_action_new (EvDocumentModel *model,
+                    GMenu           *menu)
 {
+        g_return_val_if_fail (EV_IS_DOCUMENT_MODEL (model), NULL);
+        g_return_val_if_fail (G_IS_MENU (menu), NULL);
 
-        GSList *proxies, *l;
-
-        g_return_if_fail (EV_IS_ZOOM_ACTION (action));
-        g_return_if_fail (EV_IS_WINDOW (window));
-
-        if (action->priv->window == window)
-                return;
-
-        action->priv->window = window;
-        proxies = gtk_action_get_proxies (GTK_ACTION (action));
-        for (l = proxies; l && l->data; l = g_slist_next (l)) {
-                if (EV_IS_ZOOM_ACTION_WIDGET (l->data))
-                        ev_zoom_action_widget_set_window (EV_ZOOM_ACTION_WIDGET (l->data), window);
-        }
+        return GTK_WIDGET (g_object_new (EV_TYPE_ZOOM_ACTION,
+                                         "document-model", model,
+                                         "menu", menu,
+                                         NULL));
 }
 
 gboolean
diff --git a/shell/ev-zoom-action.h b/shell/ev-zoom-action.h
index 67a23f4..8da4ff8 100644
--- a/shell/ev-zoom-action.h
+++ b/shell/ev-zoom-action.h
@@ -25,8 +25,6 @@
 #include <evince-document.h>
 #include <evince-view.h>
 
-#include "ev-window.h"
-
 G_BEGIN_DECLS
 
 #define EV_TYPE_ZOOM_ACTION            (ev_zoom_action_get_type ())
@@ -41,42 +39,20 @@ typedef struct _EvZoomActionClass   EvZoomActionClass;
 typedef struct _EvZoomActionPrivate EvZoomActionPrivate;
 
 struct _EvZoomAction {
-        GtkAction parent;
+        GtkBox parent;
 
         EvZoomActionPrivate *priv;
 };
 
 struct _EvZoomActionClass {
-        GtkActionClass parent_class;
-};
-
-static const struct {
-        const gchar *name;
-        float        level;
-} zoom_levels[] = {
-        { "50%", 0.5 },
-        { "70%", 0.7071067811 },
-        { "85%", 0.8408964152 },
-        { "100%", 1.0 },
-        { "125%", 1.1892071149 },
-        { "150%", 1.4142135623 },
-        { "175%", 1.6817928304 },
-        { "200%", 2.0 },
-        { "300%", 2.8284271247 },
-        { "400%", 4.0 },
-        { "800%", 8.0 },
-        { "1600%", 16.0 },
-        { "3200%", 32.0 },
-        { "6400%", 64.0 }
+        GtkBoxClass parent_class;
 };
 
-GType    ev_zoom_action_get_type        (void);
+GType      ev_zoom_action_get_type        (void);
 
-void     ev_zoom_action_set_model       (EvZoomAction    *action,
-                                         EvDocumentModel *model);
-gboolean ev_zoom_action_get_popup_shown (EvZoomAction    *action);
-void     ev_zoom_action_set_window      (EvZoomAction    *action,
-                                         EvWindow        *window);
+GtkWidget *ev_zoom_action_new             (EvDocumentModel *model,
+                                           GMenu           *menu);
+gboolean   ev_zoom_action_get_popup_shown (EvZoomAction    *action);
 
 G_END_DECLS
 
diff --git a/shell/evince-menus.ui b/shell/evince-menus.ui
index b69c341..d148e1c 100644
--- a/shell/evince-menus.ui
+++ b/shell/evince-menus.ui
@@ -174,4 +174,28 @@
       </item>
     </section>
   </menu>
+
+  <menu id="zoom-menu">
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Fit Pa_ge</attribute>
+        <attribute name="action">win.sizing-mode</attribute>
+        <attribute name="target">fit-page</attribute>
+        <attribute name="accel">f</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Fit _Width</attribute>
+        <attribute name="action">win.sizing-mode</attribute>
+        <attribute name="target">fit-width</attribute>
+        <attribute name="accel">w</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Automatic</attribute>
+        <attribute name="action">win.sizing-mode</attribute>
+        <attribute name="target">automatic</attribute>
+      </item>
+    </section>
+    <section>
+    </section>
+  </menu>
 </interface>
diff --git a/shell/evince-ui.xml b/shell/evince-ui.xml
index ae51200..b4e1ba1 100644
--- a/shell/evince-ui.xml
+++ b/shell/evince-ui.xml
@@ -19,12 +19,4 @@
     <separator/>
     <menuitem name="SaveAttachmentAs" action="SaveAttachmentAs"/>
   </popup>
-
-  <popup name="ZoomSelectorPopup">
-    <menuitem name="ViewFitPage" action="ViewFitPage"/>
-    <menuitem name="ViewFitWidth" action="ViewFitWidth"/>
-    <menuitem name="ViewZoomAutomatic" action="ViewZoomAutomatic"/>
-    <separator/>
-    <placeholder name="ViewZoomItems"/>
-  </popup>
 </ui>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]