Suggestion for improvement:
- make seek and volume gesture mutually exclusive (they kind of already are), so when you started a seek action you cannot adjust volume until you completely lifted your fingers/aborted the scroll action or at least have a slight delay until you can change to the other scroll direction. The reason is, sometimes you want to seek and accidentally adjust the volume
This is exactly how it is implemented at the moment. I took everything you just mentioned into consideration. Your description is almost an exact translation of my code (look in GestureHandler). In fact, I had to, because I immediately noticed that problem (when scrolling diagonally, both seeking and volume are affected simultaneously). And yes, there is a delay of 1/6 seconds, i.e. one sixth of a second, between gestures. If I'm scrolling mostly up (most events have a greater dy than dx), and I suddenly receive a scroll left/right within that time interval ("scroll session" I call it) it will be smartly ignored. I played around with different time intervals, and tested each one. 1/6 seems to work quite well (no overlap between gestures) and still allows the controls to be quite responsive.
- another point would be to maybe restrict volume adjusting to the playerControlsView (where the actual volume slider is) and restrict seek to nowPlayingView (where the actual seek slider is).
I don't agree with this at all. First and foremost, no user in the world will be able to figure this behavior out without spending time on it ... this would result in most users not even being able to use the gestures and they will give up on it. Secondly, even if the user knows how it behaves, that behavior would make it more difficult for the user who would have to first move the mouse cursor all the way up to the player controls box. And if he overshoots and goes above it, "Oh ****, let's go down now". Not a good user experience. It is already a bit annoying if he is over the playlist window and has to move it up/left/right to the main window. It shouldn't be made more difficult. The whole point of a gesture is ease of use and convenience, so let's keep it simple. If you're over the main window, you're manipulating controls on it. If you're over the playlist window, you're controlling the playlist view.
Check out the VLC media player's scrolling behavior (VLC is my preferred video player). You don't have to be over the controls box to trigger those functions with gestures. Anywhere over the screen, your gesture will take effect. This is easy for the user.
This would enable a possible 2-finger gesture for changing tracks when the mouse is in the playerControlsView. Alternatively disable window moving for the playlistControlsView, so 3-finger-gesture would work.
Since I don't agree with restricting the scrolling to the player controls view, the first point here doesn't apply. However, I'm considering the 2nd option - disabling window moving, so that the 3-finger gesture works. That's not a bad idea. But, even if it is done, it should be configurable. Let the user decide what is more important - the Aural player 3-finger gesture, or the general MacOS one (window moving).
- instead of a sensitivity setting you could add accelerated scrolling sensitivity to the scrolling gesture, so the faster you scroll the higher the impact. Maybe you could have a look at IINAs source code since they have implemented this, even though the code looks a bit messy. This method in MainWindowController is related to the scrolling gestures:
'override func scrollWheel(with event: NSEvent)'
That sounds like a good idea. It's best to manipulate the underlying gesture itself, instead of setting different numerical values for how fast the scroll affects the controls. However, again, this still needs to be configurable. Only, what happens behind the scenes will now be different (affecting the low-level scroll gesture itself, instead of what happens afterwards).
For example docking the playlist when main window movement is involved to make space to the playlist both windows overlap and it looks something like this:
View attachment 736751
So the problem here is (example):
- main window is closer to the left screen edge than the width of the playlist
- playlist gets moved first with restricted alignment to the screen
- so now, since the playlist is wider both windows overlap
- and only now the main window moves away from the edge (playlist window moves along with the main window)
Wow, I tested my docking/maximize code for hours upon hours, and it never did anything like that. Is this specific to High Sierra, I wonder ? I seriously tested it a thousand times, and that kind of overlap never happened - not one single time. But, thanks for letting me know.
To solve this (better solution in the edit below), you should first move the main window to make space. After that dock the playlist window so it will automatically align with the screen edge.
So just switch the sequence of those two actions (moving and docking)
Edit: either you do it like I described, or you keep the order but do not restrain the playlist window from going off the screen, since it will be dragged back into the screen automatically when the main window moves. Thats probably the better solution.
Well, since I never saw that problem with the way it is now, I don't see why the order needs to be changed. I put a lot of thought into it, and a TON of testing, and it never failed. I do have one idea - I'm going to disable the window animations. Theoretically, that shouldn't fix the problem, but you never know. I know for a fact that animating the windows results in more window events (captured by NSWindowDelegate) than not animating them. I tried this out when I was working on that code. Maybe the animation is screwing up the positioning. I will disable it in my next build, and let's see if that fixes it.
Either way, I think it will need to be tested on your system, so I think the better solution is for you to change the code on your system (if/when you have time), test it, and post the solution. I will not be able to test it on my system, since I'm running Sierra and everything already works perfectly. So, it will be very inefficient for me to come up with a "fix", submit it, you test it, come back to me saying it doesn't work, etc. If you write the code, you'll be able to immediately test it and modify the code as needed. Hope this makes sense ?
Alternatively, can you note down an exact sequence of steps, so I can try to reproduce it on my system ? Starting from app startup, to the point where the improper docking occurs, step by step. And I will try to reproduce it here. (The problem is I can only test on Sierra)
Something like this would be great (if you have time):
- Set view preference for window location to be "Center" and playlist docking location to "bottom"
- Quit Aural
- Start Aural
- Drag window all the way to the right
- Dock playlist to right
- ERROR: Playlist window overlaps main window
---
Also i would really consider to move the docking controls to the main window, like I did.
Nah, I don't think so

