From f77c0fb15ec8ee8010564dff83838d892176607d Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 22 Mar 2006 16:11:48 +0000 Subject: [PATCH] send a GtkWidget** instead of a GtkNotebookPage* when doing tabs DnD, this 2006-03-22 Carlos Garnacho * gtk/gtknotebook.c: send a GtkWidget** instead of a GtkNotebookPage* when doing tabs DnD, this allows DnD interaction with other widgets, added some docs for this too. * tests/testnotebookdnd.c: add some code to test it. --- ChangeLog | 7 ++++ ChangeLog.pre-2-10 | 7 ++++ gtk/gtknotebook.c | 89 ++++++++++++++++++++++++++++------------- tests/testnotebookdnd.c | 72 ++++++++++++++++++++++++++++++++- 4 files changed, 145 insertions(+), 30 deletions(-) diff --git a/ChangeLog b/ChangeLog index 984b10911a..4d96cb40d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2006-03-22 Carlos Garnacho + + * gtk/gtknotebook.c: send a GtkWidget** instead of a GtkNotebookPage* + when doing tabs DnD, this allows DnD interaction with other widgets, + added some docs for this too. + * tests/testnotebookdnd.c: add some code to test it. + 2006-03-22 Matthias Clasen * gtk/gtk.symbols: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 984b10911a..4d96cb40d2 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,10 @@ +2006-03-22 Carlos Garnacho + + * gtk/gtknotebook.c: send a GtkWidget** instead of a GtkNotebookPage* + when doing tabs DnD, this allows DnD interaction with other widgets, + added some docs for this too. + * tests/testnotebookdnd.c: add some code to test it. + 2006-03-22 Matthias Clasen * gtk/gtk.symbols: diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index 9dd499b3d5..016d8eb6ec 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -40,7 +40,6 @@ #include "gtkalias.h" #include "gtkdnd.h" - #define ARROW_SIZE 12 #define ARROW_SPACING 0 #define SCROLL_DELAY_FACTOR 5 @@ -2847,33 +2846,36 @@ gtk_notebook_drag_drop (GtkWidget *widget, static void do_detach_tab (GtkNotebook *from, GtkNotebook *to, - GtkNotebookPage *page_info, + GtkWidget *child, gint x, gint y) { - GtkWidget *child, *tab_label, *menu_label; + GtkWidget *tab_label, *menu_label; gboolean tab_expand, tab_fill, reorderable, detachable; GList *element; guint tab_pack; gint page_num; - menu_label = tab_label = child = NULL; + menu_label = gtk_notebook_get_menu_label (from, child); - if (page_info->menu_label) - menu_label = g_object_ref (page_info->menu_label); + if (menu_label) + g_object_ref (menu_label); - if (page_info->tab_label) - tab_label = g_object_ref (page_info->tab_label); + tab_label = gtk_notebook_get_tab_label (from, child); + + if (tab_label) + g_object_ref (tab_label); - if (page_info->child) - child = g_object_ref (page_info->child); + g_object_ref (child); - /* preserve properties */ - tab_expand = page_info->expand; - tab_fill = page_info->fill; - tab_pack = page_info->pack; - reorderable = page_info->reorderable; - detachable = page_info->detachable; + gtk_container_child_get (GTK_CONTAINER (from), + child, + "tab-expand", &tab_expand, + "tab-fill", &tab_fill, + "tab-pack", &tab_pack, + "reorderable", &reorderable, + "detachable", &detachable, + NULL); gtk_container_remove (GTK_CONTAINER (from), child); @@ -2912,7 +2914,6 @@ gtk_notebook_drag_data_get (GtkWidget *widget, guint time) { GtkNotebook *dest_notebook, *notebook; - gint page_num; if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") && (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") || @@ -2920,15 +2921,14 @@ gtk_notebook_drag_data_get (GtkWidget *widget, return; notebook = GTK_NOTEBOOK (widget); - page_num = g_list_index (notebook->children, notebook->cur_page); if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB")) { gtk_selection_data_set (data, data->target, 8, - (void*) notebook->cur_page, - sizeof (GtkNotebookPage)); + (void*) ¬ebook->cur_page->child, + sizeof (gpointer)); } else { @@ -2944,7 +2944,7 @@ gtk_notebook_drag_data_get (GtkWidget *widget, window_creation_hook_data); if (dest_notebook) - do_detach_tab (notebook, dest_notebook, notebook->cur_page, 0, 0); + do_detach_tab (notebook, dest_notebook, notebook->cur_page->child, 0, 0); } } @@ -2959,7 +2959,7 @@ gtk_notebook_drag_data_received (GtkWidget *widget, { GtkNotebook *notebook; GtkWidget *source_widget; - GtkNotebookPage *page_info; + GtkWidget **child; notebook = GTK_NOTEBOOK (widget); source_widget = gtk_drag_get_source_widget (context); @@ -2967,13 +2967,13 @@ gtk_notebook_drag_data_received (GtkWidget *widget, if (source_widget && data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB")) { - page_info = (void*) data->data; + child = (void*) data->data; - do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, page_info, x, y); + do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child, x, y); gtk_drag_finish (context, TRUE, FALSE, time); } - - gtk_drag_finish (context, FALSE, FALSE, time); + else + gtk_drag_finish (context, FALSE, FALSE, time); } /* Private GtkContainer Methods : @@ -6920,10 +6920,43 @@ gtk_notebook_get_tab_detachable (GtkNotebook *notebook, * @child: a child #GtkWidget * @detachable: whether the tab is detachable or not * - * Sets whether the tab can be detached from @notebook to another notebook. + * Sets whether the tab can be detached from @notebook to another + * notebook or widget. * * Note that 2 notebooks must share a common group identificator - * (see gtk_notebook_set_group_id ()) to allow tabs interchange between them. + * (see gtk_notebook_set_group_id ()) to allow automatic tabs + * interchange between them. + * + * If you want a widget to interact with a notebook through DnD + * (i.e.: accept dragged tabs from it) it must be set as a drop + * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook + * will fill the selection with a GtkWidget** pointing to the child + * widget that corresponds to the dropped tab. + * + * + * static void + * on_drop_zone_drag_data_received (GtkWidget *widget, + * GdkDragContext *context, + * gint x, + * gint y, + * GtkSelectionData *selection_data, + * guint info, + * guint time, + * gpointer user_data) + * { + * GtkWidget *notebook; + * GtkWidget **child; + * + * notebook = gtk_drag_get_source_widget (context); + * child = (void*) selection_data->data; + * + * process_widget (*child); + * gtk_container_remove (GTK_CONTAINER (notebook), *child); + * } + * + * + * If you want a notebook to accept drags from other widgets, + * you will have to set your own DnD code to do it. * * Since: 2.10 **/ diff --git a/tests/testnotebookdnd.c b/tests/testnotebookdnd.c index 4c48af5649..f47d93a6f2 100644 --- a/tests/testnotebookdnd.c +++ b/tests/testnotebookdnd.c @@ -1,3 +1,4 @@ +/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */ /* * GTK - The GIMP Toolkit * Copyright (C) 2006 Carlos Garnacho Parro @@ -64,6 +65,10 @@ gchar *tabs4 [] = { NULL }; +static const GtkTargetEntry button_targets[] = { + { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 }, +}; + static GtkNotebook* window_creation_function (GtkNotebook *source_notebook, GtkWidget *child, @@ -94,6 +99,46 @@ on_page_reordered (GtkNotebook *notebook, GtkWidget *child, guint page_num, gpoi g_print ("page %d reordered\n", page_num); } +static void +on_notebook_drag_begin (GtkWidget *widget, + GdkDragContext *context, + gpointer data) +{ + GdkPixbuf *pixbuf; + guint page_num; + + page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)); + + pixbuf = gtk_widget_render_icon (widget, + (page_num % 2) ? GTK_STOCK_HELP : GTK_STOCK_STOP, + GTK_ICON_SIZE_DND, NULL); + + gtk_drag_set_icon_pixbuf (context, pixbuf, 0, 0); + g_object_unref (pixbuf); +} + +static void +on_button_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *data, + guint info, + guint time, + gpointer user_data) +{ + GtkWidget *source, *tab_label; + GtkWidget **child; + + source = gtk_drag_get_source_widget (context); + child = (void*) data->data; + + tab_label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (source), *child); + g_print ("Removing tab: %s\n", gtk_label_get_text (GTK_LABEL (tab_label))); + + gtk_container_remove (GTK_CONTAINER (source), *child); +} + static GtkWidget* create_notebook (gchar **labels, gint group_id, @@ -131,10 +176,29 @@ create_notebook (gchar **labels, g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered", G_CALLBACK (on_page_reordered), NULL); - + g_signal_connect_after (G_OBJECT (notebook), "drag-begin", + G_CALLBACK (on_notebook_drag_begin), NULL); return notebook; } +static GtkWidget* +create_trash_button (void) +{ + GtkWidget *button; + + button = gtk_button_new_from_stock (GTK_STOCK_DELETE); + + gtk_drag_dest_set (button, + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, + button_targets, + G_N_ELEMENTS (button_targets), + GDK_ACTION_MOVE); + + g_signal_connect_after (G_OBJECT (button), "drag-data-received", + G_CALLBACK (on_button_drag_data_received), NULL); + return button; +} + gint main (gint argc, gchar *argv[]) { @@ -143,7 +207,7 @@ main (gint argc, gchar *argv[]) gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - table = gtk_table_new (2, 2, TRUE); + table = gtk_table_new (3, 2, FALSE); gtk_notebook_set_window_creation_hook (window_creation_function, NULL); @@ -163,6 +227,10 @@ main (gint argc, gchar *argv[]) create_notebook (tabs4, GROUP_A, PACK_ALTERNATE, GTK_POS_RIGHT), 1, 2, 1, 2); + gtk_table_attach (GTK_TABLE (table), + create_trash_button (), 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + gtk_container_add (GTK_CONTAINER (window), table); gtk_window_set_default_size (GTK_WINDOW (window), 400, 400); gtk_widget_show_all (window);