More info on selection handling problem
- From: Roy Wood <roy wood filogix com>
- To: <gtk-devel-list gnome org>
- Subject: More info on selection handling problem
- Date: Mon, 11 Mar 2002 12:27:41 -0500
I posted this to the Anjuta-devel list, but thought I'd also post it here
in order to have the info archived somewhere in case someone else ever
runs into this problem, and to possibly generate intelligent comment from
someone smarter than myself.
-Roy
I had some time to play around on the weekend, and have more info on the
copy/paste bug.
I banged out the following sample code to demonstrate the crux of the
problem. The code creates a window with a toggle button that, when
activated, tries to supply the CLIPBOARD selection. As well, there's
another button that allows you to reparent the selection-supplying button
(it gets reparented into an hpane-- just like Anjuta is doing).
I've actually got it all working properly by doing the following:
- I initially create the hpane, the selection button, and the reparent
button, and pack them all into a vbox which is in turn added to the main
window
- The selection and reparent button are shown, but the hpane is left
hidden BUT REALIZED; thus to the user, it appears that there are just two
buttons in the vbox in the window
- When the user clicks the "Reparent" button, I move the buttons from the
vbox to the hpane and show the hpane; reparenting is done via
gtk_widget_reparent(), since it does NOT change the selection-supplying
buttons gdk window (which is a critical identifier as far as gtk/gdk
selection handling goes)
(Note-- to test that the CLIPBOARD is being supplied, just launch gedit
or something and paste away.)
So, if we could do the same kind of thing in Anjuta, copy paste would be
happy. The critical thing is to create the hpane and vpane for the
project and message panes and attach/realize them before the attempt to
gtk_widget_reparent() the notebook containing the Scintillas.
I started looking at the anjuta_gui.c and project_dbase.c files, and this
looks pretty reasonable to pull off. If anyone is familiar with the way
things are laid out, widget-wise, please save me some time spent groping
about and explain how things are set up. Any hints/warnings/gotchas are
also appreciated.
Oh-- and if you want to have this code break the same way Anjuta does,
just comment out the "gtk_widget_realize(hpane)" in main. Watch what
gets printed out for the selection_button->window pointer before and
after reparenting occurs.
-Roy
#include <gtk/gtk.h>
#include <time.h>
GdkAtom clipboard_atom = GDK_NONE;
int have_selection = FALSE;
int is_in_paned = FALSE;
GtkWidget *window = NULL;
GtkWidget *selection_button = NULL;
GtkWidget *reparent_button = NULL;
GtkWidget *vbox = NULL;
GtkWidget *hpane = NULL;
// This is where we reparent the buttons, toggling between having them in
the hpane and the vbox
void handle_reparent( GtkWidget *widget,
gint *have_selection )
{
if (is_in_paned)
{
// Move the buttons back to the vbox, then hide the hpane
gtk_widget_reparent (selection_button, vbox);
gtk_widget_reparent (reparent_button, vbox);
gtk_widget_hide (hpane);
// Note the gdk window reference of the button!
g_print("\nselection_button = 0x%X, window = 0x%X\n",(unsigned long)
selection_button,(unsigned long) (selection_button->window));
is_in_paned = FALSE;
}
else
{
// Move the buttons into the hpane and show it
gtk_widget_reparent (selection_button, hpane);
gtk_widget_reparent (reparent_button, hpane);
gtk_widget_show (hpane);
// Note the gdk window reference of the button!
g_print("\nselection_button = 0x%X, window = 0x%X\n",(unsigned long)
selection_button,(unsigned long) (selection_button->window));
is_in_paned = TRUE;
}
}
// Handle claiming/releasing the CLIPBOARD selection
void selection_toggled( GtkWidget *widget,
gint *have_selection )
{
// Note the gdk window reference of the button!
g_print("\nselection_button = 0x%X, window = 0x%X\n",(unsigned long)
selection_button,(unsigned long) (selection_button->window));
if (GTK_TOGGLE_BUTTON(widget)->active)
{
g_print("selection_toggled: claiming selection\n");
gtk_selection_owner_set(NULL,clipboard_atom,GDK_CURRENT_TIME);
*have_selection =
gtk_selection_owner_set(widget,clipboard_atom,GDK_CURRENT_TIME);
if (!*have_selection)
{
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
}
}
else
{
if (*have_selection)
{
if (gdk_selection_owner_get(clipboard_atom) == widget->window)
{
g_print("selection_toggled: releasing selection\n");
gtk_selection_owner_set (NULL, clipboard_atom,GDK_CURRENT_TIME);
*have_selection = FALSE;
}
}
}
}
// Handle losing the selection (happens when another app claims the
CLIPBOARD)
gint selection_clear( GtkWidget *widget,
GdkEventSelection *event,
gint *have_selection )
{
// Note the gdk window reference of the button!
g_print("\nselection_button = 0x%X, window = 0x%X\n",(unsigned long)
selection_button,(unsigned long) (selection_button->window));
*have_selection = FALSE;
g_print("selection_clear: selection cleared\n");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
return TRUE;
}
// Supply the date/time as the CLIPBOARD data when requested
void selection_handle( GtkWidget *widget,
GtkSelectionData *selection_data,
guint info,
guint time_stamp,
gpointer data )
{
gchar *timestr;
time_t current_time;
// Note the gdk window reference of the button!
g_print("\nselection_button = 0x%X, window = 0x%X\n",(unsigned long)
selection_button,(unsigned long) (selection_button->window));
g_print("selection_handle: supplying selection\n");
current_time = time(NULL);
timestr = asctime (localtime(¤t_time));
gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING, 8,
timestr, strlen(timestr));
}
int main( int argc,
char *argv )
{
gtk_init (&argc, &argv);
// We're going to supply the CLIPBOARD selection, so get a reference to
it
clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE);
// Create the top-level window
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Selection Test");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC
(gtk_exit), NULL);
// Contents of the main window is a vbox
vbox = gtk_vbox_new(TRUE, 5);
// Create the hpane
hpane = gtk_hpaned_new();
gtk_paned_set_handle_size(GTK_PANED(hpane),10);
gtk_paned_set_gutter_size(GTK_PANED(hpane),20);
// Create the selection button and wire it up
selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
gtk_selection_add_target(selection_button,clipboard_atom,GDK_SELECTION_TYP
E_STRING,1);
gtk_signal_connect (GTK_OBJECT(selection_button), "selection_get",
GTK_SIGNAL_FUNC(selection_handle), &have_selection);
gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
gtk_signal_connect (GTK_OBJECT(selection_button),
"selection_clear_event", GTK_SIGNAL_FUNC (selection_clear),
&have_selection);
// Create the reparent button and wire it up too
reparent_button = gtk_button_new_with_label ("Reparent");
gtk_signal_connect(GTK_OBJECT(reparent_button),"clicked",GTK_SIGNAL_FUNC(h
andle_reparent),NULL);
// Now add them all to the vbox-- hpane, as well as the buttons
gtk_box_pack_start(GTK_BOX(vbox), hpane, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), selection_button, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), reparent_button, TRUE, TRUE, 0);
// And add the vbox to the window
gtk_container_add (GTK_CONTAINER (window), vbox);
// Show what's appropriate (NOT the vbox at this point!)
gtk_widget_show (reparent_button);
gtk_widget_show (selection_button);
gtk_widget_show (vbox);
gtk_widget_show (window);
// Make sure the hpane is realized, even if it is not visible;
// If the hpane is not realized, then calls to gtk_widget_reparent()
will not work the
// way we want them to (i.e. to preserve the gdk window of our
selection-supplying widget)
gtk_widget_realize(hpane);
// For our edification, note the references to the selection-supplying
widget
g_print("\nselection_button = 0x%X, window = 0x%X\n",(unsigned long)
selection_button,(unsigned long) (selection_button->window));
gtk_main ();
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]