Tim Felgentreff uploaded a new version of Graphics to project The Trunk:
http://source.squeak.org/trunk/Graphics-tfel.355.mcz
==================== Summary ====================
Name: Graphics-tfel.355
Author: tfel
Time: 27 July 2016, 6:02:58.629152 pm
UUID: 004f1a41-9be9-c443-9853-26c892c7a2ae
Ancestors: Graphics-tpr.354
small fix to allow creating Forms from hibernated bitmaps, like the Sugar icon library does
=============== Diff against Graphics-tpr.354 ===============
Item was changed:
----- Method: Form>>setExtent:depth:bits: (in category 'private') -----
setExtent: extent depth: bitsPerPixel bits: bitmap
"Create a virtual bit map with the given extent and bitsPerPixel."
width := extent x asInteger.
width < 0 ifTrue: [width := 0].
height := extent y asInteger.
height < 0 ifTrue: [height := 0].
depth := bitsPerPixel.
depth := bitsPerPixel.
+ (bits isNil
- (bitmap isNil
or:[(bitmap class isWords and: [self bitsSize = bitmap size])
or: [bitmap class isBytes and: [self bitsSize * 4 = bitmap size]]])
ifFalse:[^self error:'Bad dimensions'].
bits := bitmap!
Tim Felgentreff uploaded a new version of EToys to project The Trunk:
http://source.squeak.org/trunk/EToys-tfel.139.mcz
==================== Summary ====================
Name: EToys-tfel.139
Author: tfel
Time: 27 July 2016, 5:58:58.495152 pm
UUID: 0a7e78da-2cb3-874b-8a82-0e22900f06c7
Ancestors: EToys-topa.138
push variableDocks from CardPlayer up to Player, to make older EToys examples work
=============== Diff against EToys-topa.138 ===============
Item was changed:
Player subclass: #CardPlayer
instanceVariableNames: 'privateMorphs'
classVariableNames: ''
poolDictionaries: ''
category: 'Etoys-Stacks'!
- CardPlayer class
- instanceVariableNames: 'variableDocks'!
!CardPlayer commentStamp: '<historical>' prior: 0!
CardPlayer
Instance variables of the Uniclass represent the data in the "fields" of each card in the stack.
Each Instance variable is some kind of value holder.
The code for the *buttons* on the background resides in the CardPlayer uniclass.
privateMorphs -- OrderedCollection of objects specific to this card.
Individual CardPlayer classes need to store the search results of any instances that are templates. As a hack, we use a class variable TemplateMatches in each individual class (CardPlayer21). It is initialized in #matchIndex:.
TemplateMatches an IndentityDictionary of
(aCardPlayer -> (list of matching cards, index in that list))
!
- CardPlayer class
- instanceVariableNames: 'variableDocks'!
Item was removed:
- ----- Method: CardPlayer class>>newVariableDocks: (in category 'variable docks') -----
- newVariableDocks: dockList
- "Set the receiver's variableDocks to be the list provided in dockList. Assimilate this new information into the receiver's slotInfo, which contains both automatically-generated variables such as the variable docks and also explicitly-user-specified variables"
-
- self variableDocks: dockList.
- self setSlotInfoFromVariableDocks!
Item was removed:
- ----- Method: CardPlayer class>>resortInstanceVariables: (in category 'user-defined inst vars') -----
- resortInstanceVariables: newList
- "Accept a new ordering for instance variables"
-
- variableDocks := newList collect: [:aName | variableDocks detect: [:d | d variableName = aName]].
- self setNewInstVarNames: newList asOrderedCollection.
- self newVariableDocks: variableDocks.
- !
Item was removed:
- ----- Method: CardPlayer class>>setNewInstVarNames: (in category 'user-defined inst vars') -----
- setNewInstVarNames: listOfStrings
- "Make listOfStrings be the new list of instance variable names for the receiver"
-
- | disappearing firstAppearing instVarString instVarList |
- instVarList := self instVarNames asOrderedCollection.
- disappearing := instVarList copy.
- disappearing removeAllFoundIn: listOfStrings.
- disappearing do:
- [:oldName | self removeAccessorsFor: oldName].
- firstAppearing := listOfStrings copy.
- firstAppearing removeAllFoundIn: instVarList.
- instVarString := String streamContents:
- [:aStream | listOfStrings do: [:aString | aStream nextPutAll: aString; nextPut: $ ]].
-
- superclass subclass: self name instanceVariableNames: instVarString
- classVariableNames: '' poolDictionaries: '' category: self categoryForUniclasses.
- firstAppearing do:
- [:newName | self compileAccessorsFor: newName].
- !
Item was removed:
- ----- Method: CardPlayer class>>setSlotInfoFromVariableDocks (in category 'variable docks') -----
- setSlotInfoFromVariableDocks
- "Get the slotInfo fixed up after a change in background shape. Those instance variables that are proactively added by the user will persist, whereas those that are automatically generated will be updated"
-
- self slotInfo copy do: "Remove old automatically-created slots"
- [:aSlotInfo | | aDock |
- (aDock := aSlotInfo variableDock) ifNotNil:
- [slotInfo removeKey: aDock variableName]].
-
- self variableDocks do: [:dock | | newInfo | "Generate fresh slots from variable docks"
- newInfo := SlotInformation new type: dock variableType.
- newInfo variableDock: dock.
- slotInfo at: dock variableName asSymbol put: newInfo]!
Item was removed:
- ----- Method: CardPlayer class>>variableDocks (in category 'variable docks') -----
- variableDocks
- "Answer the list of variable docks in the receiver. Initialize the variable-dock list if not already done."
-
- variableDocks ifNil: [variableDocks := OrderedCollection new].
- ^ variableDocks!
Item was removed:
- ----- Method: CardPlayer class>>variableDocks: (in category 'variable docks') -----
- variableDocks: dockList
- "Set the variable-dock list as indicated"
-
- variableDocks := dockList!
Item was changed:
Model subclass: #Player
instanceVariableNames: 'costume costumes'
classVariableNames: 'BiggestSubclassNumber TimeOfError'
poolDictionaries: 'References'
category: 'Etoys-Scripting'!
Player class
+ instanceVariableNames: 'scripts slotInfo variableDocks'!
- instanceVariableNames: 'scripts slotInfo'!
!Player commentStamp: '<historical>' prior: 0!
The fundamental user-scriptable entity. Always represented by a user-specific subclass of Player; instance vars and methods relate to user-defined structures.
costume is a Morph, the primary morph I am currently wearing for graphical display.
Scripts are defined in subclasses of Player. These are UniClasses.
Messages in scripts are sent to Players. A Player may delegate to its costume, or to an object the costume suggests. Or, a Player may designate some other object to receive the script messages it does not understand. (see doesNotUnderstand:) !
Player class
+ instanceVariableNames: 'scripts slotInfo variableDocks'!
- instanceVariableNames: 'scripts slotInfo'!
Item was added:
+ ----- Method: Player class>>newVariableDocks: (in category 'variable docks') -----
+ newVariableDocks: dockList
+ "Set the receiver's variableDocks to be the list provided in dockList. Assimilate this new information into the receiver's slotInfo, which contains both automatically-generated variables such as the variable docks and also explicitly-user-specified variables"
+
+ self variableDocks: dockList.
+ self setSlotInfoFromVariableDocks!
Item was added:
+ ----- Method: Player class>>resortInstanceVariables: (in category 'user-defined inst vars') -----
+ resortInstanceVariables: newList
+ "Accept a new ordering for instance variables"
+
+ variableDocks := newList collect: [:aName | variableDocks detect: [:d | d variableName = aName]].
+ self setNewInstVarNames: newList asOrderedCollection.
+ self newVariableDocks: variableDocks.
+ !
Item was added:
+ ----- Method: Player class>>setNewInstVarNames: (in category 'user-defined inst vars') -----
+ setNewInstVarNames: listOfStrings
+ "Make listOfStrings be the new list of instance variable names for the receiver"
+
+ | disappearing firstAppearing instVarString instVarList |
+ instVarList := self instVarNames asOrderedCollection.
+ disappearing := instVarList copy.
+ disappearing removeAllFoundIn: listOfStrings.
+ disappearing do:
+ [:oldName | self removeAccessorsFor: oldName].
+ firstAppearing := listOfStrings copy.
+ firstAppearing removeAllFoundIn: instVarList.
+ instVarString := String streamContents:
+ [:aStream | listOfStrings do: [:aString | aStream nextPutAll: aString; nextPut: $ ]].
+
+ superclass subclass: self name instanceVariableNames: instVarString
+ classVariableNames: '' poolDictionaries: '' category: self categoryForUniclasses.
+ firstAppearing do:
+ [:newName | self compileAccessorsFor: newName].
+ !
Item was added:
+ ----- Method: Player class>>setSlotInfoFromVariableDocks (in category 'variable docks') -----
+ setSlotInfoFromVariableDocks
+ "Get the slotInfo fixed up after a change in background shape. Those instance variables that are proactively added by the user will persist, whereas those that are automatically generated will be updated"
+
+ self slotInfo copy do: "Remove old automatically-created slots"
+ [:aSlotInfo | | aDock |
+ (aDock := aSlotInfo variableDock) ifNotNil:
+ [slotInfo removeKey: aDock variableName]].
+
+ self variableDocks do: [:dock | | newInfo | "Generate fresh slots from variable docks"
+ newInfo := SlotInformation new type: dock variableType.
+ newInfo variableDock: dock.
+ slotInfo at: dock variableName asSymbol put: newInfo]!
Item was added:
+ ----- Method: Player class>>variableDocks (in category 'variable docks') -----
+ variableDocks
+ "Answer the list of variable docks in the receiver. Initialize the variable-dock list if not already done."
+
+ variableDocks ifNil: [variableDocks := OrderedCollection new].
+ ^ variableDocks!
Item was added:
+ ----- Method: Player class>>variableDocks: (in category 'variable docks') -----
+ variableDocks: dockList
+ "Set the variable-dock list as indicated"
+
+ variableDocks := dockList!
Item was changed:
Player subclass: #UnscriptedPlayer
+ instanceVariableNames: 'patch'
- instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Etoys-Scripting'!
UnscriptedPlayer class
instanceVariableNames: 'ephemeralPlayerRef'!
!UnscriptedPlayer commentStamp: '<historical>' prior: 0!
My instances are Player objects that have not been scripted, and which hence do not require a unique scripts dictionary, etc. As soon as the needed, I am transformed automatically into a unique subclass of Player.!
UnscriptedPlayer class
instanceVariableNames: 'ephemeralPlayerRef'!
Item was added:
+ ----- Method: UnscriptedPlayer>>getPatch (in category 'access') -----
+ getPatch
+ ^ patch!
Item was added:
+ ----- Method: UnscriptedPlayer>>setPatch: (in category 'access') -----
+ setPatch: t1
+ patch := t1!
Changes to Trunk (http://source.squeak.org/trunk.html) in the last 24 hours:
http://lists.squeakfoundation.org/pipermail/packages/2016-July/068303.html
Name: Monticello-tfel.637
Ancestors: Monticello-cmm.636
add a button for rejecting all incoming conflicts that only change AST
=============================================
http://lists.squeakfoundation.org/pipermail/packages/2016-July/068304.html
Name: Files-cmm.161
Ancestors: Files-cmm.160
- Soften the change to FileDirectory>>#/ to be more backward compatible, and extend it to DirectoryEntry.
- We have #assureExistence, add #assureAbsence for safely ensuring a directory does not exist without having to write a error-handler.
=============================================
http://lists.squeakfoundation.org/pipermail/packages/2016-July/068305.html
Name: Installer-Core-cmm.414
Ancestors: Installer-Core-cmm.407
Support more configuration use-cases:
* Automatically addLocalRepositories and addRemoteRepositories to the MC browser when merging packages.
* Ability to #copyLocalVersionsToRemoteFor: a package. This can be used as a single 'commit' of all changes across multiple packages (which reside in their own repositories).
- Connectors was moved back to SqueakSource.
- webClientSsp seems to be just as current at SqueakSource as it does at SS3.
- Fixed some assumptions in the package-definitions that assumed they exist in their same repository as their prerequisite packages.
=============================================
Chris Muller uploaded a new version of Files to project The Trunk:
http://source.squeak.org/trunk/Files-cmm.161.mcz
==================== Summary ====================
Name: Files-cmm.161
Author: cmm
Time: 25 July 2016, 3:52:18.391906 pm
UUID: 23aaa0dc-71b3-4585-a06a-25a113d14404
Ancestors: Files-cmm.160
- Soften the change to FileDirectory>>#/ to be more backward compatible, and extend it to DirectoryEntry.
- We have #assureExistence, add #assureAbsence for safely ensuring a directory does not exist without having to write a error-handler.
=============== Diff against Files-cmm.160 ===============
Item was added:
+ ----- Method: DirectoryEntryDirectory>>/ (in category 'access') -----
+ / aString
+ ^ self asFileDirectory / aString!
Item was added:
+ ----- Method: DirectoryEntryDirectory>>assureAbsence (in category 'file operations') -----
+ assureAbsence
+ self asFileDirectory assureAbsence!
Item was added:
+ ----- Method: DirectoryEntryDirectory>>delete (in category 'file operations') -----
+ delete
+ self asFileDirectory recursiveDelete!
Item was changed:
----- Method: FileDirectory>>/ (in category 'path access') -----
/ aString
+ "Answer a FileDirectory on a subdirectory named aString, of the receiver. If there is already a file named aString in the receiver directory, answer its Entry."
+ | dir |
+ dir := FileDirectory on: (self fullNameFor: aString).
+ ^ dir exists
+ ifTrue: [ dir ]
+ ifFalse:
+ [ self
+ entryAt: aString
+ ifAbsent: [ dir ] ]!
- "Answer a FileDirectory on a subdirectory named aString, of the receiver."
- ^ FileDirectory directoryEntryFor: (self fullNameFor: aString)!
Item was added:
+ ----- Method: FileDirectory>>assureAbsence (in category 'file directory') -----
+ assureAbsence
+ self exists ifTrue: [ self recursiveDelete ]!
Levente Uzonyi uploaded a new version of Network to project The Inbox:
http://source.squeak.org/inbox/Network-ul.180.mcz
==================== Summary ====================
Name: Network-ul.180
Author: ul
Time: 25 July 2016, 8:40:01.001452 pm
UUID: 2f23a55c-fec5-41ac-95bd-6a8c2458be95
Ancestors: Network-nice.179
Socket changes:
- fixed the comment of #isOtherEndConnected and #isThisEndConnected
- do not slice the data (TCP) in the image in #sendData:. Let the VM, the kernel, the hardware deal with that.
- use #isOtherEndConnected when receiving data, and #isThisEndConnected when sending data instead of #isConnected
- move away from #milliseconds:since:, since we have a clock that won't roll over
=============== Diff against Network-nice.179 ===============
Item was changed:
----- Method: Socket>>closeAndDestroy: (in category 'connection open/close') -----
closeAndDestroy: timeoutSeconds
"First, try to close this connection gracefully. If the close attempt fails or times out, abort the connection. In either case, destroy the socket. Do nothing if the socket has already been destroyed (i.e., if its socketHandle is nil)."
+ socketHandle ifNil: [ ^self ].
+ self isThisEndConnected ifTrue: [
+ self close. "Close this end." ].
+ (self waitForDisconnectionFor: timeoutSeconds) ifFalse: [
+ "The other end has not closed the connect yet, so we will just abort it."
+ self primSocketAbortConnection: socketHandle ].
+ self destroy!
- socketHandle ifNotNil: [
- self isConnected ifTrue: [
- self close. "close this end"
- (self waitForDisconnectionFor: timeoutSeconds) ifFalse: [
- "The other end didn't close so we just abort the connection"
- self primSocketAbortConnection: socketHandle]].
- self destroy].
- !
Item was changed:
----- Method: Socket>>discardReceivedData (in category 'receiving') -----
discardReceivedData
"Discard any data received up until now, and return the number of bytes discarded."
| buf totalBytesDiscarded |
buf := String new: 10000.
totalBytesDiscarded := 0.
+ [self isOtherEndConnected and: [self dataAvailable]] whileTrue: [
- [self isConnected and: [self dataAvailable]] whileTrue: [
totalBytesDiscarded :=
totalBytesDiscarded + (self receiveDataInto: buf)].
^ totalBytesDiscarded
!
Item was changed:
----- Method: Socket>>isOtherEndConnected (in category 'queries') -----
isOtherEndConnected
+ "Return true if this socket is connected, or this end has closed the connection but not the other end, so we can still receive data."
- "Return true if this socket is connected, or this end has closed the connection but not the other end, so we can still send data."
| state |
socketHandle ifNil: [ ^false ].
(state := self primSocketConnectionStatus: socketHandle) == Connected ifTrue: [ ^true ].
^state == ThisEndClosed
!
Item was changed:
----- Method: Socket>>isThisEndConnected (in category 'queries') -----
isThisEndConnected
+ "Return true if this socket is connected, other the other end has closed the connection but not this end, so we can still send data."
- "Return true if this socket is connected, other the other end has closed the connection but not this end, so we can still receive data."
| state |
socketHandle ifNil: [ ^false ].
(state := self primSocketConnectionStatus: socketHandle) == Connected ifTrue: [ ^true ].
^state == OtherEndClosed
!
Item was changed:
----- Method: Socket>>sendData: (in category 'sending') -----
sendData: aStringOrByteArray
"Send all of the data in the given array, even if it requires multiple calls to send it all. Return the number of bytes sent."
"An experimental version use on slow lines: Longer timeout and smaller writes to try to avoid spurious timeouts."
| bytesSent bytesToSend count |
bytesToSend := aStringOrByteArray size.
bytesSent := 0.
[bytesSent < bytesToSend] whileTrue: [
(self waitForSendDoneFor: 60)
ifFalse: [ConnectionTimedOut signal: 'send data timeout; data not sent'].
count := self primSocket: socketHandle
sendData: aStringOrByteArray
startIndex: bytesSent + 1
+ count: bytesToSend - bytesSent.
- count: (bytesToSend - bytesSent min: DefaultSendBufferSize).
bytesSent := bytesSent + count].
^ bytesSent
!
Item was changed:
----- Method: Socket>>waitForConnectionFor:ifTimedOut:ifRefused: (in category 'waiting') -----
waitForConnectionFor: timeout ifTimedOut: timeoutBlock ifRefused: refusedBlock
"Wait up until the given deadline for a connection to be established. Return true if it is established by the deadline, false if not."
+ | deadline timeLeft status |
+ deadline := Time millisecondClockValue + (timeout * 1000) truncated.
+ (status := self primSocketConnectionStatus: socketHandle) == Connected ifTrue: [^true].
+ [ (status == WaitingForConnection) and: [ (timeLeft := deadline - Time millisecondClockValue) > 0 ] ]
- | startTime msecsDelta msecsEllapsed status |
- startTime := Time millisecondClockValue.
- msecsDelta := (timeout * 1000) truncated.
- status := self primSocketConnectionStatus: socketHandle.
- status = Connected ifTrue: [^true].
- [(status = WaitingForConnection) and: [(msecsEllapsed := Time millisecondsSince: startTime) < msecsDelta]]
whileTrue: [
+ semaphore waitTimeoutMSecs: timeLeft.
+ status := self primSocketConnectionStatus: socketHandle ].
+ status == Connected ifTrue: [ ^true ].
+ status == WaitingForConnection
+ ifTrue: [ timeoutBlock value ]
+ ifFalse: [ refusedBlock value ].
+ ^false!
- semaphore waitTimeoutMSecs: msecsDelta - msecsEllapsed.
- status := self primSocketConnectionStatus: socketHandle].
- status = Connected
- ifFalse: [
- status = WaitingForConnection
- ifTrue: [timeoutBlock value]
- ifFalse: [refusedBlock value].
- ^false].
- ^ true!
Item was changed:
----- Method: Socket>>waitForConnectionUntil: (in category 'waiting') -----
waitForConnectionUntil: deadline
"Wait up until the given deadline for a connection to be established. Return true if it is established by the deadline, false if not."
+ | status timeLeft |
- | status waitTime |
[
(status := self primSocketConnectionStatus: socketHandle) == Connected ifTrue: [ ^true ].
status == WaitingForConnection ifFalse: [ ^false ].
+ (timeLeft := deadline - Time millisecondClockValue) <= 0 ifTrue: [ ^false ].
+ semaphore waitTimeoutMSecs: timeLeft ] repeat!
- (waitTime := deadline - Time millisecondClockValue) > 0 ifFalse: [ ^false ].
- semaphore waitTimeoutMSecs: waitTime ] repeat!
Item was changed:
----- Method: Socket>>waitForDataFor:ifClosed:ifTimedOut: (in category 'waiting') -----
waitForDataFor: timeout ifClosed: closedBlock ifTimedOut: timedOutBlock
"Wait for the given nr of seconds for data to arrive."
+ | deadline timeLeft |
- | startTime msecsDelta |
socketHandle ifNil: [ ^closedBlock value ].
+ deadline := Time millisecondClockValue + (timeout * 1000) truncated.
- startTime := Time millisecondClockValue.
- msecsDelta := (timeout * 1000) truncated.
[
(self primSocketReceiveDataAvailable: socketHandle) ifTrue: [ ^self ].
+ self isOtherEndConnected ifFalse: [ ^closedBlock value ].
+ (timeLeft := deadline - Time millisecondClockValue) <= 0 ifTrue: [ ^timedOutBlock value ].
- self isConnected ifFalse: [ ^closedBlock value ].
- (Time millisecondsSince: startTime) < msecsDelta ifFalse: [ ^timedOutBlock value ].
"Providing a maximum for the time for waiting is a workaround for a VM bug which causes sockets waiting for data forever in some rare cases, because the semaphore doesn't get signaled. Remove the ""min: self class maximumReadSemaphoreWaitTimeout"" part when the bug is fixed."
readSemaphore waitTimeoutMSecs:
+ (timeLeft min: self class maximumReadSemaphoreWaitTimeout) ] repeat!
- (msecsDelta - (Time millisecondsSince: startTime) min: self class maximumReadSemaphoreWaitTimeout) ] repeat!
Item was changed:
----- Method: Socket>>waitForDataIfClosed: (in category 'waiting') -----
waitForDataIfClosed: closedBlock
"Wait indefinitely for data to arrive. This method will block until
data is available or the socket is closed."
socketHandle ifNil: [ ^closedBlock value ].
[
(self primSocketReceiveDataAvailable: socketHandle) ifTrue: [ ^self ].
+ self isOtherEndConnected ifFalse: [ ^closedBlock value ].
- self isConnected ifFalse: [ ^closedBlock value ].
"ul 8/13/2014 21:16
Providing a maximum for the time for waiting is a workaround for a VM bug which
causes sockets waiting for data forever in some rare cases, because the semaphore
doesn't get signaled. Replace the ""waitTimeoutMSecs: self class maximumReadSemaphoreWaitTimeout""
part with ""wait"" when the bug is fixed."
readSemaphore waitTimeoutMSecs: self class maximumReadSemaphoreWaitTimeout ] repeat!
Item was changed:
----- Method: Socket>>waitForDisconnectionFor: (in category 'waiting') -----
waitForDisconnectionFor: timeout
"Wait for the given nr of seconds for the connection to be broken.
Return true if it is broken by the deadline, false if not.
The client should know the connection is really going to be closed
(e.g., because he has called 'close' to send a close request to the other end)
before calling this method."
+ | deadline |
+ deadline := Time millisecondClockValue + (timeout * 1000) truncated.
+ [ self isOtherEndConnected and: [ deadline - Time millisecondClockValue > 0 ] ]
+ whileTrue: [
+ self discardReceivedData.
+ "Providing a maximum for the time for waiting is a workaround for a VM bug which causes sockets waiting for data forever in some rare cases, because the semaphore doesn't get signaled. Remove the ""min: self class maximumReadSemaphoreWaitTimeout"" part when the bug is fixed."
+ readSemaphore waitTimeoutMSecs:
+ (deadline - Time millisecondClockValue min: self class maximumReadSemaphoreWaitTimeout) ].
+ ^self isOtherEndConnected!
- | startTime msecsDelta status |
- startTime := Time millisecondClockValue.
- msecsDelta := (timeout * 1000) truncated.
- status := self primSocketConnectionStatus: socketHandle.
- [((status == Connected) or: [(status == ThisEndClosed)]) and:
- [(Time millisecondsSince: startTime) < msecsDelta]] whileTrue: [
- self discardReceivedData.
- "Providing a maximum for the time for waiting is a workaround for a VM bug which causes sockets waiting for data forever in some rare cases, because the semaphore doesn't get signaled. Remove the ""min: self class maximumReadSemaphoreWaitTimeout"" part when the bug is fixed."
- readSemaphore waitTimeoutMSecs:
- (msecsDelta - (Time millisecondsSince: startTime) min: self class maximumReadSemaphoreWaitTimeout).
- status := self primSocketConnectionStatus: socketHandle].
- ^ status ~= Connected!
Item was changed:
----- Method: Socket>>waitForSendDoneFor: (in category 'waiting') -----
waitForSendDoneFor: timeout
"Wait up until the given deadline for the current send operation to complete. Return true if it completes by the deadline, false if not."
+ | deadline timeleft |
+ deadline := Time millisecondClockValue + (timeout * 1000) truncated.
- | startTime msecsDelta msecsEllapsed |
- startTime := Time millisecondClockValue.
- msecsDelta := (timeout * 1000) truncated.
[
(self primSocketSendDone: socketHandle) ifTrue: [ ^true ].
+ self isThisEndConnected ifFalse: [ ^false ].
+ (timeleft := deadline - Time millisecondClockValue) <= 0 ifTrue: [ ^false ].
+ writeSemaphore waitTimeoutMSecs: timeleft ] repeat!
- self isConnected ifFalse: [ ^false ].
- (msecsEllapsed := Time millisecondsSince: startTime) < msecsDelta ifFalse: [ ^false ].
- writeSemaphore waitTimeoutMSecs: msecsDelta - msecsEllapsed ] repeat!