GTK3 and multithreading, replacing deprecated functions - c

I would like to replace deprecated functions gdk_threads_enter()/leave() in my application that uses threads. The application as it is now, works perfect (although i am not sure if this is the right way to do it).
My main loop, runs the gtk_main and the signal handlers. When i receive a start button, i start a thread, that runs in the background along the main. How can i update the GUI from that thread. I know per the Documentation of GTK3 and GDK3, they say avoid it by using
gdk_threads_add_idle()
or
gdk_threads_add_timeout()
But how do I do this if I want the updating to be done only when I click start?
is there any example. I am not asking how to use gdk_threads_add_idle(), I am asking how to run worker function in the main without a thread after clicking start.
Button clicked --> start the worker function "in thread previously" --> update large amount of GUI elements in the GUI window.

You have 3 ways to do it:
make computation in the button callback and use gtk_event_pending()/gtk_main_iteration()
use g_idle_add() or others, and gtk_event_pending()/gtk_main_iteration()
use a thread, eventually a mutex, and g_idle_add() or others. Normally, a mutex isn't needed but it may solve some bugs or
Heisenbugs.
The third solution seems to be the best, because with the first two methods, I experienced some problems when exiting the application while a computation was running. The application didn't exit and was printing a lot of "Gtk Critical" warnings. (I tried it on Windows and mingw32).
1. button callback:
If you want to run the worker thread in the main gtk loop, you can directly make the computation in the button callback, updating the GUI and treating events from it with gtk_event_pending() and gtk_main_iteration(), as in the following sample code:
void on_button_clicked(GtkButton * button, gpointer data) {
// do some computation...
// modify the GUI:
gtk_label_set_text(label,"text");
// run the main iteration to update the GUI,
// you need to call these functions even if the GUI wasn't modified,
// in order to get it responsive and treat events from it:
while(gtk_events_pending()) gtk_main_iteration();
// do some other computation...
// huge computation in a loop:
while(1) {
// do some computation...
// update the GUI and treat events from it:
while(gtk_events_pending()) gtk_main_iteration();
}
}
2. g_idle_add():
You can also use, instead of g_thread_new(), gdk_thread_add_idle()(in the case some libraries not under your control may use gdk_threads_enter()/leave()) or g_idle_add() or g_main_context_invoke():
gboolean compute_func(gpointer data) {
// do some computation...
// modify the GUI:
gtk_label_set_text(label,"text");
// run the main loop to update the GUI and get it responsive:
while(gtk_events_pending()) gtk_main_iteration();
// do some other computation...
// huge computation in a loop:
while(1) {
// do some computation...
// update GUI and treat events from it:
while(gtk_events_pending()) gtk_main_iteration();
}
return FALSE;
}
void on_button_clicked(GtkButton * button, gpointer data) {
g_idle_add(compute_func,data);
}
3. thread and mutex:
In some cases using a thread make the computation to be faster, so when using a worker thread NOT in the main gtk loop, and when updating the GUI in function added to the main loop with gdk_threads_add_idle() or g_idle_add() from the worker thread, you may have to lock the access to the GUI using a mutex, because there may be a conflict between the functions accessing the GUI. The mutex have to be initialized with g_mutex_init(&mutex_interface); before beeing used by the application. For example:
GMutex mutex_interface;
gboolean update_gui(gpointer data) {
g_mutex_lock(&mutex_interface);
// update the GUI here:
gtk_button_set_label(button,"label");
// And read the GUI also here, before the mutex to be unlocked:
gchar * text = gtk_entry_get_text(GTK_ENTRY(entry));
g_mutex_unlock(&mutex_interface);
return FALSE;
}
gpointer threadcompute(gpointer data) {
int count = 0;
while(count <= 10000) {
printf("\ntest %d",count);
// sometimes update the GUI:
gdk_threads_add_idle(update_gui,data);
// or:
g_idle_add(update_gui,data);
count++;
}
return NULL;
}
void on_button_clicked(GtkButton * button, gpointer data) {
g_thread_new("thread",threadcompute,data);
}
If you need the functions updating the GUI to be executed in a specific order, you need to add two counters and to assign a number to each function called with g_idle_add() or gdk_threads_add_ilde():
GMutex mutex_interface;
typedef struct _data DATA;
struct _data {
gchar label[1000];
GtkWidget * w;
int num;
};
int counter = 0;
int counter2 = 0;
gboolean update_gui(gpointer data) {
DATA * d = (DATA *)data;
debutloop:
g_mutex_lock(&mutex_interface);
if(d->num != counter2) {
g_mutex_unlock(&mutex_interface);
goto debutloop;
}
counter2++;
// update the GUI here:
gtk_button_set_label(GTK_BUTTON(d->w),d->label);
// And read the GUI also here, before the mutex to be unlocked:
gchar * text = gtk_entry_get_text(GTK_ENTRY(entry));
g_mutex_unlock(&mutex_interface);
free(d);
return FALSE;
}
gpointer threadcompute(gpointer data) {
int count = 0;
while(count <= 10000) {
printf("\ntest %d",count);
DATA * d = (DATA*)malloc(sizeof(DATA));
sprintf(d->label,"%d",count);
d->w = (GtkWidget*)data;
d->num = counter;
counter++;
// update the GUI:
g_idle_add(update_gui,d);
count++;
}
return NULL;
}
void on_button_clicked(GtkButton * button, gpointer data) {
g_thread_new("thread",threadcompute,button);
}
I have also tested the case of locking individual widgets instead of the whole GUI, and it seems to work.

