How Can I Create a Series of Minimal App Windows That Only Consist of a Titlebar?

I expected that 32 would be the max, 16 in each monitor, 31 on the laptop running without an external monitor. When I discovered that I could go past that, I stopped at 40 for experimental purposes (41 in two monitors).

If I can make something that scales to 40, then it should handle 20 easily. Having to physically switch to each and every desktop to find a desktop by name is not practical.

I can put a TextEdit window in each Desktop or a Notes window, or Finder or a lot of things, and I can quickly switch to that Desktop by activating the window by name from an easily accessible list. But I use TextEdit and Notes and Finder a lot.

So I've been expecting that would have to dedicate some unused but minimally functional app to this purpose.

It started to look like KBM's HTML Prompt could do it, but that turns out to have been wishful thinking. It could generate the ideal geometry window, but it can't list all open windows by title. And its not good about windows being moved from Desktop to Desktop. I haven't yet tried building a script that creates an HTML Prompt window on multiple Desktops, but when I create multiple windows on one desktop and try to move one of them to another Desktop, all the other HTML Prompt windows come along with it. That suggests that part of the listing problem is that they are not really separate windows.

I suppose I could build my own app (theoretically, I'm not that app builder, yet) that has no other purpose than to display a title and list all the titles of all windows -- provided that it could also do what TE and Finder and Notes can do, but a lot of apps can't, and that's have each window stay in its original desktop through a reboot. That's the original question in this thread, an app that is only a titlebar where I can list the titles and which hopefully stays on its Desktop when rebooting.

Thanks for the reminder about the Script Debugger Forum. Maybe I should post the question on Ask Different or Stack Exchange too. All the "build your own app" tutorials that I have found don't go near the topics that I need.

And then there's AltTab, Which, and Contexts, mentioned above. AltTab isn't what I need, for reasons described in item #32 above, but the others might get me there, I haven't looked yet.

Again, thanks to everyone for thinking about this.

@gglick @Frankb
Hi Gabe, hi Frank,

Do you have a link for Which? Googling for it, I've been unable to come up with search terms that don't just offer to tell me which apps I have on my Mac.

sure, here is
Witch

the other link is in the text from gglick
I do have Witch and Contexts,

Yes you understand correctly. It takes about as long as it takes to manually switch between each window. And you have to have a hotkey for each window. Or, you could just have a hotkey for the first window, and another hotkey to move to the next window.

I don't believe it is what you need. However, if you really want to try it out, I can set it up to work with just the two hotkeys, and post it. Let me know.

1 Like

Thanks Dan. I'm inclined to agree with you, even without trying it out. Your tool works for what you need it for, but it's not practical for me to use to generate a menu of Desktop Workspaces to pick from for a desktop switch.

The folks over at AltTab are struggling with a change in OSX 12.2 that breaks the technique they've been using, and one of the ideas they're working on is to put an invisible app in each Desktop Workspace so they can switch Desktops quickly to gather all the windows that are in each Workspace. That's very like where I've been heading, although I don't care if the app is invisible. I can use it to display the name of the current DTWS.

So I'm still experimenting, waiting for the right combination of ideas to gel.

Thanks for the help.

2 Likes

Hey August,

Well – there's a thought...

Create a stay-open AppleScript applet with an idle handler that collects open apps and windows as appropriate into properties.

Then you can query the applet and ask what windows are open with little to no lag time.

As long as the applets all have different names, I think you might well be able to call from anywhere.

You'll have to test to be sure.

If that works you could also have a force-refresh handler, so you're not completely dependent upon the idle-time.

-Chris

1 Like

Thanks Chris,

I really like that concept. However, other stuff you wrote suggests you might be making it harder than I think it needs to be. (And maybe that's my problem, too.)

That sounds like reinventing AltTab or Contexts. In my current thinking and design, I am emphatically NOT interested in listing every open window of every open app. To me, that defeats the point of having multiple Desktop Workspaces (DTWS).

Unfortunately, that is what most of the "Desktop Managers" out there focus on. But listing open windows does not work for me, that's why I put related windows from different apps into separate Desktops. Very often those are the same apps, just open on different files, different folders, different web pages. So systems that support switching from app to app easily are useless as well.

I've seen myself have 80 to 100 windows open, Notes, TextEdit, Finder, Browser with several tabs, Preview, maybe Terminal, and who knows what else for each of a dozen or more different ongoing projects or tasks. Listing all the windows is not helpful. Listing all the apps is not helpful. That's why I put them in separate Desktops.

The challenge for me at the moment is how to I assign a name to each DTWS and then list all the names. CurrentKey Stats, which is my inspiration, uses invisible windows, where the window title is the Desktop name. I'm trying to recreate that so I have something workable and maintainable that works for OSX versions newer than Mojave, now that CKS has been abandoned.

Also, I don't care if the windows are invisible. In fact an unobtrusive window that consists of only a titlebar, that I can position at the top or bottom of the screen, seems like it would be very useful in identifying which Desktop I'm in.

I had hoped, based on Peter's suggestion above, that KBM's HTML Prompt could work, but despite that idea dominating the previous conversation in this thread, it turns out that listing the open KBM HTML Prompt windows in all Desktops is not simple. If other people also have a need for listing open KBM HTML Prompt windows, maybe we can lobby Peter to look into providing that feature.

At this point, I seem to have two options:

  • Write my own app that just makes window titlebars and can list them in AppleScript, which is currently beyond me.
  • Find a lightweight app that is properly behaved enough and that I don't care to use for its intended purpose, e.g. some ASCII text editor, and dedicate that app to providing my DTWS identifiers.

If you see other alternatives than the above, please suggest something.

The first option is what I was trying to ask for in the OP. I haven't always been clear in my explanations of what I'm looking for. I hope I am clearer here. (I'm certainly wordy, not a good sign.)

As for my second option, Stickies would work as a dedicated, lightweight app to put a name on a Desktop, except that when you reboot, all open Stickies windows open the first Desktop, which adds 20 minutes of moving Stickies around to the reboot process, which makes it painful enough to be useless.

However, when you suggested:

that made me think that a background process that kept track of current names and position could provide data to automate moving all the Stickies after a reboot. That seems like a kludgey patch when other apps do the same thing transparently. I'm currently voting for simplicity.

Notes seems like it will work, except that I already use Notes for other purposes, particularly sharing between my laptop and my iPhone and sharing to-do lists, shopping lists, project lists, etc. with my wife. I suppose I could put all the Desktop names in a folder that I otherwise ignore.

I tried using TextEdit, but I also use TextEdit for other purposes. Also, I've run into a problem that with somewhere around 20 TE windows open, on reboot it doesn't transparently put everything on the original desktops, instead it does the same thing as Stickies, reopening all windows on the same Desktop.

So that's where my thinking is at this point. I'm trying to name 40 Desktops to manage 100 open windows. At least be able to do that, so I have some headroom when I'm using 25 Desktops and 40 windows.

Thanks for your help. It does help to have other people at least thinking about the issues.

What you're not understanding (I think) is that the applets on the different desktop will be limited to the desktop they're on (again I think).

You'll have to test.

I reiterate that you're probably better off with a focused use utility for all this, but the applet route may work pretty well if you're determined to roll your own.

You'll have to test though; I have other things to do and am still on Mojave for that matter.

Thanks. That's a new idea: an applet on each desktop that keeps track of the name of the desktop and its position (Desktop Number in Mission Control).

If I could find one, I'd be happy with that. I can define the UX for that utility, but I'm not the guy to build it (yet).

Of course -- I really appreciate all the time and attention you've given to help me stumble my way through this.

I am too. The Catalina installer insists that my hard drive is defective because it's not S.M.A.R.T. enough. So after getting all my incompatible app issues handled (hopefully, we'll see...) I'm stalled on updating to the now unsupported Catalina until I can replace my hard drive. I'm still optimistic that my Mac usage will eventually include a supported OS, at least for a while.

1 Like

Clear a variable.

Use the Execute a JavaScript in Custom Prompt action to execute JavaScript in all the windows.

In the JavaScript, add the name and id of the window to the variable.

As for activating the window, I'm not sure how to do that. It's probably possible.

1 Like

Peter - When I do this:
image
... the result is always blank.

Javascript
let windowInfo = window.KeyboardMaestro.GetVariable("WindowTest");
windowInfo += `${document.body.dataset.kmwindowid}: ${document.title}\n`
window.KeyboardMaestro.SetVariable("WindowTest", windowInfo);

If I add a "Pause" action before displaying the results:
image
... the result only ever contains 1 line, as though it is being overwritten each time.

So I thought maybe the Javascript was being run asynchronously in each Prompt. So I created this macro:
image

... and changed the Javascript to this:
image
... and it worked.

Javascript
window.KeyboardMaestro.Trigger(
	"C7942FCE-2AE5-485B-B6F0-9A316D7D8CD5",
	`${document.body.dataset.kmwindowid}: ${document.title}`);

Do you have any thoughts on this? Am I correct about the asynchronous execution? Any idea of how to do this better?

You will probably have to trigger a macro with a parameter from the JavaScript, and have it append the title to the variable.

All of the windows are executing at once, so they are probably all reading the empty variable, adding their own name, and then writing the single line to the variable.

Include a Semaphore Lock action at the start of the Update Variable macro to ensure it runs to completion before starting the next one (although, since there is an action for Append Variable with Text, and that action probably is synchronous anyway, it likely wont be necessary).

1 Like

Right - that's what I ended up with. Good to know I was on the right track.

2 Likes

This here is the reason that I haven't pursued the Custom Prompt direction (yet) -- being able to activate the selected window is crucial to the workflow I'm trying to develop.

DanThomas, I haven't worked through your example well enough to actually follow it. Were you sending text to each of a bunch of Custom HTML Prompt windows? Was this part of answering Peter's open question of how to activate a selected window?

For a while I had been pursuing the idea that I might simply list all windows and filter for whatever titles followed my naming pattern of " Desktop Workspace Identifying Title" (DTWSID) where "X" will be the hotkey in the generated "Prompt With List" menu. See Activate (Focus) the First Window (Of Any App) That Contains “Search String”.

Algorithmically that seemed a very flexible direction, but when I found that AppleScript was taking two minutes to search for all the windows of all the open apps and list them, that was not a practical way to generate a Desktop Choice Menu.

I've also been looking at what it might take to actually create an AppleScriptable Swift app with XCode. My best lead on that so far has been Making Your Mac App’s Data Scriptable
which has a sample app in GitHub that demos adding and retrieving data from an XCode app -- making an app accessible from AppleScript requires creating a dictionary of AppleScript events that the app can respond to. In its simplicity, that article doesn't show how to get AppleScript to access a Swift function or a menu item. But it's a start. Last night I also found Making A Mac App Scriptable Tutorial which demos a window-based To-Do-List app. While more complicated, it may have more of what I need.

Just checking in...

I don't remember what it was related to. But as for activating a Custom HTML Prompt and bringing it to the foreground, I converted my Custom HTML Prompt to an Electron app, so it's an application now and I can alt-tab to it.

2 Likes

It would be interesting to read more about your Electron conversion.

1 Like

Yes, please tell us more! Or point us to described it in the Electron Forum, or ...

As an application, can you get a list of all its windows?

Unless you're a Javascript developer, I wouldn't recommend even considering it. Also, there's no real communication with Keyboard Maestro, except for what's available via KM's URL Scheme.

In theory you could get information back from KM using the URL Scheme and having KM write the response to a file, but that's problematic at best.

I'm using it for a project that isn't really related to Keyboard Maestro, except that I had originally written it as a Custom HTML Prompt.

Browse the Electron.js docs and I think you'll see right away what kind of knowledge it requires.

3 Likes

Thanks for the perspective.

I've done some JavaScript development -- back near the turn of the century when I was working at Adobe, I wrote some JavaScript tools for modifying reviewer comments in a PDF to tag them with their resolution status: Urgent, Resolved, Open Questions, Ignore, Postpone, but it's been 20 years and this is a totally different context and, as you say, it's not really the tool for the job.

Can any of the app-creation-savvy developer types here offer me suggestions?

I've been pursuing the direction of using XCode to create a small app that can be called by AppleScript to do what I want.

It's an adventure. Along the way I upgraded my Mac's hard drive so that I had room to install XCode (the biggest app I've ever seen) which also allowed me to upgrade to Catalina (finally!) and weeks later I'm still cleaning up the debris from that.

I'm stumbling my way around XCode and Swift. I've used many other programming languages, from Fortran to JavaScript, but nothing at the Application level like this.

I found out that the key piece of being able to call an app from AppleScript is the SDEF file, an XML file that lists all the AppleScript operations that the app can recognize. And I've found out that this is a very poorly documented aspect of the Apple ecosystem. I found a couple of good tutorials, especially Boilerplate to Add AppleScript to Your macOS App in 2020 (as well as some really bad ones).

I've gotten to the point where I have a function defined in AppDelegate.swift called createNewWindowWithTitle. When I call that function within applicationDidFinishLaunching, it works fine. I simply start the app and I automatically get the window I specified in the function call.

Here's createNewWindowWithTitle:

    @objc func createNewWindowWithTitle(_ title: String, width: CGFloat, height: CGFloat) {
        let window = NSWindow(contentRect: NSRect(x: 0, y: 0,
                width: width, height: height),
                styleMask: [NSWindow.StyleMask.titled],
                backing: NSWindow.BackingStoreType.buffered,
                defer: false)
        window.title = title
        window.makeKeyAndOrderFront(nil)
    }

As I said, it works.

But I'm missing key concepts on how to call that function from whatever it is that the SDEF entry can trigger. SDEF is in XML. Is there a field where I enter the function name to call when accessed by AppleScript? Is there a field to enter the Swift code (in the function definition above) to execute? Or do I need an observer in AppDelegate.swift that somehow watches for when the entry in SDEF gets activated? Or what?

All the tutorials that I've found so far that get anywhere near this all focus on how to use AppleScript to automate interactions with the app's primary window. But my windows don't have any interactions and none of the windows are primary. They are all placeholders and that's all they ever need to be.

Can any of the app-creation-savvy developer types here offer me suggestions of where to look for documentation or tutorials? Can you make enough sense out of what I don't know how to ask about to be able to point me to the right terminology? Just finding out about SDEF files gave me a keyword to search on. What's next?

Thanks.