I have a GUI application which is written in C/gtk+(v 2.x). If I clicked on a menu item of the main window, following function will get called and will show a dialog.
dialog_ui * create_dialog ()
{
dlg = malloc (sizeof(dialog_ui));
dlg->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
...
gtk_widget_show_all (dlg->window);
return dlg;
}
This is the dialog_ui structue
typedef struct _dialog_ui
{
GtkWidget * window;
...
} dialog_ui;
This is the dlg variable in the header file.
dialog_ui * dlg;
My problem is, i'm calling the malloc in the create_dialog function. But I can't figure out from where can I call free, because GUI is event driven. I thought about destroy-event, but I want to know the correct way to do this. Any ideas.. ?
Often times you have a modal dialog which you call using gtk_dialog_run() rather than gtk_widget_show(). The gtk_dialog_run() function will not return until the user closes the dialog, returning a response which you can use to determine if they clicked Yes, Ok, Cancel, Close, etc. You an see an example of that in the GtkDialog API documentation.
Since you're just showing your own GtkWindow, your main application code could connect to the "destroy" signal of the GtkWindow and free the struct that references the widget there.
As a side note, rather than using malloc, you may want to take a look at some of the Memory Allocation functions provided by GLib.
When you don't need the dialog anymore, and you're not going to access it anymore (for example when it's closed) you can free the allocated memory. Doing it in the destroy event is a good place.
Related
I'm trying to create a GTK-3 Application and in the initialization process I want to check if the GSetting's value is set, otherwise I want to show a "startup" dialog which will be only on the first run visible.
The GObject's has a _init suffix which can be used for the class initialization. In that case the MyGtkApplication will be constructed, which is based on GtkApplication. The GtkApplication has the startup-thing which can be used for the initialization too.
In that example, I still need to implement the _init function for GApplicationClass.
GApplicationClass *gapp_class;
gapp_class = G_APPLICATION_CLASS (class);
gapp_class->startup = app_startup;
// This must be always implemented, because the MyGtkApplication is "GtkApplication"-based class.
void app_init(MyGtkApplication *app) {
// Check and show the modal dialog if key does not exist?
}
// This will overwrite the GApplicatio's "startup".
void app_startup(GApplication *app) {
// Check and show the modal dialog if key does not exist?
}
Currently app_init does not have a body.
What is the difference and which one should I use?
Regards,
TheAifam5.
init is basically the constructor of the GApplication object. Use it for initializing the object's private data and putting it into a consistent state.
startup is invoked when the application starts. In particular, after you have called g_application_run() and the main event loop is started, and the application has checked that it is the only instance running. You don't want to show dialog boxes before then, so startup is the right place to do that.
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.
According to GObject reference
g_signal_connect_swapped(instance, detailed_signal, c_handler, data); connects a GCallback function to a signal for a particular object. The instance on which the signal is emitted and data will be swapped when calling the handler.
I don't quite get what this means. Does this mean that the data will point to the object pointed to byinstance and instance will point to the object that was pointed to by data or am I making a mistake here?
If former is the case then what is the logic behind this?
You understand correctly.
This allows you to do tricks like the following: You have a button (let's call it button), that is supposed to hide another widget (let's call it textview) when pressed.
You can then do
g_signal_connect_swapped(button, 'clicked', G_CALLBACK(gtk_widget_hide), textview);
to achieve that. When the button is pressed, it generates the 'clicked' signal, and the callback is called with textview as the first argument, and button as the second. In this case the callback is gtk_widget_hide() which only takes one argument, so the second argument is ignored, because that's the way the C calling convention works.
It's the same as the following, but shorter.
static void
on_button_clicked(GtkButton *button, GtkWidget *textview)
{
gtk_widget_hide(textview);
}
...elsewhere...
g_signal_connect(button, 'clicked', G_CALLBACK(on_button_clicked), textview);
Basically it saves you from having to write an extra function if you hand-code your interface. Of course, there may be some far more practical use that I've never understood.
I have seen RocketDock redirect the minimize animation in Vista so windows minimize to the dock, and am just curious how this was done. Is the actual minimize animation redirected to the dock, or is something like a hook to stop Windows from minimizing the window and RocketDock has a custom animation when the window is minimized?
I am working on an open source multi-monitor taskbar project called "OpenMMT." I've recently discovered (through many headaches) how to accomplish this.
The following explanation assumes that you know how to go about using RegisterShellHookWindow.
On the window procedure that will receive the shell hooks, look for HSHELL_GETMINRECT.
Now, from here on out is where I had problems. According to MSDN, the lparam member passed contains a pointer to a "SHELLHOOK" object. Which is true, however, I could not get it to work for the simple fact that the "rc" member of that structure, is a RECT that differs from the actual RECT structure in the Windows header files. The RECT in the header files uses LONG for its members, were as on here, we want SHORT.
Anyways, here's a snippet on how I accomplished this.
Structures to define:
typedef struct {
SHORT left;
SHORT top;
SHORT right;
SHORT bottom;
} REALRECT, *LPREALRECT;
typedef struct {
HWND hWnd;
REALRECT rc;
} DOCUMENT_ME_RIGHT_MICROSOFT, *LPDOCUMENT_ME_RIGHT_MICROSOFT;
Then on the Window Procedure:
case HSHELL_GETMINRECT:
{
LPDOCUMENT_ME_RIGHT_MICROSOFT lpShellHook = (LPDOCUMENT_ME_RIGHT_MICROSOFT)lParam;
// lpShellHook now contains all the info. If you want to change the location
// of the animation, simply change the lpShellHook->rc members to point
// to the right coordinates and then return TRUE;
return TRUE;
}
When minimizing programs from my application I encountered some instances where the animation would default back to the original one. I resolved this by minimizing them like so:
void MinimizeApp(HWND hWnd) {
SetForegroundWindow(hWnd);
ShowWindowAsync(hWnd, SW_MINIMIZE);
}
If you want more info regarding my project or you just want to peek at the source, feel free to do so at https://github.com/Fafson/OpenMMT
The ptMinPosition member of the WINDOWPLACEMENT structure specifies the coordinates of the window when it is minimized, so SetWindowPlacement function can be used to that effect. But some testing shows the window should not have a task bar button for that to work (i.e. no WS_EX_APPWINDOW).
I don't know how RocketDock works, but I guess this could be achieved by installing a global WH_CBT hook, and acting upon (setting the ex_style and then setting minimized coordinates) HCBT_MINMAX notification.
You can use the AnimateWindow API function, and pass it e.g. AW_HOR_POSITIVE | AW_VER_POSITIVE to get a diagonal animation.
I'd start with a global hook catching WM_SYSCOMMAND/SC_MINIMIZE, and use AnimateWindow to target the top right corner.
If this doesn't provide the desired effect, the next step would be to use WM_PRINT/WM_PRINTCLIENT to get a copy of the window into a bitmap (I believe this is what AnimateWindow does internally), then hiding the window and doing my own animation.
I tried to call,
g_io_scheduler_push_job(job_func, ¶m, 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.