tags:

views:

281

answers:

1

I'm making a trivial text editor (as an exercise) in GTK using Glade, GtkBuilder, and C. I have an edit menu with Cut, Copy, and Paste as well as a GtkTextView for the text. GtkTextView automatically binds the cut/copy/paste sequences for itself (and even provides menu items if you right click). I want to connect the Cut, Copy, and Paste menu items in my menu bar to my text view so they will act as expected.

Note that this is a two-way connection. (1) When one of the Cut, Copy, or Paste GtkMenuItem's is activated, it tells the GtkTextView to do something. (2) When a selection is made or cleared in the GtkTextView, Cut and Copy are enabled or disabled respectively (see gedit as an example). Moreover, (3) whether or not Paste is enabled depends on the state of the clipboard.

How do I connect my Cut, Copy, and Paste menu items to the text view? Is there a way to do it in Glade, or will my C program need some extra code for this? Is there a streamlined way to do this, or do I need to implement all three behaviors stated in the above paragraph manually?

+1  A: 

You will need some extra C code, but not much. For this example I am assuming you're using GtkActions for your menu items, but if you're not the solution should be similar.

First make the callbacks for the cut, copy, and paste actions in Glade. When you connect the signals, pass some data structure containing at least pointers to the cut, copy, and paste actions, and the text view, as user data.

void
on_cut(GtkAction *action, SomeStruct *data)
{
    g_signal_emit_by_name(data->view, "cut-clipboard", NULL);
    gtk_action_set_sensitive(data->paste_action, TRUE);
}

void
on_copy(GtkAction *action, SomeStruct *data)
{
    g_signal_emit_by_name(data->view, "copy-clipboard", NULL);
    gtk_action_set_sensitive(data->paste_action, TRUE);
}

void
on_paste(GtkAction *action, SomeStruct *data)
{
    g_signal_emit_by_name(data->view, "paste-clipboard", NULL);
}

Next, connect to the notify::has-selection signal of your GtkTextBuffer:

void
on_has_selection_notify(GtkTextBuffer *buffer, GParamSpec *pspec, SomeStruct *data)
{
    gboolean has_selection = gtk_text_buffer_get_has_selection(buffer);
    gtk_action_set_sensitive(data->cut_action, has_selection);
    gtk_action_set_sensitive(data->copy_action, has_selection);
}

To determine the initial state of the paste action (in case there is text on the clipboard when you start the application) run the following code while you're constructing your interface:

gtk_action_set_sensitive(data->paste_action, 
    gtk_clipboard_wait_is_text_available(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)));

This assumes there's no way for the user to clear the clipboard manually (most programs don't let you do that.)

Caveat lector: the code as typed here is all untested.

ptomato
Thanks, this worked (I didn't know at first you could connect to a property via "notify::property-name"). However, I think I found a better way to handle the clipboard: connect to the "owner-change" signal of the clipboard. This signal seems to be emitted every time the clipboard is updated. On my system, this worked for all the edge cases I could think of.
Joey Adams