diff --git a/README.md b/README.md index 69e6acf..1805754 100644 --- a/README.md +++ b/README.md @@ -60,15 +60,16 @@ The other lines in this comment, that is, the lines that do _not_ begin with project, that is just one line: the line that includes `procmon.h`, the header file for the C code that we want to access. -Down [in the Go program's `main` function](procmon.go#L50), we spawn a goroutine to listen on a -channel for changes: +Down [in the Go program's `main` function](procmon.go#L50), we spawn a +goroutine to listen on a channel for changes: ```go go reportChanges() ``` -The `reportChanges` function simply reads values off of a channel and prints -them: +[The `reportChanges` +function](https://github.com/jordanorelli/procmon/blob/master/procmon.go#L38-L47) +simply reads values off of a channel and prints them: ```go func reportChanges() { @@ -106,12 +107,12 @@ void MonitorProcesses() { } ``` -This function does two things: it starts by accessing a singleton of our -Objective-C class `ProcWatcher` (that's `[ProcWatcher shared]`, which is defined -[here](ProcWatcher.m#L6)) and -invoking its `startWatching` method. This subscribes our `ProcWatcher` instance -to OS notifications. We'll come back to how the ProcWatcher subscribes to -events in a bit. +This function does two things: it starts by accessing a singleton of [our +Objective-C class `ProcWatcher`](ProcWatcher.m#L4) (that's `[ProcWatcher +shared]`, which is defined [here](ProcWatcher.m#L6)) and invoking [its +`startWatching` method](ProcWatcher.m#L16). This subscribes our `ProcWatcher` +instance to OS notifications. We'll come back to how the ProcWatcher subscribes +to events in a bit. #### sidebar: the Run Loop @@ -135,11 +136,9 @@ returns in the Go program, the Go runtime ends the process, which is _not_ what we want. So this call gives us two things: it sets up the notification system infrastructure, and it prevents our program from terminating. -#### back to observing NSNotifications +#### end sidebar: back to observing NSNotifications -[The `startWatching` -method](ProcWatcher.m#L6) -accesses the current OSX user's +[The `startWatching` method](ProcWatcher.m#L16) accesses the current OSX user's [`NSWorkspace`](https://developer.apple.com/reference/appkit/nsworkspace). The `NSWorkspace` handle allows us to hook into [`NSNotificationCenter`](https://developer.apple.com/reference/foundation/nsnotificationcenter) @@ -148,7 +147,7 @@ subscribe to the `NSWorkspaceDidLaunchApplicationNotification` and `NSWorkspaceDidTerminateApplicationNotification` notifications. Here's the subscription to the `NSWorkspaceDidLaunchApplicationNotification` notification, which is signaled by the operating system to inform an observer that an -application has been launched by the user: +application has been launched by the user: ```obj-c void (^handleAppLaunch) (NSNotification*) = ^(NSNotification* note) { @@ -190,7 +189,7 @@ bridging code in C that can be imported by our own C code. This allows our own C code to call back into the Go program and invoke Go functions. cgo will silently generate this C header file behind the scenes. That C header file, which is given the totally obvious and well-documented name `_cgo_export.h` is -generated when you run `go build` by cgo, used to help compile our C code, and +generated by cgo when you run `go build`, used to help compile our C code, and then deleted. You won't notice it getting written and deleted because it goes by so quickly, but it's there, and it's on disk when our C code gets compiled. In order to access those definitions from our C code, our C code has to import @@ -229,7 +228,19 @@ typedef GoInt64 GoInt; typedef long long GoInt64; ``` +That intermediate type is generated automatically by cgo in the intermediate +header file `_cgo_export.h` (before deleting it). If you want to look at this +file as a reference to see what is visible to your C code, you can manually +invoke cgo with `go tool cgo ...`, passing in the files to be processed by cgo. +You shouldn't need to do this in the normal case, but it can be useful for +debugging. + Anyway, calling that C function invokes the corresponding Go function `AppStarted`, which writes a value onto a channel. That value is read off of the channel by our `reportChanges` goroutine and used to print out the name of the App that had been launched or terminated by the user. + +Feel free to run the project on OSX. After running it, you should get no output +and your terminal should be under procmon's control. Open _another_ OSX app and +you should see a line like `started: com.apple.Notes` (if you start Notes.app, +for example). If you don't ... pull requests welcome ;)