What the documentation says is that you can still run your worker function in a thread, you just can't use GTK and GDK functions from that thread. So, you can still start the thread when you click start. But instead of updating GUI elements from the thread, you have to schedule them to be updated from the main thread by using gdk_threads_add_idle().
So your diagram should look something like this:
Main thread Worker thread
|
Button clicked
| \________
| \
| Start worker function
| |
| Computation
| |
| Want to update GUI
| |
| gdk_threads_add_idle(function1, data1)
| ______________/|
|/ |
v More computation
function1 runs |
| Want to update GUI
GUI updated |
| gdk_threads_add_idle(function2, data2)
| ______________/|
|/ |
v More computation
function2 runs |
|
etc...
If this is too complicated for your use case, and you have a computation in your worker thread that returns control to your worker thread often enough (say, you are calculating something in a loop), then you can run the calculation entirely in the main thread without locking up the GUI by briefly returning control to the GUI main loop, like so:
for (lots of items) {
result = do_short_calculation_on(one_item);
update_gui(result);
while (gtk_events_pending())
gtk_main_iteration();
}

I get this running error when i close the main window: Gtk-CRITICAL
**: gtk_widget_get_parent: assertion 'GTK_IS_WIDGET (widget)' failed
I think i have found a solution, using two global variables that indicate to the callback to stop and to call gtk_main_quit(), and having trapped the "destroy" signal for the main window into a self defined callback named gtk_main_quit2() in the following example:
int process_running = 0; // indicate if the "process" is running
int stopprocess = 0; // indicate to the callback to stop or not
void gtk_main_quit2(GtkWidget * window, gpointer data) {
if(process_running == 0) gtk_main_quit(); // if the "process" isn't running
// then quit
stopprocess = 1; // indicate to the button callback to stop and quit
}
void on_button_clicked(GtkButton * button, gpointer data) {
// indicate the "process" is running:
process_running = 1;
// do some computation...
while(gtk_events_pending()) gtk_main_iteration();
if(stopprocess == 1) {
// if close button clicked then quit:
gtk_main_quit();
return;
}
// do some other computation...
// huge computation in a loop:
while(1) {
// do some computation...
while(gtk_events_pending()) gtk_main_iteration();
if(stopprocess == 1) {
// if close button clicked then quit:
gtk_main_quit();
return;
}
}
while(gtk_events_pending()) gtk_main_iteration();
// indicate the "process" is finished:
process_running = 0;
// in the case the user clicked close button just at the end of computation:
if(stopprocess == 1) {
gtk_main_quit();
return;
}
}
int main() {
gtk_init();
Gtkwidget * window = create_window();
g_signal_connect ((gpointer) window, "destroy", G_CALLBACK(gtk_main_quit2), NULL);
gtk_main();
}
If you still have some gtk warnings after having clicked the close button, you can try to trap the "delete-event" signal instead of the "destroy" signal on the main window.

