I'm trying to debug an issue in my GLFW/Metal application where when I start moving the window, the window "yanks", meaning the window freezes for a second, then jumps to where the mouse has moved meanwhile and as long as I don't release the mouse it moves smoothly after the initial freeze. Note that during the freeze period the run loop does not halt (I tested that by printing in the loop).
I reduced the problem to only Cocoa API calls, basically by copying the GLFW implementation and removing anything unnecessary.
Here is the code:
#include <thread>
#include <AppKit/AppKit.h>
@interface MyAppDelegate : NSObject<NSApplicationDelegate> @end
@implementation MyAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
location:NSMakePoint(0, 0)
modifierFlags:0
timestamp:0
windowNumber:0
context:nil
subtype:0
data1:0
data2:0];
[NSApp postEvent:event atStart:YES];
[NSApp stop:nil];
}
@end // MyAppDelegate
static void init() {
@autoreleasepool {
[NSApplication sharedApplication];
MyAppDelegate* delegate = [[MyAppDelegate alloc] init];
[NSApp setDelegate:delegate];
if (![[NSRunningApplication currentApplication] isFinishedLaunching])
[NSApp run];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
} // autoreleasepool
}
static void pollEvents() {
@autoreleasepool {
NSEvent* event;
while ((event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode
dequeue:YES])) {
[NSApp sendEvent:event];
}
}
}
static void waitEvents() {
@autoreleasepool {
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue:YES];
[NSApp sendEvent:event];
pollEvents();
}
}
static NSWindow* makeWindow(int width, int height) {
NSRect contentRect = NSMakeRect(0, 0, width, height);
NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;
styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);
styleMask |= NSWindowStyleMaskResizable;
NSWindow* window = [[NSWindow alloc]
initWithContentRect:contentRect
styleMask:styleMask
backing:NSBackingStoreBuffered
defer:NO];
[window center];
[window orderFront:nil];
return window;
}
static void simulateRenderering() {
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}
int main() {
init();
makeWindow(800, 500);
while (true) {
simulateRenderering(); // If I don't call this the problem goes away
pollEvents(); // If I call waitEvents() instead the problem also goes away
}
}
I have no idea if the Cocoa API is supposed to be used like this, but this is what GLFW does.
As the comments suggest, if I don't sleep for a few milliseconds in the loop or if I call waitevents() instead of pollEvents(), the window moves smoothly.
So my question is, why does my window "yank" like this, and how can I make it go away, preferably without fundamentally changing the basic architecture.