Generic Cut/Copy/Paste/Delete/Select All/Undo/Redo actions

master
Yevgen Muntyan 2008-05-06 23:21:11 -05:00
parent 3b3d54f1ed
commit 8c65b775fa
9 changed files with 1103 additions and 136 deletions

View File

@ -8,12 +8,6 @@
#define MOO_EDIT_ACCEL_SAVE MOO_ACCEL_SAVE
#define MOO_EDIT_ACCEL_SAVE_AS MOO_ACCEL_SAVE_AS
#define MOO_EDIT_ACCEL_CLOSE MOO_ACCEL_CLOSE
#define MOO_EDIT_ACCEL_UNDO MOO_ACCEL_UNDO
#define MOO_EDIT_ACCEL_REDO MOO_ACCEL_REDO
#define MOO_EDIT_ACCEL_CUT MOO_ACCEL_CUT
#define MOO_EDIT_ACCEL_COPY MOO_ACCEL_COPY
#define MOO_EDIT_ACCEL_PASTE MOO_ACCEL_PASTE
#define MOO_EDIT_ACCEL_SELECT_ALL MOO_ACCEL_SELECT_ALL
#define MOO_EDIT_ACCEL_PAGE_SETUP MOO_ACCEL_PAGE_SETUP
#define MOO_EDIT_ACCEL_PRINT MOO_ACCEL_PRINT

View File

