#tag Class Protected Class Task Inherits Thread #tag Event Sub Run() InternalPushEvent( New TaskEvent( TaskEvent.Types.Begin ) ) Try RaiseEvent Run Catch exc As ThreadEndException // FIXME: we probably want to make sure this isn't being sent because // the app is quitting? InternalPushEvent( New TaskEvent( TaskEvent.Types.Killed ) ) Raise exc End Try InternalPushEvent( New TaskEvent( TaskEvent.Types.Finished ) ) End Sub #tag EndEvent #tag Method, Flags = &h1000 Sub Constructor() mLock = New CriticalSection mTimer = New Timer AddHandler mTimer.Action, WeakAddressOf InternalDispatchEvents End Sub #tag EndMethod #tag Method, Flags = &h21 Private Sub InternalDispatchEvents(sender as Timer) // Takes the events in the queue and dispatches them to the correct event handler. // // NOTE: must be called from the main thread. While True Dim currentEvent As TaskEvent mLock.Enter If mEvents.UBound >= 0 Then currentEvent = mEvents( 0 ) mEvents.Remove( 0 ) Else mLock.Leave Exit Sub End If mLock.Leave Select Case currentEvent.type Case TaskEvent.Types.Begin RaiseEvent Begin Case TaskEvent.Types.UpdateUI RaiseEvent UpdateUI( currentEvent.Arguments ) Case TaskEvent.Types.Finished RaiseEvent Finished Case TaskEvent.Types.Killed RaiseEvent Killed End Select Wend End Sub #tag EndMethod #tag Method, Flags = &h21 Private Sub InternalPushEvent(evt as TaskEvent) // Adds an event to the event queue. This can be called from any thread, but is // usually called from the non-main thread. mLock.Enter mEvents.Append( evt ) mTimer.Period = 0 mTimer.Mode = Timer.ModeSingle mLock.Leave End Sub #tag EndMethod #tag Method, Flags = &h0 Sub UpdateUI(args as Dictionary) // Adds an UpdateUI event to the queue, which will eventually be dequeued // on the main thread and raise the UpdateUI event. Dim evt As New TaskEvent( TaskEvent.Types.updateUI ) evt.Arguments = args internalPushEvent( evt ) End Sub #tag EndMethod #tag Method, Flags = &h0 Sub UpdateUI(paramarray args as Pair) // Adds an UpdateUI event to the queue, which will eventually be dequeued // on the main thread and raise the UpdateUI event. // // This specific method is a convenience function in order to be able to // use Pair literals. For example: // UpdateUI( "progress": 10, "total_progress": 100 ) Dim d As New Dictionary For Each arg As Pair In args d.Value( arg.Left ) = arg.Right Next Self.UpdateUI( d ) End Sub #tag EndMethod #tag Hook, Flags = &h0 Event Begin() #tag EndHook #tag Hook, Flags = &h0 Event Finished() #tag EndHook #tag Hook, Flags = &h0 Event Killed() #tag EndHook #tag Hook, Flags = &h0 Event Run() #tag EndHook #tag Hook, Flags = &h0 Event UpdateUI(args as Dictionary) #tag EndHook #tag Property, Flags = &h21 #tag Note The queue of pending events. This is protected by mLock in order to provide thread safety. #tag EndNote Private mEvents() As TaskEvent #tag EndProperty #tag Property, Flags = &h21 Private mLock As CriticalSection #tag EndProperty #tag Property, Flags = &h21 #tag Note This timer is used to punt events from the thread onto the main thread, where InternalDispatchEvents will process all of the queued events. #tag EndNote Private mTimer As Timer #tag EndProperty #tag ViewBehavior #tag ViewProperty Name="Index" Visible=true Group="ID" Type="Integer" EditorType="Integer" #tag EndViewProperty #tag ViewProperty Name="Left" Visible=true Group="Position" Type="Integer" #tag EndViewProperty #tag ViewProperty Name="Name" Visible=true Group="ID" Type="String" EditorType="String" #tag EndViewProperty #tag ViewProperty Name="Priority" Visible=true Group="Behavior" InitialValue="5" Type="Integer" #tag EndViewProperty #tag ViewProperty Name="StackSize" Visible=true Group="Behavior" InitialValue="0" Type="Integer" #tag EndViewProperty #tag ViewProperty Name="Super" Visible=true Group="ID" Type="String" EditorType="String" #tag EndViewProperty #tag ViewProperty Name="Top" Visible=true Group="Position" Type="Integer" #tag EndViewProperty #tag EndViewBehavior End Class #tag EndClass