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
Related
I have a program written in C using the GTK library. In the GUI I have a set of radio buttons, and depending on what button is selected changes if an entry can be edited (or sensitive as gtk calls it).
I have made a struct with all the widgets that I need to pass to my signal handlers. It looks like this (with other widgets removed for simplicity).
typedef struct _gui_ctx {
// more widgets in here
GtkWidget *entry;
} gui_ctx;
And in main I define one like so
gui_ctx ctx;
My entry looks like
GtkWidget *entry = gtk_entry_new();
ctx.entry = entry; //add it to the ctx
My radio buttons look like
GtkWidget *radio_key = gtk_radio_button_new_with_label(NULL, "Key");
GtkWidget *radio_password = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_key), "Password");
GtkWidget *radio_random = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio_key), "Random");
I attach the signal handlers as such
g_signal_connect(radio_key, "toggled", G_CALLBACK(use_key), &ctx);
g_signal_connect(radio_password, "toggled", G_CALLBACK(use_password), &ctx);
g_signal_connect(radio_random, "toggled", G_CALLBACK(use_random), &ctx);
The signal handlers are all basically the same. They are all the same type like so
void use_key(GtkWidget *widget, GdkEvent *event, gpointer data){
gui_ctx *ctx = (gui_ctx *) data;
GtkWidget *entry = ctx->entry;
gtk_widget_set_sensitive(entry, TRUE); // crashes here
}
The program crashes on the last line of the handler function. It says
Segmentation fault (core dumped)
I have tried to find why the issue is happening but it always crashes on that line. Both data and entry are not null so I don't know what's going wrong.
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.
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.
GTK uses the GSEAL option to prevent someones access to the Widget-struct.
That's great, because of objective programming in C you should use get-functions like in other languages.
Because there are no get-function for each value of GtkButton, I have some problems modifying my own GtkWidgets.
I want access to these values in struct _GtkButton
struct _GtkButton
{
....
guint GSEAL (activate_timeout);
guint GSEAL (in_button) : 1;
guint GSEAL (button_down) : 1;
....
}
I want to add an on-click event for mybutton, to cancel click events before they will be called, so I decided to reimplement:
static void gtk_real_button_pressed(GtkButton *button)
{
if (button->activate_timeout)
return;
button->button_down = TRUE;
gtk_button_update_state(button);
}
static void gtk_real_button_released(GtkButton *button)
{
if (button->button_down)
{
button->button_down = FALSE;
if (button->activate_timeout)
return;
if (button->in_button)
{
// do my own stuff here and maybe don'tcall "gtk_button_clicked(...)"
gtk_button_clicked(button);
}
gtk_button_update_state(button);
}
}
as I say at the top I now need access to button->in_button for example.
Anybody has an clue, that could help me ? :)
by the way:
guint GSEAL (button_down) : 1;
I can't figure out whats the use of : 1 in this case. :O
You have never been supposed to access those fields in the GtkButton instance structure: they are private, and only available for internal use (the reason why they are not truly private like in modern GTK code is because GtkButton existed long before we could add instance private data inside GObject - long story).
The GtkButton::clicked signal is marked at RUN_FIRST, which means that the default signal handler associated to the class is run before any callback attached using g_signal_connect().
If you want to prevent the GtkButton::clicked signal from being emitted (which is not a great idea to begin with, anyway) you can use a signal emission hook, or you can subclass GtkButton and stop the signal emission from within the default handler.
You should NEVER access the member variables like this. EVER. These are private variables. That is why GSeal was introduced. Your code may break on updates to GTK+
I now use this little function, using the gseal values was realy nothing i should do.
typedef struct _GuiOnClickHandler GuiOnClickHandler;
struct _GuiOnClickHandler
{
gboolean abortClick;
};
static void gui_recipe_button_clicked(GtkWidget *widget, gpointer data)
{
GuiOnClickHandler handler;
handler.abortClick = FALSE;
g_signal_emit_by_name((gpointer)widget, "on-click", &handler);
if (handler.abortClick)
g_signal_stop_emission_by_name((gpointer)widget, "clicked");
}
...somewhere else on init, at first place
g_signal_connect(GTK_OBJECT (button), "clicked",
G_CALLBACK (gui_recipe_button_clicked), NULL);
As shown in the example below, this callback function is when the user clicks an OK button. I can get window (the top level widget) from button by using gtk_widget_get_toplevel, but I'm stuck trying to get a widget pointer for a GtkEntry widget with name ENTRY.
/* Called when OK button is clicked */
on_BT_OK_clicked(GtkButton *button, gpointer user_data)
{
//The line directly below is the one I get an error on
GtkWidget *entry = lookup_widget( GTK_WIDGET(button), "ENTRY" );
gchar *text1, *text2;
text1 = gtk_entry_get_text( GTK_ENTRY(entry));
text2 = g_strconcat("Hello, ", text1, NULL);
GtkWidget *window = gtk_widget_get_toplevel (GTK_WIDGET(button));
GtkWidget *dialog = gtk_message_dialog_new( window,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_CLOSE,
text2);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
But I get the error "undefined reference to lookup_widget." I can find a billion examples of snippets of code using lookup_widget, but not a single one full source code example showing the headers that enable the use of it. I'm using Anjuta3.2.0 and the latest Glade plugin.
As Basile Starynkevitch says, lookup_widget() was a function generated by Glade 2. However, code generation by Glade has been deprecated for quite a long time now, in favor of (first) libglade and (later) GtkBuilder. In fact, Glade 3 won't even do it.
The preferred solution is to pass a pointer to your ENTRY as the user data pointer when you connect the signal, or, if you're using gtk_builder_connect_signals(), store a pointer to ENTRY in your class and pass the class as the user data pointer.
However, if you must use lookup_widget(), here's the source that Glade 2 generated as of about 6 years ago:
GtkWidget*
lookup_widget (GtkWidget *widget,
const gchar *widget_name)
{
GtkWidget *parent, *found_widget;
for (;;)
{
if (GTK_IS_MENU (widget))
parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
else
parent = widget->parent;
if (!parent)
parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
if (parent == NULL)
break;
widget = parent;
}
found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
widget_name);
if (!found_widget)
g_warning ("Widget not found: %s", widget_name);
return found_widget;
}
For this to work, you have to do the following for every widget contained within a toplevel window:
g_object_set_data_full (G_OBJECT (toplevel), "name-of-widget", gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref);
and then the following once for each toplevel window:
g_object_set_data (G_OBJECT (toplevel), "name-of-toplevel", toplevel);
Seems to me to be more trouble than it's worth.
Glade-2 implements lookup_widget() in support.c and the header is support.h
Once the GLADE GUI is converted to C codes these files are generated automatically.