Skip to content

Instantly share code, notes, and snippets.

@ukane-philemon
Last active July 17, 2023 11:05

Revisions

  1. ukane-philemon revised this gist Jul 17, 2023. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions MacOSCompletionHandler.md
    Original file line number Diff line number Diff line change
    @@ -10,14 +10,14 @@ Note: It will be helpful to learn some [C](https://www.tutorialspoint.com/cprog

    I'm assuming you have good knowlege of Go, and already have Go installed on your system so lets dig into the actual implementaion.

    Run this your terminal:
    Run this in your terminal:
    ```
    go get github.com/progrium/macdriver/cocoa
    go get github.com/progrium/macdriver/core
    go get github.com/progrium/macdriver/objc
    ```

    In your go file:
    In your `.go` file:
    ```
    package main // Package declaration
  2. ukane-philemon revised this gist Jul 17, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion MacOSCompletionHandler.md
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ To handle these callbacks functions, I had to implement a `CompletionHandlerDele

    The `CompletionHandlerDelegate` accepts the `completionHandler` or `decisionHandler` and it's arguments, then executes the callback function with the arguments in Objc-C.

    Note: It will be helpful to learn some [C](https://www.tutorialspoint.com/cprogramming/index.htm)/[Objc-C](https://www.tutorialspoint.com/objective_c/index.htm) like basic types, method declaration/implementation, Object declaration etc.
    Note: It will be helpful to learn some [C](https://www.tutorialspoint.com/cprogramming/index.htm)/[Objc-C](https://www.tutorialspoint.com/objective_c/index.htm) like basic types, method declaration/implementation, type/class declaration etc.

    I'm assuming you have good knowlege of Go, and already have Go installed on your system so lets dig into the actual implementaion.

  3. ukane-philemon revised this gist Jul 17, 2023. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions MacOSCompletionHandler.md
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ Some time ago, I was in search of a Go library that would give me access to nati

    To handle these callbacks functions, I had to implement a `CompletionHandlerDelegate`. You can see the implementation here: https://github.com/decred/dcrdex/blob/master/client/cmd/dexc-desktop/app_darwin.go#L5-L55

    The `CompletionHandlerDelegate` takes the method and the arguments for the method then executes the callback function with the arguments. You can see how the Objective C methods are executed in the file above.
    The `CompletionHandlerDelegate` accepts the `completionHandler` or `decisionHandler` and it's arguments, then executes the callback function with the arguments in Objc-C.

    Note: It will be helpful to learn some [C](https://www.tutorialspoint.com/cprogramming/index.htm)/[Objc-C](https://www.tutorialspoint.com/objective_c/index.htm) like basic types, method declaration/implementation, Object declaration etc.

    @@ -107,5 +107,5 @@ func main() {
    }
    ```

    If you need more completion handlers, you can implement a function or method that accepts the completion handler and it's argiments. Then execute the completion handler in Objc-C.
    If you need more completion handlers, you can add/implement more functions or methods that accepts the completion handler and it's arguments. Then execute the completion handler in Objc-C.

  4. ukane-philemon renamed this gist Jul 17, 2023. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  5. ukane-philemon revised this gist Jul 17, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion completionHandler.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    Some time ago, I was in search of a Go library that would give me access to native macOS APIs, and Macdrive popped up on my radar. It was easy to use and had implemented most of the native macOS APIs. However, I faced an issue with handling callback functions for two macOS methods:
    Some time ago, I was in search of a Go library that would give me access to native macOS APIs, and [Macdrive](https://github.com/progrium/macdriver) popped up on my radar. It was easy to use and had implemented most of the native macOS APIs. However, I faced an issue with handling callback functions for two macOS methods:
    1. [webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:](https://developer.apple.com/documentation/webkit/wkuidelegate/1641952-webview?language=objc)
    2. [webView:decidePolicyForNavigationAction:decisionHandler:](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455641-webview?language=objc)

  6. ukane-philemon revised this gist Jul 17, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion completionHandler.md
    Original file line number Diff line number Diff line change
    @@ -107,5 +107,5 @@ func main() {
    }
    ```

    If you need more completion handlers, you can implement a function or method that accepts the completion handler as the first argument and the arguments for it as a second argument.
    If you need more completion handlers, you can implement a function or method that accepts the completion handler and it's argiments. Then execute the completion handler in Objc-C.

  7. ukane-philemon revised this gist Jul 17, 2023. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions completionHandler.md
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,8 @@
    Sometime ago, I was in search of a Go library that would give me access to Native MacOS APIs and Macdrive pop'ed on my radar. It was easy to use, and has impelemented most of the Native MacOS APIs. But I faced an issue with handling callbacks functions for two macOS methods:
    Some time ago, I was in search of a Go library that would give me access to native macOS APIs, and Macdrive popped up on my radar. It was easy to use and had implemented most of the native macOS APIs. However, I faced an issue with handling callback functions for two macOS methods:
    1. [webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:](https://developer.apple.com/documentation/webkit/wkuidelegate/1641952-webview?language=objc)
    2. [webView:decidePolicyForNavigationAction:decisionHandler:](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455641-webview?language=objc)

    To handle these callbacks functions, I had to implement a `CompletionHandlerDelegate`. See: https://github.com/decred/dcrdex/blob/master/client/cmd/dexc-desktop/app_darwin.go#L5-L55
    To handle these callbacks functions, I had to implement a `CompletionHandlerDelegate`. You can see the implementation here: https://github.com/decred/dcrdex/blob/master/client/cmd/dexc-desktop/app_darwin.go#L5-L55

    The `CompletionHandlerDelegate` takes the method and the arguments for the method then executes the callback function with the arguments. You can see how the Objective C methods are executed in the file above.

  8. ukane-philemon renamed this gist Jul 17, 2023. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  9. ukane-philemon created this gist Jul 17, 2023.
    111 changes: 111 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,111 @@
    Sometime ago, I was in search of a Go library that would give me access to Native MacOS APIs and Macdrive pop'ed on my radar. It was easy to use, and has impelemented most of the Native MacOS APIs. But I faced an issue with handling callbacks functions for two macOS methods:
    1. [webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:](https://developer.apple.com/documentation/webkit/wkuidelegate/1641952-webview?language=objc)
    2. [webView:decidePolicyForNavigationAction:decisionHandler:](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455641-webview?language=objc)

    To handle these callbacks functions, I had to implement a `CompletionHandlerDelegate`. See: https://github.com/decred/dcrdex/blob/master/client/cmd/dexc-desktop/app_darwin.go#L5-L55

    The `CompletionHandlerDelegate` takes the method and the arguments for the method then executes the callback function with the arguments. You can see how the Objective C methods are executed in the file above.

    Note: It will be helpful to learn some [C](https://www.tutorialspoint.com/cprogramming/index.htm)/[Objc-C](https://www.tutorialspoint.com/objective_c/index.htm) like basic types, method declaration/implementation, Object declaration etc.

    I'm assuming you have good knowlege of Go, and already have Go installed on your system so lets dig into the actual implementaion.

    Run this your terminal:
    ```
    go get github.com/progrium/macdriver/cocoa
    go get github.com/progrium/macdriver/core
    go get github.com/progrium/macdriver/objc
    ```

    In your go file:
    ```
    package main // Package declaration

    /*
    #cgo CFLAGS: -x objective-c // Tells compiler we are using objective-c
    #cgo LDFLAGS: -lobjc -framework WebKit -framework AppKit // Tells linker which framework to dynamically link to

    // Import required Objc-C headers. We need these to access classes and types etc.
    #import <objc/runtime.h>
    #import <WebKit/WebKit.h>
    #import <AppKit/AppKit.h>

    // NavigationActionPolicyCancel is an integer used in Go code to represent
    // WKNavigationActionPolicyCancel
    const int NavigationActionPolicyCancel = 1;

    // CompletionHandlerDelegate implements methods required for executing
    // completion and decision handlers.
    @interface CompletionHandlerDelegate:NSObject
    - (void)completionHandler:(void (^)(NSArray<NSURL *> * _Nullable URLs))completionHandler withURLs:(NSArray<NSURL *> * _Nullable)URLs;
    - (void)decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler withPolicy:(int)policy;
    - (void)authenticationCompletionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler withChallenge:(NSURLAuthenticationChallenge *)challenge;
    @end

    @implementation CompletionHandlerDelegate
    // "completionHandler:withURLs" accepts a completion handler function from
    // "webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:" and
    // executes it with the provided URLs.
    - (void)completionHandler:(void (^)(NSArray<NSURL *> * _Nullable URLs))completionHandler withURLs:(NSArray<NSURL *> * _Nullable)URLs {
    completionHandler(URLs);
    }

    // "decisionHandler:withPolicy" accepts a decision handler function from
    // "webView:decidePolicyForNavigationAction:decisionHandler" and executes
    // it with the provided policy.
    - (void)decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler withPolicy:(int)policy {
    policy == NavigationActionPolicyCancel ? decisionHandler(WKNavigationActionPolicyCancel) : decisionHandler(WKNavigationActionPolicyAllow);
    }
    @end

    void* createCompletionHandlerDelegate() {
    return [[CompletionHandlerDelegate alloc] init];
    }

    */
    import "C" // Import the Cgo pseudo package
    import (
    "net/url"

    "github.com/progrium/macdriver/cocoa"
    "github.com/progrium/macdriver/core"
    "github.com/progrium/macdriver/objc"
    )

    // Initialized when the app has been started
    var appURL *url.URL
    // completionHandler handles Objective-C callback functions for some
    // delegate methods.
    var completionHandler = objc.Object_fromPointer(C.createCompletionHandlerDelegate())

    func main() {
    // .....
    // Assuming you are using the macdrive DefaultDelegateClass
    cocoa.DefaultDelegateClass.AddMethod("webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:", func(_ objc.Object, webview objc.Object, param objc.Object, fram objc.Object, completionHandlerFn objc.Object) {
    panel := objc.Get("NSOpenPanel").Send("openPanel") // Create a new panel. As of writing this class has not been implemented in macdrive but there is a PR for that.
    openFiles := panel.Send("runModal").Bool() // Start the open panel modal and convert the response to bool. "runModal" will block until the user either cancels or selects a file
    if !openFiles {
    completionHandler.Send("completionHandler:withURLs:", completionHandlerFn, nil) // Execute the completion handler with nil if the open panel was cancelled.
    return
    }
    completionHandler.Send("completionHandler:withURLs:", completionHandlerFn, panel.Send("URLs")) // Execute the completion handler with selected URLs.
    })

    cocoa.DefaultDelegateClass.AddMethod("webView:decidePolicyForNavigationAction:decisionHandler:", func(delegate objc.Object, webview objc.Object, navigation objc.Object, decisionHandler objc.Object) {
    reqURL := core.NSURLRequest_fromRef(navigation.Send("request")).URL() // Fetch the request URL
    destinationHost := reqURL.Host().String() // Get the request URL host
    var decisionPolicy int
    if appURL.Hostname() != destinationHost { // Check if the host match the app's host
    decisionPolicy = NavigationActionPolicyCancel // Set to NavigationActionPolicyCancel for external links then open the link using macOS native active APIs below.
    // See: https://developer.apple.com/documentation/appkit/nsworkspace?language=objc
    cocoa.NSWorkspace_sharedWorkspace().Send("openURL:", core.NSURL_Init(reqURL.String()))
    }
    completionHandler.Send("decisionHandler:withPolicy:", decisionHandler, decisionPolicy) // Execute the completion handler with our decision
    })

    // .....
    }
    ```

    If you need more completion handlers, you can implement a function or method that accepts the completion handler as the first argument and the arguments for it as a second argument.