I noticed that if I kill the app launched from the command line, with CTRL+C - then the subprocesses get killed, while, when clicking the close button of the window title, the process remains running.
static void * spawn_process(void *data)
{
GError *local_error = NULL;
GError **error = &local_error;
GSubprocess *process = g_subprocess_new (
G_SUBPROCESS_FLAGS_INHERIT_FDS,
error,
"podman",
"system",
"service",
"--time=0",
"unix:///tmp/podman.sock",
"--log-level=debug",
NULL
);
g_assert_no_error (local_error);
g_subprocess_wait_check(process, NULL, error);
g_assert_no_error (local_error);
g_object_unref (process);
return NULL;
}
static void activate(GtkApplication *app) {
GtkWidget *window = gtk_application_window_new(app);
GThread *process_thread = g_thread_new("Podman service", &spawn_process, NULL);
}
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;
}
I believe this is because you either have to join or abort the thread when you quit the application normally; otherwise it's orphaned and continues to run with no way to stop it. The same goes for the subprocess, you should make sure either to signal it to stop somehow (depends on which process you are spawning) or use g_subprocess_force_exit() when quitting the application.
However, if you are already spawning a subprocess, there is actually no need to start a new thread to do it in! You can use g_subprocess_wait_check_async().
I'm trying to popup an OK message box in my gtk browser, but all I'm getting is blank grey square patch without my text in it and even button is not visible.
PFB the function which I'm using to render message box :
Void DisplayOKPopup()
{
dialogue=gtk_message_dialogue_new(GTK_WINDOW(WebtBrowserWindow),
GTK_DIALOGUE_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"text message");
gtk_widget_show(dialogue);
LOGDEBUG(" 1");
gtk_dialogue_run(GTK_DIALOGUE (dialogue));
LOGDEBUG("2");
gtk_widget_destroy (dialogue);
}
As per my debug log, I can see that control is passing till LOGDEBUG("1") and after that it goes to gtk_dialogue_run after that UI is getting crashed, the line next to run i.e LOGDEBUG("2") is not getting executed.
Kindly provide your inputs as I'm working on this since 3 days:!
As concluded, the problem arises from the use of threads. There are several approaches to solve the issue but since there is not code, I'll try with a simple example so that you can recreate it on your code.
Take a global Boolean variable as a flag and on your thread, set it to true so that a "periodic" idle callback can check it and if the flag is TRUE then show the dialog. The logic is that the Gtk UI functions are called from the mainloop/main thread and not from the worker threads.
DisplayOkPopup just has a simple "counter" from 0 to MAX_INT (32 bits) and set's the global flag as TRUE.
check_for_dialog it's a callback that runs on mainloop idle time and check for the flag, if TRUE then runs the dialog.
exit is dirty and will output errors but the goal ain't that, its just a tip/hint for your solution.
Example:
#include <gtk/gtk.h>
gboolean dialog_active;
gboolean show_dialog_popup;
GtkWidget *window;
gpointer DisplayOKPopup (gpointer user_data) {
int i;
while (TRUE) {
for (i = 0; i < G_MAXINT32; i++) {
// nop
}
show_dialog_popup = TRUE;
}
return NULL;
}
gboolean check_for_dialog (gpointer user_data) {
if (show_dialog_popup == TRUE && dialog_active == FALSE) {
dialog_active = TRUE;
GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"text message");
gtk_dialog_run(GTK_DIALOG (dialog));
show_dialog_popup = FALSE;
dialog_active = FALSE;
gtk_widget_destroy(dialog);
}
return TRUE;
}
static void app_activate(GtkApplication *app, gpointer user_data) {
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Window Title Here");
gtk_window_set_default_size(GTK_WINDOW(window), 700, 400);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
//gtk_container_add(GTK_CONTAINER(window), fixed);
gtk_widget_show_all(window);
g_idle_add(check_for_dialog, NULL);
g_thread_new("my thread", DisplayOKPopup, NULL);
}
int main(int argc, char **argv) {
GtkApplication *app;
int status;
show_dialog_popup = FALSE;
dialog_active = FALSE;
app = gtk_application_new("your.application.id", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(app_activate), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
Build and run:
$ gcc -o test test.c `pkg-config --cflags --libs gtk+-3.0`
$ ./test
Result:
EDIT:
Answer to your comment is:
To have custom buttons on your dialog then use:
gtk_dialog_new_with_buttons
gtk_dialog_add_button (if dialog exists, will add 1 button)
gtk_dialog_add_buttons (same as above but can add many buttons)
Example for 1):
dialog = gtk_dialog_new_with_buttons ("My dialog",
main_app_window,
flags,
"_OK",
GTK_RESPONSE_ACCEPT,
"_Cancel",
GTK_RESPONSE_REJECT,
NULL);
Example for 2):
gtk_dialog_add_button (GTK_DIALOG(dialog),
"This is my button",
GTK_RESPONSE_ACCEPT);
Example for 3) is same as 2) but can handle many buttons and terminates with NULL.
I hope I can describe this problem well. I ran pacman Syu a couple days ago and the GTK application I'm working on stopped working correctly. I have ran it again after but the problem persists.
Basically, the program is not responding correctly. As an example, I have a button that, when pressed, should print "aqui" to the console and then move the canvas up (as in, navigate up). However the canvas is not updated, and the output is not printed. Only when I close the application, "aqui" is printed as many times as I pressed the button.
The application seems to respond when another window is opened. If I click on a button that opens a different window, the accumulated changes take effect (multiple "aqui" printed, and the canvas moves up as many times as I clicked). When I click on the button that should close the new window, the button disappears, but the window is still there. Example:
This is the code for the up button:
static gboolean moveUp(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
windowData->moveY(STEP);
gtk_widget_queue_draw((GtkWidget*) user_data);
std::cout << "aqui";
return TRUE;
}
the code for the rotate button, that opens the smaller window seen in the pictures:
static gboolean rotateWindowWindow(GtkWidget *widget, GdkEventButton *event,
gpointer user_data) {
GtkBuilder *builder;
GError *error = NULL;
builder = gtk_builder_new();
if (!gtk_builder_add_from_file(builder, "rotateWindow.glade", &error)) {
g_warning("%s", error->message);
g_free(error);
}
GtkWidget *rotateWindowWindow;
rotateWindowWindow = GTK_WIDGET( gtk_builder_get_object( builder, "rotateWindowWindow" ) );
rotationAngle = (GtkEntry*) GTK_WIDGET( gtk_builder_get_object( builder, "rotationAngle" ) );
GtkWidget* okButton = GTK_WIDGET(gtk_builder_get_object(builder, "okButton"));
g_signal_connect(G_OBJECT(okButton), "clicked", G_CALLBACK(rotateW), rotateWindowWindow);
gtk_builder_connect_signals(builder, NULL);
g_object_unref(G_OBJECT(builder));
gtk_widget_show_all(rotateWindowWindow);
gtk_main();
return TRUE;
}
the rotateW method that is called when clicking the okButton:
static gboolean rotateW(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
double angle = atof(gtk_entry_get_text(GTK_ENTRY(rotationAngle)));
windowData->rotate(angle);
displayFile->rotateAll(windowData->getAngle(), windowData->getCenter());
gtk_widget_destroy((GtkWidget*) user_data);
return TRUE;
}
and the main method:
int main(int argc, char **argv)
{
GtkWidget *viewport, *buttonUp,
*buttonDown, *buttonLeft, *buttonRight, *buttonZoomIn,
*buttonZoomOut, *newLine, *listWindow, *mainBox, *buttonClose,
*newPolygon, *newPoint, *translateButton, *scaleButton,
*rotateButton, *rotateWindowButton;
GtkDrawingArea *drawingArea;
GError *error = NULL;
origin.x = 0;
origin.y = 0;
viewportData = new Viewport(300.0, 350.0);
windowData = new Window(300.0, 350.0);
sh = new SutherlandHodgeman(windowData);
cs = new CohenSutherland(windowData);
nc = new NoClipping(windowData);
clipper = nc;
displayFile = new DisplayFile();
Polygon* l = new Polygon("line");
l->addPoint(0, 0);
l->addPoint(100, 0);
displayFile->add(l);
//l = new Polygon("line2");
//l->addPoint(5, 5);
//l->addPoint(500, 15);
//displayFile->add(l);
/* Init GTK+ */
gtk_init( &argc, &argv );
/* Create new GtkBuilder object */
mainBuilder = gtk_builder_new();
/* Load UI from file. If error occurs, report it and quit application.
* Replace "tut.glade" with your saved project. */
if( ! gtk_builder_add_from_file( mainBuilder, "interface.glade", &error ) )
{
g_warning( "%s", error->message );
g_free( error );
return 1;
}
/* Get main window pointer from UI */
mainWindow = GTK_WIDGET( gtk_builder_get_object( mainBuilder, "mainWindow" ) );
viewport = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "viewport"));
drawingArea = GTK_DRAWING_AREA(gtk_builder_get_object(mainBuilder, "drawingArea"));
listWindow = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "listWindow"));
buttonClose = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "buttonClose"));
mainBox = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "mainBox"));
buttonUp = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "buttonUp"));
buttonLeft = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "buttonLeft"));
buttonRight = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "buttonRight"));
buttonDown = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "buttonDown"));
buttonZoomIn = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "zoomIn"));
buttonZoomOut = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "zoomOut"));
translateButton = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "translateButton"));
scaleButton = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "scaleButton"));
rotateButton = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "rotateButton"));
newPolygon = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "newPolygon"));
newLine = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "newLine"));
newPoint = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "newPoint"));
cohenButton = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "cohenButton"));
sutherlandButton = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "hodgemanButton"));
noClippingButton = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "noClipping"));
rotateWindowButton = GTK_WIDGET(gtk_builder_get_object(mainBuilder, "rotateWindow"));
g_signal_connect(mainWindow, "delete_event", G_CALLBACK(exit_app), NULL);
g_signal_connect(buttonClose, "clicked", G_CALLBACK(exit_app), NULL);
g_signal_connect(G_OBJECT(drawingArea), "draw", G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(buttonUp), "clicked", G_CALLBACK(moveUp), mainWindow);
g_signal_connect(G_OBJECT(buttonDown), "clicked", G_CALLBACK(moveDown), mainWindow);
g_signal_connect(G_OBJECT(buttonLeft), "clicked", G_CALLBACK(moveLeft), mainWindow);
g_signal_connect(G_OBJECT(buttonRight), "clicked", G_CALLBACK(moveRight), mainWindow);
g_signal_connect(G_OBJECT(buttonZoomIn), "clicked", G_CALLBACK(zoomIn), mainWindow);
g_signal_connect(G_OBJECT(buttonZoomOut), "clicked", G_CALLBACK(zoomOut), mainWindow);
g_signal_connect(G_OBJECT(translateButton), "clicked", G_CALLBACK(translateWindow), mainWindow);
g_signal_connect(G_OBJECT(rotateButton), "clicked", G_CALLBACK(rotateWindow), mainWindow);
g_signal_connect(G_OBJECT(scaleButton), "clicked", G_CALLBACK(scaleWindow), mainWindow);
g_signal_connect(G_OBJECT(newLine), "clicked", G_CALLBACK(newLineWindow), NULL);
g_signal_connect(G_OBJECT(newPolygon), "clicked", G_CALLBACK(newPolygonWindow), NULL);
g_signal_connect(G_OBJECT(newPoint), "clicked", G_CALLBACK(newPointWindow), NULL);
g_signal_connect(G_OBJECT(cohenButton), "clicked", G_CALLBACK(changeClipping), mainWindow);
g_signal_connect(G_OBJECT(sutherlandButton), "clicked", G_CALLBACK(changeClipping), mainWindow);
g_signal_connect(G_OBJECT(noClippingButton), "clicked", G_CALLBACK(changeClipping), mainWindow);
g_signal_connect(G_OBJECT(rotateWindowButton), "clicked", G_CALLBACK(rotateWindowWindow), mainWindow);
/* Connect signals */
gtk_builder_connect_signals( mainBuilder, NULL );
/* Destroy builder, since we don't need it anymore */
//g_object_unref( G_OBJECT( mainBuilder ) );
/* Show window. All other widgets are automatically shown by GtkBuilder */
gtk_widget_show_all( mainWindow );
/* Start main loop */
gtk_main();
return 0;
}
If this is not enough, the full code is on github. I apologize in advance, the code is a mess.
EDIT
Adding std::endl to the end of the std::cout solved the problem of the strings not being printed in real time. Now they are being printed when I press the button, but the rest of the button's funcitonality, that has to do with affecting the interface, still doesn't update until another window opens.
EDIT 2
I made a gif showing how it's behaving right now.
I tried downgrading gtk from 3.20.6 to 3.16.1, which didn't work. I also tried downgrading every package (by editing /etc/pacman.conf and then running pacman -Syyuu) to 03/30/2016, also didn't work.
I also tried removing other instances of gtk main() with no success.
Just tried adding this code:
if(gtk_events_pending())
gtk_main_iteration();
Which force runs the main loop a single time. That also didn't solve the problem.
You may want to force GTK to refresh its pending operations.
I do it in python this way :
while gtk.events_pending(): # this forces GTK to refresh the screen
gtk.main_iteration()
As you do not mention what language you are using, you'll have to find out how to reproduce this, but it's probably just
while gtk.events_pending(): # this forces GTK to refresh the screen
gtk.main_iteration();
Your problem is taht you're callin gtk_main twice. In your main (which is ok), and in your rotateWindowWindow function (whihch is wrong). Doing so will create a new main loop, in which you'll be stuck until you exit.
Just removing that extra call should be enough to fix your issue.
I use a goocanvas and use signals for mouse events connected to some graphical items. If I use a dialog from a signal handler, all signals are broken after closing the dialog. Is this a bug of gtkmm/goocanvas or is this some kind of misuse in my program?
The wrong behavior is:
You can click somewhere in the canvas area, nothing is happen which is correct. If you click on the circle the signal handler starts the dialog which is also expected. After closing the dialog ( OK button ) you can click somewhere on the canvas and the signal handler is called which is wrong.
In my real program the signal handlers are sometimes never called and sometimes called on wrong areas and so on. A bit strange behavior. I hope someone can find the problem.
#include <gtkmm.h>
#include <goocanvasmm.h>
#include <sigc++/sigc++.h>
bool ShowDialog( const Glib::RefPtr<Goocanvas::Item>& item, GdkEventButton* ev)
{
enum { OK };
Gtk::Dialog dialog;
dialog.add_button( Gtk::Stock::OK, OK);
dialog.show_all_children();
dialog.run();
return false;
}
int main(int argc, char* argv[])
{
Gtk::Main app(&argc, &argv);
Goocanvas::init("example", "0.1", argc, argv);
Gtk::Window win;
Goocanvas::Canvas m_canvas;
m_canvas.set_size_request(640, 480);
m_canvas.set_bounds(0, 0, 800, 800);
Glib::RefPtr<Goocanvas::Item> root = m_canvas.get_root_item();
Glib::RefPtr<Goocanvas::Ellipse> outer = Goocanvas::Ellipse::create( 100,100,20,20);
outer->property_line_width() = 5;
outer->property_stroke_color() = "red";
outer->property_fill_color()="blue";
root->add_child( outer );
sigc::connection conn2= outer->signal_button_press_event().connect( sigc::ptr_fun(&ShowDialog));
win.add(m_canvas);
win.show_all_children();
Gtk::Main::run(win);
return 0;
}
I'm trying to send and receive a client-event using a GtkWidget on the win32 platform. The sending code looks like this:
GtkWidget *Wnd;
GdkNativeWindow Hnd =
#ifdef WIN32
GDK_WINDOW_HWND(Wnd->window);
#else
GDK_WINDOW_XWINDOW(Wnd->window);
#endif
GdkEvent *Event = gdk_event_new(GDK_CLIENT_EVENT);
// fill out Event params
gdk_event_send_client_message(Event, Hnd);
Receiving code looks like this:
static gboolean MyClientEvent(GtkWidget *widget, GdkEventClient *ev, MyWnd *Wnd)
{
// breakpoint here...
return TRUE;
}
GtkWidget *Wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect( G_OBJECT(Wnd),
"client-event",
G_CALLBACK(MyClientEvent),
this);
gtk_widget_add_events(Wnd, GDK_ALL_EVENTS_MASK);
I used Spy++ to see the message getting sent, so I know the sending side is ok. The receiving side however doesn't get the client-event. I was expecting my breakpoint in the callback to trigger... but it doesn't.
I'm not even sure if a GtkWindow can receive a client-event... from past experience on X11 I thought it was pretty much the same as any other GtkWidget in that respect. Maybe on the win32 platform it's kinda different. But still I'd like to be able to get this working.
I would like this to work with asynchronously, and in a thread-safe fashion, so that I can send events from worker threads up to the GUI thread.
I have a solution that seems to work. It may not be optimal but it's in the ball park.
struct GlibEventParams
{
GtkWidget *w;
GdkEvent *e;
};
static gboolean
GlibPostMessage(GlibEventParams *p)
{
GDK_THREADS_ENTER ();
gtk_propagate_event(p->w, p->e);
gdk_event_free(p->e);
delete p;
GDK_THREADS_LEAVE ();
return FALSE;
}
bool MySendEvent(GtkWidget *Wnd, GtkEvent *Event)
{
bool Status = false;
if (Event && Wnd)
{
GlibEventParams *p = new GlibEventParams;
p->w = Wnd;
p->e = gdk_event_new(GDK_CLIENT_EVENT);
*p->e = *Event;
Status = g_idle_add((GSourceFunc)GlibPostMessage, p) > 0;
}
else assert(!"No Event or Wnd");
return Status;
}
If someone else has constructive comments I'll add/modify this as required.