Related

How to create an interrupt or background task in C

I am trying to figure out how to make a background process in C, I haven't found anything online. I think the reason I haven't found much is that I may not be asking the right question.
I am working on a school project using ARM assembly and C with Raspberry Pi using the Raspbian Operating System and the GCC compiler.
For my project, I decided to do a simple alarm system. The idea is simple, I have 3 PIR sensors that detect motion, and set off a buzzer when motion is detected.
Instead of using hardware for the keypad, I chose to do a GUI where you can arm/disarm the system as well as change the password and turn on/off certain sensors. For example, if you wanted to turn off motion sensors 1 and 2, there will be buttons on the GUI to do that.
The problem I am having is that the GUI Library I'm using, (GTK3 and Glade) is event-driven, so unless a button is pressed it won't do anything. This would be fine if I only wanted to set the buzzer to on when motion is detected because I could make my own loop to watch for motion, but I really want to play some type of pattern repeatedly (example: 3 short beeps continuously until the alarm is disarmed). At the same time, I still want to have access to the GUI buttons so I can turn off the alarm. This makes me think I need an interrupt or a background process.
I'm sure there are many ways to solve this problem, but I really wanted to create sort of a background routine that could run parallel to the main task once the user's arms' the system. I have asked my professor about how to multi-thread in ARM, but he said that we do not cover this in the class. I have read that the C standard library doesn't support multi-threading, but I am sure there is a way that this can be done. If someone could just point me in the right direction I would be grateful.
Here is the GUI code I have written, along with another module I have finished to get a working prototype before I start wiring the sensors. None of this contains any assembly code because I haven't got to that yet, I wanted to get it working at a higher level and then break certain parts down to assembly. If you need all of the files I will gladly provide them, but I think this should be enough for you all to understand what I'm trying to do.
The GUI code:
/*****************************************************
* Title: User Interface
* Author:
* Date: 2/15/20
* Class: CISP 2410
*
* Description:
* ! This header file contains all of the function
* ! Declarations and definitions for the GUI
* ! Everything involving the GUI will be in
* --> this header
*
*****************************************************/
#include <gtk/gtk.h> // For gtk stuff
#include <stdlib.h> // Standard Library
#include "GUI_Ctrl.h" // Prototypes
#include "Alarm.h" // Alarm Functions
/* Private Functions */
static void UpdateLcdDisplay(char keyPadValue);
static void ClearLcdDisplay(void);
static void UpdateDisplay(void);
/***********************************/
// Global Variables
GtkWidget *g_Lbl_Lcd;
GtkWidget *g_Lbl_SysStat;
GtkWidget *g_Lbl_LogStat;
char inputBuffer[6] = {0x0};
int charCounter = 0;
const int INPUT_LIMIT = 6;
/*****************************************************
* ! Initializes all of the GUI elements
* ! Adds CSS attributes to GUI elements
* ! Also handles the formatting of text
*****************************************************/
void GUI_INIT(int argc, char* argv[])
{
GtkBuilder *builder;
GtkWidget *window;
GtkWidget *g_Lbl_Lbl1;
GtkWidget *g_Lbl_Lbl2;
// Get pointer to css file
GtkCssProvider *cssProvider = gtk_css_provider_new ();
gtk_css_provider_load_from_path(cssProvider,"UI/style.css",NULL);
gtk_init(&argc, &argv);
// get pointer to xml dat file
builder = gtk_builder_new_from_file("UI/HelloWorld.glade");
// Get pointer to main window
window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
gtk_builder_connect_signals(builder, NULL);
// Get pointer to labels
g_Lbl_Lcd = GTK_WIDGET(gtk_builder_get_object(builder, "Lbl_Lcd"));
g_Lbl_SysStat = GTK_WIDGET(gtk_builder_get_object(builder, "Lbl_SysStat"));
g_Lbl_LogStat = GTK_WIDGET(gtk_builder_get_object(builder, "Lbl_LogStat"));
g_Lbl_Lbl1 = GTK_WIDGET(gtk_builder_get_object(builder, "Lbl1"));
g_Lbl_Lbl2 = GTK_WIDGET(gtk_builder_get_object(builder, "Lbl2"));
// Align Text Right
gtk_label_set_xalign (GTK_LABEL(g_Lbl_Lcd), 1);
// Align Text Left
gtk_label_set_xalign (GTK_LABEL(g_Lbl_SysStat), 0);
gtk_label_set_xalign (GTK_LABEL(g_Lbl_LogStat), 0);
gtk_label_set_xalign (GTK_LABEL(g_Lbl_Lbl1), 0);
gtk_label_set_xalign (GTK_LABEL(g_Lbl_Lbl2), 0);
// Add CSS
gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(cssProvider), GTK_STYLE_PROVIDER_PRIORITY_USER);
// Finish setup and start GUI
g_object_unref(builder);
gtk_widget_show(window);
UpdateDisplay();
gtk_main();
return;
}
// called when window is closed
void on_window_main_destroy()
{
gtk_main_quit();
}
/*------------------END SECTION------------------*/
static void UpdateDisplay(void)
{
ClearLcdDisplay();
gtk_label_set_text(GTK_LABEL(g_Lbl_SysStat), GetSysStat());
gtk_label_set_text(GTK_LABEL(g_Lbl_LogStat), GetLogStat());
return;
}
static void UpdateLcdDisplay(char keyPadValue)
{
if (charCounter >= INPUT_LIMIT)
ClearLcdDisplay();
else
{
inputBuffer[charCounter] = keyPadValue;
charCounter++;
}
gtk_label_set_text(GTK_LABEL(g_Lbl_Lcd), inputBuffer);
return;
}
static void ClearLcdDisplay(void)
{
memset(inputBuffer, 0, 6);
charCounter = 0;
gtk_label_set_text(GTK_LABEL(g_Lbl_Lcd), inputBuffer);
return;
}
/*------------------ EVENT HANDLERS ------------------*/
void on_btn0_clicked(void) {UpdateLcdDisplay('0');}
void on_btn1_clicked(void) {UpdateLcdDisplay('1');}
void on_btn2_clicked(void) {UpdateLcdDisplay('2');}
void on_btn3_clicked(void) {UpdateLcdDisplay('3');}
void on_btn4_clicked(void) {UpdateLcdDisplay('4');}
void on_btn5_clicked(void) {UpdateLcdDisplay('5');}
void on_btn6_clicked(void) {UpdateLcdDisplay('6');}
void on_btn7_clicked(void) {UpdateLcdDisplay('7');}
void on_btn8_clicked(void) {UpdateLcdDisplay('8');}
void on_btn9_clicked(void) {UpdateLcdDisplay('9');}
void on_btnClear_clicked(void) {ClearLcdDisplay();}
void on_btnEnter_clicked(void) {UpdateDisplay();}
void on_btnLogin_clicked(void)
{
LoginLogout(inputBuffer);
UpdateDisplay();
return;
}
void on_btnArm_clicked(void)
{
ArmDisarm();
UpdateDisplay();
return;
}
Here is the code for the alarm. Note, this is just a prototype, I will be using the wiringPi library once I get this interrupt thing figured out.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Alarm.h"
// Private Function Prototypes
static int PasswordIsCorrect(char* pswAttempt);
// Global Variables
static int armed = 0;
static int loggedIn = 0;
static int PasswordIsCorrect(char* pswAttempt)
{
const char PASSWORD[] = "123";
if (!strcmp(pswAttempt, PASSWORD))
return 1;
else
return 0;
}
/*
* Returns a string,
* Used to update label
*/
char* GetSysStat(void)
{
if(armed)
return "Armed";
else
return "Disarmed";
}
/*
* Returns a string,
* Used to update label
*/
char* GetLogStat(void)
{
if(loggedIn)
return "Logged In";
else
return "Logged Out";
}
void ArmDisarm(void)
{
if (loggedIn && armed)
armed = 0;
else if(loggedIn && !armed)
armed = 1;
return;
}
void LoginLogout(char* pswAttempt)
{
if(PasswordIsCorrect(pswAttempt))
loggedIn = 1;
else
loggedIn = 0;
return;
}
Thank you all for your time!

