GTK+ standalone menu does not get shdown if not launched from terminal - c

The following program always works OK — shows the menu with one item — if launched from the terminal, but not if launched by the i3 window manager directly (when bound to a key).
In the latter case, most of the time it does print “Entering gtk main loop.”, but then simply does not get shdown; though approximately once per 20 key presses it does get shown!
Why?
#include <gtk/gtk.h>
#include <stdio.h>
static
void
deactivate_handler(GtkMenuShell *instance, gpointer user_data)
{
(void) instance; (void) user_data; // unused parameters
gtk_main_quit();
}
int
main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GtkWidget *menu = gtk_menu_new();
GtkWidget *item = gtk_menu_item_new_with_label("Test");
gtk_menu_attach(GTK_MENU(menu), item, 0, 1, 0, 1);
g_signal_connect(menu, "deactivate", G_CALLBACK(deactivate_handler), NULL);
gtk_widget_show_all(menu);
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
fprintf(stderr, "Entering gtk main loop.\n");
gtk_main();
return 0;
}

I suspect calling gtk_menu_popup before gtk_main will lead to weird behavior. You're not changing data, like gtk_widget_show_all that changes a flag, you're actually trying to do actions.
One trick I see is switching to GtkApplication and run gtk_menu_popup in response to the GtkApplication's activate signal. At that time you're already in the main loop.

Related

Setting override redirect for Gtk window leads to segmentation fault

I am trying to create an application in which I need to draw on a transparent window which stays above all other windows and invisible to the window manager, hence trying to set the override redirect of a window to true .But setting the override redirect for a GdkWindow causes segmentation fault.
#include <gtk/gtk.h>
void activate(GtkApplication *app) {
GtkWidget *window = gtk_application_window_new(app);
GdkWindow *gdk_window = gtk_widget_get_window(window);
gdk_window_set_override_redirect(gdk_window, TRUE);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
GtkApplication *app = gtk_application_new("com.github.application.name",
G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK (activate), NULL);
int status = g_application_run(G_APPLICATION (app), argc, argv);
g_object_unref(app);
return status;
}
compiling with gcc using
gcc -o out main.c `pkg-config --cflags --libs gtk+-3.0`
what am I missing here? any help is appreciated. Thanks.
gtk_widget_get_window() can return NULL. The reason your code is segfaulting is probably because you're calling gdk_window_set_override_redirect() on a NULL pointer.
For the underlying reason why gtk_widget_get_window() can return NULL: a GdkWindow maps to the concept of a surface; in X11 this is called an XWindow, hence the name. To let the compositor show your surface/XWindow, you have to explicitly map it.
GTK does the mapping operation the moment the GtkWindow widget is told to show itself (ie when you call gtk_window_present() or gtk_widget_show()). Once it actually associates with an underlying GdkWindow, it will emit the "realize" signal to which you can connect to .
So, in other words, you can either:
Call gdk_window_set_override_redirect(); after showing the window
Connect to the "realize" signal of your window variable, and call gdk_window_set_override_redirect(); inside the callback
Your code fails because gdk_window is NULL.
You can ask the window to be created with gtk_window_present:
void activate(GtkApplication *app) {
GtkWidget *window = gtk_application_window_new(app);
GdkWindow *gdk_window = gtk_widget_get_window(window);
gtk_window_present(GTK_WINDOW(window));
gdk_window_set_override_redirect(gdk_window, TRUE);
gtk_widget_show_all(window);
}

gtk_widget_show_all(window); not working when waiting on a function to return a value

