Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use server endpoint for interacting with alt-tab #768

Closed
wants to merge 4 commits into from

Conversation

ayroblu
Copy link
Contributor

@ayroblu ayroblu commented Jan 9, 2021

For solving #371
Superseeds #761

Used Swifter library, added via cocoapods.

Currently supports 4 api methods,

  • GET / -> {}
  • GET /windows -> {...}
  • PUT /window/focus, params: windowId -> ``
  • DELETE /window, params: windowId -> ``

TODO:

  • Is this okay? It doesn't bother with the whole multi month multi package etc refactor
  • Add UI preference to enable or disable the server
  • Add more api endpoints (maybe?)
  • Decide on what to expose for windows
  • Should GET / be exposed, and if so, perhaps it should show a help or something?

@lwouis
Copy link
Owner

lwouis commented Jan 10, 2021

Hey @ayroblu thanks for sharing this PR! Some first high level reaction from my phone:

  • how large is the swifter library? If it's just creating an http server maybe it's not that much more code to do it with swift stdlib. The concern here is the size of the .app, and general dependency on an external project.
  • i assume that the server is running on the main thread. I think it should be running on it's own thread. Now ideally callbacks to its endpoint would also be on that thread, and the Windows list would be concurrent. Currently it's not so callbacks should be executed on the main thread probably. This means that UI actions and HTTP actions compete with each other for the app's attention essentially
  • For the preferences, i think this feature will be used by <1% of users, so probably it's time to add an "Advanced" tab in the preferences window. Not a fan of this, but i don't see a better approach
  • Is the HTTP server really the best approach for the goal? HTTP still requires a client to interact with. A cli interface would fit the role better i think. There seem to be ways to bundle one with a GUI app which would maybe do the same thing but in a simpler way, both from the internal point of view, and the user point of view. We could have a preference to "install the cli interface" which would simply symlink the binary into the user /usr/bin. More discussion: https://stackoverflow.com/questions/12203377/combined-gui-and-command-line-os-x-app

@ayroblu
Copy link
Contributor Author

ayroblu commented Jan 10, 2021

I think it's around 1MB to the debug builds so from 20MB to 21 MB

Advanced tab: the alternative is to fork and distribute a forked version. I currently can't build a release version for certificate reasons, but if it's easy then I could just do that?
But yeah advanced tab feels the way to go if you want it

Http server: depends on how you see things, for me this is something that everyone understands, easy to maintain and quick to do. Perhaps the more efficient thing to do would be RPC with gRPC for example, but then clients also must now depend on gRPC and that's not very friendly.

If you want I can write a cli, it would just be a shell script with a bunch of if statements and curl commands like curl localhost:9999/windows.

Edit: to better answer your last point, even if you symlink the app for a cli, you still have to do cross process communication, in this case, this PR allows:
Alfred -> AltTab.app
And with XPC and a custom cli app you would get:
Alfred -> alttab-cli -> AltTab.app

The result is not so different I think

Edit 2: here is where swifter uses the async API so I don't think it's an issue, otherwise the main app wouldn't run as it would be blocked I think:
https://github.com/httpswift/swifter/blob/9483a5d459b45c3ffd059f7b55f9638e268632fd/XCode/Sources/HttpServerIO.swift#L78

@lwouis
Copy link
Owner

lwouis commented Jan 10, 2021

How about a solution like this? It's very similar in features as what you have demonstrated in this PR, except it avoids having to use the networking stack (i.e. having an HTTP server running on an open port), and doesn't require an external library. What do you think?

Also going back to what kind of interface to expose, I think going through an HTTP client is not convenient for scripting. I think people would expect some kind of binary like at and then run at --windows instead of curl localhost:port/windows. I'm not sure about the performance of both. Probably fast enough?

@ayroblu
Copy link
Contributor Author

ayroblu commented Jan 10, 2021

Ummmm well Apple events looks like what I suggested originally in terms of osascript, it does save on needing a preference and network stack so that's nice.

I'm not really sure how much the cli interface matters, once you setup an open receiver, anyone can create their own clients of their choice, and based on how niche this is I think it's fine.

@ayroblu
Copy link
Contributor Author

ayroblu commented Jan 10, 2021

Best tutorial I've found for setting up to receive apple events: https://www.raywenderlich.com/1033-making-a-mac-app-scriptable-tutorial
Still haven't quite figured out all the bits an pieces to it but I can look at it at some point

@lwouis
Copy link
Owner

lwouis commented Jan 11, 2021

Ummmm well Apple events looks like what I suggested originally in terms of osascript, it does save on needing a preference and network stack so that's nice.

Yes indeed~

anyone can create their own clients of their choice

Providing a cli interface removes this needs. The CLI could provide a text output and/or json output, that way people can pipe its output into all sorts of systems. With a CLI, there is a out-of-the-box client that people can use straight away.d

Best tutorial I've found for setting up to receive apple events: https://www.raywenderlich.com/1033-making-a-mac-app-scriptable-tutorial

I think this tutorial is about adding AppleScript not AppleEvents. I think so far AppleEvents would be more appropriate because we are talking about having a CLI client. We want that client to be fast, so in the link I shared above it would be a program written in Swift then compiled to binary, sending AppleEvents. In the tutorial you shared, they explain how to have AppleScripts interact with an app. That would mean the cli would be an AppleScript. I know AppleScript can be "compiled" as I've done it before in the alpha version of AltTab, to focus other windows. I have the hunch that it's simply better to have it in Swift and compile it, rather than having an AppleScript file in AppleScript language to deal with.

So I suggest we go with AppleEvents. That being said I don't know that much about those techs, so if anyone has more insight, please feel free to share it here

@ayroblu
Copy link
Contributor Author

ayroblu commented Jan 11, 2021

So there's two parts to Apple Events, sender and receiver, so that tutorial covers the receiving bit pretty well I think. For sending, yeah you can script or you can use swift etc, you can't send without the receiver so that's the big unknown for me, there's quite a lot of magic to make it receive the events

@lwouis
Copy link
Owner

lwouis commented Jan 11, 2021

The StackOverflow i shared covers sending AE and receiving them

@lwouis lwouis mentioned this pull request Mar 24, 2021
@Stvad Stvad mentioned this pull request Mar 28, 2021
10 tasks
@ayroblu
Copy link
Contributor Author

ayroblu commented Mar 29, 2021

Just an FYI, this is @Stvad my alfred workflow, and my resulting binary. It's already out of date so I might do something about that later, but if you want you can rebuild it after rebasing this branch off the latest master.

Alt Tab.alfredworkflow.zip
AltTab.app.zip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants