swiftmacosuser-interfaceswiftui

How can I create a custom window button that appears on every app window when a user installs my macOS app?


Basically, I want to make it so that when the user installs my macOS 14 program, another window button appears next to the standard close, minimize, and maximize buttons for every application window that is open.

Image explaining where I want to have a window button

I want to make it so that this button, when pressed, "pins" the application, and prevents the user from closing it until the user presses it again, unpinning it.

The problem is, I have no idea how to achieve this, and being new to Swift programming and app development in general, the official Xcode documentation is very confusing to me. I've also spent countless hours researching about this, but there seems to be no relevant results. I'm sure this is possible, as the Parallels Desktop app does this (It adds a custom blue button next to the traffic cone when you open the app).

Can anyone help me with this? I need help with creating the button next to the standard window buttons and disabling the close button when the they click on that button. If this is not possible directly, then are there workarounds? I'm a complete beginner to this so any help with specific and clear instructions would be appreciated.

I'm on Xcode 15 and Swift 5 BTW.

I've tried some workarounds, such as creating a toolbar, then adding a button to that toolbar, but the button ended up on the right side of the window, and I wanted it to be on the left side, right next to the standard window buttons. I also tried creating a button, then placing it at the top of the screen, but it would not let me place a button higher than the title bar.

I have also got no idea how to disable the close button, and how to make it so that every app window will have this button.


Solution

  • The best way I can think of is to use the .navigation toolbar placement, along with .frame to get them close to each other. You could try something like this:

    .toolbar {
        ToolbarItem(placement: .navigation) {
            Button {
                // Button action
            } label: {
                Image(systemName: "circle.dotted.circle.fill")
                    .resizable()
                    .scaledToFit()
                    .padding(.leading, -10)
                    .frame(width: 13, height: 13)
                    .symbolRenderingMode(.hierarchical)
            }
            .ignoresSafeArea()
            .frame(width: 0, height: 15)
            .padding(.trailing, 10)
        }
    }
    

    I tried it out and it appears to work. You will just have to format the button however you want it to look like. Not sure if there is an alternate solution or not, but hopefully this can be a good workaround for you!