I am making a dart game, and I have created the whole layout of the game page. I want to await a dart hitting the board, which can take a variable amount of time, then update the score for that dart, update the remaining points the player has left, and update the round score.
I make the layout, call gtk_widget_show_all(window);, then call await_dart_hit();
The window does not show until the dart hits though. It's as if the window can't show until the whole function ends, but I have tried making the window in a separate function, then returning, then calling await_dart_hit(); and this doesn't work either.
#include <gtk/gtk.h>
void problem_causing_wait(){
while(1);
}
void start(){
GtkWidget *window;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Start");
gtk_container_set_border_width(GTK_CONTAINER(window),10);
gtk_window_set_default_size(GTK_WINDOW(window),1000,400);
gtk_widget_show_all(window);
problem_causing_wait();
}
int main(int argc, char *argv[]) {
GtkWidget *window, *button, *button_box;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Welcome!");
gtk_window_set_default_size(GTK_WINDOW(window),1000,400);
button_box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
gtk_container_add(GTK_CONTAINER(window),button_box);
button = gtk_button_new_with_label("Get Started");
g_signal_connect (button, "clicked", G_CALLBACK (start), NULL);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_container_add(GTK_CONTAINER(button_box),button);
gtk_widget_show_all(window);
gtk_main();
return(0);
}
If you run this code, you'll see that once you click the "Get Started" button, it freezes. It doesn't show the "Start" window despite showing all before calling the problem_causing_wait() function.
Please help!
compiled with: gcc main.c -o main pkg-config --cflags --libs gtk+-3.0
As your application is running in a single thread this function "problem_causing_wait" acts as a blocking function and stops the main loop.
i think using "g_idle_add" and "g_thread_new" might solve your problem.
#include <gtk/gtk.h>
void *problem_causing_wait(){
while(1);
//update the Ui using g_idle_add
return NULL;
}
void start(){
GtkWidget *window;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Start");
gtk_container_set_border_width(GTK_CONTAINER(window),10);
gtk_window_set_default_size(GTK_WINDOW(window),1000,400);
g_thread_new("dart-game",problem_causing_wait,NULL);
gtk_widget_show_all(window);
}
int main(int argc, char *argv[]) {
GtkWidget *window, *button, *button_box;
//Initilizes Support for Concurrent Threads
XInitThreads();
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Welcome!");
gtk_window_set_default_size(GTK_WINDOW(window),1000,400);
button_box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
gtk_container_add(GTK_CONTAINER(window),button_box);
button = gtk_button_new_with_label("Get Started");
g_signal_connect (button, "clicked", G_CALLBACK (start), NULL);
//g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_container_add(GTK_CONTAINER(button_box),button);
gtk_widget_show_all(window);
gtk_main();
return(0);
}
You're not supposed to freeze the UI. Freezing the UI means no refresh, even if a refresh is needed. For example if you move another application on the foreground, then move it away, your app still has to repaint. You also can't show a countdown of the time remaining to shoot the dart. Due to that, you can't handle cases when a player completely misses the target (here, you should probably either interact with the UI or let the turn countdown expire with some feedback).
Instead, don't use threads at all, and use g_timeout_add to check every 500ms if a dart hit the board, letting the GTK+ main loop handle the polling of your I/O.

Show GtkApplicationWindow after close

I am a complete newbie when it comes to C and Gtk+.
I am trying to create an interface with a main application window. This main window has a menu, which opens a second window (of type GtkApplictionWindow).
My problem is, that once I close this second window (with the x in the top) I cannot open this second window again.
I get an error:
(api:2807): Gtk-CRITICAL **: gtk_widget_show: assertion 'GTK_IS_WIDGET (widget)' failed
I've tried attaching a function to both the destroy and the hide signals, and in my code I've tried both gtk_widget_destroy(window_connections) and gtk_widget_hide(window_connections).
My interface is created in Glade.
Here is my current code:
#include <gtk/gtk.h>
#include <stdio.h>
GtkWidget *window_connections;
int main(int argc, char *argv[]) {
GtkBuilder *builder;
GtkWidget *window;
GtkWidget *statusbar;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "glade/window_main.glade", NULL);
window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
gtk_builder_connect_signals(builder, NULL);
window_connections = GTK_WIDGET(gtk_builder_get_object(builder, "window_connections"));
statusbar = GTK_WIDGET(gtk_builder_get_object(builder, "statusbar"));
gtk_statusbar_push(GTK_STATUSBAR(statusbar), 1, "Hello, World!");
g_object_unref(builder);
gtk_widget_show(window);
gtk_main();
return 0;
}
// called when window is closed
void on_window_main_destroy() {
gtk_main_quit();
}
void window_open_connections() {
gtk_widget_show(window_connections);
}
void window_close_connections() {
gtk_widget_hide(window_connections);
}
void window_hide_test() {
printf("hide\n");
}
Help?
If you close a Window using the "X", it will be not only hidden but also destroyed afterwards.
Obviously you cannot reuse that widget later. You would need to create it again.
This is where gtk_widget_hide_on_delete() comes in handy.
You can directly connect it to the "delete-event" signal or you can call it from within your handler for that signal.
Then the widget is only hidden but can be shown again later.

