I have a window with an opengl view where content ist rendered. The problem I have in macOS is, that when I move the window from one monitor to the other, its content gets messed up. A redraw fixes the issue. Thus I need to redraw the GL Area when it gets moved from one monitor to the other. Is there any way to detect the transition of the window from one monitor to the other?
You can register for notifications that fire when the view's window changes screens: NSWindowDidChangeScreenNotification
Related
Let's say I have a floating, borderless, circular NSWindow.
It is circular because the content view simply draws a red circle.
That content view needs to be layer-backed ([contentView setWantsLayer:YES]), because I'm applying CoreAnimations on it, e.g., animated scaling.
Usually, the clickable area of a NSWindow is defined by the transparency of the pixels of the content view. However, once the content view of a NSWindow becomes layer-backed, transparent areas will also receive clicks, unfortunately.
In my case, this is a serious problem, because I only want to receive clicks within the radius. But now, a click within the rect of the window, but beyond the circle radius, will activate the window (and thus, the entire app), which it shouldn't. Also the window is draggable via the corner of its content view.
My initial thought was to implement [NSWindow sendEvent:] in a subclass and check whether the click was performed within the radius, using [theEvent locationInWindow]. I thought I could simply discard the event, if it's beyond the radius, by not calling [super sendEvent:theEvent] then. This however did not work: I noticed, that the mouseDown:; window method is called even before the sendEvent:; method.
I've search a lot but the only idea I found, was to have a proxy like non-layer backed NSWindow on top of the window, which delegates clicks conditionally, but this led to unpredictable UI behavior.
Do you guys have any idea, how to solve it?
So after a few weeks, I came to the following results:
A) Proxy window:
Make use of a non layer-backed proxy window, which is placed on top of the target window as a child window. The proxy window has the same shape, as the target window, and since it is not layer-backed, it will properly receive and ignore events. The proxy window delegates all events to the target window by overwriting sendEvent:. The target window is set to ignore all mouse events.
B) Global Mouse Pointer observation:
Install both a global and local event monitor for NSMouseMovedMask|NSLeftMouseDraggedMask events using addGlobalMonitorForEventsMatchingMask and addLocalMonitorForEventsMatchingMask. The event monitors disable and enable ignoring mouse events on all registered target windows based on the current global mouse position. In the case of circular windows, the distance between the mouse pointer and every target window must be calculated.
Both approaches work well in generally, but I've been experiencing some unpredictable misbehaviors of the child window approach (where the child window is 'out-of-sync' of its parent's position).
UPDATE: Both approaches have some significant disadvantages:
In A), the proxy window sometimes may be out of sync and may be placed slightly off the actual window.
In B), the event monitor has a big impact on battery life while moving the mouse, even if the app is not the front-most application.
If you want to Discard mouseDown event based on position you can use the:
CGPathContainsPoint(path,transform,point,eoFill):Bool
Setup your path to match your graphics. Circles, ellipses, rectangles, triangles or paths and even compositional paths (paths with holes in them).
I have a custom view that is a subview of the main window. I have a timer that fires a [self setNeedsDisplay:TRUE] that will update drawing on the view. But from what I can see, if I leave the application on the background and switch to another, it does not reflect the new drawing functions until I click again on the application.
What could I be missing?
Thank you,
Jose.
setNeedsDisplay will not fire if it thinks the user cant see what its drawing for obvious reason. This includes, offscreen and obscured views even when the app is running.
In an app where you might be drawing data over time you would draw all the relevant data while backgrounded out at once when the app resumes.
I just started using the SFML library and its fantastic. However when resizing a window by dragging the corner with my mouse i don't get the resize events until i release the mouse. This means i can't update my graphics until the mouse is released (game loop is on the gui thread) and is also causing a massive flood of events to come through of all the resize positions.
How can i make it so resizing doesn't block the thread?
Windows causes this. GetEvent() becomes blocking if you move or resize the window.
(Another funny little reason to hate this OS...)
I have solved this with a separate event-polling thread. Take a look at this:
(The interesting part for you is entirely in main.cpp.)
https://bitbucket.org/torokati44/netframework/src/93bdf20d0f65/main.cpp
In almost any Windows application, I notice that holding the mouse button down in a non-client area causes the painting to stop. Why is this required?
For example, I have a Managed Direct 3D application which displays a spinning cube. If I place the pointer over the title bar and hold the mouse button down, the cube ceases to spin even though I have not coded any such condition into my loop.
Why is painting halted? What are the benefits? Most importantly, how can I work around this?
When you click on the title bar, there's a brief pause while the window manager tries to determine whether or not you're clicking or beginning a drag (moving the window). If you're still holding down the button, then it's a drag: the window manager sets up its own message loop and pumps messages until you release the mouse. Your window should still be able to process messages, because they'll still be dispatched, but if your animation depends on a custom message loop then you'll be stuck 'till the modal drag loop ends.
Work around it by triggering your animation in response to messages: a timer seems like a good choice to me.
I have some NSViews that I'm putting in one of two layouts depending on the size of my window.
I'm adjusting the layout when the relevant superview receives the resizeSubviewsWithOldSize method.
This works, but I'd like to animate the change. So naturally I tried calling the animator proxy when I set the new frames, but the animation won't run while the user is still dragging. If I release the mouse before the animation is scheduled to be done I can see the tail end of the animation, but nothing until then. I tried making sure kCATransactionDisableActions was set to NO, but that didn't help.
Is it possible to start a new animation and actually have it run during the resize?
I don't think you can do this easily because CA's animations are run via a timer and the timer won't fire during the runloop modes that are active while the user is dragging.
If you can control the runloop as the user is dragging, play around with the runloop modes. That'll make it work. I don't think you can change it on the CA side.
This really isn't an answer, but I would advise against animating anything while dragging to resize a window. The screen is already animating (from the window moving) - further animations are likely going to be visually confusing and extraneous.
CoreAnimation effects are best used to move from one known state to another - for example, when a preference window is resizing to accompany a new pane's contents, and you know both the old and new sizes, or when you are fading an object in or out (or both). Doing animation while the window is resizing is going to be visually confusing and make it harder for the user to focus on getting the size of the window where they want it to be.