1 /*
2  * e-focus-tracker.c
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, see <http://www.gnu.org/licenses/>.
15  *
16  *
17  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
18  *
19  */
20 
21 #include "evolution-config.h"
22 
23 #include "e-focus-tracker.h"
24 
25 #include <glib/gi18n-lib.h>
26 
27 #include "e-selectable.h"
28 #include "e-widget-undo.h"
29 #include "e-content-editor.h"
30 
31 #define E_FOCUS_TRACKER_GET_PRIVATE(obj) \
32 	(G_TYPE_INSTANCE_GET_PRIVATE \
33 	((obj), E_TYPE_FOCUS_TRACKER, EFocusTrackerPrivate))
34 
35 struct _EFocusTrackerPrivate {
36 	GtkWidget *focus;  /* not referenced */
37 	GtkWindow *window;
38 
39 	GtkAction *cut_clipboard;
40 	GtkAction *copy_clipboard;
41 	GtkAction *paste_clipboard;
42 	GtkAction *delete_selection;
43 	GtkAction *select_all;
44 	GtkAction *undo;
45 	GtkAction *redo;
46 };
47 
48 enum {
49 	PROP_0,
50 	PROP_FOCUS,
51 	PROP_WINDOW,
52 	PROP_CUT_CLIPBOARD_ACTION,
53 	PROP_COPY_CLIPBOARD_ACTION,
54 	PROP_PASTE_CLIPBOARD_ACTION,
55 	PROP_DELETE_SELECTION_ACTION,
56 	PROP_SELECT_ALL_ACTION,
57 	PROP_UNDO_ACTION,
58 	PROP_REDO_ACTION
59 };
60 
G_DEFINE_TYPE(EFocusTracker,e_focus_tracker,G_TYPE_OBJECT)61 G_DEFINE_TYPE (
62 	EFocusTracker,
63 	e_focus_tracker,
64 	G_TYPE_OBJECT)
65 
66 static void
67 focus_tracker_disable_actions (EFocusTracker *focus_tracker)
68 {
69 	GtkAction *action;
70 
71 	action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
72 	if (action != NULL)
73 		gtk_action_set_sensitive (action, FALSE);
74 
75 	action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
76 	if (action != NULL)
77 		gtk_action_set_sensitive (action, FALSE);
78 
79 	action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
80 	if (action != NULL)
81 		gtk_action_set_sensitive (action, FALSE);
82 
83 	action = e_focus_tracker_get_delete_selection_action (focus_tracker);
84 	if (action != NULL)
85 		gtk_action_set_sensitive (action, FALSE);
86 
87 	action = e_focus_tracker_get_select_all_action (focus_tracker);
88 	if (action != NULL)
89 		gtk_action_set_sensitive (action, FALSE);
90 
91 	action = e_focus_tracker_get_undo_action (focus_tracker);
92 	if (action != NULL)
93 		gtk_action_set_sensitive (action, FALSE);
94 
95 	action = e_focus_tracker_get_redo_action (focus_tracker);
96 	if (action != NULL)
97 		gtk_action_set_sensitive (action, FALSE);
98 }
99 
100 static gboolean
focus_tracker_get_has_undo(GtkWidget * widget)101 focus_tracker_get_has_undo (GtkWidget *widget)
102 {
103 	if (!widget)
104 		return FALSE;
105 
106 	if (e_widget_undo_is_attached (widget))
107 		return e_widget_undo_has_undo (widget);
108 
109 	if (E_IS_CONTENT_EDITOR (widget))
110 		return e_content_editor_can_undo (E_CONTENT_EDITOR (widget));
111 
112 	return FALSE;
113 }
114 
115 static gboolean
focus_tracker_get_has_redo(GtkWidget * widget)116 focus_tracker_get_has_redo (GtkWidget *widget)
117 {
118 	if (!widget)
119 		return FALSE;
120 
121 	if (e_widget_undo_is_attached (widget))
122 		return e_widget_undo_has_redo (widget);
123 
124 	if (E_IS_CONTENT_EDITOR (widget))
125 		return e_content_editor_can_redo (E_CONTENT_EDITOR (widget));
126 
127 	return FALSE;
128 }
129 
130 static void
focus_tracker_update_undo_redo(EFocusTracker * focus_tracker,GtkWidget * widget,gboolean can_edit_text)131 focus_tracker_update_undo_redo (EFocusTracker *focus_tracker,
132                                 GtkWidget *widget,
133                                 gboolean can_edit_text)
134 {
135 	GtkAction *action;
136 	gboolean sensitive;
137 
138 	action = e_focus_tracker_get_undo_action (focus_tracker);
139 	if (action != NULL) {
140 		sensitive = can_edit_text && focus_tracker_get_has_undo (widget);
141 		gtk_action_set_sensitive (action, sensitive);
142 
143 		if (sensitive) {
144 			gchar *description;
145 
146 			description = e_widget_undo_describe_undo (widget);
147 			gtk_action_set_tooltip (action, description && *description ? description : _("Undo"));
148 			g_free (description);
149 		} else {
150 			gtk_action_set_tooltip (action, _("Undo"));
151 		}
152 	}
153 
154 	action = e_focus_tracker_get_redo_action (focus_tracker);
155 	if (action != NULL) {
156 		sensitive = can_edit_text && focus_tracker_get_has_redo (widget);
157 		gtk_action_set_sensitive (action, sensitive);
158 
159 		if (sensitive) {
160 			gchar *description;
161 
162 			description = e_widget_undo_describe_redo (widget);
163 			gtk_action_set_tooltip (action, description && *description ? description : _("Redo"));
164 			g_free (description);
165 		} else {
166 			gtk_action_set_tooltip (action, _("Redo"));
167 		}
168 	}
169 }
170 
171 static void
focus_tracker_editable_update_actions(EFocusTracker * focus_tracker,GtkEditable * editable,GdkAtom * targets,gint n_targets)172 focus_tracker_editable_update_actions (EFocusTracker *focus_tracker,
173                                        GtkEditable *editable,
174                                        GdkAtom *targets,
175                                        gint n_targets)
176 {
177 	GtkAction *action;
178 	gboolean can_edit_text;
179 	gboolean clipboard_has_text;
180 	gboolean text_is_selected;
181 	gboolean sensitive;
182 
183 	can_edit_text =
184 		gtk_editable_get_editable (editable);
185 
186 	clipboard_has_text = (targets != NULL) &&
187 		gtk_targets_include_text (targets, n_targets);
188 
189 	text_is_selected =
190 		gtk_editable_get_selection_bounds (editable, NULL, NULL);
191 
192 	action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
193 	if (action != NULL) {
194 		sensitive = can_edit_text && text_is_selected;
195 		gtk_action_set_sensitive (action, sensitive);
196 		gtk_action_set_tooltip (action, _("Cut the selection"));
197 	}
198 
199 	action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
200 	if (action != NULL) {
201 		sensitive = text_is_selected;
202 		gtk_action_set_sensitive (action, sensitive);
203 		gtk_action_set_tooltip (action, _("Copy the selection"));
204 	}
205 
206 	action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
207 	if (action != NULL) {
208 		sensitive = can_edit_text && clipboard_has_text;
209 		gtk_action_set_sensitive (action, sensitive);
210 		gtk_action_set_tooltip (action, _("Paste the clipboard"));
211 	}
212 
213 	action = e_focus_tracker_get_delete_selection_action (focus_tracker);
214 	if (action != NULL) {
215 		sensitive = can_edit_text && text_is_selected;
216 		gtk_action_set_sensitive (action, sensitive);
217 		gtk_action_set_tooltip (action, _("Delete the selection"));
218 	}
219 
220 	action = e_focus_tracker_get_select_all_action (focus_tracker);
221 	if (action != NULL) {
222 		sensitive = TRUE;  /* always enabled */
223 		gtk_action_set_sensitive (action, sensitive);
224 		gtk_action_set_tooltip (action, _("Select all text"));
225 	}
226 
227 	focus_tracker_update_undo_redo (focus_tracker, GTK_WIDGET (editable), can_edit_text);
228 }
229 
230 static void
focus_tracker_text_view_update_actions(EFocusTracker * focus_tracker,GtkTextView * text_view,GdkAtom * targets,gint n_targets)231 focus_tracker_text_view_update_actions (EFocusTracker *focus_tracker,
232                                         GtkTextView *text_view,
233                                         GdkAtom *targets,
234                                         gint n_targets)
235 {
236 	GtkAction *action;
237 	GtkTextBuffer *buffer;
238 	gboolean can_edit_text;
239 	gboolean clipboard_has_text;
240 	gboolean text_is_selected;
241 	gboolean sensitive;
242 
243 	buffer = gtk_text_view_get_buffer (text_view);
244 	can_edit_text = gtk_text_view_get_editable (text_view);
245 	clipboard_has_text = (targets != NULL) && gtk_targets_include_text (targets, n_targets);
246 	text_is_selected = gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL);
247 
248 	action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
249 	if (action != NULL) {
250 		sensitive = can_edit_text && text_is_selected;
251 		gtk_action_set_sensitive (action, sensitive);
252 		gtk_action_set_tooltip (action, _("Cut the selection"));
253 	}
254 
255 	action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
256 	if (action != NULL) {
257 		sensitive = text_is_selected;
258 		gtk_action_set_sensitive (action, sensitive);
259 		gtk_action_set_tooltip (action, _("Copy the selection"));
260 	}
261 
262 	action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
263 	if (action != NULL) {
264 		sensitive = can_edit_text && clipboard_has_text;
265 		gtk_action_set_sensitive (action, sensitive);
266 		gtk_action_set_tooltip (action, _("Paste the clipboard"));
267 	}
268 
269 	action = e_focus_tracker_get_delete_selection_action (focus_tracker);
270 	if (action != NULL) {
271 		sensitive = can_edit_text && text_is_selected;
272 		gtk_action_set_sensitive (action, sensitive);
273 		gtk_action_set_tooltip (action, _("Delete the selection"));
274 	}
275 
276 	action = e_focus_tracker_get_select_all_action (focus_tracker);
277 	if (action != NULL) {
278 		sensitive = TRUE;  /* always enabled */
279 		gtk_action_set_sensitive (action, sensitive);
280 		gtk_action_set_tooltip (action, _("Select all text"));
281 	}
282 
283 	focus_tracker_update_undo_redo (focus_tracker, GTK_WIDGET (text_view), can_edit_text);
284 }
285 
286 static void
focus_tracker_editor_update_actions(EFocusTracker * focus_tracker,EContentEditor * cnt_editor,GdkAtom * targets,gint n_targets)287 focus_tracker_editor_update_actions (EFocusTracker *focus_tracker,
288                                      EContentEditor *cnt_editor,
289                                      GdkAtom *targets,
290                                      gint n_targets)
291 {
292 	GtkAction *action;
293 	gboolean can_copy;
294 	gboolean can_cut;
295 	gboolean can_paste;
296 
297 	g_object_get (cnt_editor,
298 		      "can-copy", &can_copy,
299 		      "can-cut", &can_cut,
300 		      "can-paste", &can_paste,
301 		      NULL);
302 
303 	action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
304 	if (action != NULL) {
305 		gtk_action_set_sensitive (action, can_cut);
306 		gtk_action_set_tooltip (action, _("Cut the selection"));
307 	}
308 
309 	action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
310 	if (action != NULL) {
311 		gtk_action_set_sensitive (action, can_copy);
312 		gtk_action_set_tooltip (action, _("Copy the selection"));
313 	}
314 
315 	action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
316 	if (action != NULL) {
317 		gtk_action_set_sensitive (action, can_paste);
318 		gtk_action_set_tooltip (action, _("Paste the clipboard"));
319 	}
320 
321 	focus_tracker_update_undo_redo (focus_tracker, GTK_WIDGET (cnt_editor),
322 		e_content_editor_is_editable (cnt_editor));
323 }
324 
325 static void
focus_tracker_selectable_update_actions(EFocusTracker * focus_tracker,ESelectable * selectable,GdkAtom * targets,gint n_targets)326 focus_tracker_selectable_update_actions (EFocusTracker *focus_tracker,
327                                          ESelectable *selectable,
328                                          GdkAtom *targets,
329                                          gint n_targets)
330 {
331 	ESelectableInterface *iface;
332 	GtkAction *action;
333 
334 	iface = E_SELECTABLE_GET_INTERFACE (selectable);
335 
336 	e_selectable_update_actions (
337 		selectable, focus_tracker, targets, n_targets);
338 
339 	/* Disable actions for which the corresponding method is not
340 	 * implemented.  This allows update_actions() implementations
341 	 * to simply skip the actions they don't support, which in turn
342 	 * allows us to add new actions without disturbing the existing
343 	 * ESelectable implementations. */
344 
345 	action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
346 	if (action != NULL && iface->cut_clipboard == NULL)
347 		gtk_action_set_sensitive (action, FALSE);
348 
349 	action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
350 	if (action != NULL && iface->copy_clipboard == NULL)
351 		gtk_action_set_sensitive (action, FALSE);
352 
353 	action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
354 	if (action != NULL && iface->paste_clipboard == NULL)
355 		gtk_action_set_sensitive (action, FALSE);
356 
357 	action = e_focus_tracker_get_delete_selection_action (focus_tracker);
358 	if (action != NULL && iface->delete_selection == NULL)
359 		gtk_action_set_sensitive (action, FALSE);
360 
361 	action = e_focus_tracker_get_select_all_action (focus_tracker);
362 	if (action != NULL && iface->select_all == NULL)
363 		gtk_action_set_sensitive (action, FALSE);
364 
365 	action = e_focus_tracker_get_undo_action (focus_tracker);
366 	if (action != NULL && iface->undo == NULL)
367 		gtk_action_set_sensitive (action, FALSE);
368 
369 	action = e_focus_tracker_get_redo_action (focus_tracker);
370 	if (action != NULL && iface->redo == NULL)
371 		gtk_action_set_sensitive (action, FALSE);
372 }
373 
374 static void
focus_tracker_targets_received_cb(GtkClipboard * clipboard,GdkAtom * targets,gint n_targets,EFocusTracker * focus_tracker)375 focus_tracker_targets_received_cb (GtkClipboard *clipboard,
376                                    GdkAtom *targets,
377                                    gint n_targets,
378                                    EFocusTracker *focus_tracker)
379 {
380 	GtkWidget *focus;
381 
382 	focus = e_focus_tracker_get_focus (focus_tracker);
383 
384 	if (focus == NULL)
385 		focus_tracker_disable_actions (focus_tracker);
386 
387 	else if (E_IS_SELECTABLE (focus))
388 		focus_tracker_selectable_update_actions (
389 			focus_tracker, E_SELECTABLE (focus),
390 			targets, n_targets);
391 
392 	else if (GTK_IS_EDITABLE (focus))
393 		focus_tracker_editable_update_actions (
394 			focus_tracker, GTK_EDITABLE (focus),
395 			targets, n_targets);
396 
397 	else if (GTK_IS_TEXT_VIEW (focus))
398 		focus_tracker_text_view_update_actions (
399 			focus_tracker, GTK_TEXT_VIEW (focus),
400 			targets, n_targets);
401 
402 	else if (E_IS_CONTENT_EDITOR (focus))
403 		focus_tracker_editor_update_actions (
404 			focus_tracker, E_CONTENT_EDITOR (focus),
405 			targets, n_targets);
406 
407 	g_object_unref (focus_tracker);
408 }
409 
410 static void
focus_tracker_set_focus_cb(GtkWindow * window,GtkWidget * focus,EFocusTracker * focus_tracker)411 focus_tracker_set_focus_cb (GtkWindow *window,
412                             GtkWidget *focus,
413                             EFocusTracker *focus_tracker)
414 {
415 	while (focus != NULL) {
416 		if (E_IS_SELECTABLE (focus))
417 			break;
418 
419 		if (GTK_IS_EDITABLE (focus))
420 			break;
421 
422 		if (GTK_IS_TEXT_VIEW (focus))
423 			break;
424 
425 		if (E_IS_CONTENT_EDITOR (focus))
426 			break;
427 
428 		focus = gtk_widget_get_parent (focus);
429 	}
430 
431 	if (focus == focus_tracker->priv->focus)
432 		return;
433 
434 	focus_tracker->priv->focus = focus;
435 	g_object_notify (G_OBJECT (focus_tracker), "focus");
436 
437 	e_focus_tracker_update_actions (focus_tracker);
438 }
439 
440 static void
focus_tracker_set_window(EFocusTracker * focus_tracker,GtkWindow * window)441 focus_tracker_set_window (EFocusTracker *focus_tracker,
442                           GtkWindow *window)
443 {
444 	g_return_if_fail (GTK_IS_WINDOW (window));
445 	g_return_if_fail (focus_tracker->priv->window == NULL);
446 
447 	focus_tracker->priv->window = g_object_ref (window);
448 
449 	g_signal_connect (
450 		window, "set-focus",
451 		G_CALLBACK (focus_tracker_set_focus_cb), focus_tracker);
452 }
453 
454 static void
focus_tracker_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)455 focus_tracker_set_property (GObject *object,
456                             guint property_id,
457                             const GValue *value,
458                             GParamSpec *pspec)
459 {
460 	switch (property_id) {
461 		case PROP_WINDOW:
462 			focus_tracker_set_window (
463 				E_FOCUS_TRACKER (object),
464 				g_value_get_object (value));
465 			return;
466 
467 		case PROP_CUT_CLIPBOARD_ACTION:
468 			e_focus_tracker_set_cut_clipboard_action (
469 				E_FOCUS_TRACKER (object),
470 				g_value_get_object (value));
471 			return;
472 
473 		case PROP_COPY_CLIPBOARD_ACTION:
474 			e_focus_tracker_set_copy_clipboard_action (
475 				E_FOCUS_TRACKER (object),
476 				g_value_get_object (value));
477 			return;
478 
479 		case PROP_PASTE_CLIPBOARD_ACTION:
480 			e_focus_tracker_set_paste_clipboard_action (
481 				E_FOCUS_TRACKER (object),
482 				g_value_get_object (value));
483 			return;
484 
485 		case PROP_DELETE_SELECTION_ACTION:
486 			e_focus_tracker_set_delete_selection_action (
487 				E_FOCUS_TRACKER (object),
488 				g_value_get_object (value));
489 			return;
490 
491 		case PROP_SELECT_ALL_ACTION:
492 			e_focus_tracker_set_select_all_action (
493 				E_FOCUS_TRACKER (object),
494 				g_value_get_object (value));
495 			return;
496 
497 		case PROP_UNDO_ACTION:
498 			e_focus_tracker_set_undo_action (
499 				E_FOCUS_TRACKER (object),
500 				g_value_get_object (value));
501 			return;
502 
503 		case PROP_REDO_ACTION:
504 			e_focus_tracker_set_redo_action (
505 				E_FOCUS_TRACKER (object),
506 				g_value_get_object (value));
507 			return;
508 	}
509 
510 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
511 }
512 
513 static void
focus_tracker_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)514 focus_tracker_get_property (GObject *object,
515                             guint property_id,
516                             GValue *value,
517                             GParamSpec *pspec)
518 {
519 	switch (property_id) {
520 		case PROP_FOCUS:
521 			g_value_set_object (
522 				value,
523 				e_focus_tracker_get_focus (
524 				E_FOCUS_TRACKER (object)));
525 			return;
526 
527 		case PROP_WINDOW:
528 			g_value_set_object (
529 				value,
530 				e_focus_tracker_get_window (
531 				E_FOCUS_TRACKER (object)));
532 			return;
533 
534 		case PROP_CUT_CLIPBOARD_ACTION:
535 			g_value_set_object (
536 				value,
537 				e_focus_tracker_get_cut_clipboard_action (
538 				E_FOCUS_TRACKER (object)));
539 			return;
540 
541 		case PROP_COPY_CLIPBOARD_ACTION:
542 			g_value_set_object (
543 				value,
544 				e_focus_tracker_get_copy_clipboard_action (
545 				E_FOCUS_TRACKER (object)));
546 			return;
547 
548 		case PROP_PASTE_CLIPBOARD_ACTION:
549 			g_value_set_object (
550 				value,
551 				e_focus_tracker_get_paste_clipboard_action (
552 				E_FOCUS_TRACKER (object)));
553 			return;
554 
555 		case PROP_DELETE_SELECTION_ACTION:
556 			g_value_set_object (
557 				value,
558 				e_focus_tracker_get_delete_selection_action (
559 				E_FOCUS_TRACKER (object)));
560 			return;
561 
562 		case PROP_SELECT_ALL_ACTION:
563 			g_value_set_object (
564 				value,
565 				e_focus_tracker_get_select_all_action (
566 				E_FOCUS_TRACKER (object)));
567 			return;
568 
569 		case PROP_UNDO_ACTION:
570 			g_value_set_object (
571 				value,
572 				e_focus_tracker_get_undo_action (
573 				E_FOCUS_TRACKER (object)));
574 			return;
575 
576 		case PROP_REDO_ACTION:
577 			g_value_set_object (
578 				value,
579 				e_focus_tracker_get_redo_action (
580 				E_FOCUS_TRACKER (object)));
581 			return;
582 	}
583 
584 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
585 }
586 
587 static void
focus_tracker_dispose(GObject * object)588 focus_tracker_dispose (GObject *object)
589 {
590 	EFocusTrackerPrivate *priv;
591 
592 	priv = E_FOCUS_TRACKER_GET_PRIVATE (object);
593 
594 	g_signal_handlers_disconnect_matched (
595 		gtk_clipboard_get (GDK_SELECTION_PRIMARY),
596 		G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object);
597 
598 	g_signal_handlers_disconnect_matched (
599 		gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
600 		G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object);
601 
602 	if (priv->window != NULL) {
603 		g_signal_handlers_disconnect_matched (
604 			priv->window, G_SIGNAL_MATCH_DATA,
605 			0, 0, NULL, NULL, object);
606 		g_object_unref (priv->window);
607 		priv->window = NULL;
608 	}
609 
610 	if (priv->cut_clipboard != NULL) {
611 		g_signal_handlers_disconnect_matched (
612 			priv->cut_clipboard, G_SIGNAL_MATCH_DATA,
613 			0, 0, NULL, NULL, object);
614 		g_object_unref (priv->cut_clipboard);
615 		priv->cut_clipboard = NULL;
616 	}
617 
618 	if (priv->copy_clipboard != NULL) {
619 		g_signal_handlers_disconnect_matched (
620 			priv->copy_clipboard, G_SIGNAL_MATCH_DATA,
621 			0, 0, NULL, NULL, object);
622 		g_object_unref (priv->copy_clipboard);
623 		priv->copy_clipboard = NULL;
624 	}
625 
626 	if (priv->paste_clipboard != NULL) {
627 		g_signal_handlers_disconnect_matched (
628 			priv->paste_clipboard, G_SIGNAL_MATCH_DATA,
629 			0, 0, NULL, NULL, object);
630 		g_object_unref (priv->paste_clipboard);
631 		priv->paste_clipboard = NULL;
632 	}
633 
634 	if (priv->delete_selection != NULL) {
635 		g_signal_handlers_disconnect_matched (
636 			priv->delete_selection, G_SIGNAL_MATCH_DATA,
637 			0, 0, NULL, NULL, object);
638 		g_object_unref (priv->delete_selection);
639 		priv->delete_selection = NULL;
640 	}
641 
642 	if (priv->select_all != NULL) {
643 		g_signal_handlers_disconnect_matched (
644 			priv->select_all, G_SIGNAL_MATCH_DATA,
645 			0, 0, NULL, NULL, object);
646 		g_object_unref (priv->select_all);
647 		priv->select_all = NULL;
648 	}
649 
650 	/* Chain up to parent's dispose() method. */
651 	G_OBJECT_CLASS (e_focus_tracker_parent_class)->dispose (object);
652 }
653 
654 static void
focus_tracker_constructed(GObject * object)655 focus_tracker_constructed (GObject *object)
656 {
657 	GtkClipboard *clipboard;
658 
659 	/* Listen for "owner-change" signals from the primary selection
660 	 * clipboard to learn when text selections change in GtkEditable
661 	 * widgets.  It's a bit of an overkill, but I don't know of any
662 	 * other notification mechanism. */
663 
664 	clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
665 
666 	g_signal_connect_swapped (
667 		clipboard, "owner-change",
668 		G_CALLBACK (e_focus_tracker_update_actions), object);
669 
670 	/* Listen for "owner-change" signals from the default clipboard
671 	 * so we can update the paste action when the user cuts or copies
672 	 * something.  This is how GEdit does it. */
673 
674 	clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
675 
676 	g_signal_connect_swapped (
677 		clipboard, "owner-change",
678 		G_CALLBACK (e_focus_tracker_update_actions), object);
679 
680 	/* Chain up to parent's constructed() method. */
681 	G_OBJECT_CLASS (e_focus_tracker_parent_class)->constructed (object);
682 }
683 
684 static void
e_focus_tracker_class_init(EFocusTrackerClass * class)685 e_focus_tracker_class_init (EFocusTrackerClass *class)
686 {
687 	GObjectClass *object_class;
688 
689 	g_type_class_add_private (class, sizeof (EFocusTrackerPrivate));
690 
691 	object_class = G_OBJECT_CLASS (class);
692 	object_class->set_property = focus_tracker_set_property;
693 	object_class->get_property = focus_tracker_get_property;
694 	object_class->dispose = focus_tracker_dispose;
695 	object_class->constructed = focus_tracker_constructed;
696 
697 	g_object_class_install_property (
698 		object_class,
699 		PROP_FOCUS,
700 		g_param_spec_object (
701 			"focus",
702 			"Focus",
703 			NULL,
704 			GTK_TYPE_WIDGET,
705 			G_PARAM_READABLE));
706 
707 	g_object_class_install_property (
708 		object_class,
709 		PROP_WINDOW,
710 		g_param_spec_object (
711 			"window",
712 			"Window",
713 			NULL,
714 			GTK_TYPE_WINDOW,
715 			G_PARAM_READWRITE |
716 			G_PARAM_CONSTRUCT_ONLY));
717 
718 	g_object_class_install_property (
719 		object_class,
720 		PROP_CUT_CLIPBOARD_ACTION,
721 		g_param_spec_object (
722 			"cut-clipboard-action",
723 			"Cut Clipboard Action",
724 			NULL,
725 			GTK_TYPE_ACTION,
726 			G_PARAM_READWRITE));
727 
728 	g_object_class_install_property (
729 		object_class,
730 		PROP_COPY_CLIPBOARD_ACTION,
731 		g_param_spec_object (
732 			"copy-clipboard-action",
733 			"Copy Clipboard Action",
734 			NULL,
735 			GTK_TYPE_ACTION,
736 			G_PARAM_READWRITE));
737 
738 	g_object_class_install_property (
739 		object_class,
740 		PROP_PASTE_CLIPBOARD_ACTION,
741 		g_param_spec_object (
742 			"paste-clipboard-action",
743 			"Paste Clipboard Action",
744 			NULL,
745 			GTK_TYPE_ACTION,
746 			G_PARAM_READWRITE));
747 
748 	g_object_class_install_property (
749 		object_class,
750 		PROP_DELETE_SELECTION_ACTION,
751 		g_param_spec_object (
752 			"delete-selection-action",
753 			"Delete Selection Action",
754 			NULL,
755 			GTK_TYPE_ACTION,
756 			G_PARAM_READWRITE));
757 
758 	g_object_class_install_property (
759 		object_class,
760 		PROP_SELECT_ALL_ACTION,
761 		g_param_spec_object (
762 			"select-all-action",
763 			"Select All Action",
764 			NULL,
765 			GTK_TYPE_ACTION,
766 			G_PARAM_READWRITE));
767 
768 	g_object_class_install_property (
769 		object_class,
770 		PROP_UNDO_ACTION,
771 		g_param_spec_object (
772 			"undo-action",
773 			"Undo Action",
774 			NULL,
775 			GTK_TYPE_ACTION,
776 			G_PARAM_READWRITE));
777 
778 	g_object_class_install_property (
779 		object_class,
780 		PROP_REDO_ACTION,
781 		g_param_spec_object (
782 			"redo-action",
783 			"Redo Action",
784 			NULL,
785 			GTK_TYPE_ACTION,
786 			G_PARAM_READWRITE));
787 }
788 
789 static void
e_focus_tracker_init(EFocusTracker * focus_tracker)790 e_focus_tracker_init (EFocusTracker *focus_tracker)
791 {
792 	GtkAction *action;
793 
794 	focus_tracker->priv = E_FOCUS_TRACKER_GET_PRIVATE (focus_tracker);
795 
796 	/* Define dummy actions.  These will most likely be overridden,
797 	 * but for cases where they're not it ensures ESelectable objects
798 	 * will always get a valid GtkAction when they ask us for one. */
799 
800 	action = gtk_action_new (
801 		"cut-clipboard", _("Cu_t"),
802 		_("Cut the selection"), "edit-cut");
803 	focus_tracker->priv->cut_clipboard = action;
804 
805 	action = gtk_action_new (
806 		"copy-clipboard", _("_Copy"),
807 		_("Copy the selection"), "edit-copy");
808 	focus_tracker->priv->copy_clipboard = action;
809 
810 	action = gtk_action_new (
811 		"paste-clipboard", _("_Paste"),
812 		_("Paste the clipboard"), "edit-paste");
813 	focus_tracker->priv->paste_clipboard = action;
814 
815 	action = gtk_action_new (
816 		"delete-selection", _("_Delete"),
817 		_("Delete the selection"), "edit-delete");
818 	focus_tracker->priv->delete_selection = action;
819 
820 	action = gtk_action_new (
821 		"select-all", _("Select _All"),
822 		_("Select all text"), "edit-select-all");
823 	focus_tracker->priv->select_all = action;
824 }
825 
826 EFocusTracker *
e_focus_tracker_new(GtkWindow * window)827 e_focus_tracker_new (GtkWindow *window)
828 {
829 	g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
830 
831 	return g_object_new (E_TYPE_FOCUS_TRACKER, "window", window, NULL);
832 }
833 
834 GtkWidget *
e_focus_tracker_get_focus(EFocusTracker * focus_tracker)835 e_focus_tracker_get_focus (EFocusTracker *focus_tracker)
836 {
837 	g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL);
838 
839 	return focus_tracker->priv->focus;
840 }
841 
842 GtkWindow *
e_focus_tracker_get_window(EFocusTracker * focus_tracker)843 e_focus_tracker_get_window (EFocusTracker *focus_tracker)
844 {
845 	g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL);
846 
847 	return focus_tracker->priv->window;
848 }
849 
850 GtkAction *
e_focus_tracker_get_cut_clipboard_action(EFocusTracker * focus_tracker)851 e_focus_tracker_get_cut_clipboard_action (EFocusTracker *focus_tracker)
852 {
853 	g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL);
854 
855 	return focus_tracker->priv->cut_clipboard;
856 }
857 
858 void
e_focus_tracker_set_cut_clipboard_action(EFocusTracker * focus_tracker,GtkAction * cut_clipboard)859 e_focus_tracker_set_cut_clipboard_action (EFocusTracker *focus_tracker,
860                                           GtkAction *cut_clipboard)
861 {
862 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
863 
864 	if (cut_clipboard != NULL) {
865 		g_return_if_fail (GTK_IS_ACTION (cut_clipboard));
866 		g_object_ref (cut_clipboard);
867 	}
868 
869 	if (focus_tracker->priv->cut_clipboard != NULL) {
870 		g_signal_handlers_disconnect_matched (
871 			focus_tracker->priv->cut_clipboard,
872 			G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
873 			focus_tracker);
874 		g_object_unref (focus_tracker->priv->cut_clipboard);
875 	}
876 
877 	focus_tracker->priv->cut_clipboard = cut_clipboard;
878 
879 	if (cut_clipboard != NULL)
880 		g_signal_connect_swapped (
881 			cut_clipboard, "activate",
882 			G_CALLBACK (e_focus_tracker_cut_clipboard),
883 			focus_tracker);
884 
885 	g_object_notify (G_OBJECT (focus_tracker), "cut-clipboard-action");
886 }
887 
888 GtkAction *
e_focus_tracker_get_copy_clipboard_action(EFocusTracker * focus_tracker)889 e_focus_tracker_get_copy_clipboard_action (EFocusTracker *focus_tracker)
890 {
891 	g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL);
892 
893 	return focus_tracker->priv->copy_clipboard;
894 }
895 
896 void
e_focus_tracker_set_copy_clipboard_action(EFocusTracker * focus_tracker,GtkAction * copy_clipboard)897 e_focus_tracker_set_copy_clipboard_action (EFocusTracker *focus_tracker,
898                                            GtkAction *copy_clipboard)
899 {
900 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
901 
902 	if (copy_clipboard != NULL) {
903 		g_return_if_fail (GTK_IS_ACTION (copy_clipboard));
904 		g_object_ref (copy_clipboard);
905 	}
906 
907 	if (focus_tracker->priv->copy_clipboard != NULL) {
908 		g_signal_handlers_disconnect_matched (
909 			focus_tracker->priv->copy_clipboard,
910 			G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
911 			focus_tracker);
912 		g_object_unref (focus_tracker->priv->copy_clipboard);
913 	}
914 
915 	focus_tracker->priv->copy_clipboard = copy_clipboard;
916 
917 	if (copy_clipboard != NULL)
918 		g_signal_connect_swapped (
919 			copy_clipboard, "activate",
920 			G_CALLBACK (e_focus_tracker_copy_clipboard),
921 			focus_tracker);
922 
923 	g_object_notify (G_OBJECT (focus_tracker), "copy-clipboard-action");
924 }
925 
926 GtkAction *
e_focus_tracker_get_paste_clipboard_action(EFocusTracker * focus_tracker)927 e_focus_tracker_get_paste_clipboard_action (EFocusTracker *focus_tracker)
928 {
929 	g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL);
930 
931 	return focus_tracker->priv->paste_clipboard;
932 }
933 
934 void
e_focus_tracker_set_paste_clipboard_action(EFocusTracker * focus_tracker,GtkAction * paste_clipboard)935 e_focus_tracker_set_paste_clipboard_action (EFocusTracker *focus_tracker,
936                                             GtkAction *paste_clipboard)
937 {
938 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
939 
940 	if (paste_clipboard != NULL) {
941 		g_return_if_fail (GTK_IS_ACTION (paste_clipboard));
942 		g_object_ref (paste_clipboard);
943 	}
944 
945 	if (focus_tracker->priv->paste_clipboard != NULL) {
946 		g_signal_handlers_disconnect_matched (
947 			focus_tracker->priv->paste_clipboard,
948 			G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
949 			focus_tracker);
950 		g_object_unref (focus_tracker->priv->paste_clipboard);
951 	}
952 
953 	focus_tracker->priv->paste_clipboard = paste_clipboard;
954 
955 	if (paste_clipboard != NULL)
956 		g_signal_connect_swapped (
957 			paste_clipboard, "activate",
958 			G_CALLBACK (e_focus_tracker_paste_clipboard),
959 			focus_tracker);
960 
961 	g_object_notify (G_OBJECT (focus_tracker), "paste-clipboard-action");
962 }
963 
964 GtkAction *
e_focus_tracker_get_delete_selection_action(EFocusTracker * focus_tracker)965 e_focus_tracker_get_delete_selection_action (EFocusTracker *focus_tracker)
966 {
967 	g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL);
968 
969 	return focus_tracker->priv->delete_selection;
970 }
971 
972 void
e_focus_tracker_set_delete_selection_action(EFocusTracker * focus_tracker,GtkAction * delete_selection)973 e_focus_tracker_set_delete_selection_action (EFocusTracker *focus_tracker,
974                                              GtkAction *delete_selection)
975 {
976 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
977 
978 	if (delete_selection != NULL) {
979 		g_return_if_fail (GTK_IS_ACTION (delete_selection));
980 		g_object_ref (delete_selection);
981 	}
982 
983 	if (focus_tracker->priv->delete_selection != NULL) {
984 		g_signal_handlers_disconnect_matched (
985 			focus_tracker->priv->delete_selection,
986 			G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
987 			focus_tracker);
988 		g_object_unref (focus_tracker->priv->delete_selection);
989 	}
990 
991 	focus_tracker->priv->delete_selection = delete_selection;
992 
993 	if (delete_selection != NULL)
994 		g_signal_connect_swapped (
995 			delete_selection, "activate",
996 			G_CALLBACK (e_focus_tracker_delete_selection),
997 			focus_tracker);
998 
999 	g_object_notify (G_OBJECT (focus_tracker), "delete-selection-action");
1000 }
1001 
1002 GtkAction *
e_focus_tracker_get_select_all_action(EFocusTracker * focus_tracker)1003 e_focus_tracker_get_select_all_action (EFocusTracker *focus_tracker)
1004 {
1005 	g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL);
1006 
1007 	return focus_tracker->priv->select_all;
1008 }
1009 
1010 void
e_focus_tracker_set_select_all_action(EFocusTracker * focus_tracker,GtkAction * select_all)1011 e_focus_tracker_set_select_all_action (EFocusTracker *focus_tracker,
1012                                        GtkAction *select_all)
1013 {
1014 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
1015 
1016 	if (select_all != NULL) {
1017 		g_return_if_fail (GTK_IS_ACTION (select_all));
1018 		g_object_ref (select_all);
1019 	}
1020 
1021 	if (focus_tracker->priv->select_all != NULL) {
1022 		g_signal_handlers_disconnect_matched (
1023 			focus_tracker->priv->select_all,
1024 			G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
1025 			focus_tracker);
1026 		g_object_unref (focus_tracker->priv->select_all);
1027 	}
1028 
1029 	focus_tracker->priv->select_all = select_all;
1030 
1031 	if (select_all != NULL)
1032 		g_signal_connect_swapped (
1033 			select_all, "activate",
1034 			G_CALLBACK (e_focus_tracker_select_all),
1035 			focus_tracker);
1036 
1037 	g_object_notify (G_OBJECT (focus_tracker), "select-all-action");
1038 }
1039 
1040 GtkAction *
e_focus_tracker_get_undo_action(EFocusTracker * focus_tracker)1041 e_focus_tracker_get_undo_action (EFocusTracker *focus_tracker)
1042 {
1043 	g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL);
1044 
1045 	return focus_tracker->priv->undo;
1046 }
1047 
1048 void
e_focus_tracker_set_undo_action(EFocusTracker * focus_tracker,GtkAction * undo)1049 e_focus_tracker_set_undo_action (EFocusTracker *focus_tracker,
1050                                  GtkAction *undo)
1051 {
1052 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
1053 
1054 	if (undo != NULL) {
1055 		g_return_if_fail (GTK_IS_ACTION (undo));
1056 		g_object_ref (undo);
1057 	}
1058 
1059 	if (focus_tracker->priv->undo != NULL) {
1060 		g_signal_handlers_disconnect_matched (
1061 			focus_tracker->priv->undo,
1062 			G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
1063 			focus_tracker);
1064 		g_object_unref (focus_tracker->priv->undo);
1065 	}
1066 
1067 	focus_tracker->priv->undo = undo;
1068 
1069 	if (undo != NULL)
1070 		g_signal_connect_swapped (
1071 			undo, "activate",
1072 			G_CALLBACK (e_focus_tracker_undo),
1073 			focus_tracker);
1074 
1075 	g_object_notify (G_OBJECT (focus_tracker), "undo-action");
1076 }
1077 
1078 GtkAction *
e_focus_tracker_get_redo_action(EFocusTracker * focus_tracker)1079 e_focus_tracker_get_redo_action (EFocusTracker *focus_tracker)
1080 {
1081 	g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL);
1082 
1083 	return focus_tracker->priv->redo;
1084 }
1085 
1086 void
e_focus_tracker_set_redo_action(EFocusTracker * focus_tracker,GtkAction * redo)1087 e_focus_tracker_set_redo_action (EFocusTracker *focus_tracker,
1088                                  GtkAction *redo)
1089 {
1090 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
1091 
1092 	if (redo != NULL) {
1093 		g_return_if_fail (GTK_IS_ACTION (redo));
1094 		g_object_ref (redo);
1095 	}
1096 
1097 	if (focus_tracker->priv->redo != NULL) {
1098 		g_signal_handlers_disconnect_matched (
1099 			focus_tracker->priv->redo,
1100 			G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
1101 			focus_tracker);
1102 		g_object_unref (focus_tracker->priv->redo);
1103 	}
1104 
1105 	focus_tracker->priv->redo = redo;
1106 
1107 	if (redo != NULL)
1108 		g_signal_connect_swapped (
1109 			redo, "activate",
1110 			G_CALLBACK (e_focus_tracker_redo),
1111 			focus_tracker);
1112 
1113 	g_object_notify (G_OBJECT (focus_tracker), "redo-action");
1114 }
1115 
1116 void
e_focus_tracker_update_actions(EFocusTracker * focus_tracker)1117 e_focus_tracker_update_actions (EFocusTracker *focus_tracker)
1118 {
1119 	GtkClipboard *clipboard;
1120 
1121 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
1122 
1123 	/* Request clipboard targets asynchronously. */
1124 
1125 	clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1126 
1127 	gtk_clipboard_request_targets (
1128 		clipboard, (GtkClipboardTargetsReceivedFunc)
1129 		focus_tracker_targets_received_cb,
1130 		g_object_ref (focus_tracker));
1131 }
1132 
1133 void
e_focus_tracker_cut_clipboard(EFocusTracker * focus_tracker)1134 e_focus_tracker_cut_clipboard (EFocusTracker *focus_tracker)
1135 {
1136 	GtkWidget *focus;
1137 
1138 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
1139 
1140 	focus = e_focus_tracker_get_focus (focus_tracker);
1141 
1142 	if (E_IS_SELECTABLE (focus)) {
1143 		e_selectable_cut_clipboard (E_SELECTABLE (focus));
1144 
1145 	} else if (GTK_IS_EDITABLE (focus)) {
1146 		gtk_editable_cut_clipboard (GTK_EDITABLE (focus));
1147 
1148 	} else if (GTK_IS_TEXT_VIEW (focus)) {
1149 		GtkClipboard *clipboard;
1150 		GtkTextView *text_view;
1151 		GtkTextBuffer *buffer;
1152 		gboolean is_editable;
1153 
1154 		clipboard = gtk_widget_get_clipboard (
1155 			focus, GDK_SELECTION_CLIPBOARD);
1156 
1157 		text_view = GTK_TEXT_VIEW (focus);
1158 		buffer = gtk_text_view_get_buffer (text_view);
1159 		is_editable = gtk_text_view_get_editable (text_view);
1160 
1161 		gtk_text_buffer_cut_clipboard (buffer, clipboard, is_editable);
1162 
1163 	} else if (E_IS_CONTENT_EDITOR (focus)) {
1164 		e_content_editor_cut (E_CONTENT_EDITOR (focus));
1165 	}
1166 }
1167 
1168 void
e_focus_tracker_copy_clipboard(EFocusTracker * focus_tracker)1169 e_focus_tracker_copy_clipboard (EFocusTracker *focus_tracker)
1170 {
1171 	GtkWidget *focus;
1172 
1173 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
1174 
1175 	focus = e_focus_tracker_get_focus (focus_tracker);
1176 
1177 	if (E_IS_SELECTABLE (focus)) {
1178 		e_selectable_copy_clipboard (E_SELECTABLE (focus));
1179 
1180 	} else if (GTK_IS_EDITABLE (focus)) {
1181 		gtk_editable_copy_clipboard (GTK_EDITABLE (focus));
1182 
1183 	} else if (GTK_IS_TEXT_VIEW (focus)) {
1184 		GtkClipboard *clipboard;
1185 		GtkTextView *text_view;
1186 		GtkTextBuffer *buffer;
1187 
1188 		clipboard = gtk_widget_get_clipboard (
1189 			focus, GDK_SELECTION_CLIPBOARD);
1190 
1191 		text_view = GTK_TEXT_VIEW (focus);
1192 		buffer = gtk_text_view_get_buffer (text_view);
1193 
1194 		gtk_text_buffer_copy_clipboard (buffer, clipboard);
1195 
1196 	} else if (E_IS_CONTENT_EDITOR (focus)) {
1197 		e_content_editor_copy (E_CONTENT_EDITOR (focus));
1198 	}
1199 }
1200 
1201 void
e_focus_tracker_paste_clipboard(EFocusTracker * focus_tracker)1202 e_focus_tracker_paste_clipboard (EFocusTracker *focus_tracker)
1203 {
1204 	GtkWidget *focus;
1205 
1206 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
1207 
1208 	focus = e_focus_tracker_get_focus (focus_tracker);
1209 
1210 	if (E_IS_SELECTABLE (focus)) {
1211 		e_selectable_paste_clipboard (E_SELECTABLE (focus));
1212 
1213 	} else if (GTK_IS_EDITABLE (focus)) {
1214 		gtk_editable_paste_clipboard (GTK_EDITABLE (focus));
1215 
1216 	} else if (GTK_IS_TEXT_VIEW (focus)) {
1217 		GtkClipboard *clipboard;
1218 		GtkTextView *text_view;
1219 		GtkTextBuffer *buffer;
1220 		gboolean is_editable;
1221 
1222 		clipboard = gtk_widget_get_clipboard (
1223 			focus, GDK_SELECTION_CLIPBOARD);
1224 
1225 		text_view = GTK_TEXT_VIEW (focus);
1226 		buffer = gtk_text_view_get_buffer (text_view);
1227 		is_editable = gtk_text_view_get_editable (text_view);
1228 
1229 		gtk_text_buffer_paste_clipboard (
1230 			buffer, clipboard, NULL, is_editable);
1231 
1232 	} else if (E_IS_CONTENT_EDITOR (focus)) {
1233 		e_content_editor_paste (E_CONTENT_EDITOR (focus));
1234 	}
1235 }
1236 
1237 void
e_focus_tracker_delete_selection(EFocusTracker * focus_tracker)1238 e_focus_tracker_delete_selection (EFocusTracker *focus_tracker)
1239 {
1240 	GtkWidget *focus;
1241 
1242 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
1243 
1244 	focus = e_focus_tracker_get_focus (focus_tracker);
1245 
1246 	if (E_IS_SELECTABLE (focus)) {
1247 		e_selectable_delete_selection (E_SELECTABLE (focus));
1248 
1249 	} else if (GTK_IS_EDITABLE (focus)) {
1250 		gtk_editable_delete_selection (GTK_EDITABLE (focus));
1251 
1252 	} else if (GTK_IS_TEXT_VIEW (focus)) {
1253 		GtkTextView *text_view;
1254 		GtkTextBuffer *buffer;
1255 		gboolean is_editable;
1256 
1257 		text_view = GTK_TEXT_VIEW (focus);
1258 		buffer = gtk_text_view_get_buffer (text_view);
1259 		is_editable = gtk_text_view_get_editable (text_view);
1260 
1261 		gtk_text_buffer_delete_selection (buffer, TRUE, is_editable);
1262 	}
1263 }
1264 
1265 void
e_focus_tracker_select_all(EFocusTracker * focus_tracker)1266 e_focus_tracker_select_all (EFocusTracker *focus_tracker)
1267 {
1268 	GtkWidget *focus;
1269 
1270 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
1271 
1272 	focus = e_focus_tracker_get_focus (focus_tracker);
1273 
1274 	if (E_IS_SELECTABLE (focus)) {
1275 		e_selectable_select_all (E_SELECTABLE (focus));
1276 
1277 	} else if (GTK_IS_EDITABLE (focus)) {
1278 		gtk_editable_select_region (GTK_EDITABLE (focus), 0, -1);
1279 
1280 	} else if (GTK_IS_TEXT_VIEW (focus)) {
1281 		GtkTextView *text_view;
1282 		GtkTextBuffer *buffer;
1283 		GtkTextIter start, end;
1284 
1285 		text_view = GTK_TEXT_VIEW (focus);
1286 		buffer = gtk_text_view_get_buffer (text_view);
1287 
1288 		gtk_text_buffer_get_bounds (buffer, &start, &end);
1289 		gtk_text_buffer_select_range (buffer, &start, &end);
1290 
1291 	} else if (E_IS_CONTENT_EDITOR (focus)) {
1292 		e_content_editor_select_all (E_CONTENT_EDITOR (focus));
1293 	}
1294 }
1295 
1296 void
e_focus_tracker_undo(EFocusTracker * focus_tracker)1297 e_focus_tracker_undo (EFocusTracker *focus_tracker)
1298 {
1299 	GtkWidget *focus;
1300 
1301 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
1302 
1303 	focus = e_focus_tracker_get_focus (focus_tracker);
1304 
1305 	if (E_IS_SELECTABLE (focus))
1306 		e_selectable_undo (E_SELECTABLE (focus));
1307 	else
1308 		e_widget_undo_do_undo (focus);
1309 }
1310 
1311 void
e_focus_tracker_redo(EFocusTracker * focus_tracker)1312 e_focus_tracker_redo (EFocusTracker *focus_tracker)
1313 {
1314 	GtkWidget *focus;
1315 
1316 	g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker));
1317 
1318 	focus = e_focus_tracker_get_focus (focus_tracker);
1319 
1320 	if (E_IS_SELECTABLE (focus))
1321 		e_selectable_redo (E_SELECTABLE (focus));
1322 	else
1323 		e_widget_undo_do_redo (focus);
1324 }
1325