summary refs log tree commit diff
path: root/bin/gfx-cocoa.m
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2019-01-17 15:57:00 -0500
committerJune McEnroe <june@causal.agency>2019-01-17 15:57:00 -0500
commitb40f7ba007080624f3b976591ee6de87502c145c (patch)
treebf5e8a89001fcd3da46460e29e418f74283cf25e /bin/gfx-cocoa.m
parentReorganize bin and Makefile once again (diff)
downloadsrc-b40f7ba007080624f3b976591ee6de87502c145c.tar.gz
src-b40f7ba007080624f3b976591ee6de87502c145c.zip
Reunify gfx and bin
Diffstat (limited to 'bin/gfx-cocoa.m')
-rw-r--r--bin/gfx-cocoa.m162
1 files changed, 162 insertions, 0 deletions
diff --git a/bin/gfx-cocoa.m b/bin/gfx-cocoa.m
new file mode 100644
index 00000000..7e7b7643
--- /dev/null
+++ b/bin/gfx-cocoa.m
@@ -0,0 +1,162 @@
+/* Copyright (C) 2018  C. McEnroe <june@causal.agency>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <err.h>
+#import <stdbool.h>
+#import <stdint.h>
+#import <stdlib.h>
+#import <sysexits.h>
+
+#import "gfx.h"
+
+@interface BufferView : NSView {
+	size_t bufSize;
+	uint32_t *buf;
+	CGColorSpaceRef colorSpace;
+	CGDataProviderRef dataProvider;
+}
+@end
+
+@implementation BufferView
+- (instancetype) initWithFrame: (NSRect) frameRect {
+	colorSpace = CGColorSpaceCreateDeviceRGB();
+	return [super initWithFrame: frameRect];
+}
+
+- (void) setWindowTitle {
+	[[self window] setTitle: [NSString stringWithUTF8String: status()]];
+}
+
+- (void) draw {
+	draw(buf, [self frame].size.width, [self frame].size.height);
+	[self setNeedsDisplay: YES];
+}
+
+- (void) setFrameSize: (NSSize) newSize {
+	[super setFrameSize: newSize];
+	size_t newBufSize = 4 * newSize.width * newSize.height;
+	if (newBufSize > bufSize) {
+		bufSize = newBufSize;
+		buf = malloc(bufSize);
+		if (!buf) err(EX_OSERR, "malloc(%zu)", bufSize);
+		CGDataProviderRelease(dataProvider);
+		dataProvider = CGDataProviderCreateWithData(NULL, buf, bufSize, NULL);
+	}
+	[self draw];
+}
+
+- (void) drawRect: (NSRect) dirtyRect {
+	(void)dirtyRect;
+	NSSize size = [self frame].size;
+	CGContextRef ctx = [[NSGraphicsContext currentContext] CGContext];
+	CGImageRef image = CGImageCreate(
+		size.width, size.height,
+		8, 32, 4 * size.width,
+		colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
+		dataProvider,
+		NULL, false, kCGRenderingIntentDefault
+	);
+	CGContextDrawImage(ctx, [self frame], image);
+	CGImageRelease(image);
+}
+
+- (BOOL) acceptsFirstResponder {
+	return YES;
+}
+
+- (void) keyDown: (NSEvent *) event {
+	char in;
+	BOOL converted = [
+		[event characters]
+		getBytes: &in
+		maxLength: 1
+		usedLength: NULL
+		encoding: NSASCIIStringEncoding
+		options: 0
+		range: NSMakeRange(0, 1)
+		remainingRange: NULL
+	];
+	if (converted) {
+		if (!input(in)) {
+			[NSApp terminate: self];
+		}
+		[self draw];
+		[self setWindowTitle];
+	}
+}
+@end
+
+@interface Delegate : NSObject <NSApplicationDelegate>
+@end
+
+@implementation Delegate
+- (BOOL) applicationShouldTerminateAfterLastWindowClosed:
+	(NSApplication *) sender {
+	(void)sender;
+	return YES;
+}
+@end
+
+int main(int argc, char *argv[]) {
+	int error = init(argc, argv);
+	if (error) return error;
+
+	[NSApplication sharedApplication];
+	[NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
+	[NSApp setDelegate: [Delegate new]];
+
+	NSString *name = [[NSProcessInfo processInfo] processName];
+	NSMenu *menu = [NSMenu new];
+	[
+		menu
+		addItemWithTitle: @"Close Window"
+		action: @selector(performClose:)
+		keyEquivalent: @"w"
+	];
+	[menu addItem: [NSMenuItem separatorItem]];
+	[
+		menu
+		addItemWithTitle: [@"Quit " stringByAppendingString: name]
+		action: @selector(terminate:)
+		keyEquivalent: @"q"
+	];
+	NSMenuItem *menuItem = [NSMenuItem new];
+	[menuItem setSubmenu: menu];
+	[NSApp setMainMenu: [NSMenu new]];
+	[[NSApp mainMenu] addItem: menuItem];
+
+	NSUInteger style = NSTitledWindowMask
+		| NSClosableWindowMask
+		| NSMiniaturizableWindowMask
+		| NSResizableWindowMask;
+	NSWindow *window = [
+		[NSWindow alloc]
+		initWithContentRect: NSMakeRect(0, 0, 800, 600)
+		styleMask: style
+		backing: NSBackingStoreBuffered
+		defer: YES
+	];
+	[window center];
+
+	BufferView *view = [[BufferView alloc] initWithFrame: [window frame]];
+	[window setContentView: view];
+	[view setWindowTitle];
+
+	[window makeKeyAndOrderFront: nil];
+	[NSApp activateIgnoringOtherApps: YES];
+	[NSApp run];
+}