Articles

How to compare Go slices?

Problem: You have two slices that potentially share the same memory buffer meaning that appending to one can cause changes in another one. So, how to understand if two slices share memory? Let’s imagine we have a functions like: func IsMemoryShared(a, b []int) bool { ... } And we want to preserve following behaviour: a := []{1, 2, 3} b := []{1, 2, 3} IsMemoryShared(a, a) // true IsMemoryShared(a[:2]) // true IsMemoryShared(a, b) // false IsMemoryShared(a[1:0], b[1:0]) // false It is known that slice in Go backed by a struct and contain a pointer to a place in memory where slice data is stored and two integers - length and capacity of the slice.

How to open window in MacOS programmatically using Swift

Once I face a problem - “How can I create a normal window on Mac OS?”. Definitely it is possible to use XCode, generate new project using very modern tools and start writing events handling functions/callbacks/delegates/etc. But what if I want to do everything using code, for example last available version of Swift. And here I faced a problem cause there are no normal step-by-step guides which will explain how to do it.

Initial Commit

So, I want to Welcome everybody who at any circumstances get to this page. Recently I decided that it will be great at least to save some random things that I found interesting but also try to share it cause I strongly believe that if something become interesting to one person then this person is not alone and there is non zero probability that there is somebody else who can be interested in it.

How to open window in MacOS programmatically using Swift

April 27, 2019

Once I face a problem - “How can I create a normal window on Mac OS?”. Definitely it is possible to use XCode, generate new project using very modern tools and start writing events handling functions/callbacks/delegates/etc. But what if I want to do everything using code, for example last available version of Swift. And here I faced a problem cause there are no normal step-by-step guides which will explain how to do it. There are some information on Stack Overflow or on other sites but nothing really complete.

So, having a lot of knowledge from past how to do the same as I want on Windows using WinAPI, I started to dig into documentation and based on own mistakes start writing some code.

Here is first version of code:

import AppKit

class AppDelegate: NSObject, NSApplicationDelegate {
    var window: NSWindow!

    func applicationDidFinishLaunching(_ notification: Notification) {
        NSLog("Start app")

        window = NSWindow(contentRect: NSMakeRect(0, 0, 1024, 768),
            styleMask: [.closable, .titled],
            backing: .buffered,
            defer: false)

        window.title = "Hey, new Window!"
        window.center()
        window.orderFrontRegardless()      
    }

    func applicationWillTerminate(_ notification: Notification) {
        NSLog("Terminate app")
    }

    func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
        return true
    }
}

let app = NSApplication.shared
let appDelegate = AppDelegate()
app.delegate = appDelegate

app.run()

Basically we define AppDelegate which implements several methods which define behavior that we need from application. applicationDidFinishLaunching is called when application finished launch and simplified it is our WinMain. applicationWillTerminate - added only to be able to log fact when application is got closed. applicationShouldTerminateAfterLastWindowClosed - additional configuration for application which result in automatic close of application (it means that event loop will be stopped) when last Window object is closed, in our cases we have only one window, so when it will be closed at the same time whole application will be terminated.

This approach works and it seems like ideal solution for what we need, but the answer is - no. What is really needed is to be able to control event loop which is hidden here in run function of the application. Here we want to have full control for the events and be able to do something between events handling.

So here comes second version -

import AppKit

var running = true

class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationDidFinishLaunching(_ notification: Notification) {
        NSLog("start app")
    }

    func applicationWillTerminate(_ notification: Notification) {
        NSLog("applicationWillTerminate")
        running = false
    }
}

class WindowDelegate: NSObject, NSWindowDelegate {
    func windowDidResize(_ notification: Notification) {
        NSLog("windowDidResize")
    }

    func windowWillClose(_ notification: Notification) {
        NSLog("windowWillClose")
        running = false
    }
}

let app = NSApplication.shared
let appDelegate = AppDelegate()
app.delegate = appDelegate
app.setActivationPolicy(.regular)
app.finishLaunching()

let window = NSWindow(contentRect: NSMakeRect(0, 0, 1024, 768),
            styleMask: [.closable, .titled, .resizable, .miniaturizable],
            backing: .buffered,
            defer: true)

let windowDelegate = WindowDelegate()
window.delegate = windowDelegate
window.title = "Hey, Window under control!"
window.acceptsMouseMovedEvents = true
window.center()
window.orderFrontRegardless()

while(running) {
    var ev: NSEvent?
    ev = app.nextEvent(matching: .any, until: nil, inMode: .default, dequeue: true)
    if (ev != nil) {
        NSLog("%@", ev!)
        app.sendEvent(ev!)
    }
}

app.terminate(nil)

Good! What do we have here? First, we have two classes AppDelegate and WindowDelegate - they help us to capture events from window and application in the same way as we normally do for this objects in Mac OS. Then we create application, window and wire with delegates. Then event loop starts until global variable running is set to true basically we capture nextEvent without any filtering and if there is event we send it to default handler for the application. As far as I understand events will be handled by application, application delegate, window and window delegate (probably order is wrong, need to find some clarification of how events are propagated). Solution can be simplified, we can remove all delegates and not use them but then handling of windowDidResize for example will be non-trivial.

That’s it for today.