1
/* ev-annotation-window.c
2
* this file is part of evince, a gnome document viewer
4
* Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
5
* Copyright (C) 2007 Iñigo Martinez <inigomartinez@gmail.com>
7
* Evince is free software; you can redistribute it and/or modify it
8
* under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* Evince is distributed in the hope that it will be useful, but
13
* WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26
#include "ev-annotation-window.h"
27
#include "ev-stock-icons.h"
28
#include "ev-view-marshal.h"
29
#include "ev-document-misc.h"
43
struct _EvAnnotationWindow {
44
GtkWindow base_instance;
46
EvAnnotation *annotation;
50
GtkWidget *close_button;
65
struct _EvAnnotationWindowClass {
66
GtkWindowClass base_class;
68
void (* closed) (EvAnnotationWindow *window);
69
void (* moved) (EvAnnotationWindow *window,
74
static guint signals[N_SIGNALS];
76
G_DEFINE_TYPE (EvAnnotationWindow, ev_annotation_window, GTK_TYPE_WINDOW)
78
#define EV_ICON_SIZE_ANNOT_WINDOW (ev_annotation_window_get_icon_size())
80
/* Cut and paste from gtkwindow.c */
82
send_focus_change (GtkWidget *widget,
85
GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
87
fevent->focus_change.type = GDK_FOCUS_CHANGE;
88
fevent->focus_change.window = gtk_widget_get_window (widget);
89
fevent->focus_change.in = in;
90
if (fevent->focus_change.window)
91
g_object_ref (fevent->focus_change.window);
93
gtk_widget_send_focus_change (widget, fevent);
95
gdk_event_free (fevent);
99
get_screen_dpi (EvAnnotationWindow *window)
103
screen = gtk_window_get_screen (GTK_WINDOW (window));
104
return ev_document_misc_get_screen_dpi (screen);
108
ev_annotation_window_get_icon_size (void)
110
static GtkIconSize icon_size = 0;
112
if (G_UNLIKELY (icon_size == 0))
113
icon_size = gtk_icon_size_register ("ev-icon-size-annot-window", 8, 8);
119
ev_annotation_window_sync_contents (EvAnnotationWindow *window)
122
GtkTextIter start, end;
123
GtkTextBuffer *buffer;
124
EvAnnotation *annot = window->annotation;
126
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->text_view));
127
gtk_text_buffer_get_bounds (buffer, &start, &end);
128
contents = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
129
ev_annotation_set_contents (annot, contents);
134
ev_annotation_window_set_color (EvAnnotationWindow *window,
137
GtkStyleProperties *properties;
138
GtkStyleProvider *provider;
141
rgba.red = color->red / 65535.;
142
rgba.green = color->green / 65535.;
143
rgba.blue = color->blue / 65535.;
146
properties = gtk_style_properties_new ();
147
gtk_style_properties_set (properties, 0,
148
"background-color", &rgba,
151
provider = GTK_STYLE_PROVIDER (properties);
152
gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (window)),
153
provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
154
gtk_style_context_add_provider (gtk_widget_get_style_context (window->close_button),
155
provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
156
gtk_style_context_add_provider (gtk_widget_get_style_context (window->resize_se),
157
provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
158
gtk_style_context_add_provider (gtk_widget_get_style_context (window->resize_sw),
159
provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
160
g_object_unref (properties);
164
ev_annotation_window_label_changed (EvAnnotationMarkup *annot,
166
EvAnnotationWindow *window)
168
const gchar *label = ev_annotation_markup_get_label (annot);
170
gtk_window_set_title (GTK_WINDOW (window), label);
171
gtk_label_set_text (GTK_LABEL (window->title), label);
175
ev_annotation_window_color_changed (EvAnnotation *annot,
177
EvAnnotationWindow *window)
181
ev_annotation_get_color (annot, &color);
182
ev_annotation_window_set_color (window, &color);
186
ev_annotation_window_dispose (GObject *object)
188
EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (object);
190
if (window->annotation) {
191
ev_annotation_window_sync_contents (window);
192
g_object_unref (window->annotation);
193
window->annotation = NULL;
196
(* G_OBJECT_CLASS (ev_annotation_window_parent_class)->dispose) (object);
200
ev_annotation_window_set_property (GObject *object,
205
EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (object);
208
case PROP_ANNOTATION:
209
window->annotation = g_value_dup_object (value);
212
window->parent = g_value_get_object (value);
215
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
220
ev_annotation_window_resize (EvAnnotationWindow *window,
221
GdkEventButton *event,
224
if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
225
gtk_window_begin_resize_drag (GTK_WINDOW (window),
226
window->resize_sw == ebox ?
227
GDK_WINDOW_EDGE_SOUTH_WEST :
228
GDK_WINDOW_EDGE_SOUTH_EAST,
229
event->button, event->x_root,
230
event->y_root, event->time);
238
ev_annotation_window_set_resize_cursor (GtkWidget *widget,
239
EvAnnotationWindow *window)
241
GdkWindow *gdk_window = gtk_widget_get_window (widget);
246
if (gtk_widget_is_sensitive (widget)) {
247
GdkDisplay *display = gtk_widget_get_display (widget);
250
cursor = gdk_cursor_new_for_display (display,
251
widget == window->resize_sw ?
252
GDK_BOTTOM_LEFT_CORNER :
253
GDK_BOTTOM_RIGHT_CORNER);
254
gdk_window_set_cursor (gdk_window, cursor);
255
g_object_unref (cursor);
257
gdk_window_set_cursor (gdk_window, NULL);
262
text_view_button_press (GtkWidget *widget,
263
GdkEventButton *event,
264
EvAnnotationWindow *window)
266
ev_annotation_window_grab_focus (window);
272
ev_annotation_window_close (EvAnnotationWindow *window)
274
gtk_widget_hide (GTK_WIDGET (window));
275
g_signal_emit (window, signals[CLOSED], 0);
279
ev_annotation_window_init (EvAnnotationWindow *window)
281
GtkWidget *vbox, *hbox;
285
gtk_widget_set_can_focus (GTK_WIDGET (window), TRUE);
287
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
290
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
292
icon = gtk_image_new (); /* FIXME: use the annot icon */
293
gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
294
gtk_widget_show (icon);
296
window->title = gtk_label_new (NULL);
297
gtk_box_pack_start (GTK_BOX (hbox), window->title, TRUE, TRUE, 0);
298
gtk_widget_show (window->title);
300
window->close_button = gtk_button_new ();
301
gtk_button_set_relief (GTK_BUTTON (window->close_button), GTK_RELIEF_NONE);
302
gtk_container_set_border_width (GTK_CONTAINER (window->close_button), 0);
303
g_signal_connect_swapped (window->close_button, "clicked",
304
G_CALLBACK (ev_annotation_window_close),
306
icon = gtk_image_new_from_stock (EV_STOCK_CLOSE, EV_ICON_SIZE_ANNOT_WINDOW);
307
gtk_container_add (GTK_CONTAINER (window->close_button), icon);
308
gtk_widget_show (icon);
310
gtk_box_pack_start (GTK_BOX (hbox), window->close_button, FALSE, FALSE, 0);
311
gtk_widget_show (window->close_button);
313
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
314
gtk_widget_show (hbox);
317
swindow = gtk_scrolled_window_new (NULL, NULL);
318
window->text_view = gtk_text_view_new ();
319
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (window->text_view), GTK_WRAP_WORD);
320
g_signal_connect (window->text_view, "button_press_event",
321
G_CALLBACK (text_view_button_press),
323
gtk_container_add (GTK_CONTAINER (swindow), window->text_view);
324
gtk_widget_show (window->text_view);
326
gtk_box_pack_start (GTK_BOX (vbox), swindow, TRUE, TRUE, 0);
327
gtk_widget_show (swindow);
330
gtk_window_set_has_resize_grip (GTK_WINDOW(window), FALSE);
331
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
333
window->resize_sw = gtk_event_box_new ();
334
gtk_widget_add_events (window->resize_sw, GDK_BUTTON_PRESS_MASK);
335
g_signal_connect_swapped (window->resize_sw, "button-press-event",
336
G_CALLBACK (ev_annotation_window_resize),
338
g_signal_connect (window->resize_sw, "realize",
339
G_CALLBACK (ev_annotation_window_set_resize_cursor),
342
icon = gtk_image_new_from_stock (EV_STOCK_RESIZE_SW, EV_ICON_SIZE_ANNOT_WINDOW);
343
gtk_container_add (GTK_CONTAINER (window->resize_sw), icon);
344
gtk_widget_show (icon);
345
gtk_box_pack_start (GTK_BOX (hbox), window->resize_sw, FALSE, FALSE, 0);
346
gtk_widget_show (window->resize_sw);
348
window->resize_se = gtk_event_box_new ();
349
gtk_widget_add_events (window->resize_se, GDK_BUTTON_PRESS_MASK);
350
g_signal_connect_swapped (window->resize_se, "button-press-event",
351
G_CALLBACK (ev_annotation_window_resize),
353
g_signal_connect (window->resize_se, "realize",
354
G_CALLBACK (ev_annotation_window_set_resize_cursor),
357
icon = gtk_image_new_from_stock (EV_STOCK_RESIZE_SE, EV_ICON_SIZE_ANNOT_WINDOW);
358
gtk_container_add (GTK_CONTAINER (window->resize_se), icon);
359
gtk_widget_show (icon);
360
gtk_box_pack_end (GTK_BOX (hbox), window->resize_se, FALSE, FALSE, 0);
361
gtk_widget_show (window->resize_se);
363
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
364
gtk_widget_show (hbox);
366
gtk_container_add (GTK_CONTAINER (window), vbox);
367
gtk_container_set_border_width (GTK_CONTAINER (window), 0);
368
gtk_widget_show (vbox);
370
gtk_widget_add_events (GTK_WIDGET (window),
371
GDK_BUTTON_PRESS_MASK |
373
gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
375
gtk_container_set_border_width (GTK_CONTAINER (window), 2);
377
gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
378
gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
379
gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
380
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
384
ev_annotation_window_constructor (GType type,
385
guint n_construct_properties,
386
GObjectConstructParam *construct_params)
389
EvAnnotationWindow *window;
391
EvAnnotationMarkup *markup;
392
const gchar *contents;
398
object = G_OBJECT_CLASS (ev_annotation_window_parent_class)->constructor (type,
399
n_construct_properties,
401
window = EV_ANNOTATION_WINDOW (object);
402
annot = window->annotation;
403
markup = EV_ANNOTATION_MARKUP (annot);
405
gtk_window_set_transient_for (GTK_WINDOW (window), window->parent);
406
gtk_window_set_destroy_with_parent (GTK_WINDOW (window), FALSE);
408
label = ev_annotation_markup_get_label (markup);
409
window->is_open = ev_annotation_markup_get_popup_is_open (markup);
410
ev_annotation_markup_get_rectangle (markup, &window->rect);
412
rect = &window->rect;
414
/* Rectangle is at doc resolution (72.0) */
415
scale = get_screen_dpi (window) / 72.0;
416
gtk_window_resize (GTK_WINDOW (window),
417
(gint)((rect->x2 - rect->x1) * scale),
418
(gint)((rect->y2 - rect->y1) * scale));
420
ev_annotation_get_color (annot, &color);
421
ev_annotation_window_set_color (window, &color);
422
gtk_widget_set_name (GTK_WIDGET (window), ev_annotation_get_name (annot));
423
gtk_window_set_title (GTK_WINDOW (window), label);
424
gtk_label_set_text (GTK_LABEL (window->title), label);
426
contents = ev_annotation_get_contents (annot);
428
GtkTextBuffer *buffer;
430
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->text_view));
431
gtk_text_buffer_set_text (buffer, contents, -1);
434
g_signal_connect (annot, "notify::label",
435
G_CALLBACK (ev_annotation_window_label_changed),
437
g_signal_connect (annot, "notify::color",
438
G_CALLBACK (ev_annotation_window_color_changed),
445
ev_annotation_window_button_press_event (GtkWidget *widget,
446
GdkEventButton *event)
448
EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (widget);
450
if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
451
window->in_move = TRUE;
452
window->x = event->x_root - event->x;
453
window->y = event->y_root - event->y;
454
gtk_window_begin_move_drag (GTK_WINDOW (widget),
466
ev_annotation_window_configure_event (GtkWidget *widget,
467
GdkEventConfigure *event)
469
EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (widget);
471
if (window->in_move &&
472
(window->x != event->x || window->y != event->y)) {
473
window->x = event->x;
474
window->y = event->y;
477
return GTK_WIDGET_CLASS (ev_annotation_window_parent_class)->configure_event (widget, event);
481
ev_annotation_window_focus_in_event (GtkWidget *widget,
482
GdkEventFocus *event)
484
EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (widget);
486
if (window->in_move) {
487
if (window->orig_x != window->x || window->orig_y != window->y) {
488
window->orig_x = window->x;
489
window->orig_y = window->y;
490
g_signal_emit (window, signals[MOVED], 0, window->x, window->y);
492
window->in_move = FALSE;
499
ev_annotation_window_focus_out_event (GtkWidget *widget,
500
GdkEventFocus *event)
502
EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (widget);
504
ev_annotation_window_sync_contents (window);
510
ev_annotation_window_class_init (EvAnnotationWindowClass *klass)
512
GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
513
GtkWidgetClass *gtk_widget_class = GTK_WIDGET_CLASS (klass);
515
g_object_class->constructor = ev_annotation_window_constructor;
516
g_object_class->set_property = ev_annotation_window_set_property;
517
g_object_class->dispose = ev_annotation_window_dispose;
519
gtk_widget_class->button_press_event = ev_annotation_window_button_press_event;
520
gtk_widget_class->configure_event = ev_annotation_window_configure_event;
521
gtk_widget_class->focus_in_event = ev_annotation_window_focus_in_event;
522
gtk_widget_class->focus_out_event = ev_annotation_window_focus_out_event;
524
g_object_class_install_property (g_object_class,
526
g_param_spec_object ("annotation",
528
"The annotation associated to the window",
529
EV_TYPE_ANNOTATION_MARKUP,
531
G_PARAM_CONSTRUCT_ONLY |
532
G_PARAM_STATIC_STRINGS));
533
g_object_class_install_property (g_object_class,
535
g_param_spec_object ("parent",
540
G_PARAM_CONSTRUCT_ONLY |
541
G_PARAM_STATIC_STRINGS));
543
g_signal_new ("closed",
544
G_TYPE_FROM_CLASS (g_object_class),
545
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
546
G_STRUCT_OFFSET (EvAnnotationWindowClass, closed),
548
g_cclosure_marshal_VOID__VOID,
549
G_TYPE_NONE, 0, G_TYPE_NONE);
551
g_signal_new ("moved",
552
G_TYPE_FROM_CLASS (g_object_class),
553
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
554
G_STRUCT_OFFSET (EvAnnotationWindowClass, moved),
556
ev_view_marshal_VOID__INT_INT,
558
G_TYPE_INT, G_TYPE_INT);
563
ev_annotation_window_new (EvAnnotation *annot,
568
g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (annot), NULL);
569
g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
571
window = g_object_new (EV_TYPE_ANNOTATION_WINDOW,
579
ev_annotation_window_get_annotation (EvAnnotationWindow *window)
581
g_return_val_if_fail (EV_IS_ANNOTATION_WINDOW (window), NULL);
583
return window->annotation;
587
ev_annotation_window_set_annotation (EvAnnotationWindow *window,
590
g_return_if_fail (EV_IS_ANNOTATION_WINDOW (window));
591
g_return_if_fail (EV_IS_ANNOTATION (annot));
593
if (annot == window->annotation)
596
g_object_unref (window->annotation);
597
window->annotation = g_object_ref (annot);
598
ev_annotation_window_sync_contents (window);
599
g_object_notify (G_OBJECT (window), "annotation");
603
ev_annotation_window_is_open (EvAnnotationWindow *window)
605
g_return_val_if_fail (EV_IS_ANNOTATION_WINDOW (window), FALSE);
607
return window->is_open;
611
ev_annotation_window_get_rectangle (EvAnnotationWindow *window,
614
g_return_if_fail (EV_IS_ANNOTATION_WINDOW (window));
615
g_return_if_fail (rect != NULL);
617
*rect = window->rect;
621
ev_annotation_window_set_rectangle (EvAnnotationWindow *window,
622
const EvRectangle *rect)
624
g_return_if_fail (EV_IS_ANNOTATION_WINDOW (window));
625
g_return_if_fail (rect != NULL);
627
window->rect = *rect;
631
ev_annotation_window_grab_focus (EvAnnotationWindow *window)
633
g_return_if_fail (EV_IS_ANNOTATION_WINDOW (window));
635
if (!gtk_widget_has_focus (window->text_view)) {
636
gtk_widget_grab_focus (GTK_WIDGET (window));
637
send_focus_change (window->text_view, TRUE);
642
ev_annotation_window_ungrab_focus (EvAnnotationWindow *window)
644
g_return_if_fail (EV_IS_ANNOTATION_WINDOW (window));
646
if (gtk_widget_has_focus (window->text_view)) {
647
send_focus_change (window->text_view, FALSE);
650
ev_annotation_window_sync_contents (window);