0

I'm new to C and am trying to build a web browser using GTK, but I just can't get tabs to work!
I think this is the relevant code:

#include<gtk/gtk.h>

GtkWidget *window;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *scrollable_window;
GtkWidget *new_tab_button;
GtkWidget *tab_label;
GtkWidget *notebook;

void new_tab() {
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrollable_window, tab_label); 
}

int main(int argc, char** argv) {
gtk_init(&argc, &argv);

window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request(GTK_WIDGET(window), 1300, 768);
tab_label = gtk_label_new ("tab");
scrollable_window = gtk_scrolled_window_new(NULL,NULL);
vbox = gtk_vbox_new(false,false);
hbox = gtk_hbox_new(false,false);
hbox_web_view = gtk_hbox_new(true,0);

notebook = gtk_notebook_new ();
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
gtk_widget_show(notebook);

gtk_container_add(GTK_CONTAINER(window), scrollable_window);
gtk_container_add(GTK_CONTAINER(scrollable_window), vbox);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
gtk_container_add(GTK_CONTAINER(vbox), hbox_web_view);

new_tab_button = gtk_button_new_with_label("New tab");

g_signal_connect(new_tab_button, "clicked", G_CALLBACK(new_tab), web);
gtk_widget_show_all(window);

gtk_main();
return 0;

Everything works, but there is no notebook showing when I open the program. There is a 'new tab' button but whenever I click it it closes the program!

I think I just don't quite understand how gtk notebooks work. Could anyone help me out?

CMcGee
  • 21
  • 2
  • You have to add it to some container, don't you? Well you didn't. I can't tell you where to add it, because I can't follow your widget hierarchy. – Iharob Al Asimi Mar 04 '18 at 12:43
  • Iharob I just get the 'Can't set a parent on widget which has a parent' error no matter where I add it. – CMcGee Mar 04 '18 at 12:45
  • Also, using global variables is bad, and it indicates that you don't understand how *gtk*'s API is designed to prevent this. Read the documentation more carefully until you understand their model. – Iharob Al Asimi Mar 04 '18 at 12:46
  • Possible duplicate of [Why do I get a segmentation fault in my GTK+ signal callback?](https://stackoverflow.com/questions/48200255/why-do-i-get-a-segmentation-fault-in-my-gtk-signal-callback) – liberforce Mar 05 '18 at 09:40

1 Answers1

0

Your code indicates that you are just calling functions without reasoning why you should or not call each function.

The gtk_container_add() adds a widget to another widget that can be a container, i.e. that can contain other widgets, e.g. a GtkBox or the GtkWindow itself.

You are creating the notebook correctly, but you don't add it to any container in the widget hierarchy that has window as it's natural root.

Also, you create a scrollable_window only once but in real life — unless your design is optimizing memory and you know what you're doing — you need multiple scrollable_window instances, in fact you need a web view and all the children you're adding in your code to the window container.

Having mulitple instances of scrollable_window means that you should create each instance in your new_tab() callback, which BTW has a wrong signature, I don't know which the right signature is but it's certainly not that.

Usually GTK gives you

  • The object that generated the signal as the first parameter of the callback.
  • A pointer to your own data, that you can use to avoid global variables and make your code more robust and reusable.
  • There are some callbacks that have extra parameters, you just need to see the signal's documentation to determine which is the correct signature.
  • Some callbacks (if not all, I don't remember) return a gboolean to indicate whether or not your callback handled the event.

Ideally then,

  1. Create the notebook.

  2. Add the notebook directly to the window container, it should be your root widget.

  3. Create a "browser" in your new_tab() callback, and add it to your notebook. Use the first parameter which is mostly sure of type GtkWidget and is a pointer to your notebook thus eliminating the need for it to be global, don't use global variables, ever.

  4. Use the gpointer data — probably the last parameter to your callback — to store any context data that you need to share with your main() function.

    The ideal way to achieve independency, and completely avoid global variables is to create a structure to store your application state, although modern Gtk+ has mechanisms for this, it's still a good idea to store your data somewhere and pass it around to callbacks via the last parameter to g_signal_connect() and receive it as the last parameter to your callbacks.

Community
  • 1
  • 1
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97