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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
26 #include "ev-annotation-window.h"
27 #include "ev-stock-icons.h"
28 #include "ev-view-marshal.h"
42 struct _EvAnnotationWindow {
43 GtkWindow base_instance;
45 EvAnnotation *annotation;
49 GtkWidget *close_button;
64 struct _EvAnnotationWindowClass {
65 GtkWindowClass base_class;
67 void (* closed) (EvAnnotationWindow *window);
68 void (* moved) (EvAnnotationWindow *window,
73 static guint signals[N_SIGNALS];
75 G_DEFINE_TYPE (EvAnnotationWindow, ev_annotation_window, GTK_TYPE_WINDOW)
77 #define EV_ICON_SIZE_ANNOT_WINDOW (ev_annotation_window_get_icon_size())
79 /* Cut and paste from gtkwindow.c */
81 send_focus_change (GtkWidget *widget,
84 GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
86 g_object_ref (widget);
89 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
91 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
93 fevent->focus_change.type = GDK_FOCUS_CHANGE;
94 fevent->focus_change.window = g_object_ref (widget->window);
95 fevent->focus_change.in = in;
97 gtk_widget_event (widget, fevent);
99 g_object_notify (G_OBJECT (widget), "has-focus");
101 g_object_unref (widget);
102 gdk_event_free (fevent);
106 get_screen_dpi (GtkWindow *window)
111 screen = gtk_window_get_screen (window);
113 xdpi = 25.4 * gdk_screen_get_width (screen) / gdk_screen_get_width_mm (screen);
114 ydpi = 25.4 * gdk_screen_get_height (screen) / gdk_screen_get_height_mm (screen);
116 return (xdpi + ydpi) / 2.0;
120 ev_annotation_window_get_icon_size (void)
122 static GtkIconSize icon_size = 0;
124 if (G_UNLIKELY (icon_size == 0))
125 icon_size = gtk_icon_size_register ("ev-icon-size-annot-window", 8, 8);
131 ev_annotation_window_check_contents_modified (EvAnnotationWindow *window)
134 GtkTextIter start, end;
135 GtkTextBuffer *buffer;
136 EvAnnotation *annot = window->annotation;
138 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->text_view));
139 gtk_text_buffer_get_bounds (buffer, &start, &end);
140 contents = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
142 if (contents && annot->contents) {
143 if (strcasecmp (contents, annot->contents) != 0) {
144 g_free (annot->contents);
145 annot->contents = contents;
146 annot->changed = TRUE;
150 } else if (annot->contents) {
151 g_free (annot->contents);
152 annot->contents = NULL;
153 annot->changed = TRUE;
154 } else if (contents) {
155 annot->contents = contents;
156 annot->changed = TRUE;
161 ev_annotation_window_set_color (EvAnnotationWindow *window,
164 GtkRcStyle *rc_style;
169 /* Allocate these colors */
170 gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (window)),
171 &gcolor, FALSE, TRUE);
173 /* Apply colors to style */
174 rc_style = gtk_widget_get_modifier_style (GTK_WIDGET (window));
175 rc_style->base[GTK_STATE_NORMAL] = gcolor;
176 rc_style->bg[GTK_STATE_PRELIGHT] = gcolor;
177 rc_style->bg[GTK_STATE_NORMAL] = gcolor;
178 rc_style->bg[GTK_STATE_ACTIVE] = gcolor;
179 rc_style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_BG;
180 rc_style->color_flags[GTK_STATE_NORMAL] = GTK_RC_BG | GTK_RC_BASE;
181 rc_style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_BG;
183 /* Apply the style to the widgets */
184 g_object_ref (rc_style);
185 gtk_widget_modify_style (GTK_WIDGET (window), rc_style);
186 gtk_widget_modify_style (window->close_button, rc_style);
187 gtk_widget_modify_style (window->resize_se, rc_style);
188 gtk_widget_modify_style (window->resize_sw, rc_style);
189 g_object_unref (rc_style);
193 ev_annotation_window_dispose (GObject *object)
195 EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (object);
197 if (window->annotation) {
198 ev_annotation_window_check_contents_modified (window);
199 g_object_unref (window->annotation);
200 window->annotation = NULL;
204 ev_rectangle_free (window->rect);
208 (* G_OBJECT_CLASS (ev_annotation_window_parent_class)->dispose) (object);
212 ev_annotation_window_set_property (GObject *object,
217 EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (object);
220 case PROP_ANNOTATION:
221 window->annotation = g_value_dup_object (value);
224 window->parent = g_value_get_object (value);
227 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
232 ev_annotation_window_resize (EvAnnotationWindow *window,
233 GdkEventButton *event,
236 if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
237 gtk_window_begin_resize_drag (GTK_WINDOW (window),
238 window->resize_sw == ebox ?
239 GDK_WINDOW_EDGE_SOUTH_WEST :
240 GDK_WINDOW_EDGE_SOUTH_EAST,
241 event->button, event->x_root,
242 event->y_root, event->time);
250 ev_annotation_window_set_resize_cursor (GtkWidget *widget,
251 EvAnnotationWindow *window)
256 if (GTK_WIDGET_IS_SENSITIVE (widget)) {
257 GdkDisplay *display = gtk_widget_get_display (widget);
260 cursor = gdk_cursor_new_for_display (display,
261 widget == window->resize_sw ?
262 GDK_BOTTOM_LEFT_CORNER :
263 GDK_BOTTOM_RIGHT_CORNER);
264 gdk_window_set_cursor (widget->window, cursor);
265 gdk_cursor_unref (cursor);
267 gdk_window_set_cursor (widget->window, NULL);
272 text_view_button_press (GtkWidget *widget,
273 GdkEventButton *event,
274 EvAnnotationWindow *window)
276 ev_annotation_window_grab_focus (window);
282 ev_annotation_window_close (EvAnnotationWindow *window)
284 gtk_widget_hide (GTK_WIDGET (window));
285 g_signal_emit (window, signals[CLOSED], 0);
289 ev_annotation_window_init (EvAnnotationWindow *window)
291 GtkWidget *vbox, *hbox;
295 GTK_WIDGET_SET_FLAGS (window, GTK_CAN_FOCUS);
297 vbox = gtk_vbox_new (FALSE, 0);
300 hbox = gtk_hbox_new (FALSE, 0);
302 icon = gtk_image_new (); /* FIXME: use the annot icon */
303 gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
304 gtk_widget_show (icon);
306 window->title = gtk_label_new (NULL);
307 gtk_box_pack_start (GTK_BOX (hbox), window->title, TRUE, TRUE, 0);
308 gtk_widget_show (window->title);
310 window->close_button = gtk_button_new ();
311 gtk_button_set_relief (GTK_BUTTON (window->close_button), GTK_RELIEF_NONE);
312 gtk_container_set_border_width (GTK_CONTAINER (window->close_button), 0);
313 g_signal_connect_swapped (window->close_button, "clicked",
314 G_CALLBACK (ev_annotation_window_close),
316 icon = gtk_image_new_from_stock (EV_STOCK_CLOSE, EV_ICON_SIZE_ANNOT_WINDOW);
317 gtk_container_add (GTK_CONTAINER (window->close_button), icon);
318 gtk_widget_show (icon);
320 gtk_box_pack_start (GTK_BOX (hbox), window->close_button, FALSE, FALSE, 0);
321 gtk_widget_show (window->close_button);
323 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
324 gtk_widget_show (hbox);
327 swindow = gtk_scrolled_window_new (NULL, NULL);
328 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
329 GTK_POLICY_AUTOMATIC,
330 GTK_POLICY_AUTOMATIC);
331 window->text_view = gtk_text_view_new ();
332 g_signal_connect (window->text_view, "button_press_event",
333 G_CALLBACK (text_view_button_press),
335 gtk_container_add (GTK_CONTAINER (swindow), window->text_view);
336 gtk_widget_show (window->text_view);
338 gtk_box_pack_start (GTK_BOX (vbox), swindow, TRUE, TRUE, 0);
339 gtk_widget_show (swindow);
342 hbox = gtk_hbox_new (FALSE, 0);
344 window->resize_sw = gtk_event_box_new ();
345 gtk_widget_add_events (window->resize_sw, GDK_BUTTON_PRESS_MASK);
346 g_signal_connect_swapped (window->resize_sw, "button-press-event",
347 G_CALLBACK (ev_annotation_window_resize),
349 g_signal_connect (window->resize_sw, "realize",
350 G_CALLBACK (ev_annotation_window_set_resize_cursor),
353 icon = gtk_image_new_from_stock (EV_STOCK_RESIZE_SW, EV_ICON_SIZE_ANNOT_WINDOW);
354 gtk_container_add (GTK_CONTAINER (window->resize_sw), icon);
355 gtk_widget_show (icon);
356 gtk_box_pack_start (GTK_BOX (hbox), window->resize_sw, FALSE, FALSE, 0);
357 gtk_widget_show (window->resize_sw);
359 window->resize_se = gtk_event_box_new ();
360 gtk_widget_add_events (window->resize_se, GDK_BUTTON_PRESS_MASK);
361 g_signal_connect_swapped (window->resize_se, "button-press-event",
362 G_CALLBACK (ev_annotation_window_resize),
364 g_signal_connect (window->resize_se, "realize",
365 G_CALLBACK (ev_annotation_window_set_resize_cursor),
368 icon = gtk_image_new_from_stock (EV_STOCK_RESIZE_SE, EV_ICON_SIZE_ANNOT_WINDOW);
369 gtk_container_add (GTK_CONTAINER (window->resize_se), icon);
370 gtk_widget_show (icon);
371 gtk_box_pack_end (GTK_BOX (hbox), window->resize_se, FALSE, FALSE, 0);
372 gtk_widget_show (window->resize_se);
374 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
375 gtk_widget_show (hbox);
377 gtk_container_add (GTK_CONTAINER (window), vbox);
378 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
379 gtk_widget_show (vbox);
381 gtk_widget_add_events (GTK_WIDGET (window),
382 GDK_BUTTON_PRESS_MASK |
384 gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
386 gtk_container_set_border_width (GTK_CONTAINER (window), 2);
388 gtk_window_set_accept_focus (GTK_WINDOW (window), FALSE);
389 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
390 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
391 gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
392 gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
396 ev_annotation_window_constructor (GType type,
397 guint n_construct_properties,
398 GObjectConstructParam *construct_params)
401 EvAnnotationWindow *window;
408 object = G_OBJECT_CLASS (ev_annotation_window_parent_class)->constructor (type,
409 n_construct_properties,
411 window = EV_ANNOTATION_WINDOW (object);
412 annot = window->annotation;
414 gtk_window_set_transient_for (GTK_WINDOW (window), window->parent);
415 gtk_window_set_destroy_with_parent (GTK_WINDOW (window), FALSE);
420 "is_open", &window->is_open,
421 "rectangle", &window->rect,
425 /* Rectangle is at doc resolution (72.0) */
426 scale = get_screen_dpi (GTK_WINDOW (window)) / 72.0;
427 gtk_window_resize (GTK_WINDOW (window),
428 (gint)((rect->x2 - rect->x1) * scale),
429 (gint)((rect->y2 - rect->y1) * scale));
430 ev_annotation_window_set_color (window, &annot->color);
431 gtk_widget_set_name (GTK_WIDGET (window), annot->name);
432 gtk_window_set_title (GTK_WINDOW (window), label);
433 gtk_label_set_text (GTK_LABEL (window->title), label);
434 gtk_window_set_opacity (GTK_WINDOW (window), opacity);
437 if (annot->contents) {
438 GtkTextBuffer *buffer;
440 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->text_view));
441 gtk_text_buffer_set_text (buffer, annot->contents, -1);
448 ev_annotation_window_button_press_event (GtkWidget *widget,
449 GdkEventButton *event)
451 EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (widget);
453 if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
454 window->in_move = TRUE;
455 window->x = event->x;
456 window->y = event->y;
457 gtk_window_begin_move_drag (GTK_WINDOW (widget),
469 ev_annotation_window_configure_event (GtkWidget *widget,
470 GdkEventConfigure *event)
472 EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (widget);
474 if (window->in_move &&
475 (window->x != event->x || window->y != event->y)) {
476 window->x = event->x;
477 window->y = event->y;
480 return GTK_WIDGET_CLASS (ev_annotation_window_parent_class)->configure_event (widget, event);
484 ev_annotation_window_focus_in_event (GtkWidget *widget,
485 GdkEventFocus *event)
487 EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (widget);
489 if (window->in_move) {
490 window->orig_x = window->x;
491 window->orig_y = window->y;
498 ev_annotation_window_focus_out_event (GtkWidget *widget,
499 GdkEventFocus *event)
501 EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (widget);
503 if (window->in_move &&
504 (window->orig_x != window->x || window->orig_y != window->y)) {
505 window->in_move = FALSE;
506 g_signal_emit (window, signals[MOVED], 0, window->x, window->y);
513 ev_annotation_window_class_init (EvAnnotationWindowClass *klass)
515 GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
516 GtkWidgetClass *gtk_widget_class = GTK_WIDGET_CLASS (klass);
518 g_object_class->constructor = ev_annotation_window_constructor;
519 g_object_class->set_property = ev_annotation_window_set_property;
520 g_object_class->dispose = ev_annotation_window_dispose;
522 gtk_widget_class->button_press_event = ev_annotation_window_button_press_event;
523 gtk_widget_class->configure_event = ev_annotation_window_configure_event;
524 gtk_widget_class->focus_in_event = ev_annotation_window_focus_in_event;
525 gtk_widget_class->focus_out_event = ev_annotation_window_focus_out_event;
527 g_object_class_install_property (g_object_class,
529 g_param_spec_object ("annotation",
531 "The annotation associated to the window",
532 EV_TYPE_ANNOTATION_MARKUP,
534 G_PARAM_CONSTRUCT_ONLY));
535 g_object_class_install_property (g_object_class,
537 g_param_spec_object ("parent",
542 G_PARAM_CONSTRUCT_ONLY));
544 g_signal_new ("closed",
545 G_TYPE_FROM_CLASS (g_object_class),
546 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
547 G_STRUCT_OFFSET (EvAnnotationWindowClass, closed),
549 g_cclosure_marshal_VOID__VOID,
550 G_TYPE_NONE, 0, G_TYPE_NONE);
552 g_signal_new ("moved",
553 G_TYPE_FROM_CLASS (g_object_class),
554 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
555 G_STRUCT_OFFSET (EvAnnotationWindowClass, moved),
557 ev_view_marshal_VOID__INT_INT,
559 G_TYPE_INT, G_TYPE_INT);
564 ev_annotation_window_new (EvAnnotation *annot,
569 g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (annot), NULL);
570 g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
572 window = g_object_new (EV_TYPE_ANNOTATION_WINDOW,
580 ev_annotation_window_get_annotation (EvAnnotationWindow *window)
582 g_return_val_if_fail (EV_IS_ANNOTATION_WINDOW (window), NULL);
584 return window->annotation;
588 ev_annotation_window_set_annotation (EvAnnotationWindow *window,
591 g_return_if_fail (EV_IS_ANNOTATION_WINDOW (window));
592 g_return_if_fail (EV_IS_ANNOTATION (annot));
594 if (annot == window->annotation)
597 g_object_unref (window->annotation);
598 window->annotation = g_object_ref (annot);
599 ev_annotation_window_check_contents_modified (window);
600 g_object_notify (G_OBJECT (window), "annotation");
604 ev_annotation_window_is_open (EvAnnotationWindow *window)
606 g_return_val_if_fail (EV_IS_ANNOTATION_WINDOW (window), FALSE);
608 return window->is_open;
612 ev_annotation_window_get_rectangle (EvAnnotationWindow *window)
614 g_return_val_if_fail (EV_IS_ANNOTATION_WINDOW (window), NULL);
620 ev_annotation_window_set_rectangle (EvAnnotationWindow *window,
623 g_return_if_fail (EV_IS_ANNOTATION_WINDOW (window));
624 g_return_if_fail (rect != NULL);
626 *window->rect = *rect;
630 ev_annotation_window_grab_focus (EvAnnotationWindow *window)
632 g_return_if_fail (EV_IS_ANNOTATION_WINDOW (window));
634 if (!GTK_WIDGET_HAS_FOCUS (window->text_view)) {
635 gtk_widget_grab_focus (GTK_WIDGET (window));
636 send_focus_change (window->text_view, TRUE);
641 ev_annotation_window_ungrab_focus (EvAnnotationWindow *window)
643 g_return_if_fail (EV_IS_ANNOTATION_WINDOW (window));
645 if (GTK_WIDGET_HAS_FOCUS (window->text_view)) {
646 send_focus_change (window->text_view, FALSE);
649 ev_annotation_window_check_contents_modified (window);