Help with background processes please

Hello,

I have an app, myApp, which is used to display images, (.jpg, png), in a folder, “Debut”; as a new image is added to the folder it is displayed in an image well in myApp.

The images are added when I click on “Take snapshot” in another program, Debut, the program name is Debut and the folder name is also Debut.

So, to take a snapshot, Debut has to be the active app and myApp has to be a background process.

My app has a timer in Mode 2, which polls for folderitem count in “Debut”.
What happens is that when a snapshot is taken the image goes into the folder, “Debut”, but because myApp is in the background it is not aware that the folder count has changed.

How can I make myApp which is in the background to process to still poll for folderitem count in “Debut”.

Thanks.

Lennox

File system events
Basically you register to be notified when certain things happen in the file system & when they do you get a notification
You can then do whatever is appropriate - like moving your app to be in the foreground

MacOSLIb has them for OS X
MBS plugins have something for OS X & Windows

Thanks Norman.

I’ll try the MacOSLib.

Lennox

I would also suggest perhaps using IPC sockets, you could then send messages between the two apps. If you wanted, you could even send the image data over the socket and avoid having to hit the disk, which would save power consumption.

Thanks Sam,

IPC sockets would be a good way to do it. I have been advised about IPC sockets for various things previously, but I have never been able to do it, an example project would be fantastic, do you have a link for any IPC example project that you would like to share?

Thanks again Sam.

Lennox

Hi Norman,

Is this what you are referring to? FileManager/FSIterator/Methods/VisibleCount.

Function VisibleCount(f as FolderItem) As UInt32
if not f.Exists then
return 0
end if
if not f.Directory then
return 0
end if

#if targetMacOS
soft declare function FSCatalogSearch lib CarbonLib (iterator as Ptr, ByRef searchCriteria as FSSearchParams, maximumObjects as UInt32, ByRef actualObjects as UInt32, ByRef containerChanged as Boolean, whichInfo as Uint32, catalogInfos as Ptr, refs as Ptr, specs as Ptr, names as Ptr) as Int16

dim iterator as new FSIterator(f, FSIterator.kFSIterateFlat)

//build search criteria
const fsSBFlFndrInfo = 8 //For files only search by the file’s Finder info.
const fsSBDrUsrWds = 8 //For directories only search by the directory’s Finder info.
const fsSBFlParID = 8192 //For files only search by the file’s parent ID.
dim criteria as FSSearchParams
criteria.searchTime = 0
criteria.searchBits = fsSBFlFndrInfo + fsSBFlParID
criteria.searchNameLength = 0
criteria.searchName = nil

//add parent dir criterion

dim searchInfo1 as new MemoryBlock(FSCatalogInfo.Size)
searchInfo1.UInt32Value(4) = f.MacDirID
searchInfo1.Long(80) = FileManager.kIsInvisible

criteria.searchInfo1 = searchInfo1

dim searchInfo2 as new MemoryBlock(FSCatalogInfo.Size)
searchInfo2.Long(80) = FileManager.kIsInvisible

criteria.searchInfo2 = searchInfo2

const maximumObjects = 16
dim actualObjects as UInt32
dim containerChanged as Boolean

dim nameArray as new MemoryBlock(maximumObjects*HFSUniStr255.Size)

dim OSErr as Int16 = FSCatalogSearch(iterator, criteria, maximumObjects, actualObjects, containerChanged, 0, nil, nil, nil, nameArray)
if OSErr <> noErr then
  break
end if

return actualObjects

#endif
End Function

Lennox

Hi Sam,

I found one in the example folder, I will try that, IPCSocket.xojo_binary_project.
Thanks.

Lennox

[quote=263256:@Lennox Jacob]Hi Norman,

Is this what you are referring to? [/quote]
No
Try the FSEventModule

Hi Norman,

I’ve seen this …
Private Sub HandleEvent(numEvents as integer, eventPaths as Ptr, eventFlags as Ptr, eventIDs as Ptr)
#if TargetMacOS

#pragma DisableBackgroundTasks
#pragma StackOverflowChecking false

