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.0KB

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. @interface BufferView : NSView {
  24. size_t bufSize;
  25. uint32_t *buf;
  26. CGColorSpaceRef colorSpace;
  27. CGDataProviderRef dataProvider;
  28. }
  29. @end
  30. @implementation BufferView
  31. - (instancetype) initWithFrame: (NSRect) frameRect {
  32. colorSpace = CGColorSpaceCreateDeviceRGB();
  33. return [super initWithFrame: frameRect];
  34. }
  35. - (void) setWindowTitle {
  36. [[self window] setTitle: [NSString stringWithUTF8String: status()]];
  37. }
  38. - (void) draw {
  39. draw(buf, [self frame].size.width, [self frame].size.height);
  40. [self setNeedsDisplay: YES];
  41. }
  42. - (void) setFrameSize: (NSSize) newSize {
  43. [super setFrameSize: newSize];
  44. size_t newBufSize = 4 * newSize.width * newSize.height;
  45. if (newBufSize > bufSize) {
  46. bufSize = newBufSize;
  47. buf = malloc(bufSize);
  48. if (!buf) err(EX_OSERR, "malloc(%zu)", bufSize);
  49. CGDataProviderRelease(dataProvider);
  50. dataProvider = CGDataProviderCreateWithData(NULL, buf, bufSize, NULL);
  51. }
  52. [self draw];
  53. }
  54. - (void) drawRect: (NSRect) dirtyRect {
  55. (void)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 *) sender {
  97. (void)sender;
  98. return YES;
  99. }
  100. @end
  101. int main(int argc, char *argv[]) {
  102. int error = init(argc, argv);
  103. if (error) return error;
  104. [NSApplication sharedApplication];
  105. [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
  106. [NSApp setDelegate: [Delegate new]];
  107. NSString *name = [[NSProcessInfo processInfo] processName];
  108. NSMenu *menu = [NSMenu new];
  109. [
  110. menu
  111. addItemWithTitle: @"Close Window"
  112. action: @selector(performClose:)
  113. keyEquivalent: @"w"
  114. ];
  115. [menu addItem: [NSMenuItem separatorItem]];
  116. [
  117. menu
  118. addItemWithTitle: [@"Quit " stringByAppendingString: name]
  119. action: @selector(terminate:)
  120. keyEquivalent: @"q"
  121. ];
  122. NSMenuItem *menuItem = [NSMenuItem new];
  123. [menuItem setSubmenu: menu];
  124. [NSApp setMainMenu: [NSMenu new]];
  125. [[NSApp mainMenu] addItem: menuItem];
  126. NSUInteger style = NSTitledWindowMask
  127. | NSClosableWindowMask
  128. | NSMiniaturizableWindowMask
  129. | NSResizableWindowMask;
  130. NSWindow *window = [
  131. [NSWindow alloc]
  132. initWithContentRect: NSMakeRect(0, 0, 800, 600)
  133. styleMask: style
  134. backing: NSBackingStoreBuffered
  135. defer: YES
  136. ];
  137. [window center];
  138. BufferView *view = [[BufferView alloc] initWithFrame: [window frame]];
  139. [window setContentView: view];
  140. [view setWindowTitle];
  141. [window makeKeyAndOrderFront: nil];
  142. [NSApp activateIgnoringOtherApps: YES];
  143. [NSApp run];
  144. }