My problem is the operation of the for loop with GUI application. I am writing a program that opens other programs by clicking on the run button (for testing), during the run my UI starts to hang. How to make my UI work simultaneously with another application without freezing? And so that all elements are clickable during the for loop
main.c - gtk code
#include <gtk/gtk.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
GtkWidget *window;
GtkWidget *run_button;
GtkWidget *stop_button;
GtkWidget *button_box;
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
gtk_window_set_title(GTK_WINDOW(window), "Application - Launch GUI Tests");
gtk_window_set_default_size(GTK_WINDOW(window), 600, 480);
/* create button box - start / stop buttons */
button_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_set_homogeneous(GTK_BOX(button_box), TRUE);
stop_button = gtk_button_new_with_label("Stop");
run_button = gtk_button_new_with_label("Run");
/* button box pack */
gtk_box_pack_start(GTK_BOX(button_box), stop_button, FALSE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(button_box), run_button, FALSE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(window), button_box);
/* signals */
g_signal_connect(G_OBJECT(window), "destroy", gtk_main_quit, NULL);
g_signal_connect(G_OBJECT(run_button), "clicked", G_CALLBACK(on_run_button_clicked), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
when I click on the run button this code starts working (below)
void on_run_button_clicked(GtkWidget *run_button)
{
char *list[] = {"xfce4-terminal", "gnome-application", "test-app", "firefox"};
pid_t child;
int status;
for (int i = 0; *(list + i); i++) {
switch(child = fork()) {
case -1:
perror("child - fork error");
exit(EXIT_FAILURE);
case 0: /* child process exec another program */
execlp(list[i], list[i], NULL);
exit(127);
default: /* the parent waits until the program is closed */
wait(&status);
//check_status(status);
}
}
}
And the applications are started in turn until the user closes them, but the problem is that the main application starts to hang and the stop button is unavailable. How to fix it? Helps me, please
Looks like gtk_main() in main() isn't able to do its thing because on_run_button_clicked() is stuck in wait().
You need to make sure on_run_button_clicked() actually returns.
Related
I am programming on linux program and I am trying to prepare program with GTK+3, but I don't know how close program automatically after execute the function without kill that execute.
the step that i want in my program is:
open gtk window and this window there is button (open Xreader).
press button, it tells system to execute xreader program.
close gtk window automatically without needing to close xreader .
here is my code
#include<stdio.h>
#include<gtk/gtk.h>
static void
open_app(GtkWidget *Widget, gpointer data){
system("xreader");
gtk_main_quit();
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button1;
gtk_init(&argc, &argv);
/*make window */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/*give name to the window*/
gtk_window_set_title(GTK_WINDOW(window), "launcher");
/*make size of window*/
gtk_window_set_default_size(GTK_WINDOW(window), 700, 700);
/*open the window in the meddal*/
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
button1 = gtk_button_new_with_label("Open Xreader");
gtk_container_add(GTK_CONTAINER(window), button1);
gtk_widget_show_all(window);
g_signal_connect(button1,"clicked",G_CALLBACK(open_app), NULL);
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return 0;
}
everytime trying to execute my program and press the button (open Xreader) gtk not close till close xreader .
You cannot use system here, because according to its documentation, https://man7.org/linux/man-pages/man3/system.3.html
system() returns after the command has been completed.
Since you are using gtk, don't forget library functions provided by glib. It has a bunch of functions related to process and thread handling. For example, you can use GSubprocess class from glib, g_subprocess_new.
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
static void open_app(GtkWidget *Widget, gpointer data) {
g_subprocess_new(G_SUBPROCESS_FLAGS_NONE, NULL, "xreader", NULL);
gtk_main_quit();
}
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *button1;
gtk_init(&argc, &argv);
/*make window */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/*give name to the window*/
gtk_window_set_title(GTK_WINDOW(window), "launcher");
/*make size of window*/
gtk_window_set_default_size(GTK_WINDOW(window), 700, 700);
/*open the window in the meddal*/
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
button1 = gtk_button_new_with_label("Open Xreader");
gtk_container_add(GTK_CONTAINER(window), button1);
gtk_widget_show_all(window);
g_signal_connect(button1, "clicked", G_CALLBACK(open_app), NULL);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return 0;
}
I'm working with Cairo and GTK3.0 and I got problems that I have no clue on how to solve.
Currently I have 2 oddities that I do not have the knowledge of to solve.
The draw event is called whenever the terminal floats over the drawing window.
The program does not pas the gtk_main(); function.
I will provide my code below, which is very basic, it is based on this: http://zetcode.com/gfx/cairo/cairobackends/ , the GTK window part.
I eventually just need a window that I can call the draw event on whenever I want in my code.
#include <cairo.h>
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int xStart;
int yStart;
int xEnd;
int yEnd;
} lineData;
int i = 0;
int gonnaDraw = 0;
lineData *lines;
int lineSize = 0;
/**
* The drawing with the cairo elements is done here.
* The new line is saved to an array.
* Eventually there should be a loop that draws all lines in the array.
*/
static void do_drawing(cairo_t *cr) {
printf("I'm endless, somehow.\n");
if(lineSize != 0) { //We only want to draw in the infinite for loop, not before it.
cairo_set_source_rgb(cr, 255, 0, 0);
cairo_set_line_width(cr, 1.0);
lineData newLine = { 10.0 + i, 50.0 + i, 100.0 + i, 50.0 + i };
//lines[lineSize - 1] = newLine;
cairo_move_to(cr, newLine.xStart, newLine.xEnd);
cairo_line_to(cr, newLine.yStart, newLine.yEnd);
cairo_stroke(cr);
i = i + 10;
printf("i: %d\n", i);
gonnaDraw = 1;
}
}
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data) {
do_drawing(cr);
return FALSE;
}
int main (int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *darea;
printf("1\n");
gtk_init(&argc, &argv);
printf("2\n");
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
printf("3\n");
darea = gtk_drawing_area_new();
printf("4\n");
gtk_container_add(GTK_CONTAINER(window), darea);
printf("5\n");
g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
printf("6\n");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 800, 800);
gtk_window_set_title(GTK_WINDOW(window), "GTK window");
printf("7\n");
gtk_widget_show_all(window);
printf("8\n");
gtk_main(); // If I'm removed I got no drawing window.
printf("9\n"); // I do not show up.
lines = (lineData *) malloc(lineSize * sizeof(lineData));
for(;;) {
if(gonnaDraw == 1) {
lineSize++;
printf("lineSize: %d\n", lineSize);
lines = (lineData *) realloc(lines, lineSize * sizeof(lineData));
gtk_widget_queue_draw(window);
gonnaDraw = 0;
}
}
return 0;
}
Compiled with standard method.
You almost understand the GTK+ drawing model now. Question 1 is a consequence of it: when another window goes over yours, the window system tells GTK+ that that area needs to be redrawn. This is what i meant when I talked about clipping.
Now the other part is understanding the GTK+ event model. All window systems operate in such a way that all programs run on a loop that consists of while the program is alive, get a message from the window system and act on it. This is what gtk_main() does. gtk_main() not returning is normal; it doesn't return until a call to gtk_main_quit(). Apart from using signals to perform actions when a widget is interacted with, there are two ways you can "hook into" the main loop: g_timeout_add(), which runs a function on schedule, and g_idle_add(), which runs a function when next possible. The former is useful if you want something to happen every so often; the latter is useful if you want a worker thread to signal the UI to update. The GLib documentation on main loops will tell you more. I'm still not sure what your end goal is, so I suppose you can try playing with both to see what happens.
– andlabs
Here is a program in which there are two buttons (Connect and Disconnect). While clicking on 'connect' button, it calls 'button1_clicked_do_job()' function having while with some condition. On the other hand 'disconnect' button is used to change the condition of while. The problem is the Disconnect button is not working. How do I activate disconnect while 'connect' callback function didn't get returned to main()?
Here is the code:
#include<gtk/gtk.h>
static int check=1;
void button2_clicked_disconnect(GtkWidget *widget, gpointer data2)
{
check=0; //Change the condition of while
}
void button1_clicked_do_job(GtkWidget *widget, gpointer data1)
{
do{
g_print("Accept Connection\n");
sleep(2);
} while(check==1);
g_print("Reject Connection\n");
}
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *button1;
GtkWidget *button2;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 250, 150);
gtk_window_set_title(GTK_WINDOW(window), "Connect_N__Disconnect");
fixed = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), fixed);
button1 = gtk_button_new_with_label("Connect");
gtk_widget_set_size_request(button1, 80, 30);
gtk_fixed_put(GTK_FIXED(fixed), button1, 30, 50);
button2 = gtk_button_new_with_label("Disconnect");
gtk_widget_set_size_request(button2, 80, 30);
gtk_fixed_put(GTK_FIXED(fixed), button2, 130, 50);
g_signal_connect(G_OBJECT(button1), "clicked",
G_CALLBACK(button1_clicked_do_job), NULL);
g_signal_connect(G_OBJECT(button2), "clicked",
G_CALLBACK(button2_clicked_disconnect), NULL);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Generally speaking you should not run blocking code (like a long running while-loop) in the main thread because it makes the app unresponsive -- all functions should preferably return in milliseconds. In your case you also expect the main loop to call your other event handler but never give the main loop a chance to do it: the while loop just keeps executing forever. In other words: the first handler needs to return before the main loop can call the second one.
How to fix that depends on what your actual problem is: Using asynchronous code or idle handlers should be the first option, and a worker thread is another (but please only add threads when you know that you actually need them). It's also possible to "pump" the event loop manually but that should really be the last option. See main loop reference for details.
Your example would look something like this:
gboolean check_connection (gpointer user_data)
{
/* g_print what you want based on check value */
if (check == 0)
return FALSE;
return TRUE;
}
void button1_clicked_do_job(GtkWidget *widget, gpointer data1)
{
g_timeout_add_seconds (2, check_connection, NULL);
}
This question already has an answer here:
save current window as image using gtk#
(1 answer)
Closed 4 years ago.
This is a piece of code which creates a window:
#include <gtk/gtk.h>
static GtkWidget* createWindow()
{
GtkWidget *window;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
gtk_widget_set_name(window, "GtkLauncher");
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
return window;
}
int main(int argc, char* argv[])
{
GtkWidget *main_window;
gtk_init(&argc, &argv);
if (!g_thread_supported())
g_thread_init(NULL);
main_window = createWindow();
gtk_widget_grab_focus(main_window);
gtk_widget_show_all(main_window);
gtk_main();
return 0;
}
And in here: Convert a GTK python script to C , i got how to take a screenshot.
gdk_get_default_root_window() will give me the screenshot of the desktop.
gdk_screen_get_active_window (gdk_screen_get_default()) will give me the screenshot of any active window.
Is there any way to take the screenshot of the window being created in the code above??
I think this should do it, although you may need to iterate the main loop after showing the window to get it to paint properly, in which case you'll need some more code (I haven't tested this)
#include <unistd.h>
#include <stdio.h>
#include <gtk/gtk.h>
#include <cairo.h>
static GtkWidget* createWindow()
{
GtkWidget *window;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
gtk_widget_set_name(window, "GtkLauncher");
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
return window;
}
int main(int argc, char **argv)
{
gdk_init(&argc, &argv);
GtkWidget *main_window = createWindow();
gtk_widget_show_all(main_window);
// may not need this, it also may not be enough either
while (gtk_events_pending ()) gtk_main_iteration ();
GdkWindow *w = GDK_WINDOW(main_window);
gint width, height;
gdk_drawable_get_size(GDK_DRAWABLE(w), &width, &height);
GdkPixbuf *pb = gdk_pixbuf_get_from_drawable(NULL,
GDK_DRAWABLE(w),
NULL,
0,0,0,0,width,height);
if(pb != NULL) {
gdk_pixbuf_save(pb, "screenshot.png", "png", NULL);
g_print("Screenshot saved to screenshot.png.\n");
} else {
g_print("Unable to get the screenshot.\n");
}
return 0;
}
If it doesn't work you'll have to move the screenshot taking into an event handler that connects to some event (I'm not sure which probably window-state-event then you have to look at the event to figure out when to take the screenshot)
I am compiling this program on Windows, with gcc (MinGW) and GTK+:
#include <gtk/gtk.h>
void *destroy(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}
int main(int argc, char *argv[])
{
// Initalize GTK+
gtk_init(&argc, &argv);
// Create GTK+ window
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "destroy", G_CALLBACK(destroy), NULL);
// Show all widgets
gtk_widget_show_all(window);
// Enter loop
gtk_main();
// Exit program
return 0;
}
It compiles and runs, but the problem is that when I launch the program, it launches in a terminal window before opening the GUI window.
How do I prevent this from happening?
Edit:
Add the -mwindows flag when compiling.