On the contrary, ask the question, "What is being docked ?" The playlist is being docked, so let the controls be on the playlist window. Put them on the main window and no one will ever figure out what those controls are. Now, one exception to this rule is the buttons that show/hide FX and playlist. Those 2 buttons need to be on the main window, because the main window is always visible. So, if you hide the playlist and need to show it again, you can only do so if the button is visible. So, it makes sense to have those 2 buttons on the main window. But, the controls to dock the playlist are specific to the playlist, so ...
Remember - most users want things to be quick and intuitive. Things need to be readily accessible and easy to figure out. Very few people are going to put their mouse cursor over the controls over the main window to see what they do. If they wanna move the playlist, they will look at the playlist window. "Let's see what these buttons do. Oh that icon looks like docking icon. This is the playlist window, so that control docks the playlist."
An idea I had was maybe turn the effects into popover views only leaving the effect buttons permanently visible.
This way the size of the effect view can be independent. So when you need more space for the Equalizer by adding additional features to it, you can make the view bigger.
Hmmm ... this is food for thought. Definitely open to consideration. I'm not saying yes or no right now, but will think about it.
---
One thing I'm also dealing with at the moment (besides DI) is Core Animation debuging in macOS to significantly improve performance. Found an article about that here:
http://jwilling.com/blog/debugging-core-animation-on-osx/
Also 'WWDC 2014 - Session 220 - macOS' at around 44:30 minutes has some interesting facts about layer behavior regarding performance.
https://developer.apple.com/videos/play/wwdc2014/220/
So how is that information helpful?
Will need to confirm this, but maybe when the gif images are shown the whole window gets updated permanently, thus leading to the heavy impact on the CPU. (this is only a guess)
Also when you take a look at my OutlineView example you can maybe also have a look at the difference of CPU and memory when enabling/disabling CALayer of the Views. When enabled, the CPU goes down while scrolling, but memory goes up because the cells are cached as an image file with CALayer enabled (at least that's how I read it).
Kudos on doing the research ! This is exactly the kind of input I could use, because I don't have the time or patience to do it myself (remember my #1 and #2 priorities

). So, it is great that you are researching these things and providing input that can be applied to Aural. Keep it up.
BTW, about your outline view example app, can you please upload a GIF demo. I'm not able to run your code (old XCode and Swift v), and just looking at the code is not going to give me any idea how it works. Post a 30 second GIF clip demonstrating what it does. Keep the CPU/memory monitor (in XCode) open so I can see how your app impacts those parameters.
LiceCap is a great screen capture (to GIF) tool. All my GIFs I post here were done by LiceCap.
[doublepost=1511040020][/doublepost]
So the problem here is (example):
1- main window is closer to the left screen edge than the width of the playlist
2- playlist gets moved first with restricted alignment to the screen
3- so now, since the playlist is wider both windows overlap
4- and only now the main window moves away from the edge (playlist window moves along with the main window)
Actually, point #2 is incorrect. The playlist, when it moves initially, is not restricted in any way (I just revisited the code, in addition to testing it 10 more times). It goes wherever it needs to go for the docking. Yes, playlist does move first, but it is unrestricted in its movement.
Then, if the playlist is off-screen, both windows move. BTW, you're also mistaken that the playlist moves along with the main window. Yes, it will visually move, but the underlying frame does not move. I spent hours on this problem, till I realized that moving only the main window will also move the playlist window visually, but the playlist frame stayed where it was. At first, I didn't understand this behavior at all. If the playlist moves visually, its underlying frame should also move, but for some reason, it doesn't.
Maybe, somehow, this was a bug on Sierra, and I compensated for it in my code. Then, Apple fixed it in High Sierra (so the underlying frame moves with the window), and so you're now seeing the extra playlist movement causing the overlap ?
I guess I will have to change how the code is written, after all. Currently, I'm using affine transformations, which was a big mistake. I should be using absolute locations, like I was before.