How to get webcam feed to GTK window?

I need to get webcam video feed using C, GTK2/3, Cairo.
However can't find any references about it.
Below shows how did I try using opencv. It is unsuccessful.I need to know some other method using gstreamer, cairo.
I'm expecting simple code to get video to GTK window. Really appreciate if someone can provide example code.
/*
gcc -o weby3 att3.c `pkg-config --libs --cflags gtk+-2.0 opencv`
*/
#include "highgui.h"
#include <gtk/gtk.h>
#include <opencv/cv.h>
#include <opencv/cxcore.h>
GdkPixbuf* pix;
IplImage* frame;
CvCapture* capture;
gboolean
expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
while(1) {
frame = cvQueryFrame( capture );
if(!frame) break;
pix = gdk_pixbuf_new_from_data((guchar*) frame->imageData,
GDK_COLORSPACE_RGB, FALSE, frame->depth, frame->width,
frame->height, (frame->widthStep), NULL, NULL);
gdk_draw_pixbuf(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE (widget)], pix, 0, 0, 0, 0,
-1, -1, GDK_RGB_DITHER_NONE, 0, 0); /* Other possible values are GDK_RGB_DITHER_MAX, GDK_RGB_DITHER_NORMAL */
char c = cvWaitKey(33);
if( c == 27 ) break;
}
cvReleaseCapture( &capture );
return TRUE;
}
int main( int argc, char** argv ) {
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *drawing_area;
gtk_init (&argc, &argv);
CvCapture* capture = cvCreateCameraCapture(0);
/* create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Hello WebCam and OpenCV!");
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Now add a child widget to the aspect frame */
drawing_area = gtk_drawing_area_new();
/* window since we are forcing a aspect ratio */
gtk_widget_set_size_request(drawing_area, 600, 400);
gtk_container_add(GTK_CONTAINER (window), drawing_area);
gtk_widget_show(drawing_area);
g_signal_connect (G_OBJECT (drawing_area), "expose_event",
G_CALLBACK (expose_event_callback), NULL);
/* and the window */
gtk_widget_show (window);
/* All GTK applications must have a gtk_main(). Control ends here
* and waits for an event to occur (like a key press or
* mouse event). */
gtk_main ();
return 0;
}
The main problem I see here is that you're not properly integrating your opencv code into the GTK event model.
GTK basically works with a message pump. Messages are sent in a queue, and GTK reads and unqueue them to react to those messages. In GTK 2, the expose-event event is emitted when a widget or portion of it needs to be drawn (in GTK 3, the draw event is used). You're suposed to connect a callback to that event to catch the event. Then in your callback, you draw a single frame, and then give the control back to GTK. It will call your callback again when it needs the next frame.
The problem here is that you never give the hand back to GTK, as your opencv code is enclosed in an infinite while(1) loop. You should instead just draw a single frame, and return.
The key event logic should also be handled using GTK, and not in your expose-event callback. Just call gtk_main_quit once you have seen the keystroke you're waiting for.
EDIT:
Once you can display one frame, you have to display them all. Call gtk_widget_queue_draw to tell GTK that the widget needs to be redrawn.
Once this is done, you'll see that you need some way of calling gtk_widget_queue_draw periodically. This is easilly done with GLib functions like g_timeout_add or g_idle_add. These functions tell the main event loop (what I called "message pump" above") to call a callback after a determined amount of time (for g_timeout_add) or just when there is no other events to process (for g_idle_add). Call gtk_widget_queue_draw in that callback and you're done.
Be aware that g_timeout_add doesn't allow to have a perfect timing, so the time between each frame may be too different from one frame to another. You may avoid this by augmenting the priority passed to g_timeout_add. You may also use a GTimer to compute in your timeout callback the time elapsed between the last frame and the current time, and deduce time remaining until your next frame. Then call g_timeout_add with that more accurate time. Don't forget to return FALSE instead of TRUE at the end of the timeout callback if you use the GTimer trick, otherwise you'll have n timeout callbacks running at frame n.

