/* OpenIDA - Outil d'analyse de fichiers binaires
* gtkdockpanel.c - manipulation et affichage de panneaux dockables
*
* Copyright (C) 2009 Cyrille Bagard
*
* This file is part of OpenIDA.
*
* OpenIDA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* OpenIDA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar. If not, see .
*/
#include "gtkdockpanel.h"
#include
#include
#include "gtkdropwindow.h"
#include "iodamarshal.h"
/* Valide ou non le terme d'un "Drag and drop". */
static gboolean gtk_dock_panel_drag_drop_cb(GtkDockPanel *, GdkDragContext *, gint, gint, guint, gpointer);
/* Procède au "Drag and drop" effectif. */
static void gtk_dock_panel_drag_data_received_cb(GtkDockPanel *, GdkDragContext *, gint, gint, GtkSelectionData *, guint, guint, gpointer);
/* Accompagne le déplacement sur une cible de "Drag and drop". */
static gboolean gtk_dock_panel_drag_motion_cb(GtkDockPanel *, GdkDragContext *, gint, gint, guint, gpointer);
/* Note la fin des visites sur une cible de "Drag and drop". */
static void gtk_dock_panel_drag_leave_cb(GtkDockPanel *, GdkDragContext *, guint, gpointer);
/* Procède au démarrage d'un "Drag and drop". */
static void gtk_dock_panel_drag_begin_cb(GtkDockPanel *, GdkDragContext *, gpointer);
/* Procède à l'envoi depuis la source à la destination. */
static void gtk_dock_panel_drag_data_get_cb(GtkDockPanel *, GdkDragContext *, GtkSelectionData *, guint, guint, gpointer );
/* Marque l'arrêt d'un "Drag and drop". */
static void gtk_dock_panel_drag_end_cb(GtkDockPanel *, GdkDragContext *, gpointer);
/* Nettoie les traces d'un "Drag and drop". */
//static void gtk_dock_panel_drag_data_delete_cb(GtkDockPanel *, GdkDragContext *, gpointer);
/* Ajoute un paquet d'informations à la station dockable. */
static void _gtk_dock_panel_add_item(GtkDockPanel *, GDockItem *, gint);
/* Remplace le panneau d'un membre actuellement affiché. */
static void on_dock_item_content_changed(GDockItem *, GtkWidget *, GtkWidget *, GtkDockPanel *);
/* Supprime un paquet d'informations à la station dockable. */
static void _gtk_dock_panel_remove_item(GtkDockPanel *, GDockItem *, GtkWidget *);
/* Met à jour le titre du support de panneaux dockables. */
static gboolean gtk_dock_panel_update_title(GtkNotebook *, GtkNotebookPage *, guint, gpointer);
/******************************************************************************/
#define _BYTE 8
#define _WORD 16
#define _DWORD 32
/******************************************************************************/
/* Define a list of data types called "targets" that a destination widget will
* accept. The string type is arbitrary, and negotiated between DnD widgets by
* the developer. An enum or GQuark can serve as the integer target id. */
enum {
TARGET_INT32,
TARGET_STRING,
TARGET_DOCKITEM,
TARGET_ROOTWIN
};
/* datatype (string), restrictions on DnD (GtkTargetFlags), datatype (int) */
static GtkTargetEntry target_list[] = {
{ "INTEGER", 0, TARGET_INT32 },
{ "STRING", 0, TARGET_STRING },
{ "OpenIDA/dock-item", 0, TARGET_DOCKITEM },
{ "application/x-rootwindow-drop", 0, TARGET_ROOTWIN }
};
static guint n_targets = G_N_ELEMENTS (target_list);
/* Détermine le type du composant d'affichage des morceaux. */
G_DEFINE_TYPE(GtkDockPanel, gtk_dock_panel, GTK_TYPE_VBOX)
/******************************************************************************
* *
* Paramètres : class = classe GTK à initialiser. *
* *
* Description : Procède à l'initialisation de l'afficheur de morceaux. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_dock_panel_class_init(GtkDockPanelClass *class)
{
g_signal_new("switch-item",
GTK_TYPE_DOCK_PANEL,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(GtkDockPanelClass, switch_item),
NULL, NULL,
g_cclosure_user_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, G_TYPE_DOCK_ITEM);
}
/******************************************************************************
* *
* Paramètres : dpanel = composant GTK à initialiser. *
* *
* Description : Procède à l'initialisation de la station dockable. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_dock_panel_init(GtkDockPanel *dpanel)
{
GtkWidget *eventbox1;
GtkWidget *hbox1;
GtkWidget *button1;
GtkWidget *image1;
GtkWidget *button2;
GtkWidget *image2;
eventbox1 = gtk_event_box_new ();
gtk_widget_show (eventbox1);
gtk_box_pack_start (GTK_BOX (dpanel), eventbox1, FALSE, TRUE, 0);
hbox1 = gtk_hbox_new (FALSE, 0);
gtk_widget_show (hbox1);
gtk_container_add (GTK_CONTAINER (eventbox1), hbox1);
dpanel->title = GTK_LABEL(gtk_label_new(("titre")));
gtk_widget_show(GTK_WIDGET(dpanel->title));
gtk_box_pack_start(GTK_BOX (hbox1), GTK_WIDGET(dpanel->title), TRUE, TRUE, 0);
gtk_label_set_use_markup(GTK_LABEL(dpanel->title), TRUE);
gtk_misc_set_alignment(GTK_MISC(dpanel->title), 0, 0.5);
button1 = gtk_button_new ();
gtk_widget_show (button1);
gtk_box_pack_start (GTK_BOX (hbox1), button1, FALSE, FALSE, 0);
gtk_button_set_relief (GTK_BUTTON (button1), GTK_RELIEF_NONE);
image1 = gtk_image_new_from_stock ("gtk-media-play", GTK_ICON_SIZE_MENU);
gtk_widget_show (image1);
gtk_container_add (GTK_CONTAINER (button1), image1);
gtk_widget_set_size_request (image1, 10, 10);
button2 = gtk_button_new ();
gtk_widget_show (button2);
gtk_box_pack_start (GTK_BOX (hbox1), button2, FALSE, FALSE, 0);
gtk_button_set_relief (GTK_BUTTON (button2), GTK_RELIEF_NONE);
image2 = gtk_image_new_from_stock ("gtk-close", GTK_ICON_SIZE_MENU);
gtk_widget_show (image2);
gtk_container_add (GTK_CONTAINER (button2), image2);
gtk_widget_set_size_request (image2, 10, 10);
dpanel->notebook = gtk_notebook_new ();
gtk_widget_show (dpanel->notebook);
gtk_box_pack_start (GTK_BOX (dpanel), dpanel->notebook, TRUE, TRUE, 0);
gtk_notebook_set_show_border (GTK_NOTEBOOK (dpanel->notebook), FALSE);
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (dpanel->notebook), GTK_POS_BOTTOM);
gtk_notebook_set_scrollable (GTK_NOTEBOOK (dpanel->notebook), TRUE);
/* Make the "well label" a DnD destination. */
gtk_drag_dest_set
(
GTK_WIDGET(dpanel), /* widget that will accept a drop */
GTK_DEST_DEFAULT_MOTION /* default actions for dest on DnD */
| GTK_DEST_DEFAULT_HIGHLIGHT,
target_list, /* lists of target to support */
n_targets, /* size of list */
GDK_ACTION_COPY /* what to do with data after dropped */
);
/* Make the "coin button" a DnD source. */
/* Why doesn't GtkLabel work here? */
gtk_drag_source_set
(
GTK_WIDGET(dpanel), /* widget will be drag-able */
GDK_BUTTON1_MASK, /* modifier that will start a drag */
target_list, /* lists of target to support */
n_targets, /* size of list */
GDK_ACTION_COPY /* what to do with data after dropped */
);
/* Côté destination */
g_signal_connect(dpanel, "drag-drop", G_CALLBACK(gtk_dock_panel_drag_drop_cb), NULL);
g_signal_connect(dpanel, "drag-data-received", G_CALLBACK(gtk_dock_panel_drag_data_received_cb), NULL);
g_signal_connect(dpanel, "drag-motion", G_CALLBACK(gtk_dock_panel_drag_motion_cb), NULL);
g_signal_connect(dpanel, "drag-leave", G_CALLBACK(gtk_dock_panel_drag_leave_cb), NULL);
/* Côté source */
g_signal_connect(dpanel, "drag-begin", G_CALLBACK(gtk_dock_panel_drag_begin_cb), NULL);
g_signal_connect(dpanel, "drag-data-get", G_CALLBACK(gtk_dock_panel_drag_data_get_cb), NULL);
g_signal_connect(dpanel, "drag-end", G_CALLBACK(gtk_dock_panel_drag_end_cb), NULL);
//g_signal_connect(dpanel, "drag-data-delete", G_CALLBACK(gtk_dock_panel_drag_data_delete_cb), NULL);
g_signal_connect(dpanel->notebook, "switch-page", G_CALLBACK(gtk_dock_panel_update_title), dpanel);
dpanel->dropwin = gtk_drop_window_new();
/* Make the "well label" a DnD destination. */
gtk_drag_dest_set
(
dpanel->dropwin, /* widget that will accept a drop */
GTK_DEST_DEFAULT_MOTION /* default actions for dest on DnD */
| GTK_DEST_DEFAULT_HIGHLIGHT,
target_list, /* lists of target to support */
n_targets, /* size of list */
GDK_ACTION_COPY /* what to do with data after dropped */
);
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Crée un nouveau composant pour station dockable. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget *gtk_dock_panel_new(void)
{
return g_object_new(GTK_TYPE_DOCK_PANEL, NULL);
}
/******************************************************************************
* *
* Paramètres : dpanel = composant à l'origine de la manoeuvre. *
* context = contexte de l'opération de "Drag and drop". *
* x = abscisse du pointeur relaché. *
* y = ordonnée du pointeur relaché. *
* time = date de l'opération. *
* data = adresse non utilisée ici. *
* *
* Description : Valide ou non le terme d'un "Drag and drop". *
* *
* Retour : TRUE si l'opération peut continuer, FALSE sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
static gboolean gtk_dock_panel_drag_drop_cb(GtkDockPanel *dpanel, GdkDragContext *context, gint x, gint y, guint time, gpointer data)
{
gboolean result; /* Ordre à retourner */
GdkAtom target; /* Type d'élément à déplacer */
result = (context->targets != NULL);
printf(" ## DRAG DROP ## %p\n", dpanel);
if (context->targets != NULL)
{
target = GDK_POINTER_TO_ATOM(g_list_nth_data(context->targets, TARGET_DOCKITEM));
gtk_drag_get_data(GTK_WIDGET(dpanel), context, target, time);
}
return result;
}
/******************************************************************************
* *
* Paramètres : dpanel = composant à l'origine de la manoeuvre. *
* context = contexte de l'opération de "Drag and drop". *
* x = abscisse du pointeur relaché. *
* y = ordonnée du pointeur relaché. *
* selection = réceptacle pour la transmission. *
* target = type de données demandé. *
* time = date de l'opération. *
* data = adresse non utilisée ici. *
* *
* Description : Procède au "Drag and drop" effectif. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_dock_panel_drag_data_received_cb(GtkDockPanel *dpanel, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection, guint target, guint time, gpointer data)
{
GDockItem *ditem; /* Elément transféré */
gboolean success; /* Bilan de l'opération */
success = FALSE;
if (selection != NULL && selection->length >= 0)
switch (target)
{
case TARGET_DOCKITEM:
success = (selection->length == sizeof(GDockItem *));
printf(" ## DRAG DATA RCV ## %p\n", dpanel);
printf(" -- source :: %p\n", gtk_drag_get_source_widget(context));
printf(" -- dest :: %p\n", dpanel);
if (success)
{
ditem = G_DOCK_ITEM(*((GDockItem **)selection->data));
printf(" :: get ? %p - %d\n", ditem, G_IS_DOCK_ITEM(ditem));
gtk_dock_panel_remove_item(gtk_drag_get_source_widget(context), ditem);
gtk_dock_panel_add_item(dpanel, ditem);
}
break;
}
gtk_drag_finish(context, success, context->action == GDK_ACTION_MOVE, time);
}
/******************************************************************************
* *
* Paramètres : dpanel = composant à l'origine de la manoeuvre. *
* context = contexte de l'opération de "Drag and drop". *
* x = abscisse du pointeur relaché. *
* y = ordonnée du pointeur relaché. *
* time = date de l'opération. *
* data = adresse non utilisée ici. *
* *
* Description : Accompagne le déplacement sur une cible de "Drag and drop". *
* *
* Retour : TRUE pour continuer la propagation, FALSE sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
static gboolean gtk_dock_panel_drag_motion_cb(GtkDockPanel *dpanel, GdkDragContext *context, gint x, gint y, guint time, gpointer data)
{
gint new_x; /* Abscisse de la fenêtre */
gint new_y; /* Ordonnée de la fenêtre */
GtkRequisition req; /* Taille actuelle du panneau */
if (!GTK_WIDGET_VISIBLE(dpanel->dropwin))
{
gdk_window_get_origin(GTK_WIDGET(dpanel)->window, &new_x, &new_y);
new_x += GTK_WIDGET(dpanel)->allocation.x + (GTK_WIDGET(dpanel)->allocation.width - 89) / 2;
new_y += GTK_WIDGET(dpanel)->allocation.y + (GTK_WIDGET(dpanel)->allocation.height - 89) / 2;
gtk_widget_set_uposition(dpanel->dropwin, new_x, new_y);
gtk_widget_show(dpanel->dropwin);
}
return FALSE;
}
/******************************************************************************
* *
* Paramètres : dpanel = composant à l'origine de la manoeuvre. *
* context = contexte de l'opération de "Drag and drop". *
* x = abscisse du pointeur relaché. *
* y = ordonnée du pointeur relaché. *
* time = date de l'opération. *
* data = adresse non utilisée ici. *
* *
* Description : Note la fin des visites sur une cible de "Drag and drop". *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_dock_panel_drag_leave_cb(GtkDockPanel *dpanel, GdkDragContext *context, guint time, gpointer data)
{
gtk_widget_hide(dpanel->dropwin);
}
/******************************************************************************
* *
* Paramètres : dpanel = composant à l'origine de la manoeuvre. *
* context = contexte de l'opération de "Drag and drop". *
* data = adresse non utilisée ici. *
* *
* Description : Procède au démarrage d'un "Drag and drop". *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_dock_panel_drag_begin_cb(GtkDockPanel *dpanel, GdkDragContext *context, gpointer data)
{
printf(" ## DRAG BEGIN ## %p\n", dpanel);
}
/******************************************************************************
* *
* Paramètres : dpanel = composant à l'origine de la manoeuvre. *
* context = contexte de l'opération de "Drag and drop". *
* selection = réceptacle pour la transmission. *
* target = type de données demandé. *
* time = date de l'opération. *
* data = adresse non utilisée ici. *
* *
* Description : Procède à l'envoi depuis la source à la destination. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_dock_panel_drag_data_get_cb(GtkDockPanel *dpanel, GdkDragContext *context, GtkSelectionData *selection, guint target, guint time, gpointer data)
{
gint current; /* Indice de l'onglet courant */
GDockItem *ditem; /* Elément à transférer */
switch (target)
{
case TARGET_DOCKITEM:
printf(" ## DRAG GET DATA ## %p\n", dpanel);
current = gtk_notebook_get_current_page(dpanel->notebook);
ditem = G_DOCK_ITEM(g_list_nth_data(dpanel->ditems, current));
printf(" %d nth item is %p\n", current, ditem);
printf(" :: set ? %p - %d\n", ditem, G_IS_DOCK_ITEM(ditem));
gtk_selection_data_set(selection, selection->target,
32, (guchar *)&ditem, sizeof(GDockItem *));
break;
}
}
/******************************************************************************
* *
* Paramètres : dpanel = composant à l'origine de la manoeuvre. *
* context = contexte de l'opération de "Drag and drop". *
* data = adresse non utilisée ici. *
* *
* Description : Marque l'arrêt d'un "Drag and drop". *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_dock_panel_drag_end_cb(GtkDockPanel *dpanel, GdkDragContext *context, gpointer data)
{
printf(" ## DRAG END ## %p\n", dpanel);
}
/******************************************************************************
* *
* Paramètres : dpanel = composant dont le contenu est à parcourir. *
* name = désignation humaine du membre à retrouver. *
* *
* Description : Retrouve un membre du panneau d'après son nom. *
* *
* Retour : Membre trouvé ou NULL si aucun. *
* *
* Remarques : - *
* *
******************************************************************************/
GDockItem *gtk_dock_panel_item_from_name(GtkDockPanel *dpanel, const char *name)
{
GDockItem *result; /* Trouvaille à remonter */
GList *iter; /* Boucle de parcours */
const char *tmp; /* Autre nom à consulter */
result = NULL;
for (iter = dpanel->ditems; iter != NULL && result == NULL; iter = g_list_next(iter))
{
tmp = g_dock_item_get_name(G_DOCK_ITEM(iter->data));
if (strcmp(name, tmp) == 0)
result = G_DOCK_ITEM(iter->data);
}
return result;
}
/******************************************************************************
* *
* Paramètres : dpanel = composant GTK à compléter. *
* ditem = nouvel élément à intégrer. *
* *
* Description : Ajoute un paquet d'informations à la station dockable. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_dock_panel_add_item(GtkDockPanel *dpanel, GDockItem *ditem)
{
_gtk_dock_panel_add_item(dpanel, ditem, -1);
}
/******************************************************************************
* *
* Paramètres : dpanel = composant GTK à compléter. *
* ditem = nouvel élément à intégrer. *
* position = point d'insertion (-1 pour la fin). *
* *
* Description : Ajoute un paquet d'informations à la station dockable. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void _gtk_dock_panel_add_item(GtkDockPanel *dpanel, GDockItem *ditem, gint position)
{
GtkWidget *label; /* Etiquette d'onglet */
dpanel->ditems = g_list_insert(dpanel->ditems, ditem, position);
printf("[add %p to %p] list len :: %u\n", ditem, dpanel, g_list_length(dpanel->ditems));
label = gtk_label_new(g_dock_item_get_name(ditem));
gtk_widget_show(label);
gtk_notebook_insert_page(dpanel->notebook, g_dock_item_get_panel(ditem), label, position);
gtk_notebook_set_show_tabs(dpanel->notebook, g_list_length(dpanel->ditems) > 1);
g_signal_connect(ditem, "content-changed", G_CALLBACK(on_dock_item_content_changed), dpanel);
}
/******************************************************************************
* *
* Paramètres : ditem = composant GTK déjà mis à jour. *
* old = ancien panneau retiré. *
* new = nouveau panneau présenté. *
* dpanel = composant GTK à mettre à jour. *
* *
* Description : Remplace le panneau d'un membre actuellement affiché. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void on_dock_item_content_changed(GDockItem *ditem, GtkWidget *old, GtkWidget *new, GtkDockPanel *dpanel)
{
gint position; /* Position de l'onglet à maj */
position = gtk_notebook_page_num(dpanel->notebook, old);
g_signal_handlers_disconnect_by_func(dpanel->notebook, G_CALLBACK(gtk_dock_panel_update_title), dpanel);
//g_object_ref(G_OBJECT(ditem));
_gtk_dock_panel_remove_item(dpanel, ditem, old);
_gtk_dock_panel_add_item(dpanel, ditem, position);
//g_object_unref(G_OBJECT(ditem));
gtk_notebook_set_current_page(dpanel->notebook, position);
g_signal_connect(dpanel->notebook, "switch-page", G_CALLBACK(gtk_dock_panel_update_title), dpanel);
}
/******************************************************************************
* *
* Paramètres : dpanel = composant GTK à mettre à jour. *
* ditem = nouvel élément à sortir. *
* *
* Description : Supprime un paquet d'informations à la station dockable. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void gtk_dock_panel_remove_item(GtkDockPanel *dpanel, GDockItem *ditem)
{
gint pos; /* Position de l'élément visé */
g_signal_handlers_disconnect_by_func(ditem, G_CALLBACK(on_dock_item_content_changed), dpanel);
pos = g_list_index(dpanel->ditems, ditem);
dpanel->ditems = g_list_remove(dpanel->ditems, ditem);
printf("[rem %p from %p] list len :: %u\n", ditem, dpanel, g_list_length(dpanel->ditems));
gtk_widget_ref(g_dock_item_get_panel(ditem));
gtk_container_remove(GTK_CONTAINER(dpanel->notebook), g_dock_item_get_panel(ditem));
//gtk_notebook_remove_page(dpanel->notebook, pos);
g_object_unref(G_OBJECT(ditem));
gtk_notebook_set_show_tabs(dpanel->notebook, g_list_length(dpanel->ditems) > 1);
}
/******************************************************************************
* *
* Paramètres : dpanel = composant GTK à mettre à jour. *
* ditem = nouvel élément à sortir. *
* panel = panneau GTK de l'élément à supprimer. *
* *
* Description : Supprime un paquet d'informations à la station dockable. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void _gtk_dock_panel_remove_item(GtkDockPanel *dpanel, GDockItem *ditem, GtkWidget *panel)
{
gint pos; /* Position de l'élément visé */
g_signal_handlers_disconnect_by_func(ditem, G_CALLBACK(on_dock_item_content_changed), dpanel);
pos = g_list_index(dpanel->ditems, ditem);
dpanel->ditems = g_list_remove(dpanel->ditems, ditem);
printf("[rem %p from %p] list len :: %u\n", ditem, dpanel, g_list_length(dpanel->ditems));
gtk_widget_ref(panel);
gtk_container_remove(GTK_CONTAINER(dpanel->notebook), panel);
//gtk_notebook_remove_page(dpanel->notebook, pos);
gtk_notebook_set_show_tabs(dpanel->notebook, g_list_length(dpanel->ditems) > 1);
}
/******************************************************************************
* *
* Paramètres : notebook = support à l'origine de la mise à jour. *
* page = onglet mis en avant. *
* index = indice de l'onglet actuellement actif. *
* data = adresse du conteneur supérieur. *
* *
* Description : Met à jour le titre du support de panneaux dockables. *
* *
* Retour : TRUE ? *
* *
* Remarques : - *
* *
******************************************************************************/
static gboolean gtk_dock_panel_update_title(GtkNotebook *notebook, GtkNotebookPage *page, guint index, gpointer data)
{
GDockItem *ditem; /* Elément nouvellement actif */
const gchar *desc; /* Description à afficher */
char *str; /* Valeur finale reconstituée */
//printf("[%p] list len :: %u / %u\n", data, index, g_list_length(GTK_DOCK_PANEL(data)->ditems));
if (index >= g_list_length(GTK_DOCK_PANEL(data)->ditems)) return FALSE;
//printf(" >> ditem = %p\n", g_list_nth_data(GTK_DOCK_PANEL(data)->ditems, index));
//printf(" >> index :: %u vs %d\n", index, gtk_notebook_get_current_page(GTK_DOCK_PANEL(data)->notebook));
ditem = G_DOCK_ITEM(g_list_nth_data(GTK_DOCK_PANEL(data)->ditems, index));
desc = g_dock_item_get_desc(ditem);
str = calloc(strlen("") + strlen(desc) + strlen("") + 1, sizeof(char));
strcpy(str, "");
strcat(str, desc);
strcat(str, "");
gtk_label_set_markup(GTK_DOCK_PANEL(data)->title, str);
free(str);
g_signal_emit_by_name(GTK_DOCK_PANEL(data), "switch-item", ditem);
return TRUE;
}