I have tried to subscribe to touch events as:
g_signal_connect (G_OBJECT(hw), "touch-event", G_CALLBACK (gw_touch_event), pview);
but my gw_touch_event callback function is never called. Is it only for touch screens?
Question: how to receive touchpad events in GTK3 and in GTK4 ?
More details:
On "two-finger-scroll" gesture GdkEventScroll handler correctly reports GDK_SOURCE_TOUCHPAD:
GdkDevice *device = gdk_event_get_source_device(event);
if(!device) return;
GdkInputSource is = gdk_device_get_source (device);
bool is_touchpad = is == GDK_SOURCE_TOUCHPAD;
But Gtk Inspector application shows zero count of "touch-event" handler invocations.
Also my generic "event" signal handler also shows nothing here:
gboolean gw_event (GtkWidget* self, GdkEvent* event, gpointer user_data) {
GdkEventType et = gdk_event_get_event_type (event);
switch(et) {
case GDK_TOUCH_BEGIN:
case GDK_TOUCH_UPDATE:
case GDK_TOUCH_END:
case GDK_TOUCH_CANCEL:
case GDK_TOUCHPAD_SWIPE:
case GDK_TOUCHPAD_PINCH:
g_message("TOUCH EVENT: %d",et);
return false;
}
return false;
}
Related
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;
}
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
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.
I'm having the hardest time getting an integer passed to a callback function, since the last argument of g_signal_connect is required to be a pointer. Here is where I connect the signal to the callback:
for (i=0;i<10;i++)
{
...
gtk_widget_set_events(tab_ebs[i],GDK_BUTTON_PRESS_MASK);
g_signal_connect (G_OBJECT (tab_ebs[i]), "button_press_event", G_CALLBACK (tab_clicked_cb), GINT_TO_POINTER(i));
}
and here is the callback:
void tab_clicked_cb (gpointer p)
{
printf("tab #%d clicked\n", GPOINTER_TO_INT(p));
}
What I get in stdout, are statements such as:
tab #6578976 clicked
tab #6579264 clicked
tab #6579552 clicked
tab #6579840 clicked
When I only have ten tabs. How can I pass an integer to a callback fcn on a 64 bit system? Thanks.
nos got me half way there. Turns out I was also missing an argument for the event in my callback function. Here is the form that worked:
void tab_clicked (GtkWidget *widget, GdkEventButton *ev, gpointer p)
{
printf("tab #%d clicked\n", GPOINTER_TO_INT(p));
}
Your callback function is likely wrong, most Gtk callback handlers passes the widget that originated the event as the first parameter to the callback function. So it should be e.g.
void tab_clicked_cb (GtkWidget *widget, gpointer p)
{
printf("tab #%d clicked\n", GPOINTER_TO_INT(p));
}
Edit, The Gtk docs are not at all clear on what it's callback handler is for the button_press_event, the docs read as the callback handler for button_press_event doesn't receive any arguments.
I have been trying to implement Win32's MessageBox using GTK. The app uses SDL/OpenGL, so this isn't a GTK app.
I handle the initialization (gtk_init) sort of stuff inside the MessageBox function as follows:
int MessageBox(HWND hwnd, const char* text, const char* caption, UINT type)
{
GtkWidget *window = NULL;
GtkWidget *dialog = NULL;
gtk_init(>kArgc, >kArgv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);
// gcallback calls gtk_main_quit()
gtk_init_add((GtkFunction)gcallback, NULL);
if (type & MB_YESNO) {
dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, text);
} else {
dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, text);
}
gtk_window_set_title(GTK_WINDOW(dialog), caption);
gint result = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_main();
gtk_widget_destroy(dialog);
if (type & MB_YESNO) {
switch (result) {
default:
case GTK_RESPONSE_DELETE_EVENT:
case GTK_RESPONSE_NO:
return IDNO;
break;
case GTK_RESPONSE_YES:
return IDYES;
break;
}
}
return IDOK;
}
Now, I am by no means an experienced GTK programmer, and I realize that I'm probably doing something horribly wrong.
However, my problem is that the last dialog popped up with this function staying around until the process exits. Any ideas?
Hmm, ok. I'd suggest code like this, then:
typedef struct {
int type;
int result;
} DialogData;
static gboolean
display_dialog(gpointer user_data)
{
DialogData *dialog_data = user_data;
GtkWidget *dialog;
if (dialog_data->type & MB_YESNO)
dialog = gtk_message_dialog_new(...);
else
dialog = gtk_message_dialog_new(...);
// Set title, etc.
dialog_data->result = gtk_dialog_run(...);
gtk_main_quit(); // Quits the main loop run in MessageBox()
return FALSE;
}
int MessageBox(...)
{
DialogData dialog_data;
dialog_data.type = type;
gtk_idle_add(display_dialog, &dialog_data);
gtk_main();
// Do stuff based on dialog_data.result
}
The struct is required because you need to pass around a couple pieces of data. The gtk_idle_add() call adds a method to be run when the main loop is running and idle, and the FALSE return value from the display_dialog() call means that it's only run once. After we get the result from the dialog, we quit the main loop. That'll cause the gtk_main() in your main MessageBox() method to return, and you'll be able to access the result from there.
To manage a dialog box with GTK+, use a GtkDialog and gtk_dialog_run() instead of managing a window and a main loop by yourself.
EDIT / ADDENDUM :
What I mean is "just use" : I don't understand why you create a windows you never use and a main loop which seems useless (at least from the piece of code you posted). You can write something as short as :
int MessageBox(HWND hwnd, const char* text, const char* caption, UINT type)
{
GtkWidget *dialog ;
/* Instead of 0, use GTK_DIALOG_MODAL to get a modal dialog box */
if (type & MB_YESNO)
dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, text );
else
dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, text );
gtk_window_set_title(GTK_WINDOW(dialog), caption);
gint result = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy( GTK_WIDGET(dialog) );
if (type & MB_YESNO)
{
switch (result)
{
default:
case GTK_RESPONSE_DELETE_EVENT:
case GTK_RESPONSE_NO:
return IDNO;
case GTK_RESPONSE_YES:
return IDYES;
}
return IDOK;
}
}
A few things:
You are creating (and not using) an unnecessary toplevel window, named window. You can just delete these lines:
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);
Also, the flow doesn't seem quite right. gtk_main() starts the GTK main loop, which blocks until something exits it. gtk_dialog_run() also starts a main loop, but it exits as soon as one of the buttons is clicked.
I think it might be enough for you to remove the gtk_init_add() and gtk_main() calls, and simply deal with the return value. Also the gtk_widget_destroy() call is unnecessary, as the dialog window is automatically destroyed when gtk_dialog_run() returns.