Jump to content
untoldwind

Yet another window layout workflow

Recommended Posts

I was not very happy with the existing solutions, so I just created my own.

 

The workflow itself is quite simple just typ in the keyword "lay" (or chose another of your liking) followed by:

  • full = Maximize
  • left, right, top, bottom = Halves of screen
  • topleft, topright, bottomleft, bottomright = Quaters of screen
  • 11,12,13,21,22,23,31,32,33 = Thrids of screen
  • 11-12,11-13,11-21,11-22 ... = Some other sizes based on thrids
  • ... well the script is quite flexible, so I'm waiting for suggestions

Bildschirmfoto%202013-09-24%20um%2013.54

Bildschirmfoto%202013-09-24%20um%2013.55

 

For MacOS 10.8 (Mountain Lion):

The workflow itself can be found here:

https://github.com/untoldwind/alfred2-layout/raw/1.0_Mountain_Lion/Layout.alfredworkflow

and (obviously) its sources here:

https://github.com/untoldwind/alfred2-layout

 

For MacOS 10.9 (Mavericks):

The version above does not work (unluckily). An alternative (though somewhat experimental) version can be found here:

Release: https://github.com/untoldwind/alfred2-layout/raw/1.1_Mavericks/Layout.alfredworkflow

Experimental (Bleeding edge): https://github.com/untoldwind/alfred2-layout/raw/master/Layout.alfredworkflow

 

By the way: It is multi-screen-able. Even though you cannot move windows from one screen to another (yet?) the scripts tries to figure out with screen you mean (depending on the size of the visible area).

 

A short note about the implementation:

Edited by untoldwind

Share this post


Link to post

Wow. AWESOME !

 

Just have one tiny feedback : I use the full black theme "Minimalist Dark" by Hannes Egler and your icons are confusing because i only can see the white part of them. For example, i can't see the "full" icon xD

 

And that's it. :)

Share this post


Link to post

And now it's perfect… but i found another issue.

 

When an app has multiple windows, for example Adium (Contact list and messages), it seems that, even if i focus the message window, it resizes the contact list. :/

Share this post


Link to post

Ok, that one was/is more tricky ...

 

In short: Adium should work now (I checked the 1.5.7 version)

 

Longer story:

As said before I try to move the window directly if the application supports scripting. Adium actually does support scripting, but - to my understanding - the "windows" array is supposed to be ordered by z-index (i.e. the top-most window should be at first position). For some reason Adium thinks differently and always reports the "Contacts" window first, regardless which window actually has focus.

I'm a bit new to this MacOS-scripting business, so I'm not entirely sure if this is a bug in Adium or not. Anyway: I solved this by putting Adium on a blacklist, so that its windows are moved by SystemEvents as well, which seems to produce the correct results.

 

Maybe there is a better solution ...

Share this post


Link to post

Pretty neat! :)

 

Any possibility of extending this to support Full Screen apps (e.g. Chrome on OS X Lion)? Perhaps options to enter/exit/toggle full screen mode?

Share this post


Link to post

To my knowledge there is not generic way to toggle the full screen mode via scripting, at least I've found no such property/action so far. Of course it should be possible to trigger a menu-item event, which would be application-specific though and quite cumbersome to maintain.

 

At the moment I'm taking a look at Atomac (https://pypi.python.org/pypi/atomac/1.1.0). Even though it is a testing framework, it circumvents some of the restrictions I've encountered with the scripting bridge. Not sure though if I can (or should) include this in an Alfred workflow

Share this post


Link to post

You might want to check out http://spectacleapp.com/.  It is full open source, so you can get ideas from it. I use it all the time. I been toying with the idea to take that base and open it all up to scripting with AAppleScript. Then making workflows like this from it's core would be a synch. But, alas, I am not finding enough time for that project.

Edited by raguay.customct

Share this post


Link to post

The following Applescript might help for turning applications fullscreen:

    tell application "System Events"
        try
            tell front window of (first process whose frontmost is true)
                set isFullScreen to get value of attribute "AXFullScreen"
                set value of attribute "AXFullScreen" to not isFullScreen
            end tell
        end try
    end tell

Share this post


Link to post

I experience long delay ( > 3 second ) for any action. Sometimes, the `Python Launcher.app` show up briefly. Does anyone have the same issue?

 

Share this post


Link to post

I ran into that same issue with the delays, but I never noticed the Python Launcher.app showing up. The delays made me go back to using one that I wrote with Applescript that is sometimes wonky (I never ironed out certain bugs) but doesn't have those delays.

Share this post


Link to post

Thanks for all the feedback.

 

Lets focus on the most pressing issue first:

I also noted this short flicker of the "python.app", I just did not realized that it might be *that* slow. This seems to related to PyObjC  and/or the ScriptingBridge.

As an experiment I reimplemented the main script in ruby, which seems to run much more smoothly (as I can tell). You can find this in a separate branch on github: https://github.com/untoldwind/alfred2-layout/raw/ruby/Layout.alfredworkflow

(Hopefully this helps...)

 

As for the full-screen mode: Thanks for the short script, I'll experiment with it and figure out how to integrate it into the workflow.

 

And thanks for the hint to Spectacle, so far I was just aware for several Shareware (closed-source) applications in this regard. I did a short code-dive there, at its core Spectacle seems to use the ZeroKit, which is a small Objective-C wrapper around the Accessibility-API. This is quite informative, but I'm not sure if it is possible to do any of this from within a python,ruby,whatever-script ... without the use of some native wrapper like the already mentions atomac.

Share this post


Link to post

Sounds great. I'll check out the Ruby Version.

 

