2012-02-05 11:24:34 +01:00
/* See LICENSE file for license and copyright information */
# include <girara/utils.h>
# include <girara/settings.h>
2012-02-05 22:55:30 +01:00
# include <girara/datastructures.h>
2012-03-07 09:17:05 +01:00
# include <girara/session.h>
# include <string.h>
# include <glib/gi18n.h>
2014-10-26 13:19:14 +01:00
# include <math.h>
2012-02-05 11:24:34 +01:00
2012-05-28 12:43:22 +02:00
# include "links.h"
2012-03-16 14:37:54 +01:00
# include "page-widget.h"
2012-03-26 14:44:56 +02:00
# include "page.h"
2012-02-09 01:46:51 +01:00
# include "render.h"
# include "utils.h"
# include "shortcuts.h"
2013-08-21 18:32:18 +02:00
# include "zathura.h"
2012-02-09 01:46:51 +01:00
2012-02-07 18:30:46 +01:00
G_DEFINE_TYPE ( ZathuraPage , zathura_page_widget , GTK_TYPE_DRAWING_AREA )
2012-02-05 11:24:34 +01:00
2012-02-07 18:30:46 +01:00
typedef struct zathura_page_widget_private_s {
2012-05-06 23:41:25 +02:00
zathura_page_t * page ; /**< Page object */
zathura_t * zathura ; /**< Zathura object */
2012-03-07 15:12:59 +01:00
cairo_surface_t * surface ; /**< Cairo surface */
2014-10-26 13:19:14 +01:00
cairo_surface_t * thumbnail ; /**< Cairo surface */
2013-08-21 18:32:18 +02:00
ZathuraRenderRequest * render_request ; /* Request object */
2013-10-19 17:45:12 +02:00
bool cached ; /**< Cached state */
2012-05-06 23:41:25 +02:00
struct {
girara_list_t * list ; /**< List of links on the page */
bool retrieved ; /**< True if we already tried to retrieve the list of links */
bool draw ; /**< True if links should be drawn */
unsigned int offset ; /**< Offset to the links */
unsigned int n ; /**< Number */
} links ;
struct {
girara_list_t * list ; /**< A list if there are search results that should be drawn */
int current ; /**< The index of the current search result */
bool draw ; /**< Draw search results */
} search ;
struct {
girara_list_t * list ; /**< List of images on the page */
bool retrieved ; /**< True if we already tried to retrieve the list of images */
zathura_image_t * current ; /**< Image data of selected image */
} images ;
2012-03-07 15:12:59 +01:00
struct {
2012-05-06 23:41:25 +02:00
zathura_rectangle_t selection ; /**< Region selected with the mouse */
struct {
int x ; /**< X coordinate */
int y ; /**< Y coordinate */
} selection_basepoint ;
2014-05-24 18:04:59 +02:00
bool over_link ;
2012-05-06 23:41:25 +02:00
} mouse ;
2012-02-07 18:30:46 +01:00
} zathura_page_widget_private_t ;
2012-02-05 11:24:34 +01:00
2012-02-07 18:30:46 +01:00
# define ZATHURA_PAGE_GET_PRIVATE(obj) \
2013-10-19 17:45:12 +02:00
( G_TYPE_INSTANCE_GET_PRIVATE ( ( obj ) , ZATHURA_TYPE_PAGE , \
zathura_page_widget_private_t ) )
2012-02-05 11:24:34 +01:00
2012-02-14 14:26:44 +01:00
static gboolean zathura_page_widget_draw ( GtkWidget * widget , cairo_t * cairo ) ;
2012-02-07 18:30:46 +01:00
static void zathura_page_widget_finalize ( GObject * object ) ;
2014-01-19 20:51:18 +01:00
static void zathura_page_widget_dispose ( GObject * object ) ;
2012-02-07 18:30:46 +01:00
static void zathura_page_widget_set_property ( GObject * object , guint prop_id , const GValue * value , GParamSpec * pspec ) ;
static void zathura_page_widget_get_property ( GObject * object , guint prop_id , GValue * value , GParamSpec * pspec ) ;
static void zathura_page_widget_size_allocate ( GtkWidget * widget , GdkRectangle * allocation ) ;
static void redraw_rect ( ZathuraPage * widget , zathura_rectangle_t * rectangle ) ;
static void redraw_all_rects ( ZathuraPage * widget , girara_list_t * rectangles ) ;
2012-03-22 18:51:02 +01:00
static void zathura_page_widget_popup_menu ( GtkWidget * widget , GdkEventButton * event ) ;
2012-02-07 21:54:59 +01:00
static gboolean cb_zathura_page_widget_button_press_event ( GtkWidget * widget , GdkEventButton * button ) ;
2012-02-09 00:29:10 +01:00
static gboolean cb_zathura_page_widget_button_release_event ( GtkWidget * widget , GdkEventButton * button ) ;
static gboolean cb_zathura_page_widget_motion_notify ( GtkWidget * widget , GdkEventMotion * event ) ;
2014-05-25 00:52:04 +02:00
static gboolean cb_zathura_page_widget_leave_notify ( GtkWidget * widget , GdkEventCrossing * event ) ;
2012-03-22 18:51:02 +01:00
static gboolean cb_zathura_page_widget_popup_menu ( GtkWidget * widget ) ;
static void cb_menu_image_copy ( GtkMenuItem * item , ZathuraPage * page ) ;
2012-05-01 11:54:52 +02:00
static void cb_menu_image_save ( GtkMenuItem * item , ZathuraPage * page ) ;
2013-08-30 12:59:27 +02:00
static void cb_update_surface ( ZathuraRenderRequest * request , cairo_surface_t * surface , void * data ) ;
2013-10-19 17:45:12 +02:00
static void cb_cache_added ( ZathuraRenderRequest * request , void * data ) ;
static void cb_cache_invalidated ( ZathuraRenderRequest * request , void * data ) ;
2014-10-26 13:19:14 +01:00
static bool surface_small_enough ( cairo_surface_t * surface , cairo_surface_t * old ) ;
static cairo_surface_t * draw_thumbnail_image ( cairo_surface_t * surface ) ;
2012-02-05 11:24:34 +01:00
2012-10-09 01:12:18 +02:00
enum properties_e {
2012-02-05 11:24:34 +01:00
PROP_0 ,
2012-02-07 16:39:02 +01:00
PROP_PAGE ,
2012-04-03 09:02:45 +02:00
PROP_ZATHURA ,
2012-02-07 16:39:02 +01:00
PROP_DRAW_LINKS ,
2012-02-07 17:31:47 +01:00
PROP_LINKS_OFFSET ,
PROP_LINKS_NUMBER ,
2012-02-07 19:15:01 +01:00
PROP_SEARCH_RESULTS ,
PROP_SEARCH_RESULTS_LENGTH ,
2012-04-22 19:12:45 +02:00
PROP_SEARCH_RESULTS_CURRENT ,
2013-06-08 02:46:58 +02:00
PROP_DRAW_SEARCH_RESULTS ,
2012-05-15 07:52:23 +02:00
PROP_LAST_VIEW ,
2012-02-05 11:24:34 +01:00
} ;
2013-08-31 13:12:41 +02:00
enum {
TEXT_SELECTED ,
IMAGE_SELECTED ,
2014-08-22 20:42:33 +02:00
BUTTON_RELEASE ,
2014-05-24 18:04:59 +02:00
ENTER_LINK ,
LEAVE_LINK ,
2013-08-31 13:12:41 +02:00
LAST_SIGNAL
} ;
static guint signals [ LAST_SIGNAL ] = { 0 } ;
2012-02-05 11:24:34 +01:00
static void
2012-02-07 18:30:46 +01:00
zathura_page_widget_class_init ( ZathuraPageClass * class )
2012-02-05 11:24:34 +01:00
{
/* add private members */
2012-02-07 18:30:46 +01:00
g_type_class_add_private ( class , sizeof ( zathura_page_widget_private_t ) ) ;
2012-02-05 11:24:34 +01:00
/* overwrite methods */
GtkWidgetClass * widget_class = GTK_WIDGET_CLASS ( class ) ;
2013-10-19 17:45:12 +02:00
widget_class - > draw = zathura_page_widget_draw ;
2012-03-07 09:17:05 +01:00
widget_class - > size_allocate = zathura_page_widget_size_allocate ;
widget_class - > button_press_event = cb_zathura_page_widget_button_press_event ;
2012-02-09 00:29:10 +01:00
widget_class - > button_release_event = cb_zathura_page_widget_button_release_event ;
2012-03-07 09:17:05 +01:00
widget_class - > motion_notify_event = cb_zathura_page_widget_motion_notify ;
2014-05-25 00:52:04 +02:00
widget_class - > leave_notify_event = cb_zathura_page_widget_leave_notify ;
2012-03-22 18:51:02 +01:00
widget_class - > popup_menu = cb_zathura_page_widget_popup_menu ;
2012-02-05 11:24:34 +01:00
GObjectClass * object_class = G_OBJECT_CLASS ( class ) ;
2014-01-19 20:51:18 +01:00
object_class - > dispose = zathura_page_widget_dispose ;
2012-03-07 09:17:05 +01:00
object_class - > finalize = zathura_page_widget_finalize ;
2012-02-07 18:30:46 +01:00
object_class - > set_property = zathura_page_widget_set_property ;
object_class - > get_property = zathura_page_widget_get_property ;
2012-02-05 11:24:34 +01:00
/* add properties */
g_object_class_install_property ( object_class , PROP_PAGE ,
2013-03-25 02:58:37 +01:00
g_param_spec_pointer ( " page " , " page " , " the page to draw " , G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS ) ) ;
2012-04-03 09:02:45 +02:00
g_object_class_install_property ( object_class , PROP_ZATHURA ,
2013-03-25 02:58:37 +01:00
g_param_spec_pointer ( " zathura " , " zathura " , " the zathura instance " , G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS ) ) ;
2012-02-07 16:39:02 +01:00
g_object_class_install_property ( object_class , PROP_DRAW_LINKS ,
2013-03-25 02:58:37 +01:00
g_param_spec_boolean ( " draw-links " , " draw-links " , " Set to true if links should be drawn " , FALSE , G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS ) ) ;
2012-02-07 17:31:47 +01:00
g_object_class_install_property ( object_class , PROP_LINKS_OFFSET ,
2013-03-25 02:58:37 +01:00
g_param_spec_int ( " offset-links " , " offset-links " , " Offset for the link numbers " , 0 , INT_MAX , 0 , G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS ) ) ;
2012-02-07 17:31:47 +01:00
g_object_class_install_property ( object_class , PROP_LINKS_NUMBER ,
2013-03-25 02:58:37 +01:00
g_param_spec_int ( " number-of-links " , " number-of-links " , " Number of links " , 0 , INT_MAX , 0 , G_PARAM_READABLE | G_PARAM_STATIC_STRINGS ) ) ;
2012-02-07 16:59:42 +01:00
g_object_class_install_property ( object_class , PROP_SEARCH_RESULTS ,
2013-03-25 02:58:37 +01:00
g_param_spec_pointer ( " search-results " , " search-results " , " Set to the list of search results " , G_PARAM_WRITABLE | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS ) ) ;
2012-02-07 19:15:01 +01:00
g_object_class_install_property ( object_class , PROP_SEARCH_RESULTS_CURRENT ,
2013-03-25 02:58:37 +01:00
g_param_spec_int ( " search-current " , " search-current " , " The current search result " , - 1 , INT_MAX , 0 , G_PARAM_WRITABLE | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS ) ) ;
2012-02-07 19:15:01 +01:00
g_object_class_install_property ( object_class , PROP_SEARCH_RESULTS_LENGTH ,
2013-03-25 02:58:37 +01:00
g_param_spec_int ( " search-length " , " search-length " , " The number of search results " , - 1 , INT_MAX , 0 , G_PARAM_READABLE | G_PARAM_STATIC_STRINGS ) ) ;
2013-06-08 02:46:58 +02:00
g_object_class_install_property ( object_class , PROP_DRAW_SEARCH_RESULTS ,
g_param_spec_boolean ( " draw-search-results " , " draw-search-results " , " Set to true if search results should be drawn " , FALSE , G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS ) ) ;
2013-08-31 13:12:41 +02:00
/* add signals */
signals [ TEXT_SELECTED ] = g_signal_new ( " text-selected " ,
ZATHURA_TYPE_PAGE ,
G_SIGNAL_RUN_LAST ,
0 ,
NULL ,
NULL ,
g_cclosure_marshal_generic ,
G_TYPE_NONE ,
1 ,
G_TYPE_STRING ) ;
signals [ IMAGE_SELECTED ] = g_signal_new ( " image-selected " ,
ZATHURA_TYPE_PAGE ,
G_SIGNAL_RUN_LAST ,
0 ,
NULL ,
NULL ,
g_cclosure_marshal_generic ,
G_TYPE_NONE ,
1 ,
G_TYPE_OBJECT ) ;
2014-05-24 18:04:59 +02:00
signals [ ENTER_LINK ] = g_signal_new ( " enter-link " ,
ZATHURA_TYPE_PAGE ,
G_SIGNAL_RUN_LAST ,
0 ,
NULL ,
NULL ,
g_cclosure_marshal_generic ,
G_TYPE_NONE ,
0 ) ;
signals [ LEAVE_LINK ] = g_signal_new ( " leave-link " ,
ZATHURA_TYPE_PAGE ,
G_SIGNAL_RUN_LAST ,
0 ,
NULL ,
NULL ,
g_cclosure_marshal_generic ,
G_TYPE_NONE ,
0 ) ;
2014-08-22 20:42:33 +02:00
signals [ BUTTON_RELEASE ] = g_signal_new ( " scaled-button-release " ,
ZATHURA_TYPE_PAGE ,
G_SIGNAL_RUN_LAST ,
0 ,
NULL ,
NULL ,
g_cclosure_marshal_generic ,
G_TYPE_NONE ,
1 ,
G_TYPE_POINTER ) ;
2012-02-05 11:24:34 +01:00
}
static void
2012-02-07 18:30:46 +01:00
zathura_page_widget_init ( ZathuraPage * widget )
2012-02-05 11:24:34 +01:00
{
2012-02-07 18:30:46 +01:00
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
2013-02-24 03:26:29 +01:00
priv - > page = NULL ;
priv - > surface = NULL ;
2014-10-26 13:19:14 +01:00
priv - > thumbnail = NULL ;
2013-08-21 18:32:18 +02:00
priv - > render_request = NULL ;
2013-10-19 17:45:12 +02:00
priv - > cached = false ;
2012-05-06 23:41:25 +02:00
priv - > links . list = NULL ;
priv - > links . retrieved = false ;
priv - > links . draw = false ;
priv - > links . offset = 0 ;
priv - > links . n = 0 ;
priv - > search . list = NULL ;
priv - > search . current = INT_MAX ;
2013-06-08 02:46:58 +02:00
priv - > search . draw = false ;
2012-05-06 23:41:25 +02:00
priv - > images . list = NULL ;
priv - > images . retrieved = false ;
priv - > images . current = NULL ;
priv - > mouse . selection . x1 = - 1 ;
priv - > mouse . selection . y1 = - 1 ;
priv - > mouse . selection_basepoint . x = - 1 ;
priv - > mouse . selection_basepoint . y = - 1 ;
2014-05-25 00:52:04 +02:00
const unsigned int event_mask = GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK ;
gtk_widget_add_events ( GTK_WIDGET ( widget ) , event_mask ) ;
2012-02-05 11:24:34 +01:00
}
GtkWidget *
2012-04-03 09:02:45 +02:00
zathura_page_widget_new ( zathura_t * zathura , zathura_page_t * page )
2012-02-05 11:24:34 +01:00
{
g_return_val_if_fail ( page ! = NULL , NULL ) ;
2013-08-21 18:32:18 +02:00
GObject * ret = g_object_new ( ZATHURA_TYPE_PAGE , " page " , page , " zathura " , zathura , NULL ) ;
if ( ret = = NULL ) {
return NULL ;
}
ZathuraPage * widget = ZATHURA_PAGE ( ret ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
priv - > render_request = zathura_render_request_new ( zathura - > sync . render_thread , page ) ;
g_signal_connect_object ( priv - > render_request , " completed " ,
2013-08-30 12:59:27 +02:00
G_CALLBACK ( cb_update_surface ) , widget , 0 ) ;
2013-10-19 17:45:12 +02:00
g_signal_connect_object ( priv - > render_request , " cache-added " ,
G_CALLBACK ( cb_cache_added ) , widget , 0 ) ;
g_signal_connect_object ( priv - > render_request , " cache-invalidated " ,
G_CALLBACK ( cb_cache_invalidated ) , widget , 0 ) ;
2013-08-21 18:32:18 +02:00
return GTK_WIDGET ( ret ) ;
2012-02-05 11:24:34 +01:00
}
2014-01-19 20:51:18 +01:00
static void
zathura_page_widget_dispose ( GObject * object )
{
ZathuraPage * widget = ZATHURA_PAGE ( object ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
g_clear_object ( & priv - > render_request ) ;
G_OBJECT_CLASS ( zathura_page_widget_parent_class ) - > dispose ( object ) ;
}
2012-02-05 11:24:34 +01:00
static void
2012-02-07 18:30:46 +01:00
zathura_page_widget_finalize ( GObject * object )
2012-02-05 11:24:34 +01:00
{
2012-02-07 18:30:46 +01:00
ZathuraPage * widget = ZATHURA_PAGE ( object ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
2012-03-08 14:29:50 +01:00
2012-03-05 21:20:52 +01:00
if ( priv - > surface ! = NULL ) {
2012-02-05 11:24:34 +01:00
cairo_surface_destroy ( priv - > surface ) ;
}
2012-03-08 14:29:50 +01:00
2014-10-26 13:19:14 +01:00
if ( priv - > thumbnail ! = NULL ) {
cairo_surface_destroy ( priv - > thumbnail ) ;
}
2012-05-06 23:41:25 +02:00
if ( priv - > search . list ! = NULL ) {
girara_list_free ( priv - > search . list ) ;
2012-03-08 14:29:50 +01:00
}
2012-05-06 23:41:25 +02:00
if ( priv - > links . list ! = NULL ) {
girara_list_free ( priv - > links . list ) ;
2012-03-08 14:29:50 +01:00
}
2012-02-07 18:30:46 +01:00
G_OBJECT_CLASS ( zathura_page_widget_parent_class ) - > finalize ( object ) ;
2012-02-05 11:24:34 +01:00
}
static void
2012-02-07 18:30:46 +01:00
zathura_page_widget_set_property ( GObject * object , guint prop_id , const GValue * value , GParamSpec * pspec )
2012-02-05 11:24:34 +01:00
{
2012-02-07 18:30:46 +01:00
ZathuraPage * pageview = ZATHURA_PAGE ( object ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( pageview ) ;
2012-02-05 11:24:34 +01:00
switch ( prop_id ) {
case PROP_PAGE :
2012-04-03 09:02:45 +02:00
priv - > page = g_value_get_pointer ( value ) ;
break ;
case PROP_ZATHURA :
priv - > zathura = g_value_get_pointer ( value ) ;
2012-02-05 11:24:34 +01:00
break ;
2012-02-07 16:39:02 +01:00
case PROP_DRAW_LINKS :
2012-05-06 23:41:25 +02:00
priv - > links . draw = g_value_get_boolean ( value ) ;
2012-02-07 16:39:02 +01:00
/* get links */
2012-05-06 23:41:25 +02:00
if ( priv - > links . draw = = true & & priv - > links . retrieved = = false ) {
priv - > links . list = zathura_page_links_get ( priv - > page , NULL ) ;
priv - > links . retrieved = true ;
priv - > links . n = ( priv - > links . list = = NULL ) ? 0 : girara_list_size ( priv - > links . list ) ;
2012-02-07 16:39:02 +01:00
}
2012-05-06 23:41:25 +02:00
if ( priv - > links . retrieved = = true & & priv - > links . list ! = NULL ) {
GIRARA_LIST_FOREACH ( priv - > links . list , zathura_link_t * , iter , link )
2012-10-09 01:12:18 +02:00
if ( link ! = NULL ) {
zathura_rectangle_t rectangle = recalc_rectangle ( priv - > page , zathura_link_get_position ( link ) ) ;
redraw_rect ( pageview , & rectangle ) ;
}
2012-05-06 23:41:25 +02:00
GIRARA_LIST_FOREACH_END ( priv - > links . list , zathura_link_t * , iter , link ) ;
2012-02-07 16:39:02 +01:00
}
break ;
2012-02-07 17:31:47 +01:00
case PROP_LINKS_OFFSET :
2012-05-06 23:41:25 +02:00
priv - > links . offset = g_value_get_int ( value ) ;
2012-02-07 17:31:47 +01:00
break ;
2012-02-07 16:59:42 +01:00
case PROP_SEARCH_RESULTS :
2012-05-06 23:41:25 +02:00
if ( priv - > search . list ! = NULL & & priv - > search . draw ) {
redraw_all_rects ( pageview , priv - > search . list ) ;
girara_list_free ( priv - > search . list ) ;
2012-02-07 16:59:42 +01:00
}
2012-05-06 23:41:25 +02:00
priv - > search . list = g_value_get_pointer ( value ) ;
if ( priv - > search . list ! = NULL & & priv - > search . draw ) {
priv - > links . draw = false ;
redraw_all_rects ( pageview , priv - > search . list ) ;
2012-02-07 16:59:42 +01:00
}
2012-05-06 23:41:25 +02:00
priv - > search . current = - 1 ;
2012-02-07 17:33:45 +01:00
break ;
2012-02-07 19:15:01 +01:00
case PROP_SEARCH_RESULTS_CURRENT : {
2012-05-06 23:41:25 +02:00
g_return_if_fail ( priv - > search . list ! = NULL ) ;
if ( priv - > search . current > = 0 & & priv - > search . current < ( signed ) girara_list_size ( priv - > search . list ) ) {
zathura_rectangle_t * rect = girara_list_nth ( priv - > search . list , priv - > search . current ) ;
2012-02-07 19:15:01 +01:00
zathura_rectangle_t rectangle = recalc_rectangle ( priv - > page , * rect ) ;
redraw_rect ( pageview , & rectangle ) ;
}
int val = g_value_get_int ( value ) ;
2012-02-07 20:29:29 +01:00
if ( val < 0 ) {
2012-05-06 23:41:25 +02:00
priv - > search . current = girara_list_size ( priv - > search . list ) ;
2012-02-07 19:15:01 +01:00
} else {
2012-05-06 23:41:25 +02:00
priv - > search . current = val ;
2014-04-07 16:00:19 +02:00
if ( priv - > search . draw = = true & & val > = 0 & & val < ( signed ) girara_list_size ( priv - > search . list ) ) {
zathura_rectangle_t * rect = girara_list_nth ( priv - > search . list , priv - > search . current ) ;
zathura_rectangle_t rectangle = recalc_rectangle ( priv - > page , * rect ) ;
2012-04-22 19:12:45 +02:00
redraw_rect ( pageview , & rectangle ) ;
}
2012-02-07 19:15:01 +01:00
}
break ;
}
2013-06-08 02:46:58 +02:00
case PROP_DRAW_SEARCH_RESULTS :
2012-05-06 23:41:25 +02:00
priv - > search . draw = g_value_get_boolean ( value ) ;
2013-06-08 02:46:58 +02:00
/*
* we do the following instead of only redrawing the rectangles of the
* search results in order to avoid the rectangular margins that appear
* around the search terms after their highlighted rectangular areas are
* redrawn without highlighting .
*/
if ( priv - > search . list ! = NULL & & zathura_page_get_visibility ( priv - > page ) ) {
2013-08-30 15:43:43 +02:00
gtk_widget_queue_draw ( GTK_WIDGET ( object ) ) ;
2013-06-08 02:46:58 +02:00
}
2012-04-22 19:12:45 +02:00
break ;
2012-02-07 17:31:47 +01:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , prop_id , pspec ) ;
}
}
static void
2012-02-07 18:30:46 +01:00
zathura_page_widget_get_property ( GObject * object , guint prop_id , GValue * value , GParamSpec * pspec )
2012-02-07 17:31:47 +01:00
{
2012-02-07 18:30:46 +01:00
ZathuraPage * pageview = ZATHURA_PAGE ( object ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( pageview ) ;
2012-02-07 17:31:47 +01:00
switch ( prop_id ) {
case PROP_LINKS_NUMBER :
2012-05-06 23:41:25 +02:00
g_value_set_int ( value , priv - > links . n ) ;
2012-02-07 16:59:42 +01:00
break ;
2012-02-07 19:15:01 +01:00
case PROP_SEARCH_RESULTS_LENGTH :
2012-05-06 23:41:25 +02:00
g_value_set_int ( value , priv - > search . list = = NULL ? 0 : girara_list_size ( priv - > search . list ) ) ;
2012-02-07 19:15:01 +01:00
break ;
case PROP_SEARCH_RESULTS_CURRENT :
2012-05-06 23:41:25 +02:00
g_value_set_int ( value , priv - > search . list = = NULL ? - 1 : priv - > search . current ) ;
2012-02-07 19:15:01 +01:00
break ;
2012-02-07 20:29:29 +01:00
case PROP_SEARCH_RESULTS :
2012-05-06 23:41:25 +02:00
g_value_set_pointer ( value , priv - > search . list ) ;
2012-02-07 20:29:29 +01:00
break ;
2013-06-08 02:46:58 +02:00
case PROP_DRAW_SEARCH_RESULTS :
g_value_set_boolean ( value , priv - > search . draw ) ;
break ;
2012-02-05 11:24:34 +01:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , prop_id , pspec ) ;
}
}
2012-02-14 14:26:44 +01:00
static gboolean
zathura_page_widget_draw ( GtkWidget * widget , cairo_t * cairo )
{
2012-02-07 18:30:46 +01:00
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
2012-02-14 14:26:44 +01:00
2013-11-25 18:57:59 +01:00
zathura_document_t * document = zathura_page_get_document ( priv - > page ) ;
2012-02-14 14:26:44 +01:00
const unsigned int page_height = gtk_widget_get_allocated_height ( widget ) ;
const unsigned int page_width = gtk_widget_get_allocated_width ( widget ) ;
2014-10-26 13:19:14 +01:00
if ( priv - > surface ! = NULL | | priv - > thumbnail ! = NULL ) {
2012-02-05 11:24:34 +01:00
cairo_save ( cairo ) ;
2012-03-30 18:24:00 +02:00
unsigned int rotation = zathura_document_get_rotation ( document ) ;
2012-03-27 21:59:35 +02:00
switch ( rotation ) {
2012-02-05 11:24:34 +01:00
case 90 :
cairo_translate ( cairo , page_width , 0 ) ;
break ;
case 180 :
cairo_translate ( cairo , page_width , page_height ) ;
break ;
case 270 :
cairo_translate ( cairo , 0 , page_height ) ;
break ;
}
2012-03-27 21:59:35 +02:00
if ( rotation ! = 0 ) {
cairo_rotate ( cairo , rotation * G_PI / 180.0 ) ;
2012-02-05 11:24:34 +01:00
}
2014-10-26 13:19:14 +01:00
if ( priv - > surface ! = NULL ) {
cairo_set_source_surface ( cairo , priv - > surface , 0 , 0 ) ;
cairo_paint ( cairo ) ;
cairo_restore ( cairo ) ;
} else {
const unsigned int height = cairo_image_surface_get_height ( priv - > thumbnail ) ;
const unsigned int width = cairo_image_surface_get_width ( priv - > thumbnail ) ;
const unsigned int pheight = ( rotation % 180 ? page_width : page_height ) ;
const unsigned int pwidth = ( rotation % 180 ? page_height : page_width ) ;
cairo_scale ( cairo , pwidth / ( double ) width , pheight / ( double ) height ) ;
cairo_set_source_surface ( cairo , priv - > thumbnail , 0 , 0 ) ;
cairo_pattern_set_extend ( cairo_get_source ( cairo ) , CAIRO_EXTEND_PAD ) ;
if ( pwidth < width | | pheight < height ) {
/* pixman bilinear downscaling is slow */
cairo_pattern_set_filter ( cairo_get_source ( cairo ) , CAIRO_FILTER_FAST ) ;
}
cairo_set_operator ( cairo , CAIRO_OPERATOR_SOURCE ) ;
cairo_paint ( cairo ) ;
cairo_restore ( cairo ) ;
zathura_render_request ( priv - > render_request , g_get_real_time ( ) ) ;
return FALSE ;
}
2012-02-05 22:55:30 +01:00
/* draw rectangles */
char * font = NULL ;
girara_setting_get ( priv - > zathura - > ui . session , " font " , & font ) ;
float transparency = 0.5 ;
girara_setting_get ( priv - > zathura - > ui . session , " highlight-transparency " , & transparency ) ;
if ( font ! = NULL ) {
cairo_select_font_face ( cairo , font , CAIRO_FONT_SLANT_NORMAL , CAIRO_FONT_WEIGHT_BOLD ) ;
}
2012-06-04 11:46:35 +02:00
2012-02-07 16:59:42 +01:00
g_free ( font ) ;
2012-02-05 22:55:30 +01:00
2012-02-07 16:39:02 +01:00
/* draw links */
2012-05-06 23:41:25 +02:00
if ( priv - > links . draw = = true & & priv - > links . n ! = 0 ) {
2012-02-07 17:31:47 +01:00
unsigned int link_counter = 0 ;
2012-05-06 23:41:25 +02:00
GIRARA_LIST_FOREACH ( priv - > links . list , zathura_link_t * , iter , link )
2012-10-09 01:12:18 +02:00
if ( link ! = NULL ) {
zathura_rectangle_t rectangle = recalc_rectangle ( priv - > page , zathura_link_get_position ( link ) ) ;
2012-02-07 16:39:02 +01:00
2012-10-09 01:12:18 +02:00
/* draw position */
2013-12-01 16:04:04 +01:00
const GdkRGBA color = priv - > zathura - > ui . colors . highlight_color ;
cairo_set_source_rgba ( cairo , color . red , color . green , color . blue , transparency ) ;
2012-10-09 01:12:18 +02:00
cairo_rectangle ( cairo , rectangle . x1 , rectangle . y1 ,
( rectangle . x2 - rectangle . x1 ) , ( rectangle . y2 - rectangle . y1 ) ) ;
cairo_fill ( cairo ) ;
/* draw text */
cairo_set_source_rgba ( cairo , 0 , 0 , 0 , 1 ) ;
cairo_set_font_size ( cairo , 10 ) ;
cairo_move_to ( cairo , rectangle . x1 + 1 , rectangle . y2 - 1 ) ;
char * link_number = g_strdup_printf ( " %i " , priv - > links . offset + + + link_counter ) ;
cairo_show_text ( cairo , link_number ) ;
g_free ( link_number ) ;
}
2012-05-06 23:41:25 +02:00
GIRARA_LIST_FOREACH_END ( priv - > links . list , zathura_link_t * , iter , link ) ;
2012-02-07 16:39:02 +01:00
}
2012-02-07 16:59:42 +01:00
/* draw search results */
2012-05-06 23:41:25 +02:00
if ( priv - > search . list ! = NULL & & priv - > search . draw = = true ) {
2012-02-07 19:28:20 +01:00
int idx = 0 ;
2012-05-06 23:41:25 +02:00
GIRARA_LIST_FOREACH ( priv - > search . list , zathura_rectangle_t * , iter , rect )
2012-10-09 01:12:18 +02:00
zathura_rectangle_t rectangle = recalc_rectangle ( priv - > page , * rect ) ;
2012-02-07 16:59:42 +01:00
2012-10-09 01:12:18 +02:00
/* draw position */
if ( idx = = priv - > search . current ) {
2013-12-01 16:04:04 +01:00
const GdkRGBA color = priv - > zathura - > ui . colors . highlight_color_active ;
cairo_set_source_rgba ( cairo , color . red , color . green , color . blue , transparency ) ;
2012-10-09 01:12:18 +02:00
} else {
2013-12-01 16:04:04 +01:00
const GdkRGBA color = priv - > zathura - > ui . colors . highlight_color ;
cairo_set_source_rgba ( cairo , color . red , color . green , color . blue , transparency ) ;
2012-10-09 01:12:18 +02:00
}
cairo_rectangle ( cairo , rectangle . x1 , rectangle . y1 ,
( rectangle . x2 - rectangle . x1 ) , ( rectangle . y2 - rectangle . y1 ) ) ;
cairo_fill ( cairo ) ;
+ + idx ;
2012-05-06 23:41:25 +02:00
GIRARA_LIST_FOREACH_END ( priv - > search . list , zathura_rectangle_t * , iter , rect ) ;
2012-02-07 16:59:42 +01:00
}
2012-02-09 00:29:10 +01:00
/* draw selection */
2012-05-06 23:41:25 +02:00
if ( priv - > mouse . selection . y2 ! = - 1 & & priv - > mouse . selection . x2 ! = - 1 ) {
2013-12-01 16:04:04 +01:00
const GdkRGBA color = priv - > zathura - > ui . colors . highlight_color ;
cairo_set_source_rgba ( cairo , color . red , color . green , color . blue , transparency ) ;
2012-05-06 23:41:25 +02:00
cairo_rectangle ( cairo , priv - > mouse . selection . x1 , priv - > mouse . selection . y1 ,
2012-10-09 01:12:18 +02:00
( priv - > mouse . selection . x2 - priv - > mouse . selection . x1 ) , ( priv - > mouse . selection . y2 - priv - > mouse . selection . y1 ) ) ;
2012-03-25 04:16:06 +02:00
cairo_fill ( cairo ) ;
2012-02-09 00:29:10 +01:00
}
2012-02-05 11:24:34 +01:00
} else {
/* set background color */
2013-08-24 00:07:32 +02:00
if ( zathura_renderer_recolor_enabled ( priv - > zathura - > sync . render_thread ) = = true ) {
2013-12-01 15:47:28 +01:00
GdkRGBA color ;
2013-08-24 00:07:32 +02:00
zathura_renderer_get_recolor_colors ( priv - > zathura - > sync . render_thread , & color , NULL ) ;
2013-12-01 15:47:28 +01:00
cairo_set_source_rgb ( cairo , color . red , color . green , color . blue ) ;
2012-06-04 11:46:35 +02:00
} else {
2013-12-01 16:04:04 +01:00
const GdkRGBA color = priv - > zathura - > ui . colors . render_loading_bg ;
cairo_set_source_rgb ( cairo , color . red , color . green , color . blue ) ;
2012-06-04 11:46:35 +02:00
}
2012-02-14 14:26:44 +01:00
cairo_rectangle ( cairo , 0 , 0 , page_width , page_height ) ;
2012-02-05 11:24:34 +01:00
cairo_fill ( cairo ) ;
bool render_loading = true ;
girara_setting_get ( priv - > zathura - > ui . session , " render-loading " , & render_loading ) ;
/* write text */
if ( render_loading = = true ) {
2013-08-24 00:07:32 +02:00
if ( zathura_renderer_recolor_enabled ( priv - > zathura - > sync . render_thread ) = = true ) {
2013-12-01 15:47:28 +01:00
GdkRGBA color ;
2013-08-24 00:07:32 +02:00
zathura_renderer_get_recolor_colors ( priv - > zathura - > sync . render_thread , NULL , & color ) ;
2013-12-01 15:47:28 +01:00
cairo_set_source_rgb ( cairo , color . red , color . green , color . blue ) ;
2012-06-04 11:46:35 +02:00
} else {
2013-12-01 16:04:04 +01:00
const GdkRGBA color = priv - > zathura - > ui . colors . render_loading_fg ;
2014-05-26 22:06:38 +02:00
cairo_set_source_rgb ( cairo , color . red , color . green , color . blue ) ;
2012-06-04 11:46:35 +02:00
}
2012-06-20 16:57:51 +02:00
const char * text = _ ( " Loading... " ) ;
2012-02-05 11:24:34 +01:00
cairo_select_font_face ( cairo , " Sans " , CAIRO_FONT_SLANT_NORMAL , CAIRO_FONT_WEIGHT_NORMAL ) ;
cairo_set_font_size ( cairo , 16.0 ) ;
cairo_text_extents_t extents ;
cairo_text_extents ( cairo , text , & extents ) ;
2012-02-14 14:26:44 +01:00
double x = page_width * 0.5 - ( extents . width * 0.5 + extents . x_bearing ) ;
double y = page_height * 0.5 - ( extents . height * 0.5 + extents . y_bearing ) ;
2012-02-05 11:24:34 +01:00
cairo_move_to ( cairo , x , y ) ;
cairo_show_text ( cairo , text ) ;
}
/* render real page */
2013-10-19 17:45:12 +02:00
zathura_render_request ( priv - > render_request , g_get_real_time ( ) ) ;
2012-02-05 11:24:34 +01:00
}
return FALSE ;
}
static void
2012-02-07 18:30:46 +01:00
zathura_page_widget_redraw_canvas ( ZathuraPage * pageview )
2012-02-05 11:24:34 +01:00
{
GtkWidget * widget = GTK_WIDGET ( pageview ) ;
gtk_widget_queue_draw ( widget ) ;
}
2014-10-26 13:19:14 +01:00
/* high enough but not causing noticable delay in scaling */
# define THUMBNAIL_MAX_SIZE (8*1024*1024)
/* smaller than max to be replaced by actual renders */
# define THUMBNAIL_INITIAL_SIZE (THUMBNAIL_MAX_SIZE / 4)
/* small enough to make bilinear downscaling fast */
# define THUMBNAIL_MAX_SCALE 0.5
static bool
surface_small_enough ( cairo_surface_t * surface , cairo_surface_t * old )
{
if ( cairo_surface_get_type ( surface ) ! = CAIRO_SURFACE_TYPE_IMAGE )
return true ;
const unsigned int width = cairo_image_surface_get_width ( surface ) ;
const unsigned int height = cairo_image_surface_get_height ( surface ) ;
if ( width * height > THUMBNAIL_MAX_SIZE )
return false ;
if ( old ! = NULL ) {
const unsigned int width_old = cairo_image_surface_get_width ( old ) ;
const unsigned int height_old = cairo_image_surface_get_height ( old ) ;
if ( width * height < width_old * height_old )
return false ;
}
return true ;
}
static cairo_surface_t *
draw_thumbnail_image ( cairo_surface_t * surface )
{
unsigned int width = cairo_image_surface_get_width ( surface ) ;
unsigned int height = cairo_image_surface_get_height ( surface ) ;
double scale = sqrt ( ( double ) THUMBNAIL_INITIAL_SIZE / ( width * height ) ) ;
if ( scale > THUMBNAIL_MAX_SCALE )
scale = THUMBNAIL_MAX_SCALE ;
width = width * scale ;
height = height * scale ;
cairo_surface_t * thumbnail ;
thumbnail = cairo_surface_create_similar ( surface , CAIRO_CONTENT_COLOR , width , height ) ;
cairo_t * cr = cairo_create ( thumbnail ) ;
cairo_scale ( cr , scale , scale ) ;
cairo_set_source_surface ( cr , surface , 0 , 0 ) ;
cairo_pattern_set_filter ( cairo_get_source ( cr ) , CAIRO_FILTER_BILINEAR ) ;
cairo_set_operator ( cr , CAIRO_OPERATOR_SOURCE ) ;
cairo_paint ( cr ) ;
cairo_destroy ( cr ) ;
return thumbnail ;
}
2012-02-05 11:24:34 +01:00
void
2014-10-26 13:19:14 +01:00
zathura_page_widget_update_surface ( ZathuraPage * widget , cairo_surface_t * surface , bool keep_thumbnail )
2012-02-05 11:24:34 +01:00
{
2012-02-07 18:30:46 +01:00
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
2014-10-26 13:19:14 +01:00
bool new_render = ( priv - > surface = = NULL & & priv - > thumbnail = = NULL ) ;
2012-02-07 14:56:57 +01:00
if ( priv - > surface ! = NULL ) {
2012-02-05 11:24:34 +01:00
cairo_surface_destroy ( priv - > surface ) ;
2013-07-27 16:25:20 +02:00
priv - > surface = NULL ;
2012-02-05 11:24:34 +01:00
}
2013-07-27 16:25:20 +02:00
if ( surface ! = NULL ) {
2013-10-19 17:45:12 +02:00
priv - > surface = surface ;
cairo_surface_reference ( surface ) ;
2014-10-26 13:19:14 +01:00
if ( surface_small_enough ( surface , priv - > thumbnail ) ) {
if ( priv - > thumbnail ! = NULL )
cairo_surface_destroy ( priv - > thumbnail ) ;
priv - > thumbnail = surface ;
cairo_surface_reference ( surface ) ;
} else if ( new_render ) {
priv - > thumbnail = draw_thumbnail_image ( surface ) ;
}
} else if ( ! keep_thumbnail & & priv - > thumbnail ! = NULL ) {
cairo_surface_destroy ( priv - > thumbnail ) ;
priv - > thumbnail = NULL ;
2013-07-27 01:34:42 +02:00
}
2012-02-05 11:24:34 +01:00
/* force a redraw here */
2013-03-24 06:47:10 +01:00
if ( priv - > surface ! = NULL ) {
zathura_page_widget_redraw_canvas ( widget ) ;
}
2012-02-05 11:24:34 +01:00
}
2013-08-30 12:59:27 +02:00
static void
2013-10-19 17:45:12 +02:00
cb_update_surface ( ZathuraRenderRequest * UNUSED ( request ) ,
cairo_surface_t * surface , void * data )
2013-08-30 12:59:27 +02:00
{
ZathuraPage * widget = data ;
g_return_if_fail ( ZATHURA_IS_PAGE ( widget ) ) ;
2014-10-26 13:19:14 +01:00
zathura_page_widget_update_surface ( widget , surface , false ) ;
2013-08-30 12:59:27 +02:00
}
2013-10-19 17:45:12 +02:00
static void
cb_cache_added ( ZathuraRenderRequest * UNUSED ( request ) , void * data )
{
ZathuraPage * widget = data ;
g_return_if_fail ( ZATHURA_IS_PAGE ( widget ) ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
priv - > cached = true ;
}
static void
cb_cache_invalidated ( ZathuraRenderRequest * UNUSED ( request ) , void * data )
{
ZathuraPage * widget = data ;
g_return_if_fail ( ZATHURA_IS_PAGE ( widget ) ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
if ( zathura_page_widget_have_surface ( widget ) = = true & &
priv - > cached = = true & &
zathura_page_get_visibility ( priv - > page ) = = false ) {
/* The page was in the cache but got removed and is invisible, so get rid of
* the surface . */
2014-10-26 13:19:14 +01:00
zathura_page_widget_update_surface ( widget , NULL , false ) ;
2013-10-19 17:45:12 +02:00
}
priv - > cached = false ;
}
2012-02-05 11:24:34 +01:00
static void
2012-02-07 18:30:46 +01:00
zathura_page_widget_size_allocate ( GtkWidget * widget , GdkRectangle * allocation )
2012-02-05 11:24:34 +01:00
{
2012-02-07 18:30:46 +01:00
GTK_WIDGET_CLASS ( zathura_page_widget_parent_class ) - > size_allocate ( widget , allocation ) ;
2013-11-28 14:16:17 +01:00
ZathuraPage * page = ZATHURA_PAGE ( widget ) ;
zathura_page_widget_abort_render_request ( page ) ;
2014-10-26 13:19:14 +01:00
zathura_page_widget_update_surface ( page , NULL , true ) ;
2012-02-05 11:24:34 +01:00
}
2012-02-05 22:55:30 +01:00
static void
2012-02-07 18:30:46 +01:00
redraw_rect ( ZathuraPage * widget , zathura_rectangle_t * rectangle )
2012-02-05 22:55:30 +01:00
{
2012-10-09 01:12:18 +02:00
/* cause the rect to be drawn */
2012-02-05 22:55:30 +01:00
GdkRectangle grect ;
2012-02-07 16:39:02 +01:00
grect . x = rectangle - > x1 ;
2012-02-07 21:45:32 +01:00
grect . y = rectangle - > y1 ;
2012-12-14 15:22:16 +01:00
grect . width = ( rectangle - > x2 + 1 ) - rectangle - > x1 ;
grect . height = ( rectangle - > y2 + 1 ) - rectangle - > y1 ;
2013-10-19 17:45:12 +02:00
gtk_widget_queue_draw_area ( GTK_WIDGET ( widget ) , grect . x , grect . y , grect . width , grect . height ) ;
2012-02-05 22:55:30 +01:00
}
2012-02-07 16:59:42 +01:00
static void
2012-02-07 18:30:46 +01:00
redraw_all_rects ( ZathuraPage * widget , girara_list_t * rectangles )
2012-02-07 16:59:42 +01:00
{
2012-02-07 18:30:46 +01:00
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
2012-02-07 16:59:42 +01:00
GIRARA_LIST_FOREACH ( rectangles , zathura_rectangle_t * , iter , rect )
2014-05-26 22:06:38 +02:00
zathura_rectangle_t rectangle = recalc_rectangle ( priv - > page , * rect ) ;
redraw_rect ( widget , & rectangle ) ;
2012-02-07 16:59:42 +01:00
GIRARA_LIST_FOREACH_END ( rectangles , zathura_recantgle_t * , iter , rect ) ;
}
2012-02-07 16:39:02 +01:00
zathura_link_t *
2012-02-07 18:30:46 +01:00
zathura_page_widget_link_get ( ZathuraPage * widget , unsigned int index )
2012-02-05 22:55:30 +01:00
{
2012-02-07 16:39:02 +01:00
g_return_val_if_fail ( widget ! = NULL , NULL ) ;
2012-02-07 18:30:46 +01:00
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
2012-02-07 16:39:02 +01:00
g_return_val_if_fail ( priv ! = NULL , NULL ) ;
2012-02-05 22:55:30 +01:00
2012-05-06 23:41:25 +02:00
if ( priv - > links . list ! = NULL & & index > = priv - > links . offset & &
girara_list_size ( priv - > links . list ) > index - priv - > links . offset ) {
return girara_list_nth ( priv - > links . list , index - priv - > links . offset ) ;
2012-02-07 17:31:47 +01:00
} else {
return NULL ;
}
2012-02-05 22:55:30 +01:00
}
2012-02-07 18:56:17 +01:00
2012-02-07 21:54:59 +01:00
static gboolean
cb_zathura_page_widget_button_press_event ( GtkWidget * widget , GdkEventButton * button )
2012-02-07 18:56:17 +01:00
{
g_return_val_if_fail ( widget ! = NULL , false ) ;
g_return_val_if_fail ( button ! = NULL , false ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
2012-10-05 00:41:05 +02:00
if ( girara_callback_view_button_press_event ( widget , button , priv - > zathura - > ui . session ) = = true ) {
return true ;
}
2012-03-22 18:51:02 +01:00
if ( button - > button = = 1 ) { /* left click */
if ( button - > type = = GDK_BUTTON_PRESS ) {
/* start the selection */
2012-05-06 23:41:25 +02:00
priv - > mouse . selection_basepoint . x = button - > x ;
priv - > mouse . selection_basepoint . y = button - > y ;
priv - > mouse . selection . x1 = button - > x ;
priv - > mouse . selection . y1 = button - > y ;
priv - > mouse . selection . x2 = button - > x ;
priv - > mouse . selection . y2 = button - > y ;
2012-03-22 18:51:02 +01:00
} else if ( button - > type = = GDK_2BUTTON_PRESS | | button - > type = = GDK_3BUTTON_PRESS ) {
/* abort the selection */
2012-05-06 23:41:25 +02:00
priv - > mouse . selection_basepoint . x = - 1 ;
priv - > mouse . selection_basepoint . y = - 1 ;
priv - > mouse . selection . x1 = - 1 ;
priv - > mouse . selection . y1 = - 1 ;
priv - > mouse . selection . x2 = - 1 ;
priv - > mouse . selection . y2 = - 1 ;
2012-03-22 18:51:02 +01:00
}
return true ;
} else if ( button - > button = = 3 ) { /* right click */
zathura_page_widget_popup_menu ( widget , button ) ;
return true ;
2012-02-09 00:29:10 +01:00
}
2012-03-22 18:51:02 +01:00
2012-02-09 00:29:10 +01:00
return false ;
}
static gboolean
cb_zathura_page_widget_button_release_event ( GtkWidget * widget , GdkEventButton * button )
{
g_return_val_if_fail ( widget ! = NULL , false ) ;
g_return_val_if_fail ( button ! = NULL , false ) ;
2014-08-22 20:42:33 +02:00
if ( button - > type ! = GDK_BUTTON_RELEASE ) {
2012-02-09 00:29:10 +01:00
return false ;
}
2014-08-22 20:42:33 +02:00
const int oldx = button - > x ;
const int oldy = button - > y ;
2012-02-09 00:54:32 +01:00
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
2012-03-26 14:44:56 +02:00
zathura_document_t * document = zathura_page_get_document ( priv - > page ) ;
2012-02-09 00:54:32 +01:00
2014-08-22 20:42:33 +02:00
const double scale = zathura_document_get_scale ( document ) ;
button - > x / = scale ;
button - > y / = scale ;
g_signal_emit ( ZATHURA_PAGE ( widget ) , signals [ BUTTON_RELEASE ] , 0 , button ) ;
button - > x = oldx ;
button - > y = oldy ;
if ( button - > button ! = 1 ) {
return false ;
}
2012-05-06 23:41:25 +02:00
if ( priv - > mouse . selection . y2 = = - 1 & & priv - > mouse . selection . x2 = = - 1 ) {
2012-02-09 00:29:10 +01:00
/* simple single click */
2012-02-07 18:56:17 +01:00
/* get links */
2012-05-06 23:41:25 +02:00
if ( priv - > links . retrieved = = false ) {
priv - > links . list = zathura_page_links_get ( priv - > page , NULL ) ;
priv - > links . retrieved = true ;
priv - > links . n = ( priv - > links . list = = NULL ) ? 0 : girara_list_size ( priv - > links . list ) ;
2012-02-07 18:56:17 +01:00
}
2012-05-06 23:41:25 +02:00
if ( priv - > links . list ! = NULL & & priv - > links . n > 0 ) {
GIRARA_LIST_FOREACH ( priv - > links . list , zathura_link_t * , iter , link )
2012-10-09 01:12:18 +02:00
zathura_rectangle_t rect = recalc_rectangle ( priv - > page , zathura_link_get_position ( link ) ) ;
if ( rect . x1 < = button - > x & & rect . x2 > = button - > x
& & rect . y1 < = button - > y & & rect . y2 > = button - > y ) {
zathura_link_evaluate ( priv - > zathura , link ) ;
}
2012-05-06 23:41:25 +02:00
GIRARA_LIST_FOREACH_END ( priv - > links . list , zathura_link_t * , iter , link ) ;
2012-02-07 18:56:17 +01:00
}
2012-02-09 00:29:10 +01:00
} else {
2012-05-06 23:41:25 +02:00
redraw_rect ( ZATHURA_PAGE ( widget ) , & priv - > mouse . selection ) ;
2012-02-28 10:02:20 +01:00
2014-08-22 20:42:33 +02:00
zathura_rectangle_t tmp = priv - > mouse . selection ;
2012-08-13 18:17:20 +02:00
2014-08-22 20:42:33 +02:00
double scale = zathura_document_get_scale ( document ) ;
tmp . x1 / = scale ;
tmp . x2 / = scale ;
tmp . y1 / = scale ;
tmp . y2 / = scale ;
2012-02-09 00:29:10 +01:00
2014-08-22 20:42:33 +02:00
char * text = zathura_page_get_text ( priv - > page , tmp , NULL ) ;
if ( text ! = NULL ) {
if ( strlen ( text ) > 0 ) {
/* emit text-selected signal */
g_signal_emit ( ZATHURA_PAGE ( widget ) , signals [ TEXT_SELECTED ] , 0 , text ) ;
2014-07-26 16:14:29 +02:00
}
2012-03-07 09:17:05 +01:00
2014-08-22 20:42:33 +02:00
g_free ( text ) ;
2012-02-09 00:29:10 +01:00
}
}
2012-02-28 10:02:20 +01:00
2012-05-06 23:41:25 +02:00
priv - > mouse . selection_basepoint . x = - 1 ;
priv - > mouse . selection_basepoint . y = - 1 ;
priv - > mouse . selection . x1 = - 1 ;
priv - > mouse . selection . y1 = - 1 ;
priv - > mouse . selection . x2 = - 1 ;
priv - > mouse . selection . y2 = - 1 ;
2012-03-07 09:17:05 +01:00
2012-02-09 00:29:10 +01:00
return false ;
}
static gboolean
cb_zathura_page_widget_motion_notify ( GtkWidget * widget , GdkEventMotion * event )
{
g_return_val_if_fail ( widget ! = NULL , false ) ;
g_return_val_if_fail ( event ! = NULL , false ) ;
2014-05-24 18:04:59 +02:00
2012-02-09 00:29:10 +01:00
if ( ( event - > state & GDK_BUTTON1_MASK ) = = 0 ) {
2014-05-24 18:04:59 +02:00
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
if ( priv - > links . retrieved = = false ) {
priv - > links . list = zathura_page_links_get ( priv - > page , NULL ) ;
priv - > links . retrieved = true ;
priv - > links . n = ( priv - > links . list = = NULL ) ? 0 : girara_list_size ( priv - > links . list ) ;
}
if ( priv - > links . list ! = NULL & & priv - > links . n > 0 ) {
bool over_link = false ;
GIRARA_LIST_FOREACH ( priv - > links . list , zathura_link_t * , iter , link )
zathura_rectangle_t rect = recalc_rectangle ( priv - > page , zathura_link_get_position ( link ) ) ;
if ( rect . x1 < = event - > x & & rect . x2 > = event - > x & & rect . y1 < = event - > y & & rect . y2 > = event - > y ) {
over_link = true ;
}
GIRARA_LIST_FOREACH_END ( priv - > links . list , zathura_link_t * , iter , link ) ;
if ( priv - > mouse . over_link ! = over_link ) {
if ( over_link = = true ) {
g_signal_emit ( ZATHURA_PAGE ( widget ) , signals [ ENTER_LINK ] , 0 ) ;
} else {
g_signal_emit ( ZATHURA_PAGE ( widget ) , signals [ LEAVE_LINK ] , 0 ) ;
}
priv - > mouse . over_link = over_link ;
}
}
2012-02-09 00:29:10 +01:00
return false ;
}
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
2012-05-06 23:41:25 +02:00
zathura_rectangle_t tmp = priv - > mouse . selection ;
if ( event - > x < priv - > mouse . selection_basepoint . x ) {
2012-02-09 00:29:10 +01:00
tmp . x1 = event - > x ;
2012-05-06 23:41:25 +02:00
tmp . x2 = priv - > mouse . selection_basepoint . x ;
2012-02-09 00:29:10 +01:00
} else {
tmp . x2 = event - > x ;
2012-05-06 23:41:25 +02:00
tmp . x1 = priv - > mouse . selection_basepoint . x ;
2012-02-09 00:29:10 +01:00
}
2012-05-06 23:41:25 +02:00
if ( event - > y < priv - > mouse . selection_basepoint . y ) {
2012-02-09 00:29:10 +01:00
tmp . y1 = event - > y ;
2012-05-06 23:41:25 +02:00
tmp . y2 = priv - > mouse . selection_basepoint . y ;
2012-02-09 00:29:10 +01:00
} else {
2012-05-06 23:41:25 +02:00
tmp . y1 = priv - > mouse . selection_basepoint . y ;
2012-02-09 00:29:10 +01:00
tmp . y2 = event - > y ;
2012-02-07 18:56:17 +01:00
}
2012-05-06 23:41:25 +02:00
redraw_rect ( ZATHURA_PAGE ( widget ) , & priv - > mouse . selection ) ;
2012-02-09 00:29:10 +01:00
redraw_rect ( ZATHURA_PAGE ( widget ) , & tmp ) ;
2012-05-06 23:41:25 +02:00
priv - > mouse . selection = tmp ;
2012-02-09 00:29:10 +01:00
2012-02-07 18:56:17 +01:00
return false ;
}
2012-03-22 18:51:02 +01:00
2014-05-25 00:52:04 +02:00
static gboolean
cb_zathura_page_widget_leave_notify ( GtkWidget * widget , GdkEventCrossing * UNUSED ( event ) )
{
g_return_val_if_fail ( widget ! = NULL , false ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
if ( priv - > mouse . over_link = = true ) {
g_signal_emit ( ZATHURA_PAGE ( widget ) , signals [ LEAVE_LINK ] , 0 ) ;
priv - > mouse . over_link = false ;
}
return false ;
}
2012-03-22 18:51:02 +01:00
static void
zathura_page_widget_popup_menu ( GtkWidget * widget , GdkEventButton * event )
{
g_return_if_fail ( widget ! = NULL ) ;
g_return_if_fail ( event ! = NULL ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
2012-05-06 23:41:25 +02:00
if ( priv - > images . retrieved = = false ) {
priv - > images . list = zathura_page_images_get ( priv - > page , NULL ) ;
priv - > images . retrieved = true ;
2012-03-22 18:51:02 +01:00
}
2012-05-06 23:41:25 +02:00
if ( priv - > images . list = = NULL ) {
2012-03-22 18:51:02 +01:00
return ;
}
/* search for underlaying image */
zathura_image_t * image = NULL ;
2012-05-06 23:41:25 +02:00
GIRARA_LIST_FOREACH ( priv - > images . list , zathura_image_t * , iter , image_it )
2014-05-26 22:06:38 +02:00
zathura_rectangle_t rect = recalc_rectangle ( priv - > page , image_it - > position ) ;
if ( rect . x1 < = event - > x & & rect . x2 > = event - > x & & rect . y1 < = event - > y & & rect . y2 > = event - > y ) {
image = image_it ;
}
2012-05-06 23:41:25 +02:00
GIRARA_LIST_FOREACH_END ( priv - > images . list , zathura_image_t * , iter , image_it ) ;
2012-03-22 18:51:02 +01:00
if ( image = = NULL ) {
return ;
}
2012-05-06 23:41:25 +02:00
priv - > images . current = image ;
2012-03-22 18:51:02 +01:00
/* setup menu */
GtkWidget * menu = gtk_menu_new ( ) ;
typedef struct menu_item_s {
char * text ;
void ( * callback ) ( GtkMenuItem * , ZathuraPage * ) ;
} menu_item_t ;
2014-08-15 18:34:21 +02:00
const menu_item_t menu_items [ ] = {
2012-05-01 11:54:52 +02:00
{ _ ( " Copy image " ) , cb_menu_image_copy } ,
{ _ ( " Save image as " ) , cb_menu_image_save } ,
2012-03-22 18:51:02 +01:00
} ;
for ( unsigned int i = 0 ; i < LENGTH ( menu_items ) ; i + + ) {
GtkWidget * item = gtk_menu_item_new_with_label ( menu_items [ i ] . text ) ;
gtk_menu_shell_append ( GTK_MENU_SHELL ( menu ) , item ) ;
gtk_widget_show ( item ) ;
g_signal_connect ( G_OBJECT ( item ) , " activate " , G_CALLBACK ( menu_items [ i ] . callback ) , ZATHURA_PAGE ( widget ) ) ;
}
/* attach and popup */
int event_button = 0 ;
int event_time = gtk_get_current_event_time ( ) ;
if ( event ! = NULL ) {
event_button = event - > button ;
event_time = event - > time ;
}
gtk_menu_attach_to_widget ( GTK_MENU ( menu ) , widget , NULL ) ;
gtk_menu_popup ( GTK_MENU ( menu ) , NULL , NULL , NULL , NULL , event_button , event_time ) ;
}
static gboolean
cb_zathura_page_widget_popup_menu ( GtkWidget * widget )
{
zathura_page_widget_popup_menu ( widget , NULL ) ;
return TRUE ;
}
static void
cb_menu_image_copy ( GtkMenuItem * item , ZathuraPage * page )
{
g_return_if_fail ( item ! = NULL ) ;
g_return_if_fail ( page ! = NULL ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( page ) ;
2012-05-06 23:41:25 +02:00
g_return_if_fail ( priv - > images . current ! = NULL ) ;
2012-03-22 18:51:02 +01:00
2012-05-06 23:41:25 +02:00
cairo_surface_t * surface = zathura_page_image_get_cairo ( priv - > page , priv - > images . current , NULL ) ;
2012-03-22 18:51:02 +01:00
if ( surface = = NULL ) {
return ;
}
2013-10-31 14:53:51 +01:00
const int width = cairo_image_surface_get_width ( surface ) ;
const int height = cairo_image_surface_get_height ( surface ) ;
2012-03-22 18:51:02 +01:00
2013-10-31 14:53:51 +01:00
GdkPixbuf * pixbuf = gdk_pixbuf_get_from_surface ( surface , 0 , 0 , width , height ) ;
2013-08-31 13:12:41 +02:00
g_signal_emit ( page , signals [ IMAGE_SELECTED ] , 0 , pixbuf ) ;
g_object_unref ( pixbuf ) ;
2013-10-31 14:53:51 +01:00
cairo_surface_destroy ( surface ) ;
2012-03-22 18:51:02 +01:00
2012-05-01 11:54:52 +02:00
/* reset */
2012-05-06 23:41:25 +02:00
priv - > images . current = NULL ;
2012-03-22 18:51:02 +01:00
}
2012-03-24 16:15:34 +01:00
2012-05-01 11:54:52 +02:00
static void
cb_menu_image_save ( GtkMenuItem * item , ZathuraPage * page )
{
g_return_if_fail ( item ! = NULL ) ;
g_return_if_fail ( page ! = NULL ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( page ) ;
2012-05-06 23:41:25 +02:00
g_return_if_fail ( priv - > images . current ! = NULL ) ;
g_return_if_fail ( priv - > images . list ! = NULL ) ;
2012-05-01 11:54:52 +02:00
/* generate image identifier */
unsigned int page_id = zathura_page_get_index ( priv - > page ) + 1 ;
unsigned int image_id = 1 ;
2012-05-06 23:41:25 +02:00
GIRARA_LIST_FOREACH ( priv - > images . list , zathura_image_t * , iter , image_it )
2013-10-19 17:45:12 +02:00
if ( image_it = = priv - > images . current ) {
break ;
}
2012-05-01 11:54:52 +02:00
2013-10-19 17:45:12 +02:00
image_id + + ;
2012-05-06 23:41:25 +02:00
GIRARA_LIST_FOREACH_END ( priv - > images . list , zathura_image_t * , iter , image_it ) ;
2012-05-01 11:54:52 +02:00
/* set command */
char * export_command = g_strdup_printf ( " :export image-p%d-%d " , page_id , image_id ) ;
girara_argument_t argument = { 0 , export_command } ;
sc_focus_inputbar ( priv - > zathura - > ui . session , & argument , NULL , 0 ) ;
g_free ( export_command ) ;
/* reset */
2012-05-06 23:41:25 +02:00
priv - > images . current = NULL ;
2012-05-01 11:54:52 +02:00
}
2012-03-24 16:15:34 +01:00
void
zathura_page_widget_update_view_time ( ZathuraPage * widget )
{
2013-10-19 17:45:12 +02:00
g_return_if_fail ( ZATHURA_IS_PAGE ( widget ) ) ;
2012-03-24 16:15:34 +01:00
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
2012-03-26 14:44:56 +02:00
if ( zathura_page_get_visibility ( priv - > page ) = = true ) {
2013-10-19 17:45:12 +02:00
zathura_render_request_update_view_time ( priv - > render_request ) ;
2012-03-24 16:15:34 +01:00
}
}
2013-07-27 16:25:20 +02:00
bool
zathura_page_widget_have_surface ( ZathuraPage * widget )
{
2013-10-19 17:45:12 +02:00
g_return_val_if_fail ( ZATHURA_IS_PAGE ( widget ) , false ) ;
2013-07-27 16:25:20 +02:00
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
return priv - > surface ! = NULL ;
}
2013-08-30 18:56:15 +02:00
void
zathura_page_widget_abort_render_request ( ZathuraPage * widget )
{
g_return_if_fail ( ZATHURA_IS_PAGE ( widget ) ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
zathura_render_request_abort ( priv - > render_request ) ;
2013-10-19 17:45:12 +02:00
/* Make sure that if we are not cached and invisible, that there is no
* surface .
*
* TODO : Maybe this should be moved somewhere else . */
if ( zathura_page_widget_have_surface ( widget ) = = true & &
priv - > cached = = false ) {
2014-10-26 13:19:14 +01:00
zathura_page_widget_update_surface ( widget , NULL , false ) ;
2013-10-19 17:45:12 +02:00
}
2013-08-30 18:56:15 +02:00
}
2014-08-22 20:42:33 +02:00
zathura_page_t *
zathura_page_widget_get_page ( ZathuraPage * widget ) {
g_return_val_if_fail ( ZATHURA_IS_PAGE ( widget ) , NULL ) ;
zathura_page_widget_private_t * priv = ZATHURA_PAGE_GET_PRIVATE ( widget ) ;
return priv - > page ;
}