Get receive keyboard an mouse events from SDL2 in WPF application

I'm trying to capture mouse and keyboard events from SDL2 using the SDL2-CS binding library. The events are polled for but these events are never raised.
I think this is because the polling needs to happen on the UI thread. I tried initializing SDL from the UI thread by calling App.Current.Dispatcher.Invoke(Init) but no events are polled.
Basic implementation of my class:
public override void Initialize()
{
if (hooked)
{
return;
}
App.Current.Dispatcher.Invoke(Init); //Run on the UI thread
}
private void Init()
{
var init = SDL.SDL_Init(SDL.SDL_INIT_VIDEO);
if (init != 0)
{
throw new Exception("Could not initialize SDL");
}
hooked = true;
ListenForEvents();
}
private void ListenForEvents()
{
SDL.SDL_Event ev;
while (true)
{
if (SDL.SDL_PollEvent(out ev) != 1) //This is continuously trigged
{
continue;
}
switch (ev.type) //This is never reached
{
case SDL.SDL_EventType.SDL_MOUSEMOTION:
if (MouseMoved != null) { MouseMoved(this, ev.motion); }
break;
...
}
}
}
I'm wondring if I'm invoking the Init on the UI thread wrong, or if the SDL initialization is wrong.
P.S. Hooking with user32.dll is not desired because this code will run on non windows environments as well.
Looking at your code I would say your UI is blocked because ListenForEvents is not running on a different thread and invoking the Init call will run the method - that never returns - on the UI thread.
It might be a good idea to call Init invoked, but then you should start a new thread for polling.

