Place popup menu below widget GTK - c

I am having some trouble placing my popup menu where I want in GTK(along the same y axis as my button so it seems to dropdown from the button).
I got it working when I was coding a similar thing in win32 but for the life of me I cannot get this thing to draw where I want!
I've done my research and I know what (I think) should work and that is when I make the call to
gtk_menu_popup()
I should pass it in a function pointer to a method for placing the popup (link to the method specification - http://developer.gnome.org/gtk/2.24/GtkMenu.html#GtkMenuPositionFunc )
But i'm a bit rubbish with function pointers ( I have the Kernighan and ritchie book beside as I speak) but I'm pretty sure I'm doing it right.
Heres my attempt at the method :
void set_position(GtkMenu *menu,gint *x,gint *y,gboolean push_in,gpointer user_data)
{
printf("Help!\n";
GtkWidget *originButton = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(menu),"button");
gdk_window_get_position(originButton->window,x,y);
//now I realise this will place it at the top of the widget but thats acceptable for now, I just want the method to be called!
}
I call it from the button handler by doing this :
static gboolean handler (GtkWidget *widget,GdkEvent *event)
{
GdkEventButton *bevent = (GdkEventButton *) event;
gtk_menu_popup(GTK_MENU(widget),NULL,NULL,set_position,bevent->button,bevent->button,bevent->time);
}
But when I compile this it says its not a GtkMenuPositionFunc, so I just cast it (dont know if thats right though).
The problem is that I dont think my method is getting called because it never prints out help :( plus it still spawns the menu wherever I click (probably due to it not calling the method or whatever it should be doing).
Any help/ideas would be greatly received :) thanks :)

I had the same problem earlier. I used the following code.
static void
set_position(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
{
GtkWidget *button = GTK_BUTTON(user_data);
gdk_window_get_origin(button->window, x, y);
*x += button->allocation.x;
*y += (button->allocation.y + (button->allocation.height));
}
static void
handler(GtkWidget *menu, GtkWidget *button)
{
GtkRequisition requisition;
gtk_widget_size_request(menu, &requisition);
if (button->allocation.width > requisition.width)
gtk_widget_set_size_request(menu, button->allocation.width, -1);
gtk_menu_popup(GTK_MENU (menu),
NULL, NULL,
(GtkMenuPositionFunc) set_position, button,
0, gtk_get_current_event_time());
}

Okay, thanks very much to Pfeiffer for his sample code. I had to make some changes to it because I was getting compiler errors (i have Werror on though).
In the set poisition method I ended up casting to a GTK_WIDGET instead of a GTK_BUTTON becauses thats what it was expecting
So my new set position method looked like :
static void set_position(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data) {
GtkWidget *button = GTK_WIDGET(user_data);
gdk_window_get_origin(button->window, x, y);
*x += button->allocation.x;
*y += (button->allocation.y + (button->allocation.height));
}
And as I couldn't figure out how to connect and pass the two widgets that Pfeiffer was passing I have this currently :
static gboolean handler(GtkWidget *widget, gpointer data) {
gtk_menu_popup(GTK_MENU(data), NULL, NULL,(GtkMenuPositionFunc)set_position,widget,(guint)widget, gtk_get_current_event_time());
return TRUE;
}
Also had to cast widget to a (guint) otherwise I got a compiler error about the 6th parameter :)
I will probably end up putting more in this method but this is the bare minimum I needed to get it to work.
That is connected using the normal gtk_signal_connect method
gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(handler), GTK_OBJECT(menu));
where button and menu are GtkButton and GtkMenu instances I was using previously :)
Full credit goes to Pfeiffer for the answer, i'm just showing what worked for me :)
Thanks and hope this helps someone :)

Related

Changing GTK label in C using signal_connect

Hello I am making GUI in GTK I have some menu items, and I am trying to change main label after clicking a mouse on specific menu element.
widgets[i][0] = gtk_menu_item_new_with_label(arrayOfStrings[i]);
//arrayOfStrings is : char** arrayOfStrings
gtk_menu_shell_append(GTK_MENU_SHELL(indicator_menu), widgets[i][0]);
I was trying this:
void set_main_label(GtkWidget *widget)
{
app_indicator_set_label(indicator, arrayOfString[2],arrayOfString[2]);
}
and after this I call it like:
g_signal_connect(widgets[i][0], "activate",G_CALLBACK(set_main_label), widgets[i][0]);
But my problem is that void set_main_label(void) must have void argument. And I need to pass there string (char*) which is stored in arrayOfStrings. What do you suggest? Now I can change label only to one specific string set in set_main_label function, but I cannot pass it as an argument into function, what do you suggest? .
This is what the user_data parameter is for. set_main_label() does not have a void argument list - check the documentation:
void
user_function (GtkMenuItem *widget,
gpointer user_data)
You can pass any argument you like into the callback via the user_data parameter. But it must be known at the time you connect the signal.
So you could do something like this:
void
set_main_label(GtkMenuItem *widget, gpointer user_data)
{
const char *label = (const char *)user_data;
app_indicator_set_label(indicator, label, label);
}
g_signal_connect(widgets[i][0], "activate",
G_CALLBACK(set_main_label), arrayOfString[2]);

How do i get access to 'gseal'ed values from gtk widget | modify GtkWidgets

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);

Implementation of gtk3's new Height-for-width Geometry Management method

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?

GTK gtk_label_set_text segmentation fault

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).

Detect which key is pressed in C

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.

Resources