How to return a value from a function called using gtk callback?

I am a beginner in gtk and C gui programming and have two specific questions while imlementing a GUI for my C application.
I have called a function via a callback in my code and the function is supposed to return a value. How to get the value in my main from the function?
What is the best way to implement many function calls either from main or nested function calls in GUI using GTK. Should i design and open new window at each function call and if that is the case then how do i close it when its job is over or do i have some way wherein i can change the content of the same window across function calls after some I/O by the functions.
Sample code where i want function hello to return a value 144 after called by callback in main.
#include <gtk/gtk.h>
static gboolean delete_event( GtkWidget *widget,
GdkEvent *event,
gpointer data )
{
g_print ("delete event occurred\n");
return FALSE;
}
int hello(GtkWidget *widget, gpointer data)
{
int a=144;
return a;
}
/* Another callback */
static void destroy( GtkWidget *widget,
gpointer data )
{
gtk_main_quit ();
}
int main( int argc,
char *argv[] )
{
GtkWidget *window;
GtkWidget *button;
int value;
gtk_init (&argc, &argv);
/* create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "delete-event",
G_CALLBACK (delete_event), NULL);
g_signal_connect (window, "destroy",
G_CALLBACK (destroy), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked",
G_CALLBACK (hello), NULL);
// printf("value is %d",value);
gtk_container_add (GTK_CONTAINER (window), button);
gtk_widget_show (button);
gtk_widget_show (window);
gtk_main ();
return 0;
}
In your main:
int value = 0;
g_signal_connect (button, "clicked", G_CALLBACK (hello), &value);
You also must respect a signal's callback prototype. In your code, you made it return an int... For the GtkButton::clicked signal, this is:
void user_function (GtkButton *button, gpointer user_data)
Then, to return your value, just modify the variable from inside the callback:
int hello (GtkWidget *widget, gpointer data)
{
int *a = data;
*a = 144;
}
If you need to return several values, use a struct instead of an int.
Your second question is very unclear to me, so I can't answer to it.
One way to pass values back from a callback would be to give a pointer to some storage to g_signal_connect(). That pointer will then be passed to your handler, which can write its "return value" there. You could also pass the address of another function (or the address of a struct containing both data and function pointer, or whatever) to enable more complex behaviors in your handler function.
As for your second question, I don't think I understand it, and anyway each question should be its own post here.
As others have said, if you need to get data out of a callback then you need to pass in a pointer and set the value at that location, because you can't return.
This makes sense if you think about what is actually happening. When you are setting the callback when you call g_signal_callback() you are not actually calling your callback, you are just passing a pointer to your function, which GTK is then storing internally for later use.
Once you call gtk_main() you turn control of your program over to the gtk main loop. There, when signals are received the gtk main loop will call into your functions, but you have no control over what is happening inside the gtk main loop, it's not expecting a return value from your function, and if you could return something, you'd have no way of telling gtk what to do with it.

Resources