More info on selection handling problem



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(&current_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]