Modal Progress Dialog - How to pass in delegate?

I have a basic form with a progress bar and want to pass in a delegate of sorts like this:
ProgressDialog.ShowAndExecute(delegate);
I can't figure out how to connect the delegate to progress messages.
void ShowAndExecute()
{
// Handle form disabling and whatnot...
thread = new Thread(new ThreadStart(ExecuteCommand));
while (thread.IsAlive)
{
Application.DoEvents();
Thread.Sleep(100);
}
}
// Example of the method I would like to pass in
void ExecuteCommand()
{
for (int i = 0; i < 10; i++) Thread.Sleep(1000);
}
I thought about creating an interface that the commands should implement. They can fire an event whenever an update occurs, but how do I let the calling thread know it was fired?
How do you handle passing in delegates that report progress through events and act (move progress bar) based on those? This is a static dialog (to make it easier to call throughout the app)
Only the ExecuteCommand knows its current progress. So some interface or class must be passed to the ExecuteCommand method. The ExecuteCommand will set the progress, then it's up to the implementation of the listener to determine what to do with the progress. In general, the listener will check if it's a significant change** in progress, and if so, it will BeginInvoke a call to update a progress bar.
** - If you process thousands of items in a short period of time, then you want to protect against calling BeginInvoke too much, otherwise it will lock up the UI thread.
void ExecuteCommand(IThreadController tc)
{
for (int i = 0; i < 10; i++) {
Thread.Sleep(1000);
tc.setProgress("processing ...", (i+1), 10);
}
}

