I am currently debugging an issue where gtk_notebook_remove_page(GTK_NOTEBOOK(nbook), page);
is crashing the program.
Looking into the implementation of the function gtk_notebook_remove_page
, I have found that it is implemented as such (from the Gnome repository):
void
gtk_notebook_remove_page (GtkNotebook *notebook,
gint page_num)
{
GtkNotebookPrivate *priv;
GList *list = NULL;
g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
priv = notebook->priv;
if (page_num >= 0)
list = g_list_nth (priv->children, page_num);
else
list = g_list_last (priv->children);
if (list)
gtk_container_remove (GTK_CONTAINER (notebook),
((GtkNotebookPage *) list->data)->child);
}
I have checked with conditional breakpoints to ensure that nbook
is a GTK_NOTEBOOK
, that page
is larger or equals to zero, and that nbook
itself is not NULL. All of the above hold true, which means that the error occurs at: gtk_container_remove (GTK_CONTAINER (notebook), ((GtkNotebookPage *) list->data)->child);
. Following this, I have found that the function gtk_container_remove
is implemented as such (similarly from the Gnome repository):
void
gtk_container_remove (GtkContainer *container,
GtkWidget *widget)
{
g_return_if_fail (GTK_IS_CONTAINER (container));
g_return_if_fail (GTK_IS_WIDGET (widget));
g_object_ref (container);
g_object_ref (widget);
g_signal_emit (container, container_signals[REMOVE], 0, widget);
_gtk_container_accessible_remove (GTK_WIDGET (container), widget);
g_object_unref (widget);
g_object_unref (container);
}
From here, we can see that the program will crash if either the condition GTK_IS_CONTAINER (container)
or GTK_IS_WIDGET (widget)
is false. Since we are performing GTK_CONTAINER(notebook)
at the point of calling gtk_container_remove
and nbook
which is passed to GtkNotebook * notebook
initially is determined not to be NULL, I suspect that the second condition is false (i.e., ((GtkNotebookPage *) list->data)->child
is a dangling pointer/invalid). However, when I try to verify what exactly is notebook->priv->children
, it will not allow me to access it as struct _GtkNotebookPrivate
is an incomplete type. This is what I have attempted:
GtkNotebookPrivate *priv;
GList *list = NULL;
priv = nbook->priv;
list = g_list_nth(priv->children, page);
/* Check if list is valid here */
/* Futher check if list->data->child is valid */
gtk_notebook_remove_page(GTK_NOTEBOOK(nbook), page);
Error message:
pointer or reference to incomplete type "struct _GtkNotebookPrivate" is not allowed
Is there a way to check the validity of GtkNotebookPrivate outside of the GTK library's own implementation (i.e., check it inline)?
Additional information:
After further digging, I found the following as the implementation of the GtkNotebookPrivate structure (from the Gnome respository):
struct _GtkNotebookPrivate
{
GtkNotebookDragOperation operation;
GtkNotebookPage *cur_page;
GtkNotebookPage *detached_tab;
GtkNotebookPage *prelight_tab;
GtkTargetList *source_targets;
GtkWidget *action_widget[N_ACTION_WIDGETS];
GtkWidget *dnd_window;
GtkWidget *menu;
GdkWindow *drag_window;
GdkWindow *event_window;
GtkCssGadget *gadget;
GtkCssGadget *stack_gadget;
GtkCssGadget *header_gadget;
GtkCssGadget *tabs_gadget;
GtkCssGadget *arrow_gadget[4];
GList *children;
GList *first_tab; /* The first tab visible (for scrolling notebooks) */
GList *focus_tab;
gint drag_begin_x;
gint drag_begin_y;
gint drag_offset_x;
gint drag_offset_y;
gint drag_window_x;
gint drag_window_y;
gint mouse_x;
gint mouse_y;
gint pressed_button;
GQuark group;
guint dnd_timer;
guint switch_tab_timer;
GList *switch_tab;
guint32 timer;
guint child_has_focus : 1;
guint click_child : 3;
guint remove_in_detach : 1;
guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
guint has_scrolled : 1;
guint in_child : 3;
guint need_timer : 1;
guint show_border : 1;
guint show_tabs : 1;
guint scrollable : 1;
guint tab_pos : 2;
guint tabs_reversed : 1;
guint rootwindow_drop : 1;
};
As per suggestions, I have tried to add in this structure declaration in my own source code as well, however, as evident, it requires dependencies such as GtkCssGadget
which again, cannot be normally accessed through the standard Gtk+ library. I do have the choice of adding in the implementation of the GtkCssGadget
and other needed structures, however, I do feel it is a very inefficient method and was wondering if any other methods were possible.
In addition, this is how GtkNotebook
is defined in gtknotebook.h
:
struct _GtkNotebook
{
/*< private >*/
GtkContainer container;
GtkNotebookPrivate *priv;
};
Is there any way to access the *priv without adding in manually all the code for GtkNotebookPrivate and its dependencies?
After further analysis and searching the Gnome repository, I have determined that it is normally (and by right, since GtkNotebookPrivate
is supposed to stay private), it is impossible to access GtkNotebook
's priv
's variables.
A workaround for similar issues can be done via the use of this function:
GtkWidget*
gtk_notebook_get_nth_page (
GtkNotebook* notebook,
int page_num
)
which will return the n-th page of the GtkNotebook * notebook
, which is basically the same thing as (GtkNotebookPage *) list->data)->child
. From here, we can check if the return value is or is not NULL to check if there is a dangling pointer or check what widget the gtk_notebook_remove_page(GTK_NOTEBOOK(nbook), page);
is trying to remove.
For example, you can do this to check that the n-th page is valid:
if (gtk_notebook_get_nth_page(GTK_NOTEBOOK(nbook), page))
{
// no error
}
else
{
// log for error, n-th page is not valid
}
gtk_notebook_remove_page(GTK_NOTEBOOK(nbook), page);