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.
Related
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.
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);
I am learning GTK+ and this simple application crashes every time I run it.
It creates a label in the main window, and every time a button is clicked (the key_press_event) the label and the title should swap.
If I comment out the gtk_label_set_text in the change_title function the title alternates correctly and the app doesn't crash. Why does gtk_label_set_text crash my app?
#include <gtk/gtk.h>
#include <string.h>
const gchar first[]="FIRST";
const gchar last[]="LAST";
static void destroy(GtkWidget *window,gpointer data)
{
gtk_main_quit();
}
static gboolean change_title(GtkWidget *widget,GtkLabel *data)
{
if(strcmp(last,gtk_window_get_title(GTK_WINDOW(widget)))){
gtk_window_set_title(GTK_WINDOW(widget),last);
gtk_label_set_text(data,first);
} else {
gtk_window_set_title(GTK_WINDOW(widget),first);
gtk_label_set_text(data,last);
}
return FALSE;
}
int main(int argc,char **argv)
{
GtkWidget *window, *label;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),last);
gtk_widget_set_size_request(window,300,100);
g_signal_connect(window,"destroy_event",G_CALLBACK(destroy),NULL);
label = gtk_label_new("caasdasdjadnjadjahadjad");
gtk_container_add(GTK_CONTAINER(window),label);
g_signal_connect(window,"key_press_event",G_CALLBACK(change_title),GTK_LABEL(label));
gtk_widget_show_all(window);
gtk_main();
return 0;
}
EDIT: I found the problem using GDB, the label pointer isn't passed correctly to the change_title function. I don't know why. (Ex: in main() label = 0xb6406608 , in change_title() label = 0x807bda8)
After doing a simple Google search on key_press_event I saw that the callback to that event have another argument between the widget and the user-data pointer. The prototype is this:
gboolean key_event_handler(GtkWidget *widget,GdkEventKey *event, gpointer data);
So simple change your function to this:
static gboolean change_title(GtkWidget *widget, GdkEventKey *event, GtkLabel *data)
and it should work.
Your change_title function has the wrong prototype.
See the documentation for the proper prototype. Most *-event signals pass the actual event as an argument in the handler function, since the handler typically needs to inspect the event in order to execute. For instance, here the GdkEventKey event will contain information about which key was pressed (or released).
I'm trying to find a way to find out which key is pressed down in C. This will be in a graphical environment, written in GTK2, but I don't think the answer lies there. I think I might be able to do this using Xlib, but I haven't been able to find anything conclusive on this.
Does anyone have any suggestions on how to do this?
I've managed to catch a keypress using the follow code:
GtkWidget *window;
void gtk_widget_set_events(window,GDK_KEY_RELEASE_MASK);
g_signal_connect(window,"key_release_event",G_CALLBACK(hello),NULL);
However, I would like to identify which key is pressed. From the link posted by Aditya Kumar, I know the answer lies with using GdkEventKey, since it is a structure which has a keyval field, but I cannot seem to get the syntax right. What is the correct way of getting this number?
This is a method I've tried:
static void hello( GtkWidget *widget,
guint data ){
g_print ("Hello World, %d was pressed\n",data);}
I tried supplying "data" by doing this when I catch the key_release_event:
g_signal_connect(window,"key_release_event",G_CALLBACK(hello),GdkEventKey.keyval);
However, I get a compiler error like so:
hello.c:85:5: error: expected ‘)’ before ‘.’ token
hello.c:85:5: error: expected expression before ‘,’ token
You are correct with your original syntax.
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
Where the key_event function looks something like (note I am using the gdk_keyval_name to convert the keyval int value to a string for printing):
static gboolean
key_event(GtkWidget *widget,
GdkEventKey *event)
{
g_printerr("%s\n",
gdk_keyval_name (event->keyval));
return FALSE;
}
Here's a complete example program:
#include <gtk/gtk.h>
static gboolean
key_event(GtkWidget *widget,
GdkEventKey *event)
{
g_printerr("%s\n",
gdk_keyval_name (event->keyval));
return FALSE;
}
int main( int argc,
char *argv[] )
{
GtkWidget *window;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
gtk_widget_show (window);
gtk_main ();
return 0;
}
while looking at the gdk reference manual i think you can capture the keyboard events using this unless you specifically want to have a 'C' program.
Here is the link to help you out.
http://www.gtk.org/api/2.6/gdk/gdk-Keyboard-Handling.html
event->keyval is a pointer to a struct, where keyval contains a integer value for the key pressed, this has been used above in a function gdk_keyval_name (event->keyval) which gets a actual name for the key.