The repository formerly known as dotfiles
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cocoa.m 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /* Copyright (c) 2018, Curtis McEnroe <programble@gmail.com>
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU Affero General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #import <Cocoa/Cocoa.h>
  17. #import <err.h>
  18. #import <stdbool.h>
  19. #import <stdint.h>
  20. #import <stdlib.h>
  21. #import <sysexits.h>
  22. #import "gfx.h"
  23. #define UNUSED __attribute__((unused))
  24. @interface BufferView : NSView {
  25. size_t bufSize;
  26. uint32_t *buf;
  27. CGColorSpaceRef colorSpace;
  28. CGDataProviderRef dataProvider;
  29. }
  30. @end
  31. @implementation BufferView
  32. - (instancetype) initWithFrame: (NSRect) frameRect {
  33. colorSpace = CGColorSpaceCreateDeviceRGB();
  34. return [super initWithFrame: frameRect];
  35. }
  36. - (void) setWindowTitle {
  37. [[self window] setTitle: [NSString stringWithUTF8String: status()]];
  38. }
  39. - (void) draw {
  40. draw(buf, [self frame].size.width, [self frame].size.height);
  41. [self setNeedsDisplay: YES];
  42. }
  43. - (void) setFrameSize: (NSSize) newSize {
  44. [super setFrameSize: newSize];
  45. size_t newBufSize = 4 * newSize.width * newSize.height;
  46. if (newBufSize > bufSize) {
  47. bufSize = newBufSize;
  48. buf = malloc(bufSize);
  49. if (!buf) err(EX_OSERR, "malloc(%zu)", bufSize);
  50. CGDataProviderRelease(dataProvider);
  51. dataProvider = CGDataProviderCreateWithData(NULL, buf, bufSize, NULL);
  52. }
  53. [self draw];
  54. }
  55. - (void) drawRect: (NSRect) UNUSED dirtyRect {
  56. NSSize size = [self frame].size;
  57. CGContextRef ctx = [[NSGraphicsContext currentContext] CGContext];
  58. CGImageRef image = CGImageCreate(
  59. size.width, size.height,
  60. 8, 32, 4 * size.width,
  61. colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
  62. dataProvider,
  63. NULL, false, kCGRenderingIntentDefault
  64. );
  65. CGContextDrawImage(ctx, [self frame], image);
  66. CGImageRelease(image);
  67. }
  68. - (BOOL) acceptsFirstResponder {
  69. return YES;
  70. }
  71. - (void) keyDown: (NSEvent *) event {
  72. char in;
  73. BOOL converted = [
  74. [event characters]
  75. getBytes: &in
  76. maxLength: 1
  77. usedLength: NULL
  78. encoding: NSASCIIStringEncoding
  79. options: 0
  80. range: NSMakeRange(0, 1)
  81. remainingRange: NULL
  82. ];
  83. if (converted) {
  84. if (!input(in)) {
  85. [NSApp terminate: self];
  86. }
  87. [self draw];
  88. [self setWindowTitle];
  89. }
  90. }
  91. @end
  92. @interface Delegate : NSObject <NSApplicationDelegate>
  93. @end
  94. @implementation Delegate
  95. - (BOOL) applicationShouldTerminateAfterLastWindowClosed:
  96. (NSApplication *) UNUSED sender {
  97. return YES;
  98. }
  99. @end
  100. int main(int argc, char *argv[]) {
  101. int error = init(argc, argv);
  102. if (error) return error;
  103. [NSApplication sharedApplication];
  104. [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
  105. [NSApp setDelegate: [Delegate new]];
  106. NSString *name = [[NSProcessInfo processInfo] processName];
  107. NSMenu *menu = [NSMenu new];
  108. [
  109. menu
  110. addItemWithTitle: @"Close Window"
  111. action: @selector(performClose:)
  112. keyEquivalent: @"w"
  113. ];
  114. [menu addItem: [NSMenuItem separatorItem]];
  115. [
  116. menu
  117. addItemWithTitle: [@"Quit " stringByAppendingString: name]
  118. action: @selector(terminate:)
  119. keyEquivalent: @"q"
  120. ];
  121. NSMenuItem *menuItem = [NSMenuItem new];
  122. [menuItem setSubmenu: menu];
  123. [NSApp setMainMenu: [NSMenu new]];
  124. [[NSApp mainMenu] addItem: menuItem];
  125. NSUInteger style = NSTitledWindowMask
  126. | NSClosableWindowMask
  127. | NSMiniaturizableWindowMask
  128. | NSResizableWindowMask;
  129. NSWindow *window = [
  130. [NSWindow alloc]
  131. initWithContentRect: NSMakeRect(0, 0, 800, 600)
  132. styleMask: style
  133. backing: NSBackingStoreBuffered
  134. defer: YES
  135. ];
  136. [window center];
  137. BufferView *view = [[BufferView alloc] initWithFrame: [window frame]];
  138. [window setContentView: view];
  139. [view setWindowTitle];
  140. [window makeKeyAndOrderFront: nil];
  141. [NSApp activateIgnoringOtherApps: YES];
  142. [NSApp run];
  143. }