Get receive keyboard an mouse events from SDL2 in WPF application - wpf

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.

Related

GTK3 and multithreading, replacing deprecated functions

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.

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

Using System.Threading.Timer in Compact Framework

I am using a System.Threading.Timer in a CF project (Windows Embedded CE 6.0), VS2005 C#, .NET 2.0.
This timer is desired because there is no possibility of reentrancy when used like this:
private System.Threading.Timer mainTimer;
private void MainForm_Load(object sender, EventArgs e)
{
// other initializations
mainTimer = new System.Threading.Timer(new TimerCallback(timerMain_Tick),
null, 100, Timeout.Infinite);
}
Which is to say, dueTime parameter is used but period is not. As long as period is Timeout.Infinite, the timer will fire once only. The timer is made thread-safe by checking for the form's InvokeRequired property. Note the check for null. It relates to my question, which I am getting to quickly.
private void timerMain_Tick(object stateInfo)
{
if (mainTimer != null)
{
if (this.InvokeRequired)
{
this.Invoke((ThreadStart)delegate
{
TimerProcess();
});
}
else
{
TimerProcess();
}
}
}
The timer must restart itself before it exits.
private void TimerProcess()
{
try
{
// do work here
}
finally
{
// retrigger
mainTimer.Change(mainTimerInterval, Timeout.Infinite);
}
}
The problem I am having is gracefully stopping this darn thing.
private void MainForm_Closing(object sender, CancelEventArgs e)
{
// shut down timer
mainTimer.Change(Timeout.Infinite, Timeout.Infinite);
mainTimer.Dispose();
mainTimer = null;
}
About 3 times in 10, the timer fires anyway, and I get an Object Disposed error. The timer code is trying to invoke the timer method AFTER the check for null.
I suspect that the timer fires, and its thread is suspended while the form is closing. I tried a state machine enumeration:
Normal state Running
Form_Closing sets Stopping state and waits in a Thread.Sleep() loop for Stopped state
Timer sees Stopping and sets Stopped state (rather than retriggering itself)
Problem I had with this is that the timer thread would not preempt the form closing method, so get stuck in endless loop.
How to fix this problem? Note that in CF, there is no Dispose(WaitHandle) method.
Interesting problem. There do not seem to be many options with the Timer in the Compact Framework.
I'm not sure how your specific code works, so adding a single static Boolean value may or may not fix your issues.
Here is how I changed your code to accept a timerOK value. If this does not solve your problem, it could give you ideas on how to approach this.
private static bool timerOK;
private static long mainTimerInterval = 200;
private System.Threading.Timer mainTimer;
private void MainForm_Load(object sender, EventArgs e) {
timerOK = true;
mainTimer = new System.Threading.Timer(new TimerCallback(timerMain_Tick), null, 100, Timeout.Infinite);
}
private void MainForm_Closing(object sender, CancelEventArgs e) {
timerOK = false;
mainTimer.Change(Timeout.Infinite, Timeout.Infinite);
mainTimer.Dispose();
mainTimer = null;
}
private void timerMain_Tick(object stateInfo) {
if (timerOK && (mainTimer != null)) {
if (this.InvokeRequired) {
this.Invoke((ThreadStart)delegate {
TimerProcess();
});
} else {
TimerProcess();
}
}
}
private void TimerProcess() {
if (!timerOK) return;
try {
// do work here
} finally {
// retrigger
mainTimer.Change(mainTimerInterval, Timeout.Infinite);
}
}
I'm using MVP so my layout is a little different, but essentially I had the same two problems to fix:
Stop the timer firing after targets in the process method are disposed
Stop the timer firing DURING disposal
First one is easily fixed as pwrgreg007 shows above, just shutdown and null the timer sometime in your 'closing' process (before the form targets are disposed) and then do a null check at the start of your timer processing event.
Second issue is a bit trickier, even if the timer (and your form) are running at the start of your processing loop, nothing stops it getting shutdown mid way through the process as it is running on a different thread. To prevent this I created a lock to be used both during the timer execution AND the timer shutdown.
//simplified presenter
public class Presenter
{
private const int REFRESH_TIME_MILLISECONDS = 5000;
private view _view;
private Timer _timer;
private object _timerLock = new object();
//CTOR
public Presenter()
{
_view = new View();
Startup();
}
//spin up presenter
public void Startup(){
//bind view shutdown event
_view.ViewClosing += Shutdown;
//start timer
_timer = new Timer(DoTimerStuff, null, REFRESH_TIME_MILLISECONDS, Timeout.Infinite);
}
//spin down presenter
public void Shutdown()
{
//wait for any DoTimerStuff locks to expire
lock (_timerLock)
{
//stop the timer
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_timer.Dispose();
_timer = null;
}
//close the view
_view.Shutdown();
}
//timer tick
private void DoTimerStuff(object state)
{
//grab a lock so we can ensure the timer doesn't get shutdown mid way through
lock (_timerLock)
{
//make sure the timer isn't shutdown (from form closing)
if (_timer == null) return;
//do your stuff here
_view.SomeInvokedCheckedProperty = "SomeValue";
//etc...
//schedule next timer execute (runs every runtime + refresh time)
_timer.Change(REFRESH_TIME_MILLISECONDS, Timeout.Infinite);
}
}
}
//simplified view
public class View : Form
{
//view properties (make sure they are invoke checked)
public SomeInvokedCheckedProperty {get;set;}
//Bound to ViewClosing
private void View_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
//stop the view closing itself
e.Cancel = true;
//tell the presenter to handle closing instead
if (ViewClosing != null) ViewClosing.Invoke();
}
}
That way..
The timer will wait to shutdown (holding up your form close) if DoTimerStuff() has the lock and is currently running
Conversely, DoTimerStuff() will wait if the timer shutdown has the lock and when it gets to continue it will correctly see the timer is shutdown (and do nothing).

