diff --git a/readme.md b/readme.md index 3f3a2f3cb..926de7789 100644 --- a/readme.md +++ b/readme.md @@ -147,14 +147,10 @@ Although the regular linux compiliation flags will work fine, to take full advan ## Compiling - macOS -##### Using gcc/clang (32 bit) - -```cc -fno-math-errno *.c -o ClassiCube -framework Carbon -framework AGL -framework OpenGL -framework IOKit``` - -##### Using gcc/clang (64 bit) - ```cc -fno-math-errno *.c interop_cocoa.m -o ClassiCube -framework Cocoa -framework OpenGL -framework IOKit -lobjc``` +Note: You may need to install Xcode before you can compile ClassiCube + ## Compiling - for Android NOTE: If you are distributing a modified version, **please change the package ID from `com.classicube.android.client` to something else** - otherwise Android users won't be able to have both ClassiCube and your modified version installed at the same time on their Android device diff --git a/src/Core.h b/src/Core.h index 067e61201..3b151d360 100644 --- a/src/Core.h +++ b/src/Core.h @@ -192,12 +192,8 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_IOS #define CC_BUILD_TOUCH #define CC_BUILD_CFNETWORK - #elif defined __x86_64__ || defined __arm64__ - #define CC_BUILD_COCOA - #define CC_BUILD_MACOS - #define CC_BUILD_CURL #else - #define CC_BUILD_CARBON + #define CC_BUILD_COCOA #define CC_BUILD_MACOS #define CC_BUILD_CURL #endif diff --git a/src/Graphics_Xbox.c b/src/Graphics_Xbox.c index e82bfcfbf..1e4505c0d 100644 --- a/src/Graphics_Xbox.c +++ b/src/Graphics_Xbox.c @@ -270,7 +270,7 @@ void Gfx_BindTexture(GfxResourceID texId) { p = pb_push1(p, NV097_SET_TEXTURE_CONTROL0, NV097_SET_TEXTURE_CONTROL0_ENABLE | MASK(NV097_SET_TEXTURE_CONTROL0_MIN_LOD_CLAMP, 0) | - MASK(NV097_SET_TEXTURE_CONTROL0_MAX_LOD_CLAMP, 1); + MASK(NV097_SET_TEXTURE_CONTROL0_MAX_LOD_CLAMP, 1)); p = pb_push1(p, NV097_SET_TEXTURE_ADDRESS, 0x00010101); // modes (0x0W0V0U wrapping: 1=wrap 2=mirror 3=clamp 4=border 5=clamp to edge) p = pb_push1(p, NV097_SET_TEXTURE_FILTER, diff --git a/src/Window_Carbon.c b/src/Window_Carbon.c deleted file mode 100644 index f94b94c25..000000000 --- a/src/Window_Carbon.c +++ /dev/null @@ -1,812 +0,0 @@ -#include "Core.h" -#if defined CC_BUILD_CARBON && !defined CC_BUILD_SDL -#include "_WindowBase.h" -#include "String.h" -#include "Funcs.h" -#include "Bitmap.h" -#include "Errors.h" -#include - -static int windowX, windowY; -static WindowRef win_handle; -static cc_bool win_fullscreen, showingDialog; - -/*########################################################################################################################* -*------------------------------------------------=---Shared with Cocoa----------------------------------------------------* -*#########################################################################################################################*/ -/* NOTE: If code here is changed, don't forget to update corresponding code in interop_cocoa.m */ -static void Window_CommonInit(void) { - CGDirectDisplayID display = CGMainDisplayID(); - CGRect bounds = CGDisplayBounds(display); - - DisplayInfo.x = (int)bounds.origin.x; - DisplayInfo.y = (int)bounds.origin.y; - DisplayInfo.Width = (int)bounds.size.width; - DisplayInfo.Height = (int)bounds.size.height; - DisplayInfo.Depth = CGDisplayBitsPerPixel(display); - DisplayInfo.ScaleX = 1; - DisplayInfo.ScaleY = 1; -} - -static pascal OSErr HandleQuitMessage(const AppleEvent* ev, AppleEvent* reply, long handlerRefcon) { - Window_RequestClose(); - return 0; -} - -static void Window_CommonCreate(void) { - /* for quit buttons in dock and menubar */ - AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, - NewAEEventHandlerUPP(HandleQuitMessage), 0, false); -} - -/* Sourced from https://www.meandmark.com/keycodes.html */ -static const cc_uint8 key_map[8 * 16] = { - 'A', 'S', 'D', 'F', 'H', 'G', 'Z', 'X', 'C', 'V', 0, 'B', 'Q', 'W', 'E', 'R', - 'Y', 'T', '1', '2', '3', '4', '6', '5', CCKEY_EQUALS, '9', '7', CCKEY_MINUS, '8', '0', CCKEY_RBRACKET, 'O', - 'U', CCKEY_LBRACKET, 'I', 'P', CCKEY_ENTER, 'L', 'J', CCKEY_QUOTE, 'K', CCKEY_SEMICOLON, CCKEY_BACKSLASH, CCKEY_COMMA, CCKEY_SLASH, 'N', 'M', CCKEY_PERIOD, - CCKEY_TAB, CCKEY_SPACE, CCKEY_TILDE, CCKEY_BACKSPACE, 0, CCKEY_ESCAPE, 0, 0, 0, CCKEY_CAPSLOCK, 0, 0, 0, 0, 0, 0, - 0, CCKEY_KP_DECIMAL, 0, CCKEY_KP_MULTIPLY, 0, CCKEY_KP_PLUS, 0, CCKEY_NUMLOCK, 0, 0, 0, CCKEY_KP_DIVIDE, CCKEY_KP_ENTER, 0, CCKEY_KP_MINUS, 0, - 0, CCKEY_KP_ENTER, CCKEY_KP0, CCKEY_KP1, CCKEY_KP2, CCKEY_KP3, CCKEY_KP4, CCKEY_KP5, CCKEY_KP6, CCKEY_KP7, 0, CCKEY_KP8, CCKEY_KP9, 'N', 'M', CCKEY_PERIOD, - CCKEY_F5, CCKEY_F6, CCKEY_F7, CCKEY_F3, CCKEY_F8, CCKEY_F9, 0, CCKEY_F11, 0, CCKEY_F13, 0, CCKEY_F14, 0, CCKEY_F10, 0, CCKEY_F12, - 'U', CCKEY_F15, CCKEY_INSERT, CCKEY_HOME, CCKEY_PAGEUP, CCKEY_DELETE, CCKEY_F4, CCKEY_END, CCKEY_F2, CCKEY_PAGEDOWN, CCKEY_F1, CCKEY_LEFT, CCKEY_RIGHT, CCKEY_DOWN, CCKEY_UP, 0, -}; -static int MapNativeKey(UInt32 key) { return key < Array_Elems(key_map) ? key_map[key] : 0; } -/* TODO: Check these.. */ -/* case 0x37: return CCKEY_LWIN; */ -/* case 0x38: return CCKEY_LSHIFT; */ -/* case 0x3A: return CCKEY_LALT; */ -/* case 0x3B: return Key_ControlLeft; */ - -/* TODO: Verify these differences from OpenTK */ -/*Backspace = 51, (0x33, CCKEY_DELETE according to that link)*/ -/*Return = 52, (0x34, ??? according to that link)*/ -/*Menu = 110, (0x6E, ??? according to that link)*/ - -void Cursor_SetPosition(int x, int y) { - CGPoint point; - point.x = x + windowX; - point.y = y + windowY; - CGDisplayMoveCursorToPoint(CGMainDisplayID(), point); -} - -static void Cursor_DoSetVisible(cc_bool visible) { - if (visible) { - CGDisplayShowCursor(CGMainDisplayID()); - } else { - CGDisplayHideCursor(CGMainDisplayID()); - } -} - -void Window_EnableRawMouse(void) { - DefaultEnableRawMouse(); - CGAssociateMouseAndMouseCursorPosition(0); -} - -void Window_UpdateRawMouse(void) { CentreMousePosition(); } -void Window_DisableRawMouse(void) { - CGAssociateMouseAndMouseCursorPosition(1); - DefaultDisableRawMouse(); -} - - -/*########################################################################################################################* -*---------------------------------------------------------General---------------------------------------------------------* -*#########################################################################################################################*/ -/* NOTE: All Pasteboard functions are OSX 10.3 or later */ -static PasteboardRef Window_GetPasteboard(void) { - PasteboardRef pbRef; - OSStatus err = PasteboardCreate(kPasteboardClipboard, &pbRef); - - if (err) Logger_Abort2(err, "Creating Pasteboard reference"); - PasteboardSynchronize(pbRef); - return pbRef; -} - -#define FMT_UTF8 CFSTR("public.utf8-plain-text") -#define FMT_UTF16 CFSTR("public.utf16-plain-text") - -void Clipboard_GetText(cc_string* value) { - PasteboardRef pbRef; - ItemCount itemCount; - PasteboardItemID itemID; - CFDataRef outData; - const UInt8* ptr; - CFIndex len; - OSStatus err; - - pbRef = Window_GetPasteboard(); - - err = PasteboardGetItemCount(pbRef, &itemCount); - if (err) Logger_Abort2(err, "Getting item count from Pasteboard"); - if (itemCount < 1) return; - - err = PasteboardGetItemIdentifier(pbRef, 1, &itemID); - if (err) Logger_Abort2(err, "Getting item identifier from Pasteboard"); - - if (!(err = PasteboardCopyItemFlavorData(pbRef, itemID, FMT_UTF16, &outData))) { - ptr = CFDataGetBytePtr(outData); - len = CFDataGetLength(outData); - if (ptr) String_AppendUtf16(value, ptr, len); - } else if (!(err = PasteboardCopyItemFlavorData(pbRef, itemID, FMT_UTF8, &outData))) { - ptr = CFDataGetBytePtr(outData); - len = CFDataGetLength(outData); - if (ptr) String_AppendUtf8(value, ptr, len); - } -} - -void Clipboard_SetText(const cc_string* value) { - PasteboardRef pbRef; - CFDataRef cfData; - UInt8 str[800]; - int len; - OSStatus err; - - pbRef = Window_GetPasteboard(); - err = PasteboardClear(pbRef); - if (err) Logger_Abort2(err, "Clearing Pasteboard"); - PasteboardSynchronize(pbRef); - - len = String_EncodeUtf8(str, value); - cfData = CFDataCreate(NULL, str, len); - if (!cfData) Logger_Abort("CFDataCreate() returned null pointer"); - - PasteboardPutItemFlavor(pbRef, 1, FMT_UTF8, cfData, 0); -} - - -/*########################################################################################################################* -*----------------------------------------------------------Wwindow--------------------------------------------------------* -*#########################################################################################################################*/ -static void RefreshWindowBounds(void) { - Rect r; - if (win_fullscreen) return; - - /* TODO: kWindowContentRgn ??? */ - GetWindowBounds(win_handle, kWindowGlobalPortRgn, &r); - windowX = r.left; Window_Main.Width = r.right - r.left; - windowY = r.top; Window_Main.Height = r.bottom - r.top; -} - -static OSStatus Window_ProcessKeyboardEvent(EventRef inEvent) { - UInt32 kind, code; - int key; - OSStatus res; - - kind = GetEventKind(inEvent); - switch (kind) { - case kEventRawKeyDown: - case kEventRawKeyRepeat: - case kEventRawKeyUp: - res = GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32, - NULL, sizeof(UInt32), NULL, &code); - if (res) Logger_Abort2(res, "Getting key button"); - - key = MapNativeKey(code); - if (key) { - Input_Set(key, kind != kEventRawKeyUp); - } else { - Platform_Log1("Ignoring unknown key %i", &code); - } - return eventNotHandledErr; - - case kEventRawKeyModifiersChanged: - res = GetEventParameter(inEvent, kEventParamKeyModifiers, typeUInt32, - NULL, sizeof(UInt32), NULL, &code); - if (res) Logger_Abort2(res, "Getting key modifiers"); - - Input_Set(CCKEY_LCTRL, code & 0x1000); - Input_Set(CCKEY_LALT, code & 0x0800); - Input_Set(CCKEY_LSHIFT, code & 0x0200); - Input_Set(CCKEY_LWIN, code & 0x0100); - Input_Set(CCKEY_CAPSLOCK, code & 0x0400); - return eventNotHandledErr; - } - return eventNotHandledErr; -} - -static OSStatus Window_ProcessWindowEvent(EventRef inEvent) { - int oldWidth, oldHeight; - - switch (GetEventKind(inEvent)) { - case kEventWindowClose: - Window_Main.Exists = false; - Event_RaiseVoid(&WindowEvents.Closing); - return eventNotHandledErr; - - case kEventWindowClosed: - Window_Main.Exists = false; - return 0; - - case kEventWindowBoundsChanged: - oldWidth = Window_Main.Width; oldHeight = Window_Main.Height; - RefreshWindowBounds(); - - if (oldWidth != Window_Main.Width || oldHeight != Window_Main.Height) { - Event_RaiseVoid(&WindowEvents.Resized); - } - return eventNotHandledErr; - - case kEventWindowActivated: - Window_Main.Focused = true; - Event_RaiseVoid(&WindowEvents.FocusChanged); - return eventNotHandledErr; - - case kEventWindowDeactivated: - Window_Main.Focused = false; - Event_RaiseVoid(&WindowEvents.FocusChanged); - return eventNotHandledErr; - - case kEventWindowDrawContent: - Event_RaiseVoid(&WindowEvents.RedrawNeeded); - return eventNotHandledErr; - } - return eventNotHandledErr; -} - -static int MapNativeMouse(EventMouseButton button) { - if (button == kEventMouseButtonPrimary) return CCMOUSE_L; - if (button == kEventMouseButtonSecondary) return CCMOUSE_R; - if (button == kEventMouseButtonTertiary) return CCMOUSE_M; - - if (button == 4) return CCMOUSE_X1; - if (button == 5) return CCMOUSE_X2; - return 0; -} - -static OSStatus Window_ProcessMouseEvent(EventRef inEvent) { - int mouseX, mouseY; - HIPoint pt, raw; - UInt32 kind; - cc_bool down; - EventMouseButton button; - SInt32 delta; - OSStatus res; - int btn; - - res = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, - NULL, sizeof(HIPoint), NULL, &pt); - /* this error comes up from the application event handler */ - if (res && res != eventParameterNotFoundErr) { - Logger_Abort2(res, "Getting mouse position"); - } - - if (Input.RawMode) { - raw.x = 0; raw.y = 0; - GetEventParameter(inEvent, kEventParamMouseDelta, typeHIPoint, NULL, sizeof(HIPoint), NULL, &raw); - Event_RaiseRawMove(&PointerEvents.RawMoved, raw.x, raw.y); - } - - if (showingDialog) return eventNotHandledErr; - mouseX = (int)pt.x; mouseY = (int)pt.y; - - /* kEventParamMouseLocation is in screen coordinates */ - /* So need to make sure mouse click lies inside window */ - /* Otherwise this breaks close/minimise/maximise in titlebar and dock */ - if (!win_fullscreen) { - mouseX -= windowX; mouseY -= windowY; - - if (mouseX < 0 || mouseX >= Window_Main.Width) return eventNotHandledErr; - if (mouseY < 0 || mouseY >= Window_Main.Height) return eventNotHandledErr; - } - - kind = GetEventKind(inEvent); - switch (kind) { - case kEventMouseDown: - case kEventMouseUp: - down = kind == kEventMouseDown; - res = GetEventParameter(inEvent, kEventParamMouseButton, typeMouseButton, - NULL, sizeof(EventMouseButton), NULL, &button); - if (res) Logger_Abort2(res, "Getting mouse button"); - - btn = MapNativeMouse(button); - if (btn) Input_Set(btn, down); break; - - return eventNotHandledErr; - - case kEventMouseWheelMoved: - res = GetEventParameter(inEvent, kEventParamMouseWheelDelta, typeSInt32, - NULL, sizeof(SInt32), NULL, &delta); - if (res) Logger_Abort2(res, "Getting mouse wheel delta"); - Mouse_ScrollWheel(delta); - return 0; - - case kEventMouseMoved: - case kEventMouseDragged: - Pointer_SetPosition(0, mouseX, mouseY); - return eventNotHandledErr; - } - return eventNotHandledErr; -} - -static OSStatus Window_ProcessTextEvent(EventRef inEvent) { - UInt32 kind; - EventRef keyEvent = NULL; - UniChar chars[17] = { 0 }; - char keyChar; - int i; - OSStatus res; - - kind = GetEventKind(inEvent); - if (kind != kEventTextInputUnicodeForKeyEvent) return eventNotHandledErr; - - /* When command key is pressed, text input should be ignored */ - res = GetEventParameter(inEvent, kEventParamTextInputSendKeyboardEvent, - typeEventRef, NULL, sizeof(keyEvent), NULL, &keyEvent); - if (!res && keyEvent) { - UInt32 modifiers = 0; - GetEventParameter(keyEvent, kEventParamKeyModifiers, - typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers); - if (modifiers & 0x0100) return eventNotHandledErr; - } - - /* TODO: is the assumption we only get 1-4 characters always valid */ - res = GetEventParameter(inEvent, kEventParamTextInputSendText, - typeUnicodeText, NULL, 16 * sizeof(UniChar), NULL, chars); - if (res) Logger_Abort2(res, "Getting text chars"); - - for (i = 0; i < 16 && chars[i]; i++) { - /* TODO: UTF16 to codepoint conversion */ - Event_RaiseInt(&InputEvents.Press, chars[i]); - } - return eventNotHandledErr; -} - -static OSStatus Window_EventHandler(EventHandlerCallRef inCaller, EventRef inEvent, void* userData) { - EventRecord record; - - switch (GetEventClass(inEvent)) { - case kEventClassAppleEvent: - /* Only event here is the apple event. */ - Platform_LogConst("Processing apple event."); - ConvertEventRefToEventRecord(inEvent, &record); - AEProcessAppleEvent(&record); - break; - - case kEventClassKeyboard: - return Window_ProcessKeyboardEvent(inEvent); - case kEventClassMouse: - return Window_ProcessMouseEvent(inEvent); - case kEventClassWindow: - return Window_ProcessWindowEvent(inEvent); - case kEventClassTextInput: - return Window_ProcessTextEvent(inEvent); - } - return eventNotHandledErr; -} - -typedef EventTargetRef (*GetMenuBarEventTarget_Func)(void); - -static void HookEvents(void) { - static const EventTypeSpec winEventTypes[] = { - { kEventClassKeyboard, kEventRawKeyDown }, - { kEventClassKeyboard, kEventRawKeyRepeat }, - { kEventClassKeyboard, kEventRawKeyUp }, - { kEventClassKeyboard, kEventRawKeyModifiersChanged }, - - { kEventClassWindow, kEventWindowClose }, - { kEventClassWindow, kEventWindowClosed }, - { kEventClassWindow, kEventWindowBoundsChanged }, - { kEventClassWindow, kEventWindowActivated }, - { kEventClassWindow, kEventWindowDeactivated }, - { kEventClassWindow, kEventWindowDrawContent }, - - { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, - { kEventClassAppleEvent, kEventAppleEvent } - }; - static const EventTypeSpec appEventTypes[] = { - { kEventClassMouse, kEventMouseDown }, - { kEventClassMouse, kEventMouseUp }, - { kEventClassMouse, kEventMouseMoved }, - { kEventClassMouse, kEventMouseDragged }, - { kEventClassMouse, kEventMouseWheelMoved } - }; - GetMenuBarEventTarget_Func getMenuBarEventTarget; - EventTargetRef target; - - target = GetWindowEventTarget(win_handle); - InstallEventHandler(target, NewEventHandlerUPP(Window_EventHandler), - Array_Elems(winEventTypes), winEventTypes, NULL, NULL); - - target = GetApplicationEventTarget(); - InstallEventHandler(target, NewEventHandlerUPP(Window_EventHandler), - Array_Elems(appEventTypes), appEventTypes, NULL, NULL); - - /* The code below is to get the menubar working. */ - /* The documentation for 'RunApplicationEventLoop' states that it installs */ - /* the standard application event handler which lets the menubar work. */ - /* However, we cannot use that since the event loop is managed by us instead. */ - /* Unfortunately, there is no proper API to duplicate that behaviour, so rely */ - /* on the undocumented GetMenuBarEventTarget to achieve similar behaviour. */ - /* TODO: This is wrong for PowerPC. But at least it doesn't crash or anything. */ -#define _RTLD_DEFAULT ((void*)-2) - getMenuBarEventTarget = DynamicLib_Get2(_RTLD_DEFAULT, "GetMenuBarEventTarget"); - InstallStandardEventHandler(GetApplicationEventTarget()); - - /* TODO: Why does this not work properly until user activates another window */ - /* Followup: Seems to be a bug in OSX http://www.sheepsystems.com/developers_blog/transformprocesstype--bette.html */ - if (getMenuBarEventTarget) { - InstallStandardEventHandler(getMenuBarEventTarget()); - } else { - Platform_LogConst("MenuBar won't work!"); - } - /* MenuRef menu = AcquireRootMenu(); */ - /* InstallStandardEventHandler(GetMenuEventTarget(menu)); */ -} - - -/*########################################################################################################################* - *--------------------------------------------------Public implementation--------------------------------------------------* - *#########################################################################################################################*/ -void Window_Init(void) { Window_CommonInit(); } - -void Window_Free(void) { } - -/* Private CGS/CGL stuff */ -typedef int CGSConnectionID; -typedef int CGSWindowID; -extern CGSConnectionID _CGSDefaultConnection(void); -extern CGSWindowID GetNativeWindowFromWindowRef(WindowRef window); -extern CGContextRef CGWindowContextCreate(CGSConnectionID conn, CGSWindowID win, void* opts); - -static CGSConnectionID conn; -static CGSWindowID winId; - -#ifndef kCGBitmapByteOrder32Host -/* Undefined in < 10.4 SDK. No issue since < 10.4 is only Big Endian PowerPC anyways */ -#define kCGBitmapByteOrder32Host 0 -#endif - -#ifdef CC_BUILD_ICON -/* See misc/mac_icon_gen.cs for how to generate this file */ -#include "_CCIcon_mac.h" - -static void ApplyIcon(void) { - CGColorSpaceRef colSpace; - CGDataProviderRef provider; - CGImageRef image; - - colSpace = CGColorSpaceCreateDeviceRGB(); - provider = CGDataProviderCreateWithData(NULL, CCIcon_Data, - Bitmap_DataSize(CCIcon_Width, CCIcon_Height), NULL); - image = CGImageCreate(CCIcon_Width, CCIcon_Height, 8, 32, CCIcon_Width * 4, colSpace, - kCGBitmapByteOrder32Host | kCGImageAlphaLast, provider, NULL, 0, 0); - - SetApplicationDockTileImage(image); - CGImageRelease(image); - CGDataProviderRelease(provider); - CGColorSpaceRelease(colSpace); -} -#else -static void ApplyIcon(void) { } -#endif - -static void DoCreateWindow(int width, int height) { - Rect r; - OSStatus res; - ProcessSerialNumber psn; - - r.left = Display_CentreX(width); r.right = r.left + width; - r.top = Display_CentreY(height); r.bottom = r.top + height; - res = CreateNewWindow(kDocumentWindowClass, - kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | - kWindowInWindowMenuAttribute | kWindowLiveResizeAttribute, &r, &win_handle); - - if (res) Logger_Abort2(res, "Creating window failed"); - RefreshWindowBounds(); - - AcquireRootMenu(); - GetCurrentProcess(&psn); - SetFrontProcess(&psn); - - /* TODO: Use BringWindowToFront instead.. (look in the file which has RepositionWindow in it) !!!! */ - HookEvents(); - Window_CommonCreate(); - Window_Main.Exists = true; - Window_Main.Handle = win_handle; - /* CGAssociateMouseAndMouseCursorPosition implicitly grabs cursor */ - - conn = _CGSDefaultConnection(); - winId = GetNativeWindowFromWindowRef(win_handle); - ApplyIcon(); -} -void Window_Create2D(int width, int height) { DoCreateWindow(width, height); } -void Window_Create3D(int width, int height) { DoCreateWindow(width, height); } - -void Window_SetTitle(const cc_string* title) { - UInt8 str[NATIVE_STR_LEN]; - CFStringRef titleCF; - int len; - - /* TODO: This leaks memory, old title isn't released */ - len = String_EncodeUtf8(str, title); - titleCF = CFStringCreateWithBytes(kCFAllocatorDefault, str, len, kCFStringEncodingUTF8, false); - SetWindowTitleWithCFString(win_handle, titleCF); -} - -int Window_GetWindowState(void) { - if (win_fullscreen) return WINDOW_STATE_FULLSCREEN; - if (IsWindowCollapsed(win_handle)) return WINDOW_STATE_MINIMISED; - return WINDOW_STATE_NORMAL; -} - -int Window_IsObscured(void) { - /* TODO: This isn't a complete fix because it doesn't check for occlusion - */ - /* so you'll still get 100% CPU usage when window is hidden in background */ - return IsWindowCollapsed(win_handle); -} - -void Window_Show(void) { - ShowWindow(win_handle); - /* TODO: Do we actually need to reposition */ - RepositionWindow(win_handle, NULL, kWindowCenterOnMainScreen); - SelectWindow(win_handle); -} - -void Window_SetSize(int width, int height) { - SizeWindow(win_handle, width, height, true); -} - -void Window_RequestClose(void) { - /* DisposeWindow only sends a kEventWindowClosed */ - Event_RaiseVoid(&WindowEvents.Closing); - if (Window_Main.Exists) DisposeWindow(win_handle); - Window_Main.Exists = false; -} - -void Window_ProcessEvents(double delta) { - EventRef theEvent; - EventTargetRef target = GetEventDispatcherTarget(); - OSStatus res; - - for (;;) { - res = ReceiveNextEvent(0, NULL, 0.0, true, &theEvent); - if (res == eventLoopTimedOutErr) break; - - if (res) { - Platform_Log1("Message Loop status: %i", &res); break; - } - if (!theEvent) break; - - SendEventToEventTarget(theEvent, target); - ReleaseEvent(theEvent); - } -} - -static void Cursor_GetRawPos(int* x, int* y) { - Point point; - GetGlobalMouse(&point); - *x = (int)point.h; *y = (int)point.v; -} - -static void ShowDialogCore(const char* title, const char* msg) { - CFStringRef titleCF = CFStringCreateWithCString(NULL, title, kCFStringEncodingASCII); - CFStringRef msgCF = CFStringCreateWithCString(NULL, msg, kCFStringEncodingASCII); - DialogRef dialog; - DialogItemIndex itemHit; - - showingDialog = true; - CreateStandardAlert(kAlertPlainAlert, titleCF, msgCF, NULL, &dialog); - CFRelease(titleCF); - CFRelease(msgCF); - - RunStandardAlert(dialog, NULL, &itemHit); - showingDialog = false; -} - -cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { - return ERR_NOT_SUPPORTED; -} - -cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { - return ERR_NOT_SUPPORTED; -} - -static CGrafPtr fb_port; -static CGColorSpaceRef colorSpace; - -void Window_AllocFramebuffer(struct Bitmap* bmp) { - if (!fb_port) fb_port = GetWindowPort(win_handle); - - bmp->scan0 = Mem_Alloc(bmp->width * bmp->height, 4, "window pixels"); - colorSpace = CGColorSpaceCreateDeviceRGB(); -} - -void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) { - CGContextRef context = NULL; - CGDataProviderRef provider; - CGImageRef image; - CGRect rect; - OSStatus err; - - /* Unfortunately CGImageRef is immutable, so changing the */ - /* underlying data doesn't change what shows when drawing. */ - /* TODO: Use QuickDraw alternative instead */ - - /* TODO: Only update changed bit.. */ - rect.origin.x = 0; rect.origin.y = 0; - rect.size.width = Window_Main.Width; - rect.size.height = Window_Main.Height; - - err = QDBeginCGContext(fb_port, &context); - if (err) Logger_Abort2(err, "Begin draw"); - /* TODO: REPLACE THIS AWFUL HACK */ - - provider = CGDataProviderCreateWithData(NULL, bmp->scan0, - Bitmap_DataSize(bmp->width, bmp->height), NULL); - image = CGImageCreate(bmp->width, bmp->height, 8, 32, bmp->width * 4, colorSpace, - kCGBitmapByteOrder32Host | kCGImageAlphaNoneSkipFirst, provider, NULL, 0, 0); - - CGContextDrawImage(context, rect, image); - CGContextSynchronize(context); - err = QDEndCGContext(fb_port, &context); - if (err) Logger_Abort2(err, "End draw"); - - CGImageRelease(image); - CGDataProviderRelease(provider); -} - -void Window_FreeFramebuffer(struct Bitmap* bmp) { - Mem_Free(bmp->scan0); - CGColorSpaceRelease(colorSpace); -} - -void Window_OpenKeyboard(struct OpenKeyboardArgs* args) { } -void Window_SetKeyboardText(const cc_string* text) { } -void Window_CloseKeyboard(void) { } - - -/*########################################################################################################################* -*-------------------------------------------------------AGL OpenGL--------------------------------------------------------* -*#########################################################################################################################*/ -#if defined CC_BUILD_GL && !defined CC_BUILD_EGL -#include - -static AGLContext ctx_handle; -static int ctx_windowWidth, ctx_windowHeight; - -static void GLContext_Check(int code, const char* place) { - cc_result res; - if (code) return; - - res = aglGetError(); - if (res) Logger_Abort2(res, place); -} - -static void GLContext_MakeCurrent(void) { - int code = aglSetCurrentContext(ctx_handle); - GLContext_Check(code, "Setting GL context"); -} - -static void GLContext_SetDrawable(void) { - CGrafPtr windowPort = GetWindowPort(win_handle); - int code = aglSetDrawable(ctx_handle, windowPort); - GLContext_Check(code, "Attaching GL context"); -} - -cc_result Window_EnterFullscreen(void) { - int width = DisplayInfo.Width; - int height = DisplayInfo.Height; - int code; - - /* TODO: Does aglSetFullScreen capture the screen anyways? */ - CGDisplayCapture(CGMainDisplayID()); - - if (!aglSetFullScreen(ctx_handle, width, height, 0, 0)) { - code = aglGetError(); - Window_ExitFullscreen(); - return code; - } - - win_fullscreen = true; - ctx_windowWidth = Window_Main.Width; - ctx_windowHeight = Window_Main.Height; - - windowX = DisplayInfo.x; Window_Main.Width = DisplayInfo.Width; - windowY = DisplayInfo.y; Window_Main.Height = DisplayInfo.Height; - - Event_RaiseVoid(&WindowEvents.Resized); - return 0; -} - -cc_result Window_ExitFullscreen(void) { - int code; - - code = aglSetDrawable(ctx_handle, NULL); - if (!code) return aglGetError(); - - CGDisplayRelease(CGMainDisplayID()); - GLContext_SetDrawable(); - - win_fullscreen = false; - /* TODO: Eliminate this if possible */ - Window_SetSize(ctx_windowWidth, ctx_windowHeight); - - RefreshWindowBounds(); - Event_RaiseVoid(&WindowEvents.Resized); - return 0; -} - -static void GLContext_GetAttribs(struct GraphicsMode* mode, GLint* attribs, cc_bool fullscreen) { - int i = 0; - - attribs[i++] = AGL_RGBA; - attribs[i++] = AGL_RED_SIZE; attribs[i++] = mode->R; - attribs[i++] = AGL_GREEN_SIZE; attribs[i++] = mode->G; - attribs[i++] = AGL_BLUE_SIZE; attribs[i++] = mode->B; - attribs[i++] = AGL_ALPHA_SIZE; attribs[i++] = mode->A; - attribs[i++] = AGL_DEPTH_SIZE; attribs[i++] = GLCONTEXT_DEFAULT_DEPTH; - - attribs[i++] = AGL_DOUBLEBUFFER; - if (fullscreen) { attribs[i++] = AGL_FULLSCREEN; } - attribs[i++] = 0; -} - -void GLContext_Create(void) { - GLint attribs[20]; - AGLPixelFormat fmt; - GDHandle gdevice; - OSStatus res; - struct GraphicsMode mode; - InitGraphicsMode(&mode); - - /* Initially try creating fullscreen compatible context */ - res = DMGetGDeviceByDisplayID(CGMainDisplayID(), &gdevice, false); - if (res) Logger_Abort2(res, "Getting display device failed"); - - GLContext_GetAttribs(&mode, attribs, true); - fmt = aglChoosePixelFormat(&gdevice, 1, attribs); - res = aglGetError(); - - /* Try again with non-compatible context if that fails */ - if (!fmt || res == AGL_BAD_PIXELFMT) { - Platform_LogConst("Failed to create full screen pixel format."); - Platform_LogConst("Trying again to create a non-fullscreen pixel format."); - - GLContext_GetAttribs(&mode, attribs, false); - fmt = aglChoosePixelFormat(NULL, 0, attribs); - res = aglGetError(); - } - if (res) Logger_Abort2(res, "Choosing pixel format"); - - ctx_handle = aglCreateContext(fmt, NULL); - GLContext_Check(0, "Creating GL context"); - aglDestroyPixelFormat(fmt); - - GLContext_SetDrawable(); - GLContext_MakeCurrent(); -} - -void GLContext_Update(void) { - if (win_fullscreen) return; - aglUpdateContext(ctx_handle); -} -cc_bool GLContext_TryRestore(void) { return true; } - -void GLContext_Free(void) { - if (!ctx_handle) return; - aglSetCurrentContext(NULL); - aglDestroyContext(ctx_handle); - ctx_handle = NULL; -} - -void* GLContext_GetAddress(const char* function) { - static const cc_string glPath = String_FromConst("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"); - static void* lib; - - if (!lib) lib = DynamicLib_Load2(&glPath); - return DynamicLib_Get2(lib, function); -} - -cc_bool GLContext_SwapBuffers(void) { - aglSwapBuffers(ctx_handle); - GLContext_Check(0, "Swapping buffers"); - return true; -} - -void GLContext_SetFpsLimit(cc_bool vsync, float minFrameMs) { - int value = vsync ? 1 : 0; - aglSetInteger(ctx_handle, AGL_SWAP_INTERVAL, &value); -} -void GLContext_GetApiInfo(cc_string* info) { } -#endif -#endif diff --git a/src/interop_cocoa.m b/src/interop_cocoa.m index 1942f08a9..34d2a7150 100644 --- a/src/interop_cocoa.m +++ b/src/interop_cocoa.m @@ -15,38 +15,9 @@ static cc_bool canCheckOcclusion; static cc_bool legacy_fullscreen; static cc_bool scroll_debugging; -/*########################################################################################################################* -*---------------------------------------------------Shared with Carbon----------------------------------------------------* -*#########################################################################################################################*/ extern size_t CGDisplayBitsPerPixel(CGDirectDisplayID display); // TODO: Try replacing with NSBitsPerPixelFromDepth([NSScreen mainScreen].depth) instead -// NOTE: If code here is changed, don't forget to update corresponding code in Window_Carbon.c -static void Window_CommonInit(void) { - CGDirectDisplayID display = CGMainDisplayID(); - CGRect bounds = CGDisplayBounds(display); - - DisplayInfo.x = (int)bounds.origin.x; - DisplayInfo.y = (int)bounds.origin.y; - DisplayInfo.Width = (int)bounds.size.width; - DisplayInfo.Height = (int)bounds.size.height; - DisplayInfo.Depth = CGDisplayBitsPerPixel(display); - DisplayInfo.ScaleX = 1; - DisplayInfo.ScaleY = 1; -} - -static pascal OSErr HandleQuitMessage(const AppleEvent* ev, AppleEvent* reply, long handlerRefcon) { - Window_RequestClose(); - return 0; -} - -static void Window_CommonCreate(void) { - scroll_debugging = Options_GetBool("scroll-debug", false); - // for quit buttons in dock and menubar - AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, - NewAEEventHandlerUPP(HandleQuitMessage), 0, false); -} - // Sourced from https://www.meandmark.com/keycodes.html static const cc_uint8 key_map[8 * 16] = { /* 0x00 */ 'A', 'S', 'D', 'F', 'H', 'G', 'Z', 'X', @@ -199,7 +170,17 @@ void Window_Init(void) { pool = [[NSAutoreleasePool alloc] init]; appHandle = [NSApplication sharedApplication]; [appHandle activateIgnoringOtherApps:YES]; - Window_CommonInit(); + + CGDirectDisplayID display = CGMainDisplayID(); + CGRect bounds = CGDisplayBounds(display); + + DisplayInfo.x = (int)bounds.origin.x; + DisplayInfo.y = (int)bounds.origin.y; + DisplayInfo.Width = (int)bounds.size.width; + DisplayInfo.Height = (int)bounds.size.height; + DisplayInfo.Depth = CGDisplayBitsPerPixel(display); + DisplayInfo.ScaleX = 1; + DisplayInfo.ScaleY = 1; // NSApplication sometimes replaces the uncaught exception handler, so set it again NSSetUncaughtExceptionHandler(LogUnhandledNSErrors); @@ -349,6 +330,11 @@ static void ApplyIcon(void) { static void ApplyIcon(void) { } #endif +static pascal OSErr HandleQuitMessage(const AppleEvent* ev, AppleEvent* reply, long handlerRefcon) { + Window_RequestClose(); + return 0; +} + #define WIN_MASK (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask) static void DoCreateWindow(int width, int height) { CCWindowDelegate* del; @@ -365,7 +351,12 @@ static void DoCreateWindow(int width, int height) { [winHandle initWithContentRect:rect styleMask:WIN_MASK backing:NSBackingStoreBuffered defer:false]; [winHandle setAcceptsMouseMovedEvents:YES]; - Window_CommonCreate(); + + scroll_debugging = Options_GetBool("scroll-debug", false); + // for quit buttons in dock and menubar + AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, + NewAEEventHandlerUPP(HandleQuitMessage), 0, false); + Window_Main.Exists = true; Window_Main.Handle = winHandle; // CGAssociateMouseAndMouseCursorPosition implicitly grabs cursor