I'm trying to create a basic opengl window with mouse input using a typical win-style event loop. The problem is that I'm pulling my hair out trying to get a NSMouseMoved event to generate. The following code outputs debug info on Mouse Up, Mouse Down, Mouse Drag, etc but no Mouse Move even though I've told the window setAcceptsMouseMovedEvents:YES. So, any ideas on how to get mouse move to work in the following example?
Obviously, the way I'm creating the window is very un-cocoa like, but I'm trying to port a makefile-based windows c++ codebase that does some tricky threading things. That's why I'm sticking with a style similar to a win32 loop using GetMsg().
Also, to build I'm just using:
gcc -o hellogl hellogl.m -framework Foundation -framework Cocoa -framework OpenGL
Thanks for the help!
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#include <OpenGL/gl.h>
#include <stdlib.h>
#interface BaseWinDelegate : NSWindow<NSWindowDelegate>
#end
#implementation BaseWinDelegate
- (void) windowWillClose:(NSNotification*)notification
{
printf("Closing.\n");
NSEvent * evt = [NSEvent otherEventWithType:NSApplicationDefined
location: NSMakePoint(0,0)
modifierFlags: 0
timestamp: 0.0
windowNumber: 0
context: nil
subtype: 0
data1: 0
data2: 0];
[NSApp postEvent:evt atStart:NO];
}
#end
#interface BaseView : NSOpenGLView
- (void) update;
- (void) drawRect:(NSRect)rect;
- (void) reshape;
#end
#implementation BaseView
- (void) drawRect:(NSRect)rect
{
glClearColor(0.2f,0.2f,0.2f,0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
[[self openGLContext] flushBuffer];
}
- (void) update
{
printf("Update.\n");
}
- (void) reshape
{
NSRect rect;
[[self openGLContext] update];
rect = [self bounds];
printf("Reshape - %f, %f\n", rect.size.width,rect.size.height);
}
#end
int main(int argc, const char * argv[])
{
printf("Starting.\n");
NSAutoreleasePool * myPool = [[NSAutoreleasePool alloc] init ];
NSApplicationLoad();
NSRect rect = NSMakeRect(100,100,640,480);
NSWindow * win = [[NSWindow alloc] initWithContentRect:rect
styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask
backing: NSBackingStoreBuffered
defer: NO];
NSOpenGLPixelFormatAttribute attributes[] =
{
NSOpenGLPFADoubleBuffer,
0
};
NSOpenGLPixelFormat* pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
BaseView * pView = [[BaseView alloc] initWithFrame:rect pixelFormat:pf];
BaseWinDelegate * myDelegate = [BaseWinDelegate alloc];
[win setDelegate:myDelegate];
[win setContentView: pView];
[win makeKeyAndOrderFront: NSApp];
[win setAcceptsMouseMovedEvents:YES];
do
{
NSEvent * evt = [NSApp nextEventMatchingMask : NSAnyEventMask
untilDate : [NSDate distantFuture]
inMode : NSDefaultRunLoopMode
dequeue : YES ];
NSEventType evtType = [evt type];
if (evtType == NSApplicationDefined)
{
break;
}
printf("%d\n",(int)evtType);
[NSApp sendEvent : evt];
} while (1);
[myPool drain];
return EXIT_SUCCESS;
}
Ok, figured it out. The problem is that it's not a foreground process. So adding this code fixes it.
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
SetFrontProcess(&psn);
That was preventing the window from becoming the key window and sending off mouse moved events. Hope it helps someone else (i.e. the 0.1% of people who like to handle their own event loop).
Related
I use Xcode to create an command line app for MacOS.And I want to open a NSWindow,However,the nswindow failed to display.Is this possible?
Here's the demo code.
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
}
NSRect frame = NSMakeRect(0, 0, 300, 300);
NSUInteger styleMask = NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskResizable|NSWindowStyleMaskMiniaturizable;
NSRect rect = [NSWindow contentRectForFrameRect:frame styleMask:styleMask];
NSWindow *nswindow = [[NSWindow alloc] initWithContentRect:rect styleMask:styleMask backing: NSBackingStoreBuffered defer:false];
[nswindow center];
[nswindow setBackgroundColor:[NSColor whiteColor]];
[nswindow orderFrontRegardless];
return 0;
}
I would like to write a simple app or script which monitors the color of the pixel under the cursor and clicks the mouse when that pixel changes color.
I've gone the Cocoa route, am now getting issues due to CGGetDisplaysWithPoint returning NULL due to my cursor being on my second monitor, which has negative mouse coordinates.
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#property NSColor *initialColor;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask handler:^(NSEvent * _Nonnull event) {
// Hitting space bar captures the initial pixel color.
if (event.keyCode == 49) {
self.initialColor = [self colorAtCursor];
NSLog(#"Cursor color: %#", self.initialColor);
}
}];
[NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:#selector(clickIfColorChanged)
userInfo:nil
repeats:YES];
}
- (NSColor *)colorAtCursor {
// Grab the current mouse location.
NSPoint mouseLoc = [NSEvent mouseLocation];
// Grab the display for said mouse location.
uint32_t count = 0;
CGDirectDisplayID displayForPoint;
CGGetDisplaysWithPoint(NSPointToCGPoint(mouseLoc), 3, &displayForPoint, &count);
// Grab the color on said display at said mouse location.
CGImageRef image =
CGDisplayCreateImageForRect(displayForPoint, CGRectMake(mouseLoc.x, mouseLoc.y, 1, 1));
NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] initWithCGImage:image];
CGImageRelease(image);
NSColor* color = [bitmap colorAtX:0 y:0];
return color;
}
- (void)clickIfColorChanged {
if (self.initialColor != nil && ![self.initialColor isEqual:[self colorAtCursor]]) {
CGEventRef down = CGEventCreateMouseEvent(NULL,
kCGEventLeftMouseDown,
NSPointToCGPoint([NSEvent mouseLocation]),
kCGMouseButtonLeft);
CGEventRef up = CGEventCreateMouseEvent(NULL,
kCGEventLeftMouseUp,
NSPointToCGPoint([NSEvent mouseLocation]),
kCGMouseButtonLeft);
CGEventPost(kCGHIDEventTap, down);
CGEventPost(kCGHIDEventTap, up);
CFRelease(down);
CFRelease(up);
self.initialColor = nil; // Stop clicking
}
}
#end
I have a subclassed NSWindow which uses the undocumented CGSSetWindowBackgroundBlurRadius method to blur a transparent background.
This is working fine however I also want to blur the title bar. In order to do this I can OR a NSFullSizeContentViewWindowMask mask to the existing style. This successfully changes the title bar to a transparent view but the blur effect is lost! Any ideas of how I can go about this?
#import "TransparentNSWindow.h"
#implementation TransparentNSWindow
typedef void * CGSConnection;
extern OSStatus CGSSetWindowBackgroundBlurRadius(CGSConnection connection, NSInteger windowNumber, int radius);
extern CGSConnection CGSDefaultConnectionForThread();
- (void)enableBlurForWindow:(NSWindow *)window
{
[window setOpaque:NO];
window.backgroundColor = [NSColor colorWithCalibratedRed:255./255. green:255./255. blue:255./255. alpha:0.4];
CGSConnection connection = CGSDefaultConnectionForThread();
CGSSetWindowBackgroundBlurRadius(connection, [window windowNumber], 20);
}
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag {
NSUInteger currentStyle = [self styleMask];
NSUInteger style = NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask;
self = [super initWithContentRect:contentRect styleMask :style backing :NSBackingStoreBuffered defer:NO ];
if (self)
{
[self setOpaque:NO];
[self setHasShadow:NO];
self.titlebarAppearsTransparent = true;
self.titleVisibility = true;
// Uncommenting this line results in a transparent title bar but no blur
//self.styleMask |= NSFullSizeContentViewWindowMask;
[self enableBlurForWindow:self];
}
return self;
}
#end
Got in touch with Apple and apparently there is no way that this can be done.
I am trying to programmatically create a Cocoa window with an OpenGL context for an OS X application. I have been unable to find an example online which does not use the Interface Builder for creating a window and OpenGL view.
All I want is for glClear to make my window magenta (0xFF00FF). However, the window remains white.
Here is my project:
AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
NSOpenGLContext *openGLContext;
}
#property (assign) NSWindow *window;
#property (assign) NSOpenGLContext *openGLContext;
- (void)draw;
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window;
#synthesize openGLContext;
static NSOpenGLPixelFormatAttribute glAttributes[] = {
0
};
- (void)draw {
NSLog(#"Drawing...");
[self.openGLContext makeCurrentContext];
glClearColor(1, 0, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
[self.openGLContext flushBuffer];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSRect frame = NSMakeRect(0, 0, 200, 200);
self.window = [[[NSWindow alloc]
initWithContentRect:frame
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO] autorelease];
[self.window makeKeyAndOrderFront:nil];
NSOpenGLPixelFormat *pixelFormat
= [[NSOpenGLPixelFormat alloc] initWithAttributes:glAttributes];
self.openGLContext = [[NSOpenGLContext alloc]
initWithFormat:pixelFormat shareContext:nil];
[self.openGLContext setView:[self.window contentView]];
[NSTimer
scheduledTimerWithTimeInterval:.1
target:self
selector:#selector(draw)
userInfo:nil
repeats:YES];
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)_app {
return YES;
}
#end
main.m
#import "AppDelegate.h"
#import <Cocoa/Cocoa.h>
int main(int argc, char **argv) {
AppDelegate *appDelegate = [[AppDelegate alloc] init];
return NSApplicationMain(argc, (const char **) argv);
}
The documentation for -[NSOpenGLContext flushBuffer] says:
Discussion
If the receiver is not a double-buffered context, this call does nothing.
You can cause your context to be double-buffered by including NSOpenGLPFADoubleBuffer in your pixel format attributes. Alternatively, you can call glFlush() instead of -[NSOpenGLContext flushBuffer] and leave your context single-buffered.
Use this code for the pixel format attributes instead.
NSOpenGLPixelFormatAttribute glAttributes[] =
{
NSOpenGLPFAColorSize, 24,
NSOpenGLPFAAlphaSize, 8,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAAccelerated,
0
};
I've tested it and you get the magenta screen you were looking for.
I'm new to the whole Cocoa/Objective-C malarky (but have years of C/C++ on *nix).
I'm trying to create a basic Cocoa application that is filled with an NSOpenGLView. I have:
chink.mm
#import <OpenGL/gl.h>
#import "chink.h"
#implementation chinkView
#synthesize window;
- (void) applicationDidFinishLaunching : (NSNotification *)aNotification {
NSLog(#"Danger, Will Robinson! Danger!");
}
- (void) dealloc
{
[window release];
[super dealloc];
}
#end
and chink.h
#interface chinkView : NSOpenGLView {
NSWindow *window;
}
#property (assign) NSWindow *window;
#end
I have a single .xib set up like
https://skitch.com/cront/ri625/chinkxib
where 'chink View' is set as delegate for Window and File Owner.
I'm getting an 'invalid drawable' error (even before the application finished launching), which to my understanding means that it is trying to instantiate the opengl view before the window (although I'm probably wrong).
What I want is the solution to this problem of creating the window and setting the opengl view inside it. Once this is done I have absolutely no problem writing the OGL (like I said, I know C++) but all this NS calls gunk is alien to me.
I'm not looking for 'why don't you do it in SDL/GLUT' answers please. Just the code to make it create the window properly.
Okay so I sacked off this approach.
Went the long route and changed to this:
chink.mm
#import <Cocoa/Cocoa.h>
#import <OpenGL/OpenGL.h>
#import <OpenGL/gl.h>
#import <OpenGL/glu.h>
#import "chink.h"
#implementation chinkNS
- (id)initWithFrame:(NSRect)frameRect
{
NSOpenGLPixelFormat * pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:(NSOpenGLPixelFormatAttribute[]) {
NSOpenGLPFAWindow,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 32,
nil
}];
if(pixelFormat == NULL)
NSLog(#"pixelFormat == NULL");
[pixelFormat autorelease];
self = [super initWithFrame:frameRect pixelFormat:pixelFormat];
if(self == NULL) {
NSLog(#"Could not initialise self");
return NULL;
}
[[self openGLContext] makeCurrentContext];
[self initGL];
return self;
}
- (void)awakeFromNib
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(windowWillMiniaturize:) name:NSWindowWillMiniaturizeNotification object:[self window]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:[self window]];
animationTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 target:self selector:#selector(timerFired) userInfo:NULL repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:animationTimer forMode:NSEventTrackingRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:animationTimer forMode:NSModalPanelRunLoopMode];
lastTime = [[NSDate date] timeIntervalSince1970];
}
- (void)drawRect:(NSRect)frame
{
NSLog(#"Chink is up and running. Let's do this thing!");
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glFlush();
[self drawGL];
[[self openGLContext] flushBuffer];
}
#pragma mark OpenGL
- (void)initGL { }
- (void)reshapeGL { }
- (void)drawGL { }
- (void)animate:(float)dt { }
#pragma mark Event Handling
- (void)timerFired
{
NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
[self animate:currentTime-lastTime];
lastTime = currentTime;
}
#pragma mark Loose ends
- (void)setFrame:(NSRect)frame
{
[super setFrame:frame];
[self reshapeGL];
}
// To get key events
- (BOOL)acceptsFirstResponder
{
return YES;
}
#end
and chink.h
#interface chinkNS : NSOpenGLView
{
NSTimer * animationTimer;
NSTimeInterval lastTime;
}
- (void)initGL;
- (void)reshapeGL;
- (void)drawGL;
- (void)animate:(float)dt;
#end
The same settings in the .xib except that it is a standard NSView that subclasses my opengl view.
I was hoping for a simpler, more elegant set up as above but you can't win 'em all.
Closed.