Dispatching events into right thread

I have developed a wrapper for a library that uses a callback to notify events. This callback is called using another thread than UI's thread, so the wrapper uses the following script to call the event handlers into the right thread for a WinForm application.
void AoComm::Utiles::Managed::DispatchEvent( Delegate^ ev, Object^ sender, Object^ args )
{
ComponentModel::ISynchronizeInvoke^ si;
array<Delegate^>^ handlers;
if(ev != nullptr)
{
handlers= ev->GetInvocationList();
for(int i = 0; i < handlers->Length; ++i)
{
// target implements ISynchronizeInvoke?
si = dynamic_cast<ComponentModel::ISynchronizeInvoke^>(handlers[i]->Target);
try{
if(si != nullptr && si->InvokeRequired)
{
IAsyncResult^ res = si->BeginInvoke(handlers[i], gcnew array<Object^>{sender, args});
si->EndInvoke(res);
}else{
Delegate^ del = handlers[i];
del->Method->Invoke( del->Target, gcnew array<Object^>{sender, args} );
}
}catch(System::Reflection::TargetException^ e){
Exception^ innerException;
if (e->InnerException != nullptr)
{
innerException = e->InnerException;
}else{
innerException = e;
}
Threading::ThreadStart^ savestack = (Threading::ThreadStart^) Delegate::CreateDelegate(Threading::ThreadStart::typeid, innerException, "InternalPreserveStackTrace", false, false);
if(savestack != nullptr) savestack();
throw innerException;// -- now we can re-throw without trashing the stack
}
}
}
}
This code works pretty well, but I have read about Dispatcher class for WPF that do the same than my code (and more, of course).
So, is there something (class, mechanism, ...) equivalent to Dispatcher class for WinForms?
Thanks.
Right, this isn't the right way to do it. Winforms and WPF have different synchronization providers, they install theirs in System::Threading::SynchronizationContext::Current.
To use it, copy the Current value in your constructor. When you are ready to fire the event, check if it is nullptr. If it was then your object got constructed in a worker thread and you should fire your event directly. If it isn't then use the Post() method to run a helper method on the UI thread. Have that helper method fire the event.

C# Winforms: BeginInvoke still running on same thread?

I'm web developer and I'm trying to step into multithreading programming.
On one form I'm trying to run a method computing values in a second thread using asynchronous delegates.
I also want a progress bar showing actual progress in UI thread been notified.
delegate void ShowProgressDelegate(int total, int value);
delegate void ComputeDelegate(int value);
//Some method simulating sophisticated computing process
private void Compute(int value)
{
ShowProgress(value, 0);
for (int i = 0; i <= value; i++)
{
ShowProgress(value, i);
}
}
//Method returning values into UI thread
private void ShowProgress(int total, int value)
{
if (!this.InvokeRequired)
{
ComputeButton.Text = value.ToString();
ProgressBar.Maximum = total;
ProgressBar.Value = value;
}
else
{
ShowProgressDelegate showDel = new ShowProgressDelegate(ShowProgress);
this.BeginInvoke(showDel, new object[] { total, value });
}
}
//firing all process
private void ComputeButton_Click(object sender, EventArgs e)
{
ComputeButton.Text = "0";
ComputeDelegate compDel = new ComputeDelegate(Compute);
compDel.BeginInvoke(100000, null, null);
}
When I run this, everything is computing without any problem except it is still running in UI thread (I suppose so, because it freezes when I click some button on the form).
Why? I also attach buildable sample project (VS2010) with same code: http://osmera.com/windowsformsapplication1.zip
Thanks for helping neewbie.
In the code you've shown, you're doing nothing other than updating the progress bar - so there are thousands of UI messages to marshal, but nothing significant happening in the non-UI thread.
If you start simulating real work in Compute, you'll see it behave more reasonably, I suspect. You need to make sure you don't swamp the UI thread with progress updates like you are doing now.

Resources