There are a couple of very inelegant hacks that you could do with Applescript in order to put it into Fullscreen Mode. The first would just be to place the clicker in that upper right hand corner of the window that has that little fullscreen icon, send a mouse click, then reposition the cursor where it started. But, that's awkward.

 

Another thing you could do is to have it send a ctrl+cmd+F keypress, which seems to be the hotkey for at least a few programs to enter into Fullscreen (often in View->Enter Full Screen). But that just seems unnecessary as it already has a hotkey, so you could also consider the Full Screen as an unnecessary feature...

 

Shawn

Share this post


Link to post

Sure another keyword is no biggy.

My current version of the workflow is kind of messed up since I was experimenting a bit, which let me in the ugly depths of MacOS accessibility ... or hell, depending on the point of view ;)

 

Anyway, the list of keywords is in the "layout_select.py" file:

layouts = [
	Layout("full", "Full", "0,0,1,1"),
	Layout("left", "Left", "0,0,0.5,1"),
	Layout("top", "Top", "0,0,1,0.5"),

Just add a line there, like:

layouts = [
        Layout("center", "Center", "0.1,0.1,0.9,0.9"),
	Layout("full", "Full", "0,0,1,1"),
	Layout("left", "Left", "0,0,0.5,1"),
	Layout("top", "Top", "0,0,1,0.5"),

And it should to the trick. The format of the last part is "<left>,<top>,<right>,<bottom>" in relative coordinates, i.e. "0.1,0.1,0.9,0.9" means "center with 10% border", "0.2,0.2,0.8.0.8" would be 20% and so on.

I'll include this in the next "release" sometime this week, once I've mopped up a bit.

Edited by untoldwind

Share this post


Link to post

I just pushed a new version to github.

 

The ruby-variant is now "official" (its still not really performant, but smoother than python)

New keywords:

  • center: Move a window to center of screen with 10% border (see previous post)
  • togglefullscreen: Toggles full screen mode. Thanks for the little Apple-Script once again.

I also added an example how to add hotkeys to the workflow.

 

As for the performance issues: I somewhat gave up on atomac and kind of wait for 10.9 if there are any changes/improvements to the scripting bridge. To my understanding multi-screen support will change, so I'll most likely have to tweak the scripts anyway.

Edited by untoldwind

Share this post


Link to post

That's cool. But it'd be cooler to display them all when the query is empty so that 1.we can learn what exists, 2.the ones we use the most end up showing up up top without typing a query.

Share this post


Link to post

Hmm... that's funny, obviously I misinterpreted the "Argument required"/"Argument optional" switch in the Alfreds Script-Filter.

 

Now there should be a full list if you just type the keyword.

There "Order by frequency" is tougher though. I was kind of hoping that Alfred would do that on itself, I think there is already a Feature-Request for this.

Share this post


Link to post

During a (quite loooong) train ride I found some time to dig more deeply into the ScriptingBridge again. I thing I found the biggest time-consumer: Finding the main window of the frontmost application. Sounds simple enough, but if you do it the naive way (like me) it can result in lots of events being fired.

 

I just update the workflow once again with a variant that should minimize the overhead and works quite nicely (and fast) for me. Would be nice to know if this eventually fixes the performance issues.

 

 

For interested coders out there: The magic is now done in the following 4 lines of ruby code:

systemevents = OSX::SBApplication.applicationWithBundleIdentifier_("com.apple.systemevents")

frontmostPredicate = OSX::NSPredicate.predicateWithFormat("frontmost == true")
frontmost = systemevents.processes().filteredArrayUsingPredicate_(frontmostPredicate).first
window = frontmost.attributes().objectWithName_("AXMainWindow").value().get()
Edited by untoldwind

Share this post


Link to post

 

During a (quite loooong) train ride I found some time to dig more deeply into the ScriptingBridge again. I thing I found the biggest time-consumer: Finding the main window of the frontmost application. Sounds simple enough, but if you do it the naive way (like me) it can result in lots of events being fired.

 

I just update the workflow once again with a variant that should minimize the overhead and works quite nicely (and fast) for me. Would be nice to know if this eventually fixes the performance issues.

 

The latest version is much faster compared to the previous versions (at least on my system), so that's great (...and yay for adding togglefullscreen).

 

If you need Alfred to learn about the most frequently used options, you need to set a uniquely identifiable "uid" attribute for each of the item nodes in the generated xml in layout_select.py. I have sent a pull request via GitHub so that you can get an idea of what I mean. This will enable you to type "lay" in Alfred and have the most used items listed as the first results. E.g I happen to use toggle full screen a lot for some reason, and now I can just key in "lay" and the first option is "Toggle full screen mode" by default.

Edited by Benzi

Share this post


Link to post

This new version is fast enough for me to partially quit using spectacle. But, I love Spectacle's nudge feature. I use <ctrl><alt>leftarrow to nudge the current window a little bit wider in that direction. Same with right arrow. If you can implement that, I will dump using Spectacles!

 

Thanks!

Share this post


Link to post

@Benzi: Cool, thanks for that - I was wondering a bit by myself. Just merged it to the current version. Hurray for social coding ;)

 

@raguary:

I fear, I have to take a closer look at Spectacles first, to fully understand this feature.

What about this:

  • If you use the keyword "left", the window is move to the left-half (obviously), but
    • if the window already is in the left-half, it will be increased to 2/3-left
  • same for "right" and maybe "top", "bottom" as well

The only problem is that its not that easy to detect if a window is actually in the left-half. E.g. "iterm" sets its height always according to the font-size of the terminal, so it might be a little smaller than "left-half of available screen" ... I'll try to figure something out.

Edited by untoldwind

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×