For a Task I need to do a Simple Webbrowser. The task also says that I should turn the context menu of the Mouse Right-Click off by using the "context-menu" callback.
What I thought doing is:
g_signal_connect(G_OBJECT(-), "context-menu", G_CALLBACK(off_context), NULL);
void off_context(GtkWidget *w, gpointer data) {
return TRUE;
}
But I don't know to which GObject I need to conect it or if this would work.
If you meant to disable it in the main Window off your Webbrowswer(Web_View) than just do this:
g_signal_connect(G_OBJECT(web_view), "context-menu", G_CALLBACK(off_context), NULL);
In your function you return TRUE which means it can't be void, here you need gboolean:
gboolean off_context(GtkWidget *w, gpointer data) {
return TRUE;
}
Related
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]);
What I wanted to do is to connect the mouse click "clicked" signal and the keypress "key_press_event" signal to the same callback function. The code started off like this:
static void s_up(GtkWidget *btn,
gpointer data)
{
code ...
}
...
int main(int argc, char **argv)
{
...
g_signal_connect(button, "clicked", G_CALLBACK(s_up), NULL);
}
It handled mouse clicks just fine. Then I wanted to add keyboard presses to it. So I changed the code to
static void s_up(GtkWidget *btn,
GdkEventKey *event
gpointer data)
{
if(event->keyval == 's')
more code ...
}
...
int main(int argc, char **argv)
{
...
g_signal_connect(button, "key_press_event", G_CALLBACK(s_up), NULL);
}
It worked when I press "s" on my keyboard.
My question is how to connect both signals to the same s_up callback function? Other than the obvious problem of if(event->keyval == 's'), I tried calling both gtk_signal_connect, and when I clicked on the button, I got SegFault pointing to s_up. Pressing "s" didn't do anything. Any help is appreciated.
You can't connect both signals directly to the same signal handler because they require different arguments.
The reason why you get a segmentation fault is because event->keyval only makes sense when you receive a key-press-event. When you receive a clicked event the second argument will be NULL, since it maps to the gpointer argument supplied with clicked events and you've set that to NULL when you installed the signal handler, so event will be NULL.
If the reason why you want to connect both signals to the same handler is that you have common code that should run no matter which signal triggered it, then the solution is to have one handler for each signal and a third function with common code that both of them can call.
Use a wrapper function to indirectly call the same callback:
static void
callback(GtkWidget *button, gpointer data)
{
/* TODO */
}
static gboolean
wrapper(GtkWidget *button, GdkEventKey *event, gpointer data)
{
if (event->keyval == 's')
callback(button, data);
return FALSE;
}
int
main(int argc, char **argv)
{
/* TODO */
g_signal_connect(button, "clicked", G_CALLBACK(callback), NULL);
g_signal_connect(button, "key-press-event", G_CALLBACK(wrapper), NULL);
/* TODO */
}
If you do not use data you can also use a single function, but in my opinion the complexity introduced is not worth the effort:
static gboolean
callback(GtkWidget *button, GdkEventKey *event)
{
if (event != NULL && event->keyval == 's')
callback(button, data);
return FALSE;
}
int
main(int argc, char **argv)
{
/* TODO */
g_signal_connect(button, "clicked", G_CALLBACK(callback), NULL);
g_signal_connect(button, "key-press-event", G_CALLBACK(callback), NULL);
/* TODO */
}
To be able to understand the latter example you must know that:
the return value is discarded if not used (you must return FALSE from a key press event if you don't want to stop the event handling);
the extra arguments in callbacks are silently discarded.
This means when callback() is called by a click you have the data value (NULL) in event while when it is called from a key press the event is properly set and data is silently discarded.
This in turn means if you add a check for event != NULL in your second example things start working.
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 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 :)