aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/text
diff options
context:
space:
mode:
authorChris Toshok <toshok@ximian.com>2003-04-03 14:06:20 +0800
committerChris Toshok <toshok@src.gnome.org>2003-04-03 14:06:20 +0800
commitd2af55db1a8119fbcdfdc262db76d78bcd282819 (patch)
tree5244f570f8638e5426ebc6ed94a66b660976649c /widgets/text
parent7143de721bd1b16c97bd123456aa60fc7e8237bd (diff)
downloadgsoc2013-evolution-d2af55db1a8119fbcdfdc262db76d78bcd282819.tar.gz
gsoc2013-evolution-d2af55db1a8119fbcdfdc262db76d78bcd282819.tar.zst
gsoc2013-evolution-d2af55db1a8119fbcdfdc262db76d78bcd282819.zip
[ either fixes #39702 or comes damn, damn close. also, fixes EText to not
2003-04-02 Chris Toshok <toshok@ximian.com> [ either fixes #39702 or comes damn, damn close. also, fixes EText to not suck *nearly* as much. ] * gal/util/e-marshal.list: add NONE:POINTER,INT,OBJECT. * gal/e-text/e-entry.h: (struct _EEntryClass): popup -> populate_popup. * gal/e-text/e-entry.c (proxy_changed): rename, the old name was too damn long. (proxy_activate): same. (proxy_populate_popup): same, and change from popup to populate_popup. (e_entry_init): track change to cb names, and populate_popup. also, pass the ECanvas's im_context to the EText. (e_entry_class_init): POPUP -> POPULATE_POPUP. * gal/e-text/e-text.h (struct _EText): remove the old selection stuff, and add im_context/reset_im_context fields. (struct _ETextClass): popup -> populate_popup. * gal/e-text/e-text.c (e_text_dispose): remove all the GtkInvisible based selection stuff, and disconnect from/unref the im_context. (e_text_set_property): add "im_context" handling. (e_text_get_property): same. (e_text_event): connect/disconnect from the IM context's signals in the FOCUS_CHANGE handler. in the KEY_PRESS/RELEASE handler, use gtk_im_context_filter_keypress if we have an im_context. also, use e_text_do_popup now instead of just emitting the "popup" signal. (e_text_copy_clipboard): new function. (e_text_delete_selection): new function. (e_text_cut_clipboard): new function. (e_text_paste_clipboard): new function. (e_text_select_all): new function. (primary_get_cb): new function, handle requests for the primary selection when we're the owner. (primary_clear_cb): new function, unfinished. (e_text_update_primary_selection): new function. (paste_received): new function, insert pasted text. (e_text_paste): new function, (popup_menu_detach): new function, not needed really. (popup_targets_received): new function, pop up the popup once we have the selection information necessary to sensitize the c/c/p buttons. (e_text_do_popup): new function, request the selection. (e_text_reset_im_context): new function. (e_text_command): for E_TEP_SELECT, call e_text_update_primary_selection. for E_TEP_DELETE/INSERT, _delete_selection -> e_text_delete_selection. for E_TEP_COPY, call e_text_copy_clipboard. for E_TEP_PASTE/E_TEP_GET_SELECTION call e_text_paste. (e_text_class_init): change the "popup" signal to "populate_popup". Also, add the "im_context" property. (e_text_commit_cb): new function. IM context callback. (e_text_retrieve_surrounding_cb): new function. IM context callback. (e_text_delete_surrounding_cb): new function. IM context callback. unfinished. svn path=/trunk/; revision=20653
Diffstat (limited to 'widgets/text')
-rw-r--r--widgets/text/e-entry.c35
-rw-r--r--widgets/text/e-entry.h2
-rw-r--r--widgets/text/e-text.c872
-rw-r--r--widgets/text/e-text.h25
4 files changed, 473 insertions, 461 deletions
diff --git a/widgets/text/e-entry.c b/widgets/text/e-entry.c
index fbd708eb66..2bcf165e0b 100644
--- a/widgets/text/e-entry.c
+++ b/widgets/text/e-entry.c
@@ -54,7 +54,7 @@ static GtkObjectClass *parent_class;
enum {
E_ENTRY_CHANGED,
E_ENTRY_ACTIVATE,
- E_ENTRY_POPUP,
+ E_ENTRY_POPULATE_POPUP,
E_ENTRY_COMPLETION_POPUP,
E_ENTRY_LAST_SIGNAL
};
@@ -98,7 +98,7 @@ struct _EEntryPrivate {
guint changed_proxy_tag;
guint activate_proxy_tag;
- guint popup_proxy_tag;
+ guint populate_popup_proxy_tag;
/* Data related to completions */
ECompletion *completion;
EEntryCompletionHandler handler;
@@ -270,7 +270,7 @@ changed_since_keypress_timeout_fn (gpointer user_data)
}
static void
-e_entry_proxy_changed (EText *text, EEntry *entry)
+proxy_changed (EText *text, EEntry *entry)
{
if (entry->priv->changed_since_keypress_tag)
gtk_timeout_remove (entry->priv->changed_since_keypress_tag);
@@ -281,15 +281,15 @@ e_entry_proxy_changed (EText *text, EEntry *entry)
}
static void
-e_entry_proxy_activate (EText *text, EEntry *entry)
+proxy_activate (EText *text, EEntry *entry)
{
g_signal_emit (entry, e_entry_signals [E_ENTRY_ACTIVATE], 0);
}
static void
-e_entry_proxy_popup (EText *text, GdkEventButton *ev, gint pos, EEntry *entry)
+proxy_populate_popup (EText *text, GdkEventButton *ev, gint pos, GtkWidget *menu, EEntry *entry)
{
- g_signal_emit (entry, e_entry_signals [E_ENTRY_POPUP], 0, ev, pos);
+ g_signal_emit (entry, e_entry_signals [E_ENTRY_POPULATE_POPUP], 0, ev, pos, menu);
}
static void
@@ -334,6 +334,7 @@ e_entry_init (GtkObject *object)
"max_lines", 1,
"editable", TRUE,
"allow_newlines", FALSE,
+ "im_context", E_CANVAS (entry->canvas)->im_context,
NULL));
g_signal_connect (entry->item,
@@ -355,16 +356,16 @@ e_entry_init (GtkObject *object)
*/
entry->priv->changed_proxy_tag = g_signal_connect (entry->item,
"changed",
- G_CALLBACK (e_entry_proxy_changed),
+ G_CALLBACK (proxy_changed),
entry);
entry->priv->activate_proxy_tag = g_signal_connect (entry->item,
"activate",
- G_CALLBACK (e_entry_proxy_activate),
+ G_CALLBACK (proxy_activate),
entry);
- entry->priv->popup_proxy_tag = g_signal_connect (entry->item,
- "popup",
- G_CALLBACK (e_entry_proxy_popup),
- entry);
+ entry->priv->populate_popup_proxy_tag = g_signal_connect (entry->item,
+ "populate_popup",
+ G_CALLBACK (proxy_populate_popup),
+ entry);
entry->priv->completion_delay = 1;
}
@@ -1214,14 +1215,14 @@ e_entry_class_init (GObjectClass *object_class)
e_marshal_NONE__NONE,
G_TYPE_NONE, 0);
- e_entry_signals[E_ENTRY_POPUP] =
- g_signal_new ("popup",
+ e_entry_signals[E_ENTRY_POPULATE_POPUP] =
+ g_signal_new ("populate_popup",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EEntryClass, popup),
+ G_STRUCT_OFFSET (EEntryClass, populate_popup),
NULL, NULL,
- e_marshal_NONE__POINTER_INT,
- G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_INT);
+ e_marshal_NONE__POINTER_INT_OBJECT,
+ G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_INT, GTK_TYPE_MENU);
e_entry_signals[E_ENTRY_COMPLETION_POPUP] =
g_signal_new ("completion_popup",
diff --git a/widgets/text/e-entry.h b/widgets/text/e-entry.h
index 8c1093638b..6e71364ee1 100644
--- a/widgets/text/e-entry.h
+++ b/widgets/text/e-entry.h
@@ -59,7 +59,7 @@ struct _EEntryClass {
void (* changed) (EEntry *entry);
void (* activate) (EEntry *entry);
- void (* popup) (EEntry *entry, GdkEventButton *ev, gint pos);
+ void (* populate_popup) (EEntry *entry, GdkEventButton *ev, gint pos, GtkMenu *menu);
void (* completion_popup) (EEntry *entry, gint visible);
};
diff --git a/widgets/text/e-text.c b/widgets/text/e-text.c
index 53fa8eb1de..15d32eefbd 100644
--- a/widgets/text/e-text.c
+++ b/widgets/text/e-text.c
@@ -43,11 +43,17 @@
#include <string.h>
#include <glib-object.h>
#include <gdk/gdkx.h> /* for BlackPixel */
-#include <gtk/gtkinvisible.h>
+#include <gtk/gtkclipboard.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkselection.h>
+#include <gtk/gtkstock.h>
#include <gtk/gtkwindow.h>
#include <gtk/gtktypebuiltins.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkimagemenuitem.h>
+#include <gtk/gtkimmulticontext.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkseparatormenuitem.h>
#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
#include <libgnome/gnome-i18n.h>
#include "gal/util/e-util.h"
@@ -69,7 +75,7 @@ enum {
E_TEXT_CHANGED,
E_TEXT_ACTIVATE,
E_TEXT_KEYPRESS,
- E_TEXT_POPUP,
+ E_TEXT_POPULATE_POPUP,
E_TEXT_STYLE_SET,
E_TEXT_LAST_SIGNAL
};
@@ -110,51 +116,59 @@ enum {
PROP_ALLOW_NEWLINES,
PROP_DRAW_BACKGROUND,
PROP_DRAW_BUTTON,
- PROP_CURSOR_POS
+ PROP_CURSOR_POS,
+ PROP_IM_CONTEXT
};
-
-enum {
- E_SELECTION_PRIMARY,
- E_SELECTION_CLIPBOARD
-};
-enum _TargetInfo {
- TARGET_UTF8_STRING,
- TARGET_UTF8,
- TARGET_COMPOUND_TEXT,
- TARGET_STRING,
- TARGET_TEXT
-};
-
-
static void e_text_command(ETextEventProcessor *tep, ETextEventProcessorCommand *command, gpointer data);
-static void e_text_get_selection(EText *text, GdkAtom selection, guint32 time);
-static void e_text_supply_selection (EText *text, guint time, GdkAtom selection, guchar *data, gint length);
-
static void e_text_text_model_changed(ETextModel *model, EText *text);
static void e_text_text_model_reposition (ETextModel *model, ETextModelReposFn fn, gpointer repos_data, gpointer data);
static void _get_tep(EText *text);
-static GtkWidget *e_text_get_invisible(EText *text);
-static void _selection_clear_event (GtkInvisible *invisible,
- GdkEventSelection *event,
- EText *text);
-static void _selection_get (GtkInvisible *invisible,
- GtkSelectionData *selection_data,
- guint info,
- guint time_stamp,
- EText *text);
-static void _selection_received (GtkInvisible *invisible,
- GtkSelectionData *selection_data,
- guint time,
- EText *text);
-
static void calc_height (EText *text);
static gboolean show_pango_rectangle (EText *text, PangoRectangle rect);
+static void e_text_do_popup (EText *text, GdkEventButton *button, int position);
+
+static void e_text_update_primary_selection (EText *text);
+static void e_text_delete_selection(EText *text);
+static void e_text_paste (EText *text, GdkAtom selection);
+static void e_text_insert(EText *text, const char *string, int value);
+
+/* GtkEditable Methods */
+static void e_text_editable_do_insert_text (GtkEditable *editable,
+ const gchar *text,
+ gint length,
+ gint *position);
+static void e_text_editable_do_delete_text (GtkEditable *editable,
+ gint start_pos,
+ gint end_pos);
+static gchar* e_text_editable_get_chars (GtkEditable *editable,
+ gint start_pos,
+ gint end_pos);
+static void e_text_editable_set_selection_bounds (GtkEditable *editable,
+ gint start_pos,
+ gint end_pos);
+static gboolean e_text_editable_get_selection_bounds (GtkEditable *editable,
+ gint *start_pos,
+ gint *end_pos);
+static void e_text_editable_set_position (GtkEditable *editable,
+ gint position);
+static gint e_text_editable_get_position (GtkEditable *editable);
+
+/* IM Context Callbacks */
+static void e_text_commit_cb (GtkIMContext *context,
+ const gchar *str,
+ EText *text);
+static gboolean e_text_retrieve_surrounding_cb (GtkIMContext *context,
+ EText *text);
+static gboolean e_text_delete_surrounding_cb (GtkIMContext *context,
+ gint offset,
+ gint n_chars,
+ EText *text);
static GnomeCanvasItemClass *parent_class;
static GdkAtom clipboard_atom = GDK_NONE;
@@ -212,16 +226,6 @@ e_text_dispose (GObject *object)
g_object_unref (text->tep);
text->tep = NULL;
- if (text->invisible)
- gtk_widget_destroy (text->invisible);
- text->invisible = NULL;
-
- g_free (text->primary_selection);
- text->primary_selection = NULL;
-
- g_free (text->clipboard_selection);
- text->clipboard_selection = NULL;
-
g_free (text->revert);
text->revert = NULL;
@@ -260,6 +264,23 @@ e_text_dispose (GObject *object)
text->layout = NULL;
}
+ if (text->im_context) {
+ g_signal_handlers_disconnect_matched (text->im_context,
+ G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL,
+ e_text_commit_cb, text);
+ g_signal_handlers_disconnect_matched (text->im_context,
+ G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL,
+ e_text_retrieve_surrounding_cb, text);
+ g_signal_handlers_disconnect_matched (text->im_context,
+ G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL,
+ e_text_delete_surrounding_cb, text);
+ g_object_unref (text->im_context);
+ text->im_context = NULL;
+ }
+
if (G_OBJECT_CLASS (parent_class)->dispose)
(* G_OBJECT_CLASS (parent_class)->dispose) (object);
}
@@ -874,6 +895,17 @@ e_text_set_property (GObject *object,
e_text_command (text->tep, &command, text);
break;
}
+
+ case PROP_IM_CONTEXT:
+ if (text->im_context)
+ g_object_unref (text->im_context);
+
+ text->im_context = g_value_get_object (value);
+ if (text->im_context)
+ g_object_ref (text->im_context);
+
+ text->need_im_reset = FALSE;
+ break;
default:
return;
@@ -1034,6 +1066,10 @@ e_text_get_property (GObject *object,
case PROP_CURSOR_POS:
g_value_set_int (value, text->selection_start);
break;
+
+ case PROP_IM_CONTEXT:
+ g_value_set_object (value, text->im_context);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -2061,9 +2097,31 @@ e_text_event (GnomeCanvasItem *item, GdkEvent *event)
GdkEventFocus *focus_event;
focus_event = (GdkEventFocus *) event;
if (focus_event->in) {
+ if (text->im_context) {
+ g_signal_connect (text->im_context, "commit",
+ G_CALLBACK (e_text_commit_cb), text);
+ g_signal_connect (text->im_context, "retrieve_surrounding",
+ G_CALLBACK (e_text_retrieve_surrounding_cb), text);
+ g_signal_connect (text->im_context, "delete_surrounding",
+ G_CALLBACK (e_text_delete_surrounding_cb), text);
+ }
start_editing (text);
text->show_cursor = FALSE; /* so we'll redraw and the cursor will be shown */
} else {
+ if (text->im_context) {
+ g_signal_handlers_disconnect_matched (text->im_context,
+ G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL,
+ e_text_commit_cb, text);
+ g_signal_handlers_disconnect_matched (text->im_context,
+ G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL,
+ e_text_retrieve_surrounding_cb, text);
+ g_signal_handlers_disconnect_matched (text->im_context,
+ G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL,
+ e_text_delete_surrounding_cb, text);
+ }
e_text_stop_editing (text);
if (text->timeout_id) {
g_source_remove(text->timeout_id);
@@ -2084,9 +2142,15 @@ e_text_event (GnomeCanvasItem *item, GdkEvent *event)
case GDK_KEY_PRESS: /* Fall Through */
case GDK_KEY_RELEASE:
if (text->editing) {
- GdkEventKey key = event->key;
+ GdkEventKey key;
gint ret;
+ if (text->im_context && gtk_im_context_filter_keypress (text->im_context, (GdkEventKey*)event)) {
+ text->need_im_reset = TRUE;
+ return 1;
+ }
+
+ key = event->key;
e_tep_event.key.time = key.time;
e_tep_event.key.state = key.state;
e_tep_event.key.keyval = key.keyval;
@@ -2156,12 +2220,9 @@ e_text_event (GnomeCanvasItem *item, GdkEvent *event)
/* We follow convention and emit popup events on right-clicks. */
if (event->type == GDK_BUTTON_PRESS && event->button.button == 3) {
- g_signal_emit (text,
- e_text_signals[E_TEXT_POPUP], 0,
- &(event->button),
- get_position_from_xy (text, event->button.x, event->button.y));
-
- break;
+ e_text_do_popup (text, &(event->button),
+ get_position_from_xy (text, event->button.x, event->button.y));
+ return TRUE;
}
/* Create our own double and triple click events,
@@ -2262,6 +2323,268 @@ e_text_event (GnomeCanvasItem *item, GdkEvent *event)
return 0;
}
+void
+e_text_copy_clipboard (EText *text)
+{
+ gint selection_start_pos;
+ gint selection_end_pos;
+ char *str;
+
+ selection_start_pos = MIN (text->selection_start, text->selection_end);
+ selection_end_pos = MAX (text->selection_start, text->selection_end);
+
+ str = g_strndup (text->text + selection_start_pos,
+ selection_end_pos - selection_start_pos);
+
+ gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas),
+ GDK_SELECTION_CLIPBOARD),
+ str, -1);
+ g_free (str);
+}
+
+void
+e_text_delete_selection(EText *text)
+{
+ int sel_start, sel_end;
+
+ sel_start = MIN(text->selection_start, text->selection_end);
+ sel_end = MAX(text->selection_start, text->selection_end);
+
+ if (sel_start != sel_end)
+ e_text_model_delete(text->model, sel_start, sel_end - sel_start);
+}
+
+void
+e_text_cut_clipboard (EText *text)
+{
+ e_text_copy_clipboard (text);
+ e_text_delete_selection (text);
+}
+
+void
+e_text_paste_clipboard (EText *text)
+{
+ ETextEventProcessorCommand command;
+
+ command.action = E_TEP_PASTE;
+ command.position = E_TEP_SELECTION;
+ command.string = "";
+ command.value = 0;
+ e_text_command(text->tep, &command, text);
+}
+
+void
+e_text_select_all (EText *text)
+{
+ ETextEventProcessorCommand command;
+
+ command.action = E_TEP_SELECT;
+ command.position = E_TEP_SELECT_ALL;
+ command.string = "";
+ command.value = 0;
+ e_text_command(text->tep, &command, text);
+}
+
+
+static void
+primary_get_cb (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ guint info,
+ gpointer data)
+{
+ EText *text = E_TEXT (data);
+ int sel_start, sel_end;
+
+ sel_start = MIN(text->selection_start, text->selection_end);
+ sel_end = MAX(text->selection_start, text->selection_end);
+
+ if (sel_start != sel_end) {
+ gchar *str = g_strndup (text->text + sel_start,
+ sel_end - sel_start);
+ gtk_selection_data_set_text (selection_data, str, -1);
+ g_free (str);
+ }
+}
+
+static void
+primary_clear_cb (GtkClipboard *clipboard,
+ gpointer data)
+{
+ EText *text = E_TEXT (data);
+
+#if notyet
+ /* XXX */
+ gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos);
+#endif
+}
+
+static void
+e_text_update_primary_selection (EText *text)
+{
+ static const GtkTargetEntry targets[] = {
+ { "UTF8_STRING", 0, 0 },
+ { "UTF-8", 0, 0 },
+ { "STRING", 0, 0 },
+ { "TEXT", 0, 0 },
+ { "COMPOUND_TEXT", 0, 0 }
+ };
+ GtkClipboard *clipboard;
+
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas), GDK_SELECTION_PRIMARY);
+
+ if (text->selection_start != text->selection_end) {
+ if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
+ primary_get_cb, primary_clear_cb, G_OBJECT (text)))
+ primary_clear_cb (clipboard, text);
+ }
+ else {
+ if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (text))
+ gtk_clipboard_clear (clipboard);
+ }
+}
+
+static void
+paste_received (GtkClipboard *clipboard,
+ const gchar *text,
+ gpointer data)
+{
+ EText *etext = E_TEXT (data);
+
+ if (text) {
+ if (etext->selection_end != etext->selection_start)
+ e_text_delete_selection (etext);
+
+ e_text_insert (etext, text, strlen (text));
+ }
+
+ g_object_unref (etext);
+}
+
+static void
+e_text_paste (EText *text, GdkAtom selection)
+{
+ g_object_ref (text);
+ gtk_clipboard_request_text (gtk_widget_get_clipboard (GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas),
+ selection),
+ paste_received, text);
+}
+
+typedef struct {
+ EText *text;
+ GdkEventButton *button;
+ int position;
+} PopupClosure;
+
+static void
+popup_menu_detach (GtkWidget *attach_widget,
+ GtkMenu *menu)
+{
+}
+
+static void
+popup_targets_received (GtkClipboard *clipboard,
+ GtkSelectionData *data,
+ gpointer user_data)
+{
+ PopupClosure *closure = user_data;
+ EText *text = closure->text;
+ GdkEventButton *button = closure->button;
+ int position = closure->position;
+ GtkWidget *popup_menu = gtk_menu_new ();
+ GtkWidget *menuitem, *submenu;
+
+ g_free (closure);
+
+ gtk_menu_attach_to_widget (GTK_MENU (popup_menu),
+ GTK_WIDGET(GNOME_CANVAS_ITEM (text)->canvas),
+ popup_menu_detach);
+
+ /* cut menu item */
+ menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_CUT, NULL);
+ gtk_widget_show (menuitem);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menuitem);
+ g_signal_connect_swapped (menuitem, "activate",
+ G_CALLBACK (e_text_cut_clipboard), text);
+ gtk_widget_set_sensitive (menuitem, text->selection_start != text->selection_end);
+
+ /* copy menu item */
+ menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_COPY, NULL);
+ gtk_widget_show (menuitem);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menuitem);
+ g_signal_connect_swapped (menuitem, "activate",
+ G_CALLBACK (e_text_copy_clipboard), text);
+ gtk_widget_set_sensitive (menuitem, text->selection_start != text->selection_end);
+
+ /* paste menu item */
+ menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PASTE, NULL);
+ gtk_widget_show (menuitem);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menuitem);
+ g_signal_connect_swapped (menuitem, "activate",
+ G_CALLBACK (e_text_paste_clipboard), text);
+ gtk_widget_set_sensitive (menuitem, gtk_selection_data_targets_include_text (data));
+
+ menuitem = gtk_menu_item_new_with_label (_("Select All"));
+ gtk_widget_show (menuitem);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menuitem);
+ g_signal_connect_swapped (menuitem, "activate",
+ G_CALLBACK (e_text_select_all), text);
+ gtk_widget_set_sensitive (menuitem, strlen (text->text) > 0);
+
+ menuitem = gtk_separator_menu_item_new ();
+ gtk_widget_show (menuitem);
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menuitem);
+
+ if (text->im_context && GTK_IS_IM_MULTICONTEXT (text->im_context)) {
+ menuitem = gtk_menu_item_new_with_label (_("Input Methods"));
+ gtk_widget_show (menuitem);
+ submenu = gtk_menu_new ();
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), menuitem);
+
+ gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text->im_context),
+ GTK_MENU_SHELL (submenu));
+ }
+
+ g_signal_emit (text,
+ e_text_signals[E_TEXT_POPULATE_POPUP],
+ 0,
+ button, position,
+ popup_menu);
+
+ gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL,
+ NULL, NULL,
+ button->button, GDK_CURRENT_TIME);
+
+ g_object_unref (text);
+}
+
+static void
+e_text_do_popup (EText *text, GdkEventButton *button, int position)
+{
+ PopupClosure *closure = g_new (PopupClosure, 1);
+
+ closure->text = text;
+ g_object_ref (closure->text);
+ closure->button = button;
+ closure->position = position;
+
+ gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas),
+ GDK_SELECTION_CLIPBOARD),
+ gdk_atom_intern ("TARGETS", FALSE),
+ popup_targets_received,
+ closure);
+}
+
+static void
+e_text_reset_im_context (EText *text)
+{
+ if (text->need_im_reset) {
+ text->need_im_reset = 0;
+ gtk_im_context_reset (text->im_context);
+ }
+}
+
/* fixme: */
static int
@@ -2532,27 +2855,11 @@ _get_position(EText *text, ETextEventProcessorCommand *command)
}
static void
-_delete_selection(EText *text)
-{
- if ( text->selection_start < text->selection_end ) {
- e_text_model_delete(text->model, text->selection_start, text->selection_end - text->selection_start);
-#if 0
- text->selection_end = text->selection_start;
-#endif
- } else {
- e_text_model_delete(text->model, text->selection_end, text->selection_start - text->selection_end);
-#if 0
- text->selection_start = text->selection_end;
-#endif
- }
-}
-
-static void
-_insert(EText *text, char *string, int value)
+e_text_insert(EText *text, const char *string, int value)
{
if (value > 0) {
if (!text->allow_newlines) {
- char *i;
+ const char *i;
for (i = string; *i; i++) {
if (*i == '\n') {
char *new_string = g_malloc (strlen (string) + 1);
@@ -2643,17 +2950,7 @@ e_text_command(ETextEventProcessor *tep, ETextEventProcessorCommand *command, gp
text->selection_start = e_text_model_validate_position (text->model, text->selection_start); /* paranoia */
text->selection_end = _get_position(text, command);
- sel_start = MIN(text->selection_start, text->selection_end);
- sel_end = MAX(text->selection_start, text->selection_end);
-
- sel_start = e_text_model_validate_position (text->model, sel_start);
-
- if (sel_start != sel_end) {
- e_text_supply_selection (text, command->time, GDK_SELECTION_PRIMARY,
- (guchar *) text->text + sel_start, sel_end - sel_start);
- } else if (text->timer) {
- g_timer_reset(text->timer);
- }
+ e_text_update_primary_selection (text);
use_start = FALSE;
@@ -2662,7 +2959,7 @@ e_text_command(ETextEventProcessor *tep, ETextEventProcessorCommand *command, gp
if (text->selection_end == text->selection_start) {
text->selection_end = _get_position(text, command);
}
- _delete_selection(text);
+ e_text_delete_selection(text);
if (text->timer) {
g_timer_reset(text->timer);
}
@@ -2673,33 +2970,29 @@ e_text_command(ETextEventProcessor *tep, ETextEventProcessorCommand *command, gp
case E_TEP_INSERT:
if (text->selection_end != text->selection_start) {
- _delete_selection(text);
+ e_text_delete_selection(text);
}
- _insert(text, command->string, command->value);
+ e_text_insert(text, command->string, command->value);
if (text->timer) {
g_timer_reset(text->timer);
}
break;
case E_TEP_COPY:
- sel_start = MIN(text->selection_start, text->selection_end);
- sel_end = MAX(text->selection_start, text->selection_end);
- if (sel_start != sel_end) {
- e_text_supply_selection (text, command->time, clipboard_atom,
- (guchar *) text->text + sel_start, sel_end - sel_start);
- }
+ e_text_copy_clipboard (text);
+
if (text->timer) {
g_timer_reset(text->timer);
}
scroll = FALSE;
break;
case E_TEP_PASTE:
- e_text_get_selection (text, clipboard_atom, command->time);
+ e_text_paste (text, GDK_NONE);
if (text->timer) {
g_timer_reset(text->timer);
}
break;
case E_TEP_GET_SELECTION:
- e_text_get_selection (text, GDK_SELECTION_PRIMARY, command->time);
+ e_text_paste (text, GDK_SELECTION_PRIMARY);
break;
case E_TEP_ACTIVATE:
g_signal_emit (text, e_text_signals[E_TEXT_ACTIVATE], 0);
@@ -2791,336 +3084,6 @@ e_text_command(ETextEventProcessor *tep, ETextEventProcessorCommand *command, gp
gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(text));
}
-static void
-_invisible_destroy (gpointer data, GObject *where_object_was)
-{
- EText *text = E_TEXT (data);
- text->invisible = NULL;
-}
-
-static GtkWidget *
-e_text_get_invisible(EText *text)
-{
- GtkWidget *invisible;
- if (text->invisible) {
- invisible = text->invisible;
- } else {
- static const GtkTargetEntry targets[] = {
- { "UTF8_STRING", 0, TARGET_UTF8_STRING },
- { "UTF-8", 0, TARGET_UTF8 },
- { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
- { "STRING", 0, TARGET_STRING },
- { "TEXT", 0, TARGET_TEXT }
- };
- static const gint n_targets = sizeof(targets) / sizeof(targets[0]);
-
- invisible = gtk_invisible_new();
- text->invisible = invisible;
-
- gtk_selection_add_targets (invisible,
- GDK_SELECTION_PRIMARY,
- targets, n_targets);
- gtk_selection_add_targets (invisible,
- clipboard_atom,
- targets, n_targets);
-
- g_signal_connect (invisible, "selection_get",
- G_CALLBACK (_selection_get),
- text);
- g_signal_connect (invisible, "selection_clear_event",
- G_CALLBACK (_selection_clear_event),
- text);
- g_signal_connect (invisible, "selection_received",
- G_CALLBACK (_selection_received),
- text);
-
- g_object_weak_ref (G_OBJECT (invisible),
- _invisible_destroy, text);
- }
- return invisible;
-}
-
-static void
-_selection_clear_event (GtkInvisible *invisible,
- GdkEventSelection *event,
- EText *text)
-{
- if (event->selection == GDK_SELECTION_PRIMARY) {
- g_free (text->primary_selection);
- text->primary_selection = NULL;
- text->primary_length = 0;
-
- text->has_selection = FALSE;
- text->needs_redraw = 1;
- gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(text));
-
- } else if (event->selection == clipboard_atom) {
- g_free (text->clipboard_selection);
- text->clipboard_selection = NULL;
- text->clipboard_length = 0;
- }
-}
-
-static void
-_selection_get (GtkInvisible *invisible,
- GtkSelectionData *selection_data,
- guint info,
- guint time_stamp,
- EText *text)
-{
- char *selection_string;
- int selection_length;
- if (selection_data->selection == GDK_SELECTION_PRIMARY) {
- selection_string = text->primary_selection;
- selection_length = text->primary_length;
- } else /* CLIPBOARD */ {
- selection_string = text->clipboard_selection;
- selection_length = text->clipboard_length;
- }
-
- if (selection_string != NULL) {
- if (info == TARGET_UTF8_STRING) {
- gtk_selection_data_set (selection_data,
- gdk_atom_intern ("UTF8_STRING", FALSE), 8,
- (const guchar *) selection_string,
- selection_length);
- } else if (info == TARGET_UTF8) {
- gtk_selection_data_set (selection_data,
- gdk_atom_intern ("UTF-8", FALSE), 8,
- (const guchar *) selection_string,
- selection_length);
- } else if (info == TARGET_STRING || info == TARGET_TEXT || info == TARGET_COMPOUND_TEXT) {
- gchar *localized_string;
-
- localized_string = e_utf8_to_gtk_string (GTK_WIDGET (GNOME_CANVAS_ITEM(text)->canvas),
- selection_string);
-
- if (info == TARGET_STRING) {
- gtk_selection_data_set (selection_data,
- GDK_SELECTION_TYPE_STRING, 8,
- (const guchar *) localized_string,
- strlen (localized_string));
- } else {
- guchar *text;
- GdkAtom encoding;
- gint format;
- gint new_length;
-
- gdk_string_to_compound_text (localized_string,
- &encoding, &format,
- &text, &new_length);
-
- gtk_selection_data_set (selection_data,
- encoding, format,
- text, new_length);
- gdk_free_compound_text (text);
- }
- g_free (localized_string);
- }
- }
-}
-
-typedef struct {
- guint32 time;
- GdkAtom selection;
-} SelectionAndTime;
-
-static const char *formats[] = {"UTF8_STRING", "UTF-8", "STRING"};
-#define E_STRING_ATOM 2
-static const int format_count = sizeof (formats) / sizeof (formats[0]);
-static GdkAtom atoms[sizeof (formats) / sizeof (formats[0])];
-static int initialized = FALSE;
-
-static inline void
-init_atoms (void)
-{
- int type;
- if (!initialized) {
- for (type = 0; type < format_count; type++)
- atoms[type] = gdk_atom_intern (formats[type], FALSE);
- initialized = TRUE;
- }
-}
-
-static void
-e_text_request_paste (EText *text)
-{
- GdkAtom format_atom;
- GtkWidget *invisible;
- int type = text->last_type_request;
-
- init_atoms ();
-
- format_atom = GDK_NONE;
-
- while (format_atom == GDK_NONE) {
- type ++;
-
- if (type >= format_count) {
- if (text->queued_requests) {
- guint32 *new_time = text->queued_requests->data;
- text->queued_requests = g_list_remove_link (text->queued_requests, text->queued_requests);
- text->last_time_request = *new_time;
- g_free (new_time);
-
- type = -1;
- continue;
- } else {
- text->last_type_request = -1;
- d(g_print ("Setting last_type_request to %d at line %d\n", text->last_type_request, __LINE__));
- text->last_time_request = 0;
- return;
- }
- }
-
- format_atom = atoms [type];
- }
-
- /* This must come before the gtk_selection_convert because sometimes _selection_received is called reentrantly. */
-
- text->last_type_request = type;
- d(g_print ("Setting last_type_request to %d at line %d\n", text->last_type_request, __LINE__));
-
- /* And request the format target for the required selection */
- invisible = e_text_get_invisible(text);
- gtk_selection_convert(invisible,
- text->last_selection_request,
- format_atom,
- text->last_time_request);
-
- return;
-}
-
-static void
-_selection_received (GtkInvisible *invisible,
- GtkSelectionData *selection_data,
- guint time,
- EText *text)
-{
- init_atoms ();
- if (selection_data->length < 0) {
- d(g_print ("Calling e_text_request_paste at line %d\n", __LINE__));
- e_text_request_paste (text);
- return;
- } else if (selection_data->type == atoms[E_STRING_ATOM]) {
- ETextEventProcessorCommand command;
- char *string;
-
- string = e_utf8_from_gtk_string_sized (GTK_WIDGET (GNOME_CANVAS_ITEM(text)->canvas),
- selection_data->data,
- selection_data->length);
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.string = string;
- command.value = strlen (string);
- command.time = time;
- e_text_command(text->tep, &command, text);
- g_free (string);
- } else {
- ETextEventProcessorCommand command;
- command.action = E_TEP_INSERT;
- command.position = E_TEP_SELECTION;
- command.string = selection_data->data;
- command.value = selection_data->length;
- command.time = time;
- e_text_command(text->tep, &command, text);
- }
-
- text->last_type_request = -1;
- d(g_print ("Setting last_type_request to %d at line %d\n", text->last_type_request, __LINE__));
- if (text->queued_requests) {
- SelectionAndTime *new_request = text->queued_requests->data;
- text->queued_requests = g_list_remove_link (text->queued_requests, text->queued_requests);
- text->last_time_request = new_request->time;
- text->last_selection_request = new_request->selection;
- g_free (new_request);
- d(g_print ("Calling e_text_request_paste at line %d\n", __LINE__));
- e_text_request_paste (text);
- }
-}
-
-static void
-e_text_get_selection(EText *text, GdkAtom selection, guint32 time)
-{
- if (text->last_type_request == -1) {
- text->last_time_request = time;
- text->last_selection_request = selection;
- d(g_print ("Calling e_text_request_paste at line %d\n", __LINE__));
- e_text_request_paste (text);
- } else {
- SelectionAndTime *new_request = g_new (SelectionAndTime, 1);
- new_request->time = time;
- new_request->selection = selection;
- /* FIXME: Queue the selection request type as well. */
- text->queued_requests = g_list_append (text->queued_requests, new_request);
- }
-}
-
-static void
-e_text_supply_selection (EText *text, guint time, GdkAtom selection, guchar *data, gint length)
-{
- gboolean successful;
- GtkWidget *invisible;
-
- invisible = e_text_get_invisible(text);
-
- if (selection == GDK_SELECTION_PRIMARY ) {
- g_free (text->primary_selection);
- text->primary_selection = g_strndup(data, length);
- text->primary_length = length;
- } else if (selection == clipboard_atom) {
- g_free (text->clipboard_selection);
- text->clipboard_selection = g_strndup(data, length);
- text->clipboard_length = length;
- }
-
- successful = gtk_selection_owner_set (invisible,
- selection,
- time);
-
- if (selection == GDK_SELECTION_PRIMARY)
- text->has_selection = successful;
-}
-
-#if 0
-static void
-e_text_real_copy_clipboard (EText *text)
-{
- guint32 time;
- gint selection_start_pos;
- gint selection_end_pos;
-
- g_return_if_fail (text != NULL);
- g_return_if_fail (E_IS_TEXT (text));
-
- time = gtk_text_get_event_time (text);
- selection_start_pos = MIN (text->selection_start, text->selection_end);
- selection_end_pos = MAX (text->selection_start, text->selection_end);
-
- if (selection_start_pos != selection_end_pos)
- {
- if (gtk_selection_owner_set (GTK_WIDGET (text->canvas),
- clipboard_atom,
- time))
- text->clipboard_text = "";
- }
-}
-
-static void
-e_text_real_paste_clipboard (EText *text)
-{
- guint32 time;
-
- g_return_if_fail (text != NULL);
- g_return_if_fail (E_IS_TEXT (text));
-
- time = e_text_get_event_time (text);
- if (text->editable)
- gtk_selection_convert (GTK_WIDGET(text->widget),
- clipboard_atom,
- gdk_atom_intern ("COMPOUND_TEXT", FALSE), time);
-}
-#endif
/* Class initialization function for the text item */
static void
@@ -3176,14 +3139,14 @@ e_text_class_init (ETextClass *klass)
e_marshal_NONE__INT_INT,
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
- e_text_signals[E_TEXT_POPUP] =
- g_signal_new ("popup",
+ e_text_signals[E_TEXT_POPULATE_POPUP] =
+ g_signal_new ("populate_popup",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ETextClass, popup),
+ G_STRUCT_OFFSET (ETextClass, populate_popup),
NULL, NULL,
- e_marshal_NONE__POINTER_INT,
- G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_INT);
+ e_marshal_NONE__POINTER_INT_OBJECT,
+ G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_INT, GTK_TYPE_MENU);
g_object_class_install_property (gobject_class, PROP_MODEL,
g_param_spec_object ("model",
@@ -3413,6 +3376,13 @@ e_text_class_init (ETextClass *klass)
0, G_MAXINT, 0,
G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, PROP_IM_CONTEXT,
+ g_param_spec_object ("im_context",
+ _( "IM Context" ),
+ _( "IM Context" ),
+ GTK_TYPE_IM_CONTEXT,
+ G_PARAM_READWRITE));
+
if (!clipboard_atom)
clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
}
@@ -3474,12 +3444,6 @@ e_text_init (EText *text)
text->has_selection = FALSE;
- text->invisible = NULL;
- text->primary_selection = NULL;
- text->primary_length = 0;
- text->clipboard_selection = NULL;
- text->clipboard_length = 0;
-
text->pointer_in = FALSE;
text->default_cursor_shown = TRUE;
text->line_wrap = FALSE;
@@ -3505,6 +3469,9 @@ e_text_init (EText *text)
text->last_time_request = 0;
text->queued_requests = NULL;
+ text->im_context = NULL;
+ text->need_im_reset = FALSE;
+
e_canvas_item_set_reflow_callback(GNOME_CANVAS_ITEM(text), e_text_reflow);
}
@@ -3523,3 +3490,44 @@ E_MAKE_TYPE (e_text,
e_text_class_init,
e_text_init,
PARENT_TYPE)
+
+
+/* IM Context Callbacks */
+static void
+e_text_commit_cb (GtkIMContext *context,
+ const gchar *str,
+ EText *text)
+{
+ if (text->selection_end != text->selection_start)
+ e_text_delete_selection (text);
+ e_text_insert (text, str, strlen (str));
+}
+
+static gboolean
+e_text_retrieve_surrounding_cb (GtkIMContext *context,
+ EText *text)
+{
+ printf ("e_text_retrieve_surrounding_cb\n");
+ gtk_im_context_set_surrounding (context,
+ text->text,
+ strlen (text->text),
+ g_utf8_offset_to_pointer (text->text, text->selection_start) - text->text);
+
+ return TRUE;
+}
+
+static gboolean
+e_text_delete_surrounding_cb (GtkIMContext *context,
+ gint offset,
+ gint n_chars,
+ EText *text)
+{
+ printf ("e_text_delete_surrounding_cb\n");
+#if 0
+ gtk_editable_delete_text (GTK_EDITABLE (entry),
+ entry->current_pos + offset,
+ entry->current_pos + offset + n_chars);
+#endif
+
+ return TRUE;
+}
diff --git a/widgets/text/e-text.h b/widgets/text/e-text.h
index 6a965a5d92..bff45111f9 100644
--- a/widgets/text/e-text.h
+++ b/widgets/text/e-text.h
@@ -37,7 +37,7 @@
#ifndef E_TEXT_H
#define E_TEXT_H
-#include <gtk/gtkobject.h>
+#include <gtk/gtkmenu.h>
#include <gal/widgets/e-font.h>
#include <gal/util/e-text-event-processor.h>
@@ -162,12 +162,7 @@ struct _EText {
ETextEventProcessor *tep; /* Text Event Processor */
gint tep_command_id;
- GtkWidget *invisible; /* For selection handling */
gboolean has_selection; /* TRUE if we have the selection */
- gchar *primary_selection; /* Primary selection text */
- gint primary_length; /* Primary selection text length */
- gchar *clipboard_selection; /* Clipboard selection text */
- gint clipboard_length; /* Clipboard selection text length*/
guint clip : 1; /* Use clip rectangle? */
guint fill_clip_rectangle : 1; /* Fill the clipping rectangle. */
@@ -216,16 +211,19 @@ struct _EText {
guint32 last_time_request; /* The time of the last selection request. */
GdkAtom last_selection_request; /* The time of the last selection request. */
GList *queued_requests; /* Queued selection requests. */
+
+ GtkIMContext *im_context;
+ gboolean need_im_reset;
};
struct _ETextClass {
GnomeCanvasItemClass parent_class;
- void (* changed) (EText *text);
- void (* activate) (EText *text);
- void (* keypress) (EText *text, guint keyval, guint state);
- void (* popup) (EText *text, GdkEventButton *ev, gint pos);
- void (* style_set) (EText *text, GtkStyle *previous_style);
+ void (* changed) (EText *text);
+ void (* activate) (EText *text);
+ void (* keypress) (EText *text, guint keyval, guint state);
+ void (* populate_popup) (EText *text, GdkEventButton *ev, gint pos, GtkMenu *menu);
+ void (* style_set) (EText *text, GtkStyle *previous_style);
};
@@ -234,6 +232,11 @@ GtkType e_text_get_type (void);
void e_text_cancel_editing (EText *text);
void e_text_stop_editing (EText *text);
+void e_text_delete_selection (EText *text);
+void e_text_cut_clipboard (EText *text);
+void e_text_paste_clipboard (EText *text);
+void e_text_select_all (EText *text);
+
G_END_DECLS
#endif