I have a main.c file where a progress bar is created and then it will be updated by other.c file.
Inside the main.c file i have this:
static void
a_func ( GtkWidget *dialog,
struct widget_t *Widget,
gint mode)
{
....
....
Widget->pBar = gtk_progress_bar_new ();
....
....
}
which create and run a dialog. When OK is pushed my_func (Widget); will be called.
Inside the other.c file i have this:
static gboolean
fill (gpointer data)
{
GtkWidget *bar = data;
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (bar));
return TRUE;
}
gint my_func (struct mystruct_t *Widget){
....
....
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (Widget->pBar));
g_timeout_add (100, fill, GTK_PROGRESS_BAR (Widget->pBar));
while (gtk_events_pending ())
gtk_main_iteration ();
....
....
}
The problem is that i'm getting this error:
GLib-GObject-WARNING **: invalid unclassed pointer in cast to 'GtkProgressBar'
Gtk-CRITICAL **: gtk_progress_bar_pulse: assertion 'GTK_IS_PROGRESS_BAR (pbar)' failed
EDIT 1:
This is a compilable example: https://gist.github.com/polslinux/96e7b18176ac66e50ee1
EDIT 2:
This is a simple workflow graph: http://it.tinypic.com/r/316us0y/8
This can not work:
crypt_file (Widget);
gtk_widget_destroy (dialog);
You add a GSource to your mainloop which modifies Widget->pBar but you never remove it. On the other hand you destroy the dialog (and thus also pBar itself as it is part of the widget sub-tree) which in turn renders Widget->pBar useless/makes it a dangling pointer.
Things you did not ask for (excuse the direct approach)
Your variable names are crappy at best, upper lower case, calling things Widget which are no widgets but mere structs.
Make sure you do not split into callbacks and other C functions. That will end up totally messy as your project grows.
Try to go for object-orientation. Create a GObject derived klass which handles the mess internally instead of passing translucent structs around.
Related
I have GTK GUI where it has a control button that opens a new window called c_window in my struct. c_window has a quit button that I need to connect to the c_quit function. When I tried to do so the window is not terminated and a warning keeps appearing each time I pressed on quit button:
(main_menu:2682): Gtk-CRITICAL **: 06:30:38.469: gtk_widget_destroy: assertion 'GTK_IS_WIDGET (widget)' failed
my c_quit function is:
static gboolean c_quit (gpointer userData)
{
message_details *details = (message_details *)userData;
gtk_widget_destroy (details->c_window);
return FALSE;
}
how do I connect it from the main
g_signal_connect(G_OBJECT(details->c_quit), "clicked", G_CALLBACK (c_quit), details->c_window);
Please note that details is my struct where I define my GtkWidget elements.
First of all, your signal connection function is:
g_signal_connect(G_OBJECT(details->c_quit), "clicked", G_CALLBACK (c_quit), details->c_window);
Which contains an unnecessary cast for details->c_quit. Additionally, you're passing the c_window field of the details pointer.
Next, your callback is:
static gboolean c_quit (gpointer userData)
{
message_details *details = (message_details *)userData;
gtk_widget_destroy (details->c_window);
return FALSE;
}
which has the wrong signature for a callback to the GtkButton::clicked signal; the correct signature would be:
static void
c_quit (GtkButton *button, gpointer data)
Additionally, I'd recommend using a proper function name for the callback, so you can easily understand what it does, and where it's referenced. For instance, something quit_button__clicked.
Inside your callback you're accessing the wrong parameter, with the wrong type:
message_details *details = (message_details *)userData;
Because you're not passing the details data, you're passing a pointer to the window itself. Additionally, gpointer is an alias to void*, and C allows implicit casting to and from a void*; this means you don't need an explicit cast there.
So, to recap:
connect the signal properly, using the correct arguments to send to your callback:
g_signal_connect (details->c_quit, "clicked",
G_CALLBACK (quit_button__clicked),
details);
use the right prototype for the signal you're connecting to, and access the right data:
static void
quit_button__clicked (GtkButton *button G_GNUC_UNUSED,
gpointer user_data)
{
message_details *details = user_data;
gtk_widget_destroy (details->c_window);
}
If you just want to call gtk_widget_destroy() on the window widget in response to a clicked signal on a GtkButton, you can also condense everything into a single call:
g_signal_connect_swapped (details->c_quit, "clicked",
G_CALLBACK (gtk_widget_destroy),
details->c_window);
The g_signal_connect_swapped() function will swap the first and last arguments of the signal when invoking the callback—the first argument being the instance that emitted the signal, and the last argument being the user data passed to connection function. This means that gtk_widget_destroy() will be called with the user data argument of g_signal_connect_swapped().
I trying to swap the window title with the label inside the window on
keypress.
Below is my code :
#include<gtk/gtk.h>
static gboolean key_press_event(GtkWidget*,GdkEvent*,gpointer);
int main(int argv, char* argc[])
{
GtkWidget *window,*label;
gtk_init(&argv,&argc);
window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Sajith");
gtk_widget_set_size_request(window,300,100);
label=gtk_label_new("Sam");
gtk_label_set_selectable(GTK_LABEL(label),TRUE);
gtk_container_add(GTK_CONTAINER(window),label);
g_signal_connect(G_OBJECT(window),"key_press_event",
G_CALLBACK(key_press_event),label);
gtk_widget_show_all(window);
gtk_main();
}
static gboolean key_press_event(GtkWidget* window, GdkEvent* event, gpointer label)
{
GtkWidget* newlabel;
newlabel=GTK_LABEL(label);
const gchar* wtitle=gtk_window_get_title(GTK_WINDOW(window));
gtk_window_set_title(GTK_WINDOW(window),gtk_label_get_text(GTK_LABEL(newlabel)));
gtk_label_set_text(GTK_LABEL(newlabel),wtitle);
/* I am not sure if I could pass wtitle here*/
return FALSE;
}
On execution the window title is successfully swapped but the label is not.
Also, I get the following warning at the terminal.
(2p1:12005): Pango-WARNING **: Invalid UTF-8 string passed to pango_layout_set_text()
Any help appreciated.
gtk_window_get_title() returns a static buffer owned by the window. This buffer will have been changed after the gtk_window_set_title() call.
To achieve what you want, you should, in your callback function, create a copy of the string. You can use strdup(), but it may not be available on all platforms. Since you are using GTK+ which depends on GLib, you can use g_strdup(). Example:
gchar* wtitle = g_strdup(gtk_window_get_title(GTK_WINDOW(window)));
Remember to free it before the callback function returns with g_free(wtitle).
As for the return value, since the callback function returns gboolean, you cannot return wtitle. For your case, I don't see any difference between returning TRUE or FALSE, as there aren't any default handlers anyway. If, instead of a label, you are using something like a GtkEntry, then you would return TRUE if you don't want the text in the entry to be replaced by your input key.
I'm attempting to attach to a toolbar button a signal associated with a keystroke supported by GtkTextView (CTRL+a, CTRL+x, etc) using the following widget structure, signal connect, and callback:
typedef struct
{
GtkWidget *window;
GtkWidget *text_view;
}EditorWidgets;
//...
g_signal_connect(cut, "clicked", G_CALLBACK(cut_button_press), editor_widgets);
//...
static void cut_button_press(GtkWidget *button, EditorWidgets *editor_widgets)
{
UNUSED(button);
GdkEvent *event = gdk_event_new(GDK_KEY_PRESS);
event->key.window = gtk_widget_get_window(editor_widgets->window);
event->key.send_event = FALSE;
event->key.time = 0;
event->key.state = GDK_CONTROL_MASK;
event->key.keyval = GDK_KEY_x;
event->key.string = g_strdup("x");
event->key.length = strlen(event->key.string);
gtk_main_do_event(event);
gdk_event_free(event);
}
When run, GDK complains with the following:
(ex1:7856): Gdk-WARNING **: Event with type 8 not holding a GdkDevice. It is most likely synthesized outside Gdk/GTK+
Which lets me know I've created the signal improperly (I assume). However, there's very little out there about having buttons emit GDK signals, so I'm at a loss for what's missing here.
As a secondary question, I remember reading somewhere that there was a GDK #define for TIME_NOW or something, but I couldn't find it again. Any hints there?
1.use "key-press-event" instead of clicked, clicked was associated with mouse pointer and keyboard enter key, something like (in python):
def on_key_press (self, widget, event):
if event.keyval == 120:
print ('test')
2.GDK_CURRENT_TIME, define at Gdk.Event class
I have a table that is filled with entry boxes, labels, and buttons.
Currently, if I compile the code, I can get input from a text box but only if the users presses the enter key, and the text only comes from the box they are currently typing in.
I would like to be able to get input from both text boxes when the "Login" button is pushed. I've tried using the same callback function that's used for enter key on the entry box, but GTK gives me an error.
If anyone could show me some code that would allow for me to get text from my entry boxes that are within tables (I know the method for retrieving data from tables and v/boxes is different) it would be greatly appreciated, as I can't seem to find it in any tutorials.
Will update w/working code.
Error when trying to attach status bar to table:
(Entry:5526): Gtk-CRITICAL **: gtk_table_attach: assertion `child->parent == NULL' failed
(Entry:5526): GLib-GObject-WARNING **: invalid cast from GtkTable' toGtkStatusbar'
Your callback function (named callback) needs to access both GtkEntry widgets in order to obtain their values. There are several ways this can be accomplished. Many GTK C programs use global variables, or global variables with file scope (ie a variable declared as static outside of any function within a file).
Remove your entry1 and entry2 variables near the top of the file before any functions:
static GtkWidget *entry1 = 0;
static GtkWidget *entry2 = 0;
And then modify the callback like so:
/* Our callback.
* The data passed to this function is printed to stdout */
static void callback( GtkWidget *widget, gpointer data)
{
const gchar *entry_text1;
const gchar *entry_text2;
g_print ("Hello again - %s was pressed\n", (char *) data);
entry_text1 = gtk_entry_get_text (GTK_ENTRY (entry1));
entry_text2 = gtk_entry_get_text (GTK_ENTRY (entry2));
g_print ("Contents of entries:\n%s\n%s\n", entry_text1, entry_text2);
}
You should additionally make similar modifications to the enter_callback function, and don't forget to remove the GtkWidget pointers to both GtkEntry from main.
As an alternative to using (static) global variables, create a data structure to hold the entries:
typedef struct login_data
{
GtkWidget *entry1;
GtkWidget *entry2;
} login_data;
This then gets passed to the callback (rather than text string as before), and the callback changes like so:
static void callback( GtkWidget *widget, gpointer data)
{
login_data* ld = (login_data*)data;
const gchar *entry_text1;
const gchar *entry_text2;
entry_text1 = gtk_entry_get_text (GTK_ENTRY (ld->entry1));
entry_text2 = gtk_entry_get_text (GTK_ENTRY (ld->entry2));
g_print ("Contents of entries:\n%s\n%s\n", entry_text1, entry_text2);
}
The data structure is dynamically allocated to prevent it going out of scope (not strictly necessary in simple applications) and this is done before using g_signal_connect to connect the callback to the entries:
login_data* ld = g_malloc(sizeof(*ld));
// callback function to execute when login is clicked
g_signal_connect (LoginButton, "clicked", G_CALLBACK (callback), (gpointer) ld);
Using this method, you must change all references to entry1 and entry2 to ld->entry1 and ld->entry2. Lastly, before the program exits, you should call g_free on the dynamically allocated struct ie g_free(ld).
BTW, for this program you don't need two separate callbacks, remove enter_callback and just use callback for both.
In continuation of my previous question
Drag and drop on a fixed container changes its size
I followed the advice given from ergosys and read the info in the link he provided.
If I understood correctly, the new way of declaring
/* LEFT FRAME */
frame1= gtk_frame_new(NULL);
gtk_table_attach(GTK_TABLE(table), frame1, 0,14,0,49,GTK_SHRINK,GTK_SHRINK,0,0);
gtk_widget_set_size_request(frame1, 360,570);
is (ignore the height for the time being)
static void
my_widget_get_preferred_width (GtkWidget *widget,
gint *minimal_width,
gint *natural_width)
{
GtkRequisition requisition;
gtk_widget_get_requisition (widget, &requisition);
*minimal_width = *natural_width = requisition.width;
}
....
/* LEFT FRAME */
frame1= gtk_frame_new(NULL);
gtk_table_attach(GTK_TABLE(table), frame1, 0,14,0,49,GTK_SHRINK,GTK_SHRINK,0,0);
gint min_width=360;
gint nat_width=360;
GTK_WIDGET_GET_CLASS(frame1)->get_preferred_width=my_widget_get_preferred_width;
my_widget_get_preferred_width(frame1,&min_width,&nat_width);
It compiles OK, but, when run, it gives me this error:
(conky_companion:19700): Gtk-WARNING **: GtkFrame 0xa00e660: widget tried to gtk_widget_get_width inside GtkWidget ::get_width implementation. Should just invoke GTK_WIDGET_GET_CLASS(widget)->get_width directly rather than using gtk_widget_get_width
without ever drawing the window and it segfaults after a while.
What am I missing here?
Or, TL;DR, what is the equivalent of
gtk_widget_set_size_request(frame1, 360,570);
in gtk3?