XCB: window will not unmap after being mapped once

I have a small example program written in C that opens a window using the XCB API.
Strictly AFTER I have created and shown the window, I would (at a later time) like to hide the window.
(Obviously in this specific example, I could remove the call to xcb_map_window, and the window would be hidden, but I want to do it at a later point in my larger application, like a toggle to show/hide the window, NOTE: I do NOT want to minimize it).
Here is the sample code (NOTE: this code now works thanks to the answer):
#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
#include <xcb/xcb.h>
void set_window_visible(xcb_connection_t* c, xcb_window_t win, bool visible) {
xcb_generic_event_t *event;
if(visible) {
// Map the window on the screen
xcb_map_window (c, win);
// Make sure the map window command is sent
xcb_flush(c);
// Wait for EXPOSE event.
//
// TODO: add timeout in-case X server does not ever send the expose event.
while(event = xcb_wait_for_event(c)) {
bool gotExpose = false;
switch(event->response_type & ~0x80) {
case XCB_EXPOSE:
gotExpose = true;
break;
default:
break; // We don't know the event type, then.
}
free(event);
if(gotExpose) {
break;
}
}
} else {
// Hide the window
xcb_unmap_window(c, win);
// Make sure the unmap window command is sent
xcb_flush(c);
}
}
int main() {
xcb_connection_t *c;
xcb_screen_t *screen;
xcb_window_t win;
xcb_generic_event_t *event;
// Open the connection to the X server
c = xcb_connect (NULL, NULL);
// Get the first screen
screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
// Ask for our window's Id
win = xcb_generate_id(c);
// Create the window
uint32_t mask = XCB_CW_EVENT_MASK;
uint32_t valwin[] = {XCB_EVENT_MASK_EXPOSURE | XCB_BUTTON_PRESS};
xcb_create_window(
c, // Connection
XCB_COPY_FROM_PARENT, // depth (same as root)
win, // window Id
screen->root, // parent window
0, 0, // x, y
150, 150, // width, height
10, // border_width
XCB_WINDOW_CLASS_INPUT_OUTPUT, // class
screen->root_visual, // visual
mask, valwin // masks
);
bool visible = true;
set_window_visible(c, win, true);
while(1) {
sleep(2);
// Toggle visibility
visible = !visible;
set_window_visible(c, win, visible);
printf("Window visible: ");
if(visible) {
printf("true.\n");
} else {
printf("false.\n");
}
}
// pause until Ctrl-C
pause();
return 0;
}
Which I compile and run with:
gcc xcbwindow.c -o xcbwindow -lxcb
./xcbwindow
From anything I can find on Google or here, I am doing everything correctly. So for clarification I am using Unity and Ubuntu 12.04 LTS:
unity --version reports:
unity 5.20.0
uname -a reports:
Linux [redacted] 3.2.0-32-generic #51-Ubuntu SMP Wed Sep 26 21:33:09 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
Can anyone explain where I've gone wrong in this code?
EDIT: updated code with a flush() at the end after xcb_unmap_window(); still doesn't work.
EDIT2: Tried code with cinnamon WM; still doesn't work (It's not a Unity bug).
EDIT3: Code updated in this post now works.
Your program simply goes too fast.
It maps the window and then immediately unmaps it. The window is top level, which means the requests are redirected to the window manager. But the window manager receives the unmap request when the window is not mapped yet, so it simply discards the request. Insert sleep(3) between the map and unmap calls and observe.
In real code, your window needs to get at least one expose event before sending out the unmap request. This guarantees it's actually mapped by the window manager.

How do i get access to 'gseal'ed values from gtk widget | modify GtkWidgets

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);

Resources