@ -265,11 +265,7 @@ enum {
/* aux properties */
PROP_CAN_RELOAD,
PROP_HAS_OPEN_DOCUMENT,
PROP_CAN_UNDO,
PROP_CAN_REDO,
PROP_HAS_SELECTION,
PROP_HAS_COMMENTS,
PROP_HAS_TEXT,
PROP_HAS_JOBS_RUNNING,
PROP_HAS_STOP_CLIENTS
};
@ -358,11 +354,7 @@ moo_edit_window_class_init (MooEditWindowClass *klass)
INSTALL_PROP (PROP_CAN_RELOAD, "can-reload");
INSTALL_PROP (PROP_HAS_OPEN_DOCUMENT, "has-open-document");
INSTALL_PROP (PROP_CAN_UNDO, "can-undo");
INSTALL_PROP (PROP_CAN_REDO, "can-redo");
INSTALL_PROP (PROP_HAS_SELECTION, "has-selection");
INSTALL_PROP (PROP_HAS_COMMENTS, "has-comments");
INSTALL_PROP (PROP_HAS_TEXT, "has-text");
INSTALL_PROP (PROP_HAS_JOBS_RUNNING, "has-jobs-running");
INSTALL_PROP (PROP_HAS_STOP_CLIENTS, "has-stop-clients");
@ -443,81 +435,6 @@ moo_edit_window_class_init (MooEditWindowClass *klass)
"condition::sensitive", "has-open-document",
NULL);
moo_window_class_new_action (window_class, "Undo", NULL,
"display-name", GTK_STOCK_UNDO,
"label", GTK_STOCK_UNDO,
"tooltip", GTK_STOCK_UNDO,
"stock-id", GTK_STOCK_UNDO,
"accel", MOO_EDIT_ACCEL_UNDO,
"closure-signal", "undo",
"closure-proxy-func", moo_edit_window_get_active_doc,
"condition::sensitive", "can-undo",
NULL);
moo_window_class_new_action (window_class, "Redo", NULL,
"display-name", GTK_STOCK_REDO,
"label", GTK_STOCK_REDO,
"tooltip", GTK_STOCK_REDO,
"stock-id", GTK_STOCK_REDO,
"accel", MOO_EDIT_ACCEL_REDO,
"closure-signal", "redo",
"closure-proxy-func", moo_edit_window_get_active_doc,
"condition::sensitive", "can-redo",
NULL);
moo_window_class_new_action (window_class, "Cut", NULL,
"display-name", GTK_STOCK_CUT,
"label", GTK_STOCK_CUT,
"tooltip", GTK_STOCK_CUT,
"stock-id", GTK_STOCK_CUT,
"accel", MOO_EDIT_ACCEL_CUT,
"closure-signal", "cut-clipboard",
"closure-proxy-func", moo_edit_window_get_active_doc,
"condition::sensitive", "has-selection",
NULL);
moo_window_class_new_action (window_class, "Copy", NULL,
"display-name", GTK_STOCK_COPY,
"label", GTK_STOCK_COPY,
"tooltip", GTK_STOCK_COPY,
"stock-id", GTK_STOCK_COPY,
"accel", MOO_EDIT_ACCEL_COPY,
"closure-signal", "copy-clipboard",
"closure-proxy-func", moo_edit_window_get_active_doc,
"condition::sensitive", "has-selection",
NULL);
moo_window_class_new_action (window_class, "Paste", NULL,
"display-name", GTK_STOCK_PASTE,
"label", GTK_STOCK_PASTE,
"tooltip", GTK_STOCK_PASTE,
"stock-id", GTK_STOCK_PASTE,
"accel", MOO_EDIT_ACCEL_PASTE,
"closure-signal", "paste-clipboard",
"closure-proxy-func", moo_edit_window_get_active_doc,
"condition::sensitive", "has-open-document",
NULL);
moo_window_class_new_action (window_class, "Delete", NULL,
"display-name", GTK_STOCK_DELETE,
"label", GTK_STOCK_DELETE,
"tooltip", GTK_STOCK_DELETE,
"stock-id", GTK_STOCK_DELETE,
"closure-signal", "delete-selection",
"closure-proxy-func", moo_edit_window_get_active_doc,
"condition::sensitive", "has-selection",
NULL);
moo_window_class_new_action (window_class, "SelectAll", NULL,
"display-name", GTK_STOCK_SELECT_ALL,
"label", GTK_STOCK_SELECT_ALL,
"tooltip", GTK_STOCK_SELECT_ALL,
"accel", MOO_EDIT_ACCEL_SELECT_ALL,
"closure-callback", moo_text_view_select_all,
"closure-proxy-func", moo_edit_window_get_active_doc,
"condition::sensitive", "has-text",
NULL);
moo_window_class_new_action (window_class, "PreviousTab", NULL,
"display-name", _("Previous Tab"),
"label", _("_Previous Tab"),
@ -963,26 +880,10 @@ static void moo_edit_window_get_property(GObject *object,
case PROP_HAS_OPEN_DOCUMENT:
g_value_set_boolean (value, ACTIVE_DOC (window) != NULL);
break;
case PROP_CAN_UNDO:
doc = ACTIVE_DOC (window);
g_value_set_boolean (value, doc && moo_text_view_can_undo (MOO_TEXT_VIEW (doc)));
break;
case PROP_CAN_REDO:
doc = ACTIVE_DOC (window);
g_value_set_boolean (value, doc && moo_text_view_can_redo (MOO_TEXT_VIEW (doc)));
break;
case PROP_HAS_SELECTION:
doc = ACTIVE_DOC (window);
g_value_set_boolean (value, doc && moo_text_view_has_selection (MOO_TEXT_VIEW (doc)));
break;
case PROP_HAS_COMMENTS:
doc = ACTIVE_DOC (window);
g_value_set_boolean (value, doc && _moo_edit_has_comments (doc, NULL, NULL));
break;
case PROP_HAS_TEXT:
doc = ACTIVE_DOC (window);
g_value_set_boolean (value, doc && moo_text_view_has_text (MOO_TEXT_VIEW (doc)));
break;
case PROP_HAS_JOBS_RUNNING:
g_value_set_boolean (value, window->priv->jobs != NULL);
break;
@ -2133,11 +2034,7 @@ edit_changed (MooEditWindow *window,
g_object_freeze_notify (G_OBJECT (window));
g_object_notify (G_OBJECT (window), "can-reload");
g_object_notify (G_OBJECT (window), "has-open-document");
g_object_notify (G_OBJECT (window), "can-undo");
g_object_notify (G_OBJECT (window), "can-redo");
g_object_notify (G_OBJECT (window), "has-selection");
g_object_notify (G_OBJECT (window), "has-comments");
g_object_notify (G_OBJECT (window), "has-text");
g_object_thaw_notify (G_OBJECT (window));
update_window_title (window);
@ -2400,16 +2297,8 @@ _moo_edit_window_insert_doc (MooEditWindow *window,
G_CALLBACK (edit_show_line_numbers_changed), window);
g_signal_connect_swapped (edit, "filename_changed",
G_CALLBACK (edit_filename_changed), window);
g_signal_connect_swapped (edit, "notify::can-undo",
G_CALLBACK (proxy_boolean_property), window);
g_signal_connect_swapped (edit, "notify::can-redo",
G_CALLBACK (proxy_boolean_property), window);
g_signal_connect_swapped (edit, "notify::has-selection",
G_CALLBACK (proxy_boolean_property), window);
g_signal_connect_swapped (edit, "notify::has-comments",
G_CALLBACK (proxy_boolean_property), window);
g_signal_connect_swapped (edit, "notify::has-text",
G_CALLBACK (proxy_boolean_property), window);
g_signal_connect_swapped (edit, "config-notify::lang",
G_CALLBACK (edit_lang_changed), window);
g_signal_connect_swapped (edit, "cursor-moved",

View File

@ -42,6 +42,7 @@
#include "mooutils/moostock.h"
#include "mooutils/mooactionfactory.h"
#include "mooutils/mooaction-private.h"
#include "mooutils/mooeditops.h"
#include "marshals.h"
#include "mooutils/mooi18n.h"
#include <gdk/gdkkeysyms.h>
@ -425,9 +426,12 @@ static void file_view_cut_clipboard (MooFileView *fileview);
static void file_view_copy_clipboard (MooFileView *fileview);
static void file_view_paste_clipboard (MooFileView *fileview);
static void edit_ops_iface_init (MooEditOpsIface *iface);
/* MOO_TYPE_FILE_VIEW */
G_DEFINE_TYPE (MooFileView, moo_file_view, GTK_TYPE_VBOX)
G_DEFINE_TYPE_WITH_CODE (MooFileView, moo_file_view, GTK_TYPE_VBOX,
G_IMPLEMENT_INTERFACE (MOO_TYPE_EDIT_OPS,
edit_ops_iface_init))
enum {
PROP_0,
@ -2420,6 +2424,62 @@ moo_file_view_get_home_dir (MooFileView *fileview)
/* Clipboard
*/
static void
edit_ops_do_op (MooEditOps *obj,
MooEditOpType type)
{
MooFileView *fileview = MOO_FILE_VIEW (obj);
switch (type)
{
case MOO_EDIT_OP_CUT:
g_signal_emit_by_name (fileview, "cut-clipboard");
break;
case MOO_EDIT_OP_COPY:
g_signal_emit_by_name (fileview, "copy-clipboard");
break;
case MOO_EDIT_OP_PASTE:
g_signal_emit_by_name (fileview, "paste-clipboard");
break;
case MOO_EDIT_OP_DELETE:
g_signal_emit_by_name (fileview, "delete-selected");
break;
case MOO_EDIT_OP_SELECT_ALL:
_moo_icon_view_select_all (fileview->priv->iconview);
break;
}
}
static gboolean
edit_ops_can_do_op (MooEditOps *obj,
MooEditOpType type)
{
MooFileView *fileview = MOO_FILE_VIEW (obj);
switch (type)
{
case MOO_EDIT_OP_CUT:
return !_moo_tree_view_selection_is_empty (fileview->priv->view);
case MOO_EDIT_OP_COPY:
return !_moo_tree_view_selection_is_empty (fileview->priv->view);
case MOO_EDIT_OP_PASTE:
return TRUE;
case MOO_EDIT_OP_DELETE:
return !_moo_tree_view_selection_is_empty (fileview->priv->view);
case MOO_EDIT_OP_SELECT_ALL:
return TRUE;
}
g_return_val_if_reached (FALSE);
}
static void
edit_ops_iface_init (MooEditOpsIface *iface)
{
iface->do_op = edit_ops_do_op;
iface->can_do_op = edit_ops_can_do_op;
}
enum {
CB_TARGET_CLIPBOARD = 1,
CB_TARGET_URI_LIST = 2,

View File

@ -17,6 +17,7 @@
#include "mooterm/mooterm-selection.h"
#include "mooterm/mootermline-private.h"
#include "mooutils/mooutils-misc.h"
#include "mooutils/mooeditops.h"
typedef struct {
@ -290,6 +291,13 @@ invalidate_segment (Segment *segm, guint num)
}
static void
notify_has_selection (MooTerm *term)
{
g_object_notify (G_OBJECT (term), "has-selection");
moo_edit_ops_can_do_op_changed (G_OBJECT (term), MOO_EDIT_OP_COPY);
}
static void
_moo_term_select_range (MooTerm *term,
const MooTermIter *start,
@ -299,12 +307,14 @@ _moo_term_select_range (MooTerm *term,
Segment new_sel;
Segment old_selection;
gboolean inv = FALSE;
gboolean had_selection;
CHECK_ITER (start);
CHECK_ITER (end);
old_selection = *GET_SELECTION (ITER_TERM (start));
CHECK_SEGMENT (&old_selection);
had_selection = !segment_empty (&old_selection);
new_sel.start = *start;
new_sel.end = *end;
@ -352,9 +362,19 @@ _moo_term_select_range (MooTerm *term,
diff));
if (_moo_term_selection_empty (term))
{
_moo_term_release_selection (term);
if (had_selection)
notify_has_selection (term);
}
else
{
_moo_term_grab_selection (term);
if (!had_selection)
notify_has_selection (term);
}
}

View File

@ -20,9 +20,11 @@
#include "marshals.h"
#include "mooutils/mooutils-misc.h"
#include "mooutils/mooutils-debug.h"
#include "mooutils/mooeditops.h"
#include <string.h>
static void moo_term_edit_ops_init (MooEditOpsIface *iface);
static void moo_term_class_init (MooTermClass *klass);
static void moo_term_init (MooTerm *term);
static void moo_term_finalize (GObject *object);
@ -110,12 +112,15 @@ enum {
enum {
PROP_0,
PROP_CURSOR_BLINKS,
PROP_FONT_NAME
PROP_FONT_NAME,
PROP_HAS_SELECTION
};
/* MOO_TYPE_TERM */
G_DEFINE_TYPE (MooTerm, moo_term, GTK_TYPE_WIDGET)
G_DEFINE_TYPE_WITH_CODE (MooTerm, moo_term, GTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (MOO_TYPE_EDIT_OPS,
moo_term_edit_ops_init))
static guint signals[LAST_SIGNAL];
@ -151,21 +156,17 @@ static void moo_term_class_init (MooTermClass *klass)
klass->reset = moo_term_reset_real;
klass->bell = moo_term_bell_real;
g_object_class_install_property (gobject_class,
PROP_CURSOR_BLINKS,
g_param_spec_boolean ("cursor-blinks",
"cursor-blinks",
"cursor-blinks",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class, PROP_CURSOR_BLINKS,
g_param_spec_boolean ("cursor-blinks", "cursor-blinks", "cursor-blinks",
FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_FONT_NAME,
g_param_spec_string ("font-name",
"font-name",
"font-name",
DEFAULT_MONOSPACE_FONT,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class, PROP_FONT_NAME,
g_param_spec_string ("font-name", "font-name", "font-name",
DEFAULT_MONOSPACE_FONT, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class, PROP_HAS_SELECTION,
g_param_spec_boolean ("has-selection", "has-selection", "has-selection",
FALSE, G_PARAM_READABLE));
signals[SET_SCROLL_ADJUSTMENTS] =
g_signal_new ("set-scroll-adjustments",
@ -455,11 +456,16 @@ static void moo_term_get_property (GObject *object,
{
MooTerm *term = MOO_TERM (object);
switch (prop_id) {
switch (prop_id)
{
case PROP_CURSOR_BLINKS:
g_value_set_boolean (value, term->priv->cursor_blinks);
break;
case PROP_HAS_SELECTION:
g_value_set_boolean (value, moo_term_get_selection_bounds (term, NULL, NULL));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1073,6 +1079,68 @@ moo_term_paste_clipboard (MooTerm *term,
}
static void
moo_term_do_edit_op (MooEditOps *obj,
MooEditOpType type)
{
MooTerm *term;
g_return_if_fail (MOO_IS_TERM (obj));
term = MOO_TERM (obj);
switch (type)
{
case MOO_EDIT_OP_COPY:
moo_term_copy_clipboard (term, GDK_SELECTION_CLIPBOARD);
break;
case MOO_EDIT_OP_PASTE:
moo_term_paste_clipboard (term, GDK_SELECTION_CLIPBOARD);
break;
case MOO_EDIT_OP_SELECT_ALL:
moo_term_select_all (term);
break;
default:
g_return_if_reached ();
break;
}
}
static gboolean
moo_term_can_do_edit_op (MooEditOps *obj,
MooEditOpType type)
{
MooTerm *term;
g_return_val_if_fail (MOO_IS_TERM (obj), FALSE);
term = MOO_TERM (obj);
switch (type)
{
case MOO_EDIT_OP_COPY:
return moo_term_get_selection_bounds (term, NULL, NULL);
case MOO_EDIT_OP_PASTE:
case MOO_EDIT_OP_SELECT_ALL:
return TRUE;
case MOO_EDIT_OP_CUT:
case MOO_EDIT_OP_DELETE:
return FALSE;
default:
g_return_val_if_reached (FALSE);
break;
}
}
static void
moo_term_edit_ops_init (MooEditOpsIface *iface)
{
iface->do_op = moo_term_do_edit_op;
iface->can_do_op = moo_term_can_do_edit_op;
}
static gboolean
process_incoming (MooTerm *term)
{

View File

@ -29,6 +29,7 @@ mooutils_include_headers = \
moobigpaned.h \
mooclosure.h \
moocombo.h \
mooeditops.h \
mooentry.h \
moofiledialog.h \
moofiltermgr.h \
@ -87,6 +88,7 @@ mooutils_sources = \
moocompat.h \
moodialogs.c \
moodialogs.h \
mooeditops.c \
mooencodings.c \
mooencodings.h \
mooencodings-data.h \

449
moo/mooutils/mooeditops.c Normal file
View File

@ -0,0 +1,449 @@
/*
* mooeditops.c
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* See COPYING file that comes with this distribution.
*/
#include "mooeditops.h"
#include "marshals.h"
#include <gtk/gtk.h>
static void
moo_edit_ops_class_init (G_GNUC_UNUSED MooEditOpsIface *iface)
{
g_signal_new ("moo-edit-ops-can-do-op-changed",
MOO_TYPE_EDIT_OPS,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
_moo_marshal_VOID__UINT,
G_TYPE_NONE, 1,
G_TYPE_UINT);
}
GType
moo_edit_ops_get_type (void)
{
static GType type;
if (G_UNLIKELY (!type))
{
GTypeInfo type_info = {
sizeof (MooEditOpsIface), /* class_size */
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) moo_edit_ops_class_init, /* class_init */
NULL
};
type = g_type_register_static (G_TYPE_INTERFACE, "MooEditOps",
&type_info, 0);
g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
}
return type;
}
void
moo_edit_ops_can_do_op_changed (GObject *obj,
MooEditOpType type)
{
g_return_if_fail (type < MOO_N_EDIT_OPS);
g_signal_emit_by_name (obj, "moo-edit-ops-can-do-op-changed", type);
}
static void
emit_can_do_op_changed (GObject *obj)
{
int i;
for (i = 0; i < MOO_N_EDIT_OPS; i++)
moo_edit_ops_can_do_op_changed (obj, i);
}
static void
editable_do_op (GtkEditable *obj,
MooEditOpType type)
{
switch (type)
{
case MOO_EDIT_OP_CUT:
gtk_editable_cut_clipboard (obj);
break;
case MOO_EDIT_OP_COPY:
gtk_editable_copy_clipboard (obj);
break;
case MOO_EDIT_OP_PASTE:
gtk_editable_paste_clipboard (obj);
break;
case MOO_EDIT_OP_DELETE:
gtk_editable_delete_selection (obj);
break;
case MOO_EDIT_OP_SELECT_ALL:
gtk_editable_select_region (obj, 0, -1);
break;
default:
g_return_if_reached ();
}
}
static gboolean
entry_can_do_op (GtkEntry *obj,
MooEditOpType type)
{
switch (type)
{
case MOO_EDIT_OP_CUT:
return gtk_editable_get_editable (GTK_EDITABLE (obj)) &&
gtk_editable_get_selection_bounds (GTK_EDITABLE (obj), NULL, NULL);
case MOO_EDIT_OP_COPY:
return gtk_editable_get_selection_bounds (GTK_EDITABLE (obj), NULL, NULL);
case MOO_EDIT_OP_PASTE:
return gtk_editable_get_editable (GTK_EDITABLE (obj));
case MOO_EDIT_OP_DELETE:
return gtk_editable_get_selection_bounds (GTK_EDITABLE (obj), NULL, NULL);
case MOO_EDIT_OP_SELECT_ALL:
{
const char *text = gtk_entry_get_text (obj);
return text && text[0];
}
break;
default:
g_return_val_if_reached (FALSE);
}
}
static void
entry_connect (GtkEntry *obj)
{
g_signal_connect (obj, "notify::selection-bound",
G_CALLBACK (emit_can_do_op_changed), NULL);
g_signal_connect (obj, "notify::text",
G_CALLBACK (emit_can_do_op_changed), NULL);
}
static void
entry_disconnect (GtkEntry *obj)
{
g_signal_handlers_disconnect_by_func (obj, (gpointer) emit_can_do_op_changed, NULL);
}
static void
textview_do_op (GtkTextView *obj,
MooEditOpType type)
{
switch (type)
{
case MOO_EDIT_OP_CUT:
g_signal_emit_by_name (obj, "cut-clipboard");
break;
case MOO_EDIT_OP_COPY:
g_signal_emit_by_name (obj, "copy-clipboard");
break;
case MOO_EDIT_OP_PASTE:
g_signal_emit_by_name (obj, "paste-clipboard");
break;
case MOO_EDIT_OP_DELETE:
g_signal_emit_by_name (obj, "delete-from-cursor", GTK_DELETE_CHARS, 1);
break;
case MOO_EDIT_OP_SELECT_ALL:
g_signal_emit_by_name (obj, "select-all");
break;
default:
g_return_if_reached ();
}
}
static gboolean
textview_can_do_op (GtkTextView *obj,
MooEditOpType type)
{
GtkTextBuffer *buffer = obj->buffer;
switch (type)
{
case MOO_EDIT_OP_CUT:
return gtk_text_view_get_editable (obj) &&
gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL);
case MOO_EDIT_OP_COPY:
return gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL);
case MOO_EDIT_OP_PASTE:
return gtk_text_view_get_editable (obj);
case MOO_EDIT_OP_DELETE:
return gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL);
case MOO_EDIT_OP_SELECT_ALL:
return gtk_text_buffer_get_char_count (buffer) != 0;
default:
g_return_val_if_reached (FALSE);
}
}
static void
textview_connect (GtkTextView *obj)
{
/* XXX */
GtkTextBuffer *buffer = obj->buffer;
if (buffer)
{
g_signal_connect_swapped (buffer, "notify::has-selection",
G_CALLBACK (emit_can_do_op_changed), obj);
g_signal_connect_swapped (buffer, "changed",
G_CALLBACK (emit_can_do_op_changed), obj);
}
}
static void
textview_disconnect (GtkTextView *obj)
{
/* XXX */
GtkTextBuffer *buffer = obj->buffer;
if (buffer)
g_signal_handlers_disconnect_by_func (buffer, (gpointer) emit_can_do_op_changed, obj);
}
void
_moo_edit_ops_do_op (GObject *obj,
MooEditOpType type)
{
g_return_if_fail (type < MOO_N_EDIT_OPS);
if (MOO_IS_EDIT_OPS (obj))
{
g_return_if_fail (MOO_EDIT_OPS_GET_IFACE (obj)->do_op != NULL);
MOO_EDIT_OPS_GET_IFACE (obj)->do_op (MOO_EDIT_OPS (obj), type);
}
else if (GTK_IS_ENTRY (obj))
{
editable_do_op (GTK_EDITABLE (obj), type);
}
else if (GTK_IS_TEXT_VIEW (obj))
{
textview_do_op (GTK_TEXT_VIEW (obj), type);
}
else
{
g_return_if_reached ();
}
}
gboolean
_moo_edit_ops_can_do_op (GObject *obj,
MooEditOpType type)
{
g_return_val_if_fail (type < MOO_N_EDIT_OPS, FALSE);
if (MOO_IS_EDIT_OPS (obj))
{
g_return_val_if_fail (MOO_EDIT_OPS_GET_IFACE (obj)->can_do_op != NULL, FALSE);
return MOO_EDIT_OPS_GET_IFACE (obj)->can_do_op (MOO_EDIT_OPS (obj), type);
}
else if (GTK_IS_TEXT_VIEW (obj))
{
return textview_can_do_op (GTK_TEXT_VIEW (obj), type);
}
else if (GTK_IS_ENTRY (obj))
{
return entry_can_do_op (GTK_ENTRY (obj), type);
}
else
{
g_return_val_if_reached (FALSE);
}
}
void
_moo_edit_ops_connect (GObject *obj)
{
if (!MOO_IS_EDIT_OPS (obj))
{
if (GTK_IS_TEXT_VIEW (obj))
textview_connect (GTK_TEXT_VIEW (obj));
else if (GTK_IS_ENTRY (obj))
entry_connect (GTK_ENTRY (obj));
else
g_return_if_reached ();
}
}
void
_moo_edit_ops_disconnect (GObject *obj)
{
if (!MOO_IS_EDIT_OPS (obj))
{
if (GTK_IS_TEXT_VIEW (obj))
textview_disconnect (GTK_TEXT_VIEW (obj));
else if (GTK_IS_ENTRY (obj))
entry_disconnect (GTK_ENTRY (obj));
else
g_return_if_reached ();
}
}
gboolean
_moo_edit_ops_check (GObject *obj)
{
return MOO_IS_EDIT_OPS (obj) ||
GTK_IS_TEXT_VIEW (obj) ||
GTK_IS_ENTRY (obj);
}
void
_moo_edit_ops_iface_install (void)
{
static gboolean been_here;
if (!been_here)
{
g_signal_new ("moo-edit-ops-can-do-op-changed",
GTK_TYPE_TEXT_VIEW,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
_moo_marshal_VOID__UINT,
G_TYPE_NONE, 1,
G_TYPE_UINT);
g_signal_new ("moo-edit-ops-can-do-op-changed",
GTK_TYPE_ENTRY,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
_moo_marshal_VOID__UINT,
G_TYPE_NONE, 1,
G_TYPE_UINT);
been_here = TRUE;
}
}
/************************************************************************/
/* MooUndoOps
*/
static void
moo_undo_ops_class_init (G_GNUC_UNUSED MooUndoOpsIface *iface)
{
g_signal_new ("moo-undo-ops-can-undo-changed",
MOO_TYPE_EDIT_OPS,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
_moo_marshal_VOID__VOID,
G_TYPE_NONE, 0);
g_signal_new ("moo-undo-ops-can-redo-changed",
MOO_TYPE_EDIT_OPS,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
_moo_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
GType
moo_undo_ops_get_type (void)
{
static GType type;
if (G_UNLIKELY (!type))
{
GTypeInfo type_info = {
sizeof (MooEditOpsIface), NULL, NULL,
(GClassInitFunc) moo_undo_ops_class_init,
NULL
};
type = g_type_register_static (G_TYPE_INTERFACE, "MooUndoOps",
&type_info, 0);
g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
}
return type;
}
void
moo_undo_ops_can_undo_changed (GObject *obj)
{
g_signal_emit_by_name (obj, "moo-edit-ops-can-undo-changed");
}
void
moo_undo_ops_can_redo_changed (GObject *obj)
{
g_signal_emit_by_name (obj, "moo-edit-ops-can-redo-changed");
}
void
_moo_undo_ops_undo (GObject *obj)
{
if (MOO_IS_UNDO_OPS (obj))
{
g_return_if_fail (MOO_UNDO_OPS_GET_IFACE (obj)->undo != NULL);
MOO_UNDO_OPS_GET_IFACE (obj)->undo (MOO_UNDO_OPS (obj));
}
else
{
g_return_if_reached ();
}
}
void
_moo_undo_ops_redo (GObject *obj)
{
if (MOO_IS_UNDO_OPS (obj))
{
g_return_if_fail (MOO_UNDO_OPS_GET_IFACE (obj)->redo != NULL);
MOO_UNDO_OPS_GET_IFACE (obj)->redo (MOO_UNDO_OPS (obj));
}
else
{
g_return_if_reached ();
}
}
gboolean
_moo_undo_ops_can_undo (GObject *obj)
{
if (MOO_IS_UNDO_OPS (obj))
{
g_return_val_if_fail (MOO_UNDO_OPS_GET_IFACE (obj)->can_undo != NULL, FALSE);
return MOO_UNDO_OPS_GET_IFACE (obj)->can_undo (MOO_UNDO_OPS (obj));
}
else
{
g_return_val_if_reached (FALSE);
}
}
gboolean
_moo_undo_ops_can_redo (GObject *obj)
{
if (MOO_IS_UNDO_OPS (obj))
{
g_return_val_if_fail (MOO_UNDO_OPS_GET_IFACE (obj)->can_redo != NULL, FALSE);
return MOO_UNDO_OPS_GET_IFACE (obj)->can_redo (MOO_UNDO_OPS (obj));
}
else
{
g_return_val_if_reached (FALSE);
}
}
gboolean
_moo_undo_ops_check (GObject *obj)
{
return MOO_IS_UNDO_OPS (obj);
}

92
moo/mooutils/mooeditops.h Normal file
View File

@ -0,0 +1,92 @@
/*
* mooeditops.h
*
* Copyright (C) 2004-2008 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* See COPYING file that comes with this distribution.
*/
#ifndef MOO_EDIT_OPS_H
#define MOO_EDIT_OPS_H
#include <glib-object.h>
G_BEGIN_DECLS
#define MOO_TYPE_EDIT_OPS (moo_edit_ops_get_type ())
#define MOO_EDIT_OPS(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOO_TYPE_EDIT_OPS, MooEditOps))
#define MOO_IS_EDIT_OPS(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOO_TYPE_EDIT_OPS))
#define MOO_EDIT_OPS_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MOO_TYPE_EDIT_OPS, MooEditOpsIface))
#define MOO_TYPE_UNDO_OPS (moo_undo_ops_get_type ())
#define MOO_UNDO_OPS(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOO_TYPE_UNDO_OPS, MooUndoOps))
#define MOO_IS_UNDO_OPS(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOO_TYPE_UNDO_OPS))
#define MOO_UNDO_OPS_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MOO_TYPE_UNDO_OPS, MooUndoOpsIface))
typedef struct MooEditOps MooEditOps;
typedef struct MooEditOpsIface MooEditOpsIface;
typedef struct MooUndoOps MooUndoOps;
typedef struct MooUndoOpsIface MooUndoOpsIface;
typedef enum {
MOO_EDIT_OP_CUT,
MOO_EDIT_OP_COPY,
MOO_EDIT_OP_PASTE,
MOO_EDIT_OP_DELETE,
MOO_EDIT_OP_SELECT_ALL
} MooEditOpType;
#define MOO_N_EDIT_OPS (MOO_EDIT_OP_SELECT_ALL+1)
struct MooEditOpsIface
{
GTypeInterface g_iface;
void (*do_op) (MooEditOps *obj,
MooEditOpType type);
gboolean (*can_do_op) (MooEditOps *obj,
MooEditOpType type);
};
struct MooUndoOpsIface
{
GTypeInterface g_iface;
void (*undo) (MooUndoOps *obj);
void (*redo) (MooUndoOps *obj);
gboolean (*can_undo) (MooUndoOps *obj);
gboolean (*can_redo) (MooUndoOps *obj);
};
GType moo_edit_ops_get_type (void) G_GNUC_CONST;
GType moo_undo_ops_get_type (void) G_GNUC_CONST;
void _moo_edit_ops_do_op (GObject *obj,
MooEditOpType type);
gboolean _moo_edit_ops_can_do_op (GObject *obj,
MooEditOpType type);
void moo_edit_ops_can_do_op_changed (GObject *obj,
MooEditOpType type);
gboolean _moo_edit_ops_check (GObject *obj);
void _moo_edit_ops_iface_install (void);
void _moo_edit_ops_connect (GObject *obj);
void _moo_edit_ops_disconnect (GObject *obj);
void _moo_undo_ops_undo (GObject *obj);
void _moo_undo_ops_redo (GObject *obj);
gboolean _moo_undo_ops_can_undo (GObject *obj);
gboolean _moo_undo_ops_can_redo (GObject *obj);
void moo_undo_ops_can_undo_changed (GObject *obj);
void moo_undo_ops_can_redo_changed (GObject *obj);
gboolean _moo_undo_ops_check (GObject *obj);
G_END_DECLS
#endif /* MOO_EDIT_OPS_H */

View File

@ -23,6 +23,7 @@
#include "mooutils/mooi18n.h"
#include "mooutils/mooutils-misc.h"
#include "mooutils/mooutils-mem.h"
#include "mooutils/mooeditops.h"
#include <gtk/gtk.h>
#include <gobject/gvaluecollector.h>
@ -56,6 +57,11 @@ struct _MooWindowPrivate {
char *name;
char *id;
GtkWidget *eo_widget;
GtkWidget *default_eo_widget;
GtkWidget *uo_widget;
GtkWidget *default_uo_widget;
guint global_accels : 1;
};
@ -125,6 +131,18 @@ static void moo_window_set_toolbar_visible (MooWindow *window,
static GtkAction *create_toolbar_style_action (MooWindow *window,
gpointer dummy);
static void moo_window_set_focus (GtkWindow *window,
GtkWidget *widget);
static void moo_window_disconnect_eo_widget (MooWindow *window);
static void moo_window_disconnect_uo_widget (MooWindow *window);
static void moo_window_action_cut (MooWindow *window);
static void moo_window_action_copy (MooWindow *window);
static void moo_window_action_paste (MooWindow *window);
static void moo_window_action_delete (MooWindow *window);
static void moo_window_action_select_all (MooWindow *window);
static void moo_window_action_undo (MooWindow *window);
static void moo_window_action_redo (MooWindow *window);
enum {
PROP_0,
@ -135,7 +153,16 @@ enum {
PROP_UI_XML,
PROP_ACTIONS,
PROP_TOOLBAR_VISIBLE,
PROP_MENUBAR_VISIBLE
PROP_MENUBAR_VISIBLE,
PROP_MEO_CAN_CUT,
PROP_MEO_CAN_COPY,
PROP_MEO_CAN_PASTE,
PROP_MEO_CAN_SELECT_ALL,
PROP_MEO_CAN_DELETE,
PROP_MUO_CAN_UNDO,
PROP_MUO_CAN_REDO
};
enum {
@ -152,11 +179,16 @@ G_DEFINE_TYPE (MooWindow, moo_window, GTK_TYPE_WINDOW)
static gpointer moo_window_grand_parent_class;
#define INSTALL_PROP(prop_id,name) \
g_object_class_install_property (gobject_class, prop_id, \
g_param_spec_boolean (name, name, name, FALSE, G_PARAM_READABLE))
static void
moo_window_class_init (MooWindowClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass);
moo_window_grand_parent_class = g_type_class_peek_parent (moo_window_parent_class);
@ -167,9 +199,12 @@ moo_window_class_init (MooWindowClass *klass)
widget_class->delete_event = moo_window_delete_event;
widget_class->key_press_event = moo_window_key_press_event;
window_class->set_focus = moo_window_set_focus;
moo_window_class_set_id (klass, "MooWindow", "Window");
_moo_edit_ops_iface_install ();
moo_window_class_new_action (klass, "ConfigureShortcuts", NULL,
"label", _("Configure _Shortcuts..."),
"no-accel", TRUE,
@ -195,6 +230,75 @@ moo_window_class_init (MooWindowClass *klass)
create_toolbar_style_action,
NULL, NULL);
moo_window_class_new_action (klass, "Cut", NULL,
"display-name", GTK_STOCK_CUT,
"label", GTK_STOCK_CUT,
"tooltip", GTK_STOCK_CUT,
"stock-id", GTK_STOCK_CUT,
"accel", MOO_ACCEL_CUT,
"closure-callback", moo_window_action_cut,
"condition::sensitive", "can-cut",
NULL);
moo_window_class_new_action (klass, "Copy", NULL,
"display-name", GTK_STOCK_COPY,
"label", GTK_STOCK_COPY,
"tooltip", GTK_STOCK_COPY,
"stock-id", GTK_STOCK_COPY,
"accel", MOO_ACCEL_COPY,
"closure-callback", moo_window_action_copy,
"condition::sensitive", "can-copy",
NULL);
moo_window_class_new_action (klass, "Paste", NULL,
"display-name", GTK_STOCK_PASTE,
"label", GTK_STOCK_PASTE,
"tooltip", GTK_STOCK_PASTE,
"stock-id", GTK_STOCK_PASTE,
"accel", MOO_ACCEL_PASTE,
"closure-callback", moo_window_action_paste,
"condition::sensitive", "can-paste",
NULL);
moo_window_class_new_action (klass, "Delete", NULL,
"display-name", GTK_STOCK_DELETE,
"label", GTK_STOCK_DELETE,
"tooltip", GTK_STOCK_DELETE,
"stock-id", GTK_STOCK_DELETE,
"closure-callback", moo_window_action_delete,
"condition::sensitive", "can-delete",
NULL);
moo_window_class_new_action (klass, "SelectAll", NULL,
"display-name", GTK_STOCK_SELECT_ALL,
"label", GTK_STOCK_SELECT_ALL,
"tooltip", GTK_STOCK_SELECT_ALL,
"stock-id", GTK_STOCK_SELECT_ALL,
"accel", MOO_ACCEL_SELECT_ALL,
"closure-callback", moo_window_action_select_all,
"condition::sensitive", "can-select-all",
NULL);
moo_window_class_new_action (klass, "Undo", NULL,
"display-name", GTK_STOCK_UNDO,
"label", GTK_STOCK_UNDO,
"tooltip", GTK_STOCK_UNDO,
"stock-id", GTK_STOCK_UNDO,
"accel", MOO_ACCEL_UNDO,
"closure-callback", moo_window_action_undo,
"condition::sensitive", "can-undo",
NULL);
moo_window_class_new_action (klass, "Redo", NULL,
"display-name", GTK_STOCK_REDO,
"label", GTK_STOCK_REDO,
"tooltip", GTK_STOCK_REDO,
"stock-id", GTK_STOCK_REDO,
"accel", MOO_ACCEL_REDO,
"closure-callback", moo_window_action_redo,
"condition::sensitive", "can-redo",
NULL);
g_object_class_install_property (gobject_class,
PROP_ACCEL_GROUP,
g_param_spec_object ("accel-group",
@ -259,6 +363,15 @@ moo_window_class_init (MooWindowClass *klass)
TRUE,
G_PARAM_READWRITE));
INSTALL_PROP (PROP_MEO_CAN_COPY, "can-copy");
INSTALL_PROP (PROP_MEO_CAN_CUT, "can-cut");
INSTALL_PROP (PROP_MEO_CAN_PASTE, "can-paste");
INSTALL_PROP (PROP_MEO_CAN_DELETE, "can-delete");
INSTALL_PROP (PROP_MEO_CAN_SELECT_ALL, "can-select-all");
INSTALL_PROP (PROP_MUO_CAN_UNDO, "can-undo");
INSTALL_PROP (PROP_MUO_CAN_REDO, "can-redo");
signals[CLOSE] =
g_signal_new ("close",
G_OBJECT_CLASS_TYPE (klass),
@ -375,6 +488,12 @@ moo_window_dispose (GObject *object)
if (window->priv)
{
window->priv->default_eo_widget = NULL;
moo_window_disconnect_eo_widget (window);
window->priv->default_uo_widget = NULL;
moo_window_disconnect_uo_widget (window);
if (window->priv->ui_xml)
g_object_unref (window->priv->ui_xml);
@ -579,6 +698,36 @@ moo_window_get_property (GObject *object,
g_value_set_boolean (value, window->priv->menubar_visible);
break;
case PROP_MEO_CAN_COPY:
g_value_set_boolean (value, window->priv->eo_widget &&
_moo_edit_ops_can_do_op (G_OBJECT (window->priv->eo_widget), MOO_EDIT_OP_COPY));
break;
case PROP_MEO_CAN_CUT:
g_value_set_boolean (value, window->priv->eo_widget &&
_moo_edit_ops_can_do_op (G_OBJECT (window->priv->eo_widget), MOO_EDIT_OP_CUT));
break;
case PROP_MEO_CAN_PASTE:
g_value_set_boolean (value, window->priv->eo_widget &&
_moo_edit_ops_can_do_op (G_OBJECT (window->priv->eo_widget), MOO_EDIT_OP_PASTE));
break;
case PROP_MEO_CAN_DELETE:
g_value_set_boolean (value, window->priv->eo_widget &&
_moo_edit_ops_can_do_op (G_OBJECT (window->priv->eo_widget), MOO_EDIT_OP_DELETE));
break;
case PROP_MEO_CAN_SELECT_ALL:
g_value_set_boolean (value, window->priv->eo_widget &&
_moo_edit_ops_can_do_op (G_OBJECT (window->priv->eo_widget), MOO_EDIT_OP_SELECT_ALL));
break;
case PROP_MUO_CAN_UNDO:
g_value_set_boolean (value, window->priv->uo_widget &&
_moo_undo_ops_can_undo (G_OBJECT (window->priv->uo_widget)));
break;
case PROP_MUO_CAN_REDO:
g_value_set_boolean (value, window->priv->uo_widget &&
_moo_undo_ops_can_redo (G_OBJECT (window->priv->uo_widget)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1792,3 +1941,247 @@ _moo_window_class_new_action_callback (MooWindowClass *klass,
g_object_unref (action_factory);
g_strfreev (conditions);
}
/*************************************************************************/
/* MooEditOps
*/
static void
moo_window_action_cut (MooWindow *window)
{
g_return_if_fail (window->priv->eo_widget != NULL);
_moo_edit_ops_do_op (G_OBJECT (window->priv->eo_widget),
MOO_EDIT_OP_CUT);
}
static void
moo_window_action_copy (MooWindow *window)
{
g_return_if_fail (window->priv->eo_widget != NULL);
_moo_edit_ops_do_op (G_OBJECT (window->priv->eo_widget),
MOO_EDIT_OP_COPY);
}
static void
moo_window_action_paste (MooWindow *window)
{
g_return_if_fail (window->priv->eo_widget != NULL);
_moo_edit_ops_do_op (G_OBJECT (window->priv->eo_widget),
MOO_EDIT_OP_PASTE);
}
static void
moo_window_action_delete (MooWindow *window)
{
g_return_if_fail (window->priv->eo_widget != NULL);
_moo_edit_ops_do_op (G_OBJECT (window->priv->eo_widget),
MOO_EDIT_OP_DELETE);
}
static void
moo_window_action_select_all (MooWindow *window)
{
g_return_if_fail (window->priv->eo_widget != NULL);
_moo_edit_ops_do_op (G_OBJECT (window->priv->eo_widget),
MOO_EDIT_OP_SELECT_ALL);
}
static void
moo_window_action_undo (MooWindow *window)
{
g_return_if_fail (window->priv->uo_widget != NULL);
_moo_undo_ops_undo (G_OBJECT (window->priv->uo_widget));
}
static void
moo_window_action_redo (MooWindow *window)
{
g_return_if_fail (window->priv->uo_widget != NULL);
_moo_undo_ops_redo (G_OBJECT (window->priv->uo_widget));
}
static void
emit_can_do_op_changed (MooWindow *window,
MooEditOpType type)
{
switch (type)
{
case MOO_EDIT_OP_CUT:
g_object_notify (G_OBJECT (window), "can-cut");
break;
case MOO_EDIT_OP_COPY:
g_object_notify (G_OBJECT (window), "can-copy");
break;
case MOO_EDIT_OP_PASTE:
g_object_notify (G_OBJECT (window), "can-paste");
break;
case MOO_EDIT_OP_DELETE:
g_object_notify (G_OBJECT (window), "can-delete");
break;
case MOO_EDIT_OP_SELECT_ALL:
g_object_notify (G_OBJECT (window), "can-select-all");
break;
default:
g_return_if_reached ();
}
}
static void
moo_window_connect_eo_widget (MooWindow *window,
GtkWidget *widget)
{
g_return_if_fail (_moo_edit_ops_check (G_OBJECT (widget)));
window->priv->eo_widget = g_object_ref (widget);
_moo_edit_ops_connect (G_OBJECT (widget));
g_signal_connect_swapped (widget, "moo-edit-ops-can-do-op-changed",
G_CALLBACK (emit_can_do_op_changed), window);
}
static void
moo_window_disconnect_eo_widget (MooWindow *window)
{
GtkWidget *widget;
widget = window->priv->eo_widget;
window->priv->eo_widget = NULL;
if (widget)
{
_moo_edit_ops_disconnect (G_OBJECT (widget));
g_signal_handlers_disconnect_by_func (widget,
(gpointer) emit_can_do_op_changed,
window);
g_object_unref (widget);
}
}
static GtkWidget *
find_widget_for_edit_ops (MooWindow *window)
{
GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window));
while (widget)
{
if (_moo_edit_ops_check (G_OBJECT (widget)))
return widget;
widget = widget->parent;
}
return window->priv ? window->priv->default_eo_widget : NULL;
}
static void
check_edit_ops_widget (MooWindow *window)
{
GtkWidget *widget;
widget = find_widget_for_edit_ops (window);
if (window->priv && widget != window->priv->eo_widget)
{
int i;
moo_window_disconnect_eo_widget (window);
if (widget)
moo_window_connect_eo_widget (window, widget);
for (i = 0; i < MOO_N_EDIT_OPS; i++)
emit_can_do_op_changed (window, i);
}
}
static void
emit_can_undo_changed (MooWindow *window)
{
g_object_notify (G_OBJECT (window), "can-undo");
}
static void
emit_can_redo_changed (MooWindow *window)
{
g_object_notify (G_OBJECT (window), "can-redo");
}
static void
moo_window_connect_uo_widget (MooWindow *window,
GtkWidget *widget)
{
g_return_if_fail (_moo_undo_ops_check (G_OBJECT (widget)));
window->priv->uo_widget = g_object_ref (widget);
g_signal_connect_swapped (widget, "moo-undo-ops-can-undo-changed",
G_CALLBACK (emit_can_undo_changed), window);
g_signal_connect_swapped (widget, "moo-undo-ops-can-redo-changed",
G_CALLBACK (emit_can_redo_changed), window);
}
static void
moo_window_disconnect_uo_widget (MooWindow *window)
{
GtkWidget *widget;
widget = window->priv->uo_widget;
window->priv->uo_widget = NULL;
if (widget)
{
g_signal_handlers_disconnect_by_func (widget,
(gpointer) emit_can_undo_changed,
window);
g_signal_handlers_disconnect_by_func (widget,
(gpointer) emit_can_redo_changed,
window);
g_object_unref (widget);
}
}
static GtkWidget *
find_widget_for_undo_ops (MooWindow *window)
{
GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window));
while (widget)
{
if (_moo_undo_ops_check (G_OBJECT (widget)))
return widget;
widget = widget->parent;
}
return window->priv ? window->priv->default_uo_widget : NULL;
}
static void
check_undo_ops_widget (MooWindow *window)
{
GtkWidget *widget;
widget = find_widget_for_undo_ops (window);
if (window->priv && widget != window->priv->uo_widget)
{
moo_window_disconnect_uo_widget (window);
if (widget)
moo_window_connect_uo_widget (window, widget);
emit_can_undo_changed (window);
emit_can_redo_changed (window);
}
}
static void
moo_window_set_focus (GtkWindow *window,
GtkWidget *widget)
{
GTK_WINDOW_CLASS (moo_window_parent_class)->set_focus (window, widget);
check_edit_ops_widget (MOO_WINDOW (window));
check_undo_ops_widget (MOO_WINDOW (window));
}