Common Misconceptions
Apr. 5th, 2010 07:49 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Xcode is a pile of garbage.
(that's not the misconception, that's the intro)
But, if you want to make apps with windows on the Mac, you have to use it, right? Wrong!
I finally got fed up with all the various shitty ways there are to make GUIs, on the Mac, from modern languages, so I am going to Fix The Problem.
(this is not to imply that RubyCocoa sucks, in fact, it's probably the only non-sucky one, but parts of it suck, like having to use Xcode)
As the very first baby step in this, I've written a program that opens a window, and unlike anyone who does the same in Xcode, I understand every. Last. Damn. Byte of it. So, I'll explain it here, and even leave this post public, that our Googly overlords might index it.
How to open a window from scratch:
First off, we're going to be writing this in Objective C. This is not as much of a hassle as you'd think. ObjC is a superset of C, so just like you can write C++ without dealing with template syntax, same deal here. A function is still a function, even if methods look a little funny.
Now, something more familiar:
The sharedApplication call starts up an NSApplication that will let us talk to the rest of the system. With that out of the way, now we make a window:
How do you compile this?
This is what actually had me stumped for a while. Turns out, most sites get this wrong, maybe it changes a lot or something. This is how I did it:
So, that's how you do it without the tools. Since this is just gcc, you could (say) embed it into another program, or write a Ruby extension for it, or whatever. Enjoy!
(that's not the misconception, that's the intro)
But, if you want to make apps with windows on the Mac, you have to use it, right? Wrong!
I finally got fed up with all the various shitty ways there are to make GUIs, on the Mac, from modern languages, so I am going to Fix The Problem.
(this is not to imply that RubyCocoa sucks, in fact, it's probably the only non-sucky one, but parts of it suck, like having to use Xcode)
As the very first baby step in this, I've written a program that opens a window, and unlike anyone who does the same in Xcode, I understand every. Last. Damn. Byte of it. So, I'll explain it here, and even leave this post public, that our Googly overlords might index it.
How to open a window from scratch:
First off, we're going to be writing this in Objective C. This is not as much of a hassle as you'd think. ObjC is a superset of C, so just like you can write C++ without dealing with template syntax, same deal here. A function is still a function, even if methods look a little funny.
#import <Foundation/Foundation.h> #import <AppKit/AppKit.h>We're importing a couple things here. Foundation gives us things like garbage collection (it's retarded, ObjC garbage collection, but we still need to have it). AppKit is chock full of stuff like NSApplication, needed to make the window server even give us the time of day, and NSWindow, the star of our little show.
Now, something more familiar:
int main(int argc, const char* argv[]){I'm not even going to explain this. You know what it does. The next two, though, are where the ObjC ugliness starts:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [NSApplication sharedApplication];We're starting up an AutoreleasePool, which is how their reference-counting memory manager works. We're not actually going to count any references, but they are, so we have to provide them with a pool.
The sharedApplication call starts up an NSApplication that will let us talk to the rest of the system. With that out of the way, now we make a window:
NSRect frame = NSMakeRect(0, 0, 200, 200); int style = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask;Every window occupies a rectangle on the screen, so this is how we tell it where to put the window and what size to make it. The style is a bitmask with things like "it should have a title bar" and "there should be a close button" and so on.
NSWindow* window = [[NSWindow alloc] initWithContentRect:frame styleMask:style backing:NSBackingStoreBuffered defer:NO];Now we create the actual window, in that rectangle, with that style. The "backing" thing is for double buffering, and "defer" is for if we want to create a window but hide it; it will buffer all messages sent to it until it's on-screen. Since we're about to display it, it doesn't really matter. Speaking of which:
[window makeKeyAndOrderFront:NSApp];Bet you thought we'd call
display
, huh? Turns out not, and this is the thing (apparently, according to StackOverflow) that confuses most people. After this, it's just some boilerplate stuff:[NSApp run]; [pool drain]; return 0; }And we're out! (we run our NSApp, drain any garbage left in the pool, and exit)
How do you compile this?
This is what actually had me stumped for a while. Turns out, most sites get this wrong, maybe it changes a lot or something. This is how I did it:
gcc main.m -o main -framework Foundation -framework AppKitThis is pretty self-explanatory. It's just like a normal gcc command line, except that the file ends in .m (best just not to think about it) and the -framework parameters. These are ObjC library bundles. You can see for yourself what you're including, in
/System/Library/Frameworks
. They've each got a bunch of headers.So, that's how you do it without the tools. Since this is just gcc, you could (say) embed it into another program, or write a Ruby extension for it, or whatever. Enjoy!