declare function CFArrayGetStringAtIndex lib CarbonLib alias "CFArrayGetValueAtIndex" (theArray as Ptr, idx as Integer) as CFStringRef
declare function CFArrayGetValueAtIndex lib CarbonLib alias "CFArrayGetValueAtIndex" (theArray as Ptr, idx as Integer) as Ptr
declare function CFNumberGetValue lib CarbonLib (nbr as Ptr, theType as integer, outValue as Ptr) as Boolean

const kCFNumberIntType = 9
const kCFNumberLongType = 10

dim id as UInt64
dim path as String
dim flags as UInt32
'dim mb as new MemoryBlock( 8 )
dim mb2, mb3 as MemoryBlock
'dim p as Ptr
dim arp() as string
dim arf() as int32
dim arid() as UInt64
dim f as FolderItem

mb2 = eventFlags
mb3 = eventIDs

for i as integer=0 to numEvents - 1
  path = CFArrayGetStringAtIndex( eventPaths, i )
  arp.Append   path
  
  if RelativeTo<>nil then
    f = GetFolderItemFromPOSIXPath( RelativeTo.POSIXPath + "/" + path )
  else
    f = GetFolderItemFromPOSIXPath( path )
  end if
  
  flags = mb2.UInt32Value( i * 4 )
  arf.Append   flags
  
  id = mb3.UInt64Value( i * 8 )
  arid.Append   id
next

RaiseEvent  FilesystemModified( arp, arf, arid )

#else

#pragma unused numEvents
#pragma unused eventPaths
#pragma unused eventFlags
#pragma unused eventIDs

#endif

End Sub

But I am not sure if this is the one and also I do not know how to call it.

If my app is in the background can it still call it?

Thanks again.

Lennox

Hi Sam,

I don’t think IPC sockets will work because I do not have access to Debut, Debut is not one of my apps, it is a commercial app.

Thanks.

Lennox

[quote=263250:@Lennox Jacob]My app has a timer in Mode 2, which polls for folderitem count in “Debut”.
What happens is that when a snapshot is taken the image goes into the folder, “Debut”, but because myApp is in the background it is not aware that the folder count has changed.[/quote]

I understand that there may be more efficient ways of doing this (depending on how many files are in that folder), but the OPs question was why did FolderItem.count not work whilst his application was in the background.

FolderItem.count called from a Timer should normally work whether the application if foreground or background. I knocked up a quick test app in MacOS and it works just fine when sent to the background…

[code] dim f as FolderItem

f = New FolderItem (SpecialFolder.Desktop)
label1.Text = Str (f.Count)[/code]

Just look in /Applications/Xojo 2016r1.1/Example Projects/Communication/IPCSocket.xojo_binary_project

This is confusing because it should not be true. The timer continues to fire even when your app does not have focus. I’d look at this a little more closely. That said, using filesystem events is a more elegant approach, albeit more difficult.

Point is YOU dont call it
You tell the OS what to notify you about & then it does
You respond to the OS notifying you

Thanks Norman,

So how do I tell the OS to notify me about that?
Some code would be appreciated.

Thanks again.

Lennox

There are examples IN MaOSLIb itself
Try the one called FSEventStream

Thanks Norman,

I downloaded the latest version of macoslib, v.187 and when I ran it I got this message "Test in Cocoa module failed: ".

I saw the example under Examples/Convenience Extensions and when I ran it and added a folder item to the UserHome folder nothing happened. I figure that it does not work on my system - Mac OS X 10.11.4 (15E65)

Any suggestions?

Thanks again.

Lennox

Hello,

I added a TextField to the window and added this to the timer
TextField3.Text = Str(Ticks)

When the Timer is activated TextField3.Text changes as expected
When the app is in the background the timer still functions, confirming that the timer works even if the app is in the background.

My app seems to be working now, with and without that testField. I don’t know what the problem was.

I would prefer using filesystem events since it is a more elegant approach as Tim mentioned, any advice on how this can be achieved? Macoslib does not appear to support Cocoa for this.

Some code would be appreciated.

Thanks again.

Lennox