24 #include <glib/gi18n-lib.h>
25 #include <gdk/gdkkeysyms.h>
100 GtkScrollType scroll);
112 #define HIDE_CURSOR_TIMEOUT 5
116 #if !GTK_CHECK_VERSION(3, 20, 0)
117 static GdkRGBA
black = { 0., 0., 0., 1. };
118 static GdkRGBA
white = { 1., 1., 1., 1. };
124 GtkWidget *widget = GTK_WIDGET (pview);
130 #if GTK_CHECK_VERSION(3, 20, 0)
131 gtk_style_context_remove_class (gtk_widget_get_style_context (widget),
134 gdk_window_set_background_rgba (gtk_widget_get_window (widget), &black);
135 gtk_widget_queue_draw (widget);
142 GtkWidget *widget = GTK_WIDGET (pview);
148 #if GTK_CHECK_VERSION(3, 20, 0)
149 gtk_style_context_remove_class (gtk_widget_get_style_context (widget),
152 gdk_window_set_background_rgba (gtk_widget_get_window (widget), &black);
153 gtk_widget_queue_draw (widget);
160 GtkWidget *widget = GTK_WIDGET (pview);
166 #if GTK_CHECK_VERSION(3, 20, 0)
167 gtk_style_context_add_class (gtk_widget_get_style_context (widget),
170 gdk_window_set_background_rgba (gtk_widget_get_window (widget), &white);
171 gtk_widget_queue_draw (widget);
178 GtkWidget *widget = GTK_WIDGET (pview);
184 gtk_widget_queue_draw (widget);
193 gdouble width, height;
204 if (pview->
monitor_width / width < pview->monitor_height / height) {
206 *view_height = (int)((pview->
monitor_width / width) * height + 0.5);
208 *view_width = (int)((pview->
monitor_height / height) * width + 0.5);
217 GtkWidget *widget = GTK_WIDGET (pview);
218 GtkAllocation allocation;
219 gint view_width, view_height;
222 &view_width, &view_height);
224 gtk_widget_get_allocation (widget, &allocation);
226 area->x = (MAX (0, allocation.width - view_width)) / 2;
227 area->y = (MAX (0, allocation.height - view_height)) / 2;
228 area->width = view_width;
229 area->height = view_height;
263 g_timeout_add_seconds (duration,
284 gtk_widget_queue_draw (GTK_WIDGET (pview));
291 gtk_widget_queue_draw (GTK_WIDGET (pview));
294 static cairo_surface_t *
298 cairo_surface_t *surface;
307 #ifdef HAVE_HIDPI_SUPPORT
309 int scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (pview));
310 cairo_surface_set_device_scale (surface, scale_factor, scale_factor);
323 cairo_surface_t *surface;
355 g_signal_connect_swapped (pview->
animation,
"frame",
358 g_signal_connect_swapped (pview->
animation,
"finished",
381 gtk_widget_queue_draw (GTK_WIDGET (pview));
391 int view_width, view_height;
397 #ifdef HAVE_HIDPI_SUPPORT
399 gint device_scale = gtk_widget_get_scale_factor (GTK_WIDGET (pview));
400 view_width *= device_scale;
401 view_height *= device_scale;
405 view_width, view_height);
406 g_signal_connect (job,
"finished",
423 g_object_unref (job);
535 g_object_notify (G_OBJECT (pview),
"current-page");
549 gtk_widget_queue_draw (GTK_WIDGET (pview));
559 if (!gtk_widget_get_realized (GTK_WIDGET (pview))) {
561 g_object_notify (G_OBJECT (pview),
"current-page");
573 switch (pview->
state) {
586 if (new_page == n_pages)
597 switch (pview->
state) {
615 #define KEY_IS_NUMERIC(keyval) \
616 ((keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9) || (keyval >= GDK_KEY_KP_0 && keyval <= GDK_KEY_KP_9))
623 GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
625 fevent->focus_change.type = GDK_FOCUS_CHANGE;
626 fevent->focus_change.window = gtk_widget_get_window (widget);
627 fevent->focus_change.in = in;
628 if (fevent->focus_change.window)
629 g_object_ref (fevent->focus_change.window);
631 gtk_widget_send_focus_change (widget, fevent);
633 gdk_event_free (fevent);
642 gtk_entry_set_text (GTK_ENTRY (pview->
goto_entry),
"");
660 switch (event->keyval) {
664 case GDK_KEY_ISO_Left_Tab:
668 case GDK_KEY_KP_Enter:
669 case GDK_KEY_ISO_Enter:
670 case GDK_KEY_BackSpace:
683 GdkEventButton *event,
698 text = gtk_entry_get_text (entry);
699 page = atoi (text) - 1;
708 GtkWidget *frame, *hbox, *
label;
709 GtkWindow *toplevel, *goto_window;
711 toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (pview)));
715 if (gtk_window_has_group (toplevel))
716 gtk_window_group_add_window (gtk_window_get_group (toplevel), goto_window);
717 else if (gtk_window_has_group (goto_window))
718 gtk_window_group_remove_window (gtk_window_get_group (goto_window), goto_window);
723 pview->
goto_window = gtk_window_new (GTK_WINDOW_POPUP);
725 gtk_window_set_screen (goto_window, gtk_widget_get_screen (GTK_WIDGET (pview)));
727 if (gtk_window_has_group (toplevel))
728 gtk_window_group_add_window (gtk_window_get_group (toplevel), goto_window);
730 gtk_window_set_modal (goto_window,
TRUE);
732 g_signal_connect (pview->
goto_window,
"delete_event",
735 g_signal_connect (pview->
goto_window,
"key_press_event",
738 g_signal_connect (pview->
goto_window,
"button_press_event",
742 frame = gtk_frame_new (NULL);
743 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
744 gtk_container_add (GTK_CONTAINER (pview->
goto_window), frame);
745 gtk_widget_show (frame);
747 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
748 gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);
749 gtk_container_add (GTK_CONTAINER (frame), hbox);
750 gtk_widget_show (hbox);
752 label = gtk_label_new (
_(
"Jump to page:"));
753 gtk_box_pack_start (GTK_BOX (hbox), label,
TRUE,
TRUE, 3);
754 gtk_widget_show (label);
755 gtk_widget_realize (label);
758 g_signal_connect (pview->
goto_entry,
"activate",
769 GtkWidgetClass *entry_parent_class;
771 entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (pview->
goto_entry));
772 (entry_parent_class->grab_focus) (pview->
goto_entry);
781 GdkEventKey *new_event;
785 screen = gtk_widget_get_screen (GTK_WIDGET (pview));
787 gdk_screen_get_width (screen) + 1,
788 gdk_screen_get_height (screen) + 1);
791 new_event = (GdkEventKey *) gdk_event_copy (event);
792 g_object_unref (new_event->window);
793 new_event->window = gtk_widget_get_window (pview->
goto_window);
794 if (new_event->window)
795 g_object_ref (new_event->window);
798 gtk_widget_event (pview->
goto_window, (GdkEvent *)new_event);
799 gdk_event_free ((GdkEvent *)new_event);
834 GdkRectangle page_area;
837 gdouble width, height;
838 gdouble new_x, new_y;
845 x = (x - page_area.x) / page_area.width;
846 y = (y - page_area.y) / page_area.height;
855 new_y = height * (1 - x);
858 new_x = width * (1 - x);
859 new_y = height * (1 - y);
862 new_x = width * (1 - y);
866 g_assert_not_reached ();
888 if (g_ascii_strcasecmp (name,
"FirstPage") == 0) {
890 }
else if (g_ascii_strcasecmp (name,
"PrevPage") == 0) {
892 }
else if (g_ascii_strcasecmp (name,
"NextPage") == 0) {
894 }
else if (g_ascii_strcasecmp (name,
"LastPage") == 0) {
930 if (pview->
cursor == view_cursor)
933 widget = GTK_WIDGET (pview);
934 if (!gtk_widget_get_realized (widget))
935 gtk_widget_realize (widget);
937 pview->
cursor = view_cursor;
940 gdk_window_set_cursor (gtk_widget_get_window (widget), cursor);
943 g_object_unref (cursor);
986 cairo_surface_t *surface)
991 cairo_surface_reference (surface);
1028 G_OBJECT_CLASS (ev_view_presentation_parent_class)->dispose (
object);
1036 *minimum = *natural = 0;
1044 *minimum = *natural = 0;
1051 GtkWidget *widget = GTK_WIDGET (pview);
1052 PangoLayout *layout;
1053 PangoFontDescription *font_desc;
1055 const gchar *text =
_(
"End of presentation. Click to exit.");
1060 layout = gtk_widget_create_pango_layout (widget, NULL);
1061 markup = g_strdup_printf (
"<span foreground=\"white\">%s</span>", text);
1062 pango_layout_set_markup (layout, markup, -1);
1065 font_desc = pango_font_description_new ();
1066 pango_font_description_set_size (font_desc, 16 * PANGO_SCALE);
1067 pango_layout_set_font_description (layout, font_desc);
1069 gtk_render_layout (gtk_widget_get_style_context (widget),
1070 cr, 15, 15, layout);
1072 pango_font_description_free (font_desc);
1073 g_object_unref (layout);
1081 GdkRectangle page_area;
1082 GdkRectangle overlap;
1083 cairo_surface_t *surface;
1084 GdkRectangle clip_rect;
1085 #if GTK_CHECK_VERSION(3, 20, 0)
1086 GtkStyleContext *context;
1088 context = gtk_widget_get_style_context (GTK_WIDGET (pview));
1089 gtk_render_background (context, cr,
1091 gtk_widget_get_allocated_width (widget),
1092 gtk_widget_get_allocated_height (widget));
1095 if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect))
1098 switch (pview->
state) {
1116 cairo_translate (cr, page_area.x, page_area.y);
1117 page_area.x = page_area.y = 0;
1140 if (gdk_rectangle_intersect (&page_area, &clip_rect, &overlap)) {
1144 if (overlap.width == page_area.width)
1147 cairo_rectangle (cr, overlap.x, overlap.y, overlap.width, overlap.height);
1148 cairo_set_source_surface (cr, surface, page_area.x, page_area.y);
1164 return gtk_bindings_activate_event (G_OBJECT (widget), event);
1166 if (event->state != 0)
1167 return gtk_bindings_activate_event (G_OBJECT (widget), event);
1169 switch (event->keyval) {
1172 case GDK_KEY_period:
1173 case GDK_KEY_KP_Decimal:
1216 gtk_window_move (GTK_WINDOW (pview->
goto_window), x, y);
1223 return gtk_bindings_activate_event (G_OBJECT (widget), event);
1228 GdkEventButton *event)
1232 switch (event->button) {
1263 GdkEventFocus *event)
1275 GdkEventMotion *event)
1288 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (pview));
1289 GdkRectangle monitor;
1292 monitor_num = gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window (GTK_WIDGET (pview)));
1293 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1315 GdkWindowAttr attributes;
1316 GtkAllocation allocation;
1318 gtk_widget_set_realized (widget,
TRUE);
1320 attributes.window_type = GDK_WINDOW_CHILD;
1321 attributes.wclass = GDK_INPUT_OUTPUT;
1322 attributes.visual = gtk_widget_get_visual (widget);
1324 gtk_widget_get_allocation (widget, &allocation);
1325 attributes.x = allocation.x;
1326 attributes.y = allocation.y;
1327 attributes.width = allocation.width;
1328 attributes.height = allocation.height;
1329 attributes.event_mask = GDK_EXPOSURE_MASK |
1330 GDK_BUTTON_PRESS_MASK |
1331 GDK_BUTTON_RELEASE_MASK |
1333 GDK_KEY_PRESS_MASK |
1334 GDK_POINTER_MOTION_MASK |
1335 GDK_POINTER_MOTION_HINT_MASK |
1336 GDK_ENTER_NOTIFY_MASK |
1337 GDK_LEAVE_NOTIFY_MASK;
1339 window = gdk_window_new (gtk_widget_get_parent_window (widget),
1341 GDK_WA_X | GDK_WA_Y |
1344 gdk_window_set_user_data (window, widget);
1345 gtk_widget_set_window (widget, window);
1346 gtk_style_context_set_background (gtk_widget_get_style_context (widget),
1354 GtkScrollType scroll)
1357 case GTK_SCROLL_PAGE_FORWARD:
1360 case GTK_SCROLL_PAGE_BACKWARD:
1364 g_assert_not_reached ();
1370 GdkEventScroll *event)
1375 state =
event->state & gtk_accelerator_get_default_mod_mask ();
1379 switch (event->direction) {
1380 case GDK_SCROLL_DOWN:
1381 case GDK_SCROLL_RIGHT:
1385 case GDK_SCROLL_LEFT:
1388 case GDK_SCROLL_SMOOTH:
1399 GdkModifierType modifiers,
1400 GtkScrollType scroll)
1402 guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left;
1404 gtk_binding_entry_add_signal (binding_set, keyval, modifiers,
1406 GTK_TYPE_SCROLL_TYPE, scroll);
1407 gtk_binding_entry_add_signal (binding_set, keypad_keyval, modifiers,
1409 GTK_TYPE_SCROLL_TYPE, scroll);
1415 const GValue *value,
1422 pview->
document = g_value_dup_object (value);
1435 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
1455 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
1469 guint n_construct_properties,
1470 GObjectConstructParam *construct_params)
1475 object = G_OBJECT_CLASS (ev_view_presentation_parent_class)->constructor (type,
1476 n_construct_properties,
1486 g_signal_connect (
object,
"notify::scale-factor",
1495 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
1496 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1497 GtkBindingSet *binding_set;
1513 #if GTK_CHECK_VERSION(3, 20, 0)
1514 gtk_widget_class_set_css_name (widget_class,
"evpresentationview");
1521 g_object_class_install_property (gobject_class,
1523 g_param_spec_object (
"document",
1528 G_PARAM_CONSTRUCT_ONLY |
1529 G_PARAM_STATIC_STRINGS));
1530 g_object_class_install_property (gobject_class,
1532 g_param_spec_uint (
"current-page",
1538 G_PARAM_STATIC_STRINGS));
1539 g_object_class_install_property (gobject_class,
1541 g_param_spec_uint (
"rotation",
1543 "Current rotation angle",
1547 G_PARAM_STATIC_STRINGS));
1548 g_object_class_install_property (gobject_class,
1550 g_param_spec_boolean (
"inverted-colors",
1552 "Whether presentation is displayed with inverted colors",
1555 G_PARAM_CONSTRUCT_ONLY |
1556 G_PARAM_STATIC_STRINGS));
1559 g_signal_new (
"change_page",
1560 G_OBJECT_CLASS_TYPE (gobject_class),
1561 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1564 g_cclosure_marshal_VOID__ENUM,
1566 GTK_TYPE_SCROLL_TYPE);
1568 g_signal_new (
"finished",
1569 G_OBJECT_CLASS_TYPE (gobject_class),
1570 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1573 g_cclosure_marshal_VOID__VOID,
1577 g_signal_new (
"external-link",
1578 G_TYPE_FROM_CLASS (gobject_class),
1579 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1582 g_cclosure_marshal_VOID__OBJECT,
1586 binding_set = gtk_binding_set_by_class (klass);
1591 gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0,
1593 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1594 gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK,
1596 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1597 gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0,
1599 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1600 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Down, 0,
1602 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1603 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Up, 0,
1605 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1606 gtk_binding_entry_add_signal (binding_set, GDK_KEY_J, 0,
1608 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1609 gtk_binding_entry_add_signal (binding_set, GDK_KEY_H, 0,
1611 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1612 gtk_binding_entry_add_signal (binding_set, GDK_KEY_L, 0,
1614 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
1615 gtk_binding_entry_add_signal (binding_set, GDK_KEY_K, 0,
1617 GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
1620 #if !GTK_CHECK_VERSION(3, 20, 0)
1624 static gsize initialization_value = 0;
1626 if (g_once_init_enter (&initialization_value)) {
1627 GtkCssProvider *provider;
1629 provider = gtk_css_provider_new ();
1630 gtk_css_provider_load_from_data (provider,
1631 "EvViewPresentation {\n"
1632 " background-color: black; }",
1634 gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
1635 GTK_STYLE_PROVIDER (provider),
1636 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1637 g_object_unref (provider);
1638 g_once_init_leave (&initialization_value, 1);
1646 gtk_widget_set_can_focus (GTK_WIDGET (pview),
TRUE);
1648 #if !GTK_CHECK_VERSION(3, 20, 0)
1657 gboolean inverted_colors)
1663 "document", document,
1664 "current_page", current_page,
1665 "rotation", rotation,
1666 "inverted_colors", inverted_colors,
1680 if (rotation >= 360)
1682 else if (rotation < 0)
1689 g_object_notify (G_OBJECT (pview),
"rotation");