Update gui during libcurl?

BlitzMax Forums/Brucey's Modules/Update gui during libcurl?

Blueapples(Posted 2008) [#1]
I am using the TEasyCurl class to do some FTP uploads. Is there a way for me to update the GUI of my program when I get the progress callback? This is what I have:

Function curlProgress:Int(data:Object, dltotal:Double, dlnow:Double, ultotal:Double, ulnow:Double)
	If ulnow <> 0 Then
		UpdateProgBar(TMainWindow.progPublish, ultotal / ulnow)
		RedrawGadget(TMainWindow.MainWindow)
		RedrawGadget(TMainWindow.progPublish)
	EndIf
EndFunction


The window isn't redrawn and the progress bar appears full after the upload finishes - i.e. when I get back to my main loop that calls WaitEvent(). Adding PollEvent() to this not only didn't help (same behavior - no redrawing) but it actually seemed to cause random events to fire elsewhere in my code. Very strange.

Anyway, RedrawGadget seems to have no immediate effect - the documentation says it might not redraw the gadget immediately and I'm afraid that's the case at least on Linux. Is there a way to force a redraw? I guess this might be more appropriate in the GUI programming area... but it is a specific problem with libcurl because it makes it sort of hard to use in a GUI program if it isn't possible. Any ideas?


Brucey(Posted 2008) [#2]
I would say some kind of "system" refresh is what you need there - SystemWait() ?

However, TEasyCurl is synchronous, so you are going to have issues like this. How's about using the A-synchronous TCurlMulti instead? Rather than waiting until the transfer is finished, it kicks *them* off in the background and relies on you to keep an eye on how they are doing, rather than the other way around.

From the ex_05 example, the main loop looks a bit like this :
Local status:Int = multi.multiPerform(running)

While status = CURLM_CALL_MULTI_PERFORM 
	status = multi.multiPerform(running)
Wend

While running And status = CURLM_OK
	' wait for network 
	If multi.multiSelect() <> -1 Then
		' pull in any new data, or at least handle timeouts 
		status = multi.multiPerform(running)
		While status = CURLM_CALL_MULTI_PERFORM 
			status = multi.multiPerform(running)
		Wend
	End If
Wend

You could stick this on a quick-firing timer, which would mean that your "main" event loop could happily update the UI like normal.


Blueapples(Posted 2008) [#3]
This is what I came up with - does this seem right? TProject.Perform() is called by a timer set to 1000 hertz.


Type TProject
' ...Snip...
	Global curlMulti:TCurlMulti = TCurlMulti.Create()
	Global curlStatus:Int
	Global curlTimer:TTimer
	Global curlRunning:Int
	
	Function Perform()
		If Not curlRunning Then
			Print "No transfers running, stop curl timer"
			SetStatusText(TMainWindow.MainWindow, "Publish complete")
			StopTimer(curlTimer)
			curlTimer = Null
		Else
			If curlStatus = CURLM_OK Then
				' wait for network 
				If curlMulti.multiSelect(1) <> -1 Then
					curlStatus = curlMulti.multiPerform(curlRunning)
				EndIf
			ElseIf curlStatus = CURLM_CALL_MULTI_PERFORM
				curlStatus = curlMulti.multiPerform(curlRunning)
			End If
		EndIf
	EndFunction

' ...Snip...
EndType


It doesn't seem to use hardly any CPU really, even when doing an upload. I have a method of the TProject class (a project is a local dir and a remote location that we want to publish local files to - much like how Coda handles projects) that turns the timer on and adds a new TCurlEasy to the multi. Seems to be pretty slick really. Had a bit of trouble with larger files, it seemed that multiSelect would fail often. A 1 second max timeout for multiSelect seems to work so far, at least with my current network connection and with the files I've tested.

Thanks for your help and for the module! Really awesome that I could put this together just using BM modules :) Now if only I had a cross platform file-change notification......


Brucey(Posted 2008) [#4]
Looks fine :-)

Now if only I had a cross platform file-change notification

I use it in wxCodeGen, but it's all tied into the wxMax framework... works well, and means I can have wxCodeGen running in the background while I edit wxFormBuilder projects, and as soon as I save it, wxCodeGen re-generates the files. It's like magic ;-)


Blueapples(Posted 2008) [#5]
It's like magic ;-) 

Best kind of code ;)