Gtk+ programming style: defining widgets - c

In virtually every example code of GTK+ I've seen so far,
the widgets of the GUI are all defined inside the main function.
At first I adopted this, but then found it highly inconvenient when
e.g. manipulating multiple widgets from a single callback function.
Of course I could just use the 'data' gpointer for that, but wouldn't I
have to wrap every widget I want to manipulate in some sort of struct first
to pass it as the 'data' argument?
Anyway, to not be bound by this, I just started defining all Widgets outside the main
function, so I can easily access them across all function. Are there any drawbacks to this style?

The drawbacks are the same as the drawbacks for using any global variable. This page has a good overview of situations when you should not (and when you should) use global variables. If you look near the bottom, you will see under "Really bad reasons to use global variables":
I don't want to pass it around all the time.
I'm afraid this is kind of what your objection sounds like. However, as the page I linked to also mentions, if you are just writing short or one-off programs, then the ease of using global variables probably outweighs the drawbacks.
The usual way in medium-sized programs is to create a struct and populate it in main(), and pass it to the callbacks:
typedef struct {
GtkWidget *window, *button, *textfield;
} Widgets;
int main(int argc, char **argv) {
gtk_init(&argc, &argv);
Widgets *w = g_slice_new0(Widgets);
w->window = gtk_window_new(... etc...
...
g_signal_connect(w->button, "clicked", G_CALLBACK(on_clicked), w);
...etc...
gtk_main();
g_slice_free(Widgets, w);
return 0;
}
In large programs, a better way is to create your own classes representing main windows, preferences dialogs, etc., and pass those classes to the various callbacks.

Related

Callback to multiple functions in C

I'm trying to write code in C (for embedded application), in which there would be event callback (caused by pressing a button) calling different functions, depending on GUI screen that is currently displayed.
Ideally I would like to "define" function like: keyXPressed() many times and programming different actions in different parts of the code (like on Screen1 do this and on Screen2 do that), so that single callback would always refer to one that is currently on. I know that multiple definitions of the functions are probably not the way and presumably some object-oriented techniques will be involved.
What are the ways of achieving such functionality in simple and elegant manner?
Use a function pointer.
void (*keyPressed)(screen *);
void keyXPressed(screen *s) {
// code here
}
void keyYPressed(screen *s) {
// code here
}
Then you can assign keyPressed = keyXPressed; or keyPressed = keyYPressed;, and call keyPressed(screen1);

How can I use GTK notebook to add tabs to my browser?

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?
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,
Create the notebook.
Add the notebook directly to the window container, it should be your root widget.
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.
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.

Gtk and C - Multi-threaded GUI Application and Removing Global Variables

I have the example GTK C application from [1] building and working as expected. I have a pretty little UI application with a + and - button to increment/decrement a value stored in a global variable, and render it in the application in a text label.
I rarely ever work with GUI applications, and I do 99% of my work in C. I have two key questions with respect to tidying up this example and using it as the basis of a project.
Is it possible to have some alternative to global variables, like a
custom struct I create in main(), and have every callback handler reference
it by changing the function protocol for increase()?
Code:
// Can this function protocol be modified?
void increase(GtkWidget *widget, gpointer label) {
count++;
sprintf(buf, "%d", count);
gtk_label_set_text(GTK_LABEL(label), buf);
}
g_signal_connect(minus, "clicked", G_CALLBACK(decrease), label);
Is there a simple means of creating a separate thread to help manage the GUI? For example, if I have a button tied/connected to a function that would take a minute to complete, is there a universally-accepted means of firing off a separate pthread that allows me to have a button or command to cancel the operation, rather than the entire UI app being blocked for the whole minute?
Thank you.
References
Cross Compiling GTK applications For the Raspberry Pi, Accessed 2014-02-20, <http://hertaville.com/2013/07/19/cross-compiling-gtk-applications-for-the-raspberry-pi/>
Yes, you can pass anything you like as the last argument to signal handlers (gpointer is a typedef for void*) just create the structure containing the label widget and the counter variable in main(), pass it as the last argument to g_signal_connect and cast it back to the proper type in your callback.
For running a calculation in another thread and delivering the result to the gtk main loop I'd look at GTask, in particular g_task_run_in_thread_async.

Initializing private data in custom Gtk+ widget which depends on parent's members (C)

I'm working on a pet project solely for the purpose of learning a few API's. It's not intended to have practical value, but rather to be relatively simple excercise to get me comfortable with libpcap, gtk+, and cairo before I use them for anything serious. This is a graphical program, implemented in C and using Gtk+ 2.x. It's eventually going to read frames with pcap (currently I just have a hardcoded test frame), then use cairo to generate pretty pictures using color values generated from the raw packet (at this stage, I'm just using cairo_show_text to print a text representation of the frame or packet). The pictures will then be drawn to a custom widget inheriting from GtkDrawingArea.
My first step, of course, is to get a decent grasp of the Gtk+ runtime environment so I can implement my widget. I've already managed to render and draw text using cairo to my custom widget. Now I'm at the point where I think the widget really needs private storage for things like the cairo_t context pointer and a GdkRegion pointer (I had not planned to use Gdk directly, but my research indicates that it may be necessary in order to call gdk_window_invalidate_region() to force my DrawingArea to refresh once I've drawn a frame, not to mention gdk_cairo_create()). I've set up private storage as a global variable (the horror! Apparently this is conventional for Gtk+. I'm still not sure how this will even work if I have multiple instances of my widget, so maybe I'm not doing this part right. Or maybe the preprocessor macros and runtime environment are doing some magic to give each instance its own copy of this struct?):
/* private data */
typedef struct _CandyDrawPanePrivate CandyDrawPanePrivate;
struct _CandyDrawPanePrivate {
cairo_t *cr;
GdkRegion *region;
};
#define CANDY_DRAW_PANE_GET_PRIVATE(obj)\
(G_TYPE_INSTANCE_GET_PRIVATE((obj), CANDY_DRAW_PANE_TYPE, CandyDrawPanePrivate))
Here's my question: Initializing the pointers in my private data struct depends on members inherited from the parent, GtkWidget:
/* instance initializer */
static void candy_draw_pane_init(CandyDrawPane *pane) {
GdkWindow *win = NULL;
/*win = gtk_widget_get_window((GtkWidget *)pane);*/
win = ((GtkWidget*)pane)->window;
if (!win)
return;
/* TODO: I should probably also check this return value */
CandyDrawPanePrivate *priv = CANDY_DRAW_PANE_GET_PRIVATE(((CandyDrawPane*)pane));
priv->cr = gdk_cairo_create(win);
priv->region = gdk_drawable_get_clip_region(win);
candy_draw_pane_update(pane);
g_timeout_add(1000, candy_draw_pane_update, pane);
}
When I replaced my old code, which called gdk_cairo_create() and gdk_drawable_get_clip_region() during my event handlers, with this code, which calls them during candy_draw_pane_init(), the application would no longer draw. Stepping through with a debugger, I can see that pane->window and pane->parent are both NULL pointers while we are within candy_draw_pane_init(). The pointers are valid later, in the Gtk event processing loop. This leads me to believe that the inherited members have not yet been initialized when my derived class' "_init()" method is called. I'm sure this is just the nature of the Gtk+ runtime environment.
So how is this sort of thing typically handled? I could add logic to my event handlers to check priv->cr and priv->region for NULL, and call gdk_cairo_create() and gdk_drawable_get_clip_region() if they are still NULL. Or I could add a "post-init" method to my CandyDrawPane widget and call it explicitly after I call candy_draw_pane_new(). I'm sure lots of other people have encountered this sort of scenario, so is there a clean and conventional way to handle it?
This is my first real foray into object-oriented C, so please excuse me if I'm using any terminology incorrectly. I think one source of my confusion is that Gtk has separate concepts of instance and class initialization. C++ may do something similar "under the hood," but if so, it isn't as obvious to the coder.
I have a feeling that if this was C++, most of the the code that's going into candy_draw_pane_init() would be in the class constructor, and any secondary initialization that depended on the constructor having completed would go into an "Init()" method (which of course is not a feature of the language, but just a commonly used convention). Is there an analogous convention for Gtk+? Or perhaps someone can give a good overview of the flow of control when these widgets are instantiated. I have not been very impressed with the quality of the official Gnome documentation. Much of it is either too high-level, contains errors and typos in code, or has broken links or missing examples. And of course the heavy use of macros makes it a little harder to follow even my own code (in this respect it reminds me of Win32 GUI development). In short, I'm sure I can struggle through this on my own and make it work, but I'd like to hear from someone experienced with Gtk+ and C what the "right" way to do this is.
For completeness, here is the header where I set up my custom widget:
#ifndef __GTKCAIRO_H__
#define __GTKCAIRO_H__ 1
#include <gtk/gtk.h>
/* Following tutorial; see gtkcairo.c */
/* Not sure about naming convention; may need revisiting */
G_BEGIN_DECLS
#define CANDY_DRAW_PANE_TYPE (candy_draw_pane_get_type())
#define CANDY_DRAW_PANE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CANDY_DRAW_PANE_TYPE, CandyDrawPane))
#define CANDY_DRAW_PANE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass)CANDY_DRAW_PANE_TYPE, CandyDrawPaneClass))
#define IS_CANDY_DRAW_PANE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CANDY_DRAW_PANE_TYPE))
#define IS_CANDY_DRAW_PANE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CANDY_DRAW_PANE_TYPE))
// official gtk tutorial, which seems to be of higher quality, does not use this.
// #define CANDY_DRAW_PANE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CANDY_DRAW_PANE_TYPE, CandyDrawPaneClass))
typedef struct {
GtkDrawingArea parent;
/* private */
} CandyDrawPane;
typedef struct {
GtkDrawingAreaClass parent_class;
} CandyDrawPaneClass;
/* method prototypes */
GtkWidget* candy_draw_pane_new(void);
GType candy_draw_pane_get_type(void);
void candy_draw_pane_clear(CandyDrawPane *cdp);
G_END_DECLS
#endif
Any insight is much appreciated. I do realize I could use a code-generating IDE and crank something out more quickly, and probably dodge having to deal with some of this stuff, but the whole point of this exercise is to get a good grasp of the Gtk runtime, so I'd prefer to write the boilerplate by hand.
This article, A Gentle Introduction to GObject Construction, may help you. Here are some tips that I thought of while looking at your code and your questions:
If your priv->cr and priv->region pointers have to change whenever the widget's GDK window changes, then you could also move that code into a signal handler for the notify::window signal. notify is a signal that fires whenever an object's property is changed, and you can narrow down the signal emission to listen to a specific property by appending it to the name of the signal like that.
You don't need to check the return value from the GET_PRIVATE macro. Looking at the source code for g_type_instance_get_private(), it can return NULL in the case of an error, but it's really unlikely, and will print warnings to the terminal. My feeling is that if GET_PRIVATE returns NULL then something has gone really wrong and you won't be able to recover and continue executing the program anyway.
You're not setting up private storage as a global variable. Where are you declaring this global variable? I only see a struct and typedef declaration at the global level. What you are most likely doing, and what is the usual practice, is calling g_type_class_add_private() in the class_init function. This reserves space within each object for your private struct. Then when you need to use it, g_type_instance_get_private() gives you a pointer to this space.
The init method is the equivalent to a constructor in C++. The class_init method has no equivalent, because all the work done there is done behind the scenes in C++. For example, in a class_init function, you might specify which functions override the parent class's virtual functions. In C++, you simply do this by defining a method in the class with the same name as the virtual method you want to override.
As far as I can tell, the only problem with your code is the fact that the GdkWindow of a GtkWidget (widget->window) is only set when the widget has been realized, which normally happens when gtk_widget_show is called. You can tell it to realize earlier by calling gtk_widget_realize, but the documentation recommends connecting to the draw or realize signal instead.

C attempt to difference a generic pointer

I tried to call,
g_io_scheduler_push_job(job_func, &param, NULL, G_PRIORITY_HIGH, generator_cancellable);
In my C/gtk+ application for running job_func() in another thread then main program. But have segfault when I call this function, and debugger said that: ** userdata attempt to difference a generic pointer**
The job_func() code is,
gboolean job_func(GIOSchedulerJob *job, GCancellable *cancellable, gpointer user_data)
{
JobParam* job_param = (JobParam*)user_data;
build(NULL, job_param->mw);
return TRUE;
}
Where JobParam,
typedef struct _JobParam
{
GtkWidget* widget;
MainWin* mw;
}JobParam;
Where MainWin,
typedef struct _MainWin
{
GtkWindow parent;
GtkWidget* scroll;
GtkWidget* box;
GtkUIManager *uimanager;
} MainWin;
And build,
void build(GtkWidget* widget, MainWin* mw)
{
gtk_list_store_clear(mw->model);
}
How can I fix it?
Thank you.
You're messing with widgets (and related stuff) off the main thread, DON'T DO THAT.
GTK functions are not thread safe unless noted otherwise in the documentation, you cannot manipulate widgets (and I'm fairly certain the GtkTreeModel implementations) in any thread except the one running the main loop. Basically just don't. I think you might be able to do this if AND ONLY IF the GtkListStore is doesn't have any GtkTreeView attached to it. (and if you're doing lots of changes it's a good idea to disconnect it first anyway, saves redraws and lots of useless events)
EDIT: the reason I mention disconnecting the TreeView from the ListStore is because I expect that you're trying to do gtk_list_store_clear() in a separate thread because it's taking too long, it's a common problem, any time you're going to add/remove a large number of rows to/from a TreeModel you should first do gtk_tree_view_set_model(treeview, NULL);
Without seeing the full code, it's hard to determine what is going on. My guess is that param is allocated on the stack based on the way you're passing it in, so the address is invalid when your job_func is actually called is invalid and dereferences garbage.
Try allocating your param using malloc and then freeing it. You can pass in a GDestroyNotify which you can call free within.

Resources