//======================================================================== // GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. // Copyright (c) 2016-2019 Camilla Löwy // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== // It is fine to use C99 in this file because it will not be built with VS //======================================================================== #include "internal.h" #include #include #include #include #include #include #include #define MIN_WINDOW_SIZE 100 static void OS4_CopyIdcmpMessage(struct IntuiMessage * src, struct MyIntuiMessage * dst); static _GLFWwindow *OS4_FindWindow(struct Window * syswin); static uint32_t *OS4_CopyImageData(const GLFWimage *surface); static int OS4_GetButtonState(uint16_t code); static int OS4_GetButton(uint16_t code); static char OS4_TranslateUnicode(uint16_t code, uint32_t qualifier); static int OS4_TranslateState(int state); static uint32_t OS4_GetWindowFlags(_GLFWwindow* window, GLFWbool fullscreen); static void OS4_SetWindowLimits(_GLFWwindow * window); static void OS4_CreateIconifyGadget(_GLFWwindow * window); static struct DiskObject *OS4_GetDiskObject(); static void OS4_HandleAppIcon(struct AppMessage * msg); static ULONG OS4_BackFill(const struct Hook *hook, struct RastPort *rastport, struct BackFillMessage *message); static char *UCS4ToUTF8(uint32_t ch, char *dst); #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif static UWORD fallbackPointerData[2 * 16] = { 0 }; static struct BitMap fallbackPointerBitMap = { 2, 16, 0, 2, 0, { (PLANEPTR)fallbackPointerData, (PLANEPTR)(fallbackPointerData + 16) } }; static struct Hook OS4_BackFillHook = { {0, 0}, /* h_MinNode */ (void *)OS4_BackFill, /* h_Entry */ 0, /* h_SubEntry */ 0 /* h_Data */ }; static void OS4_GetWindowSize(struct Window * window, int * width, int * height) { LONG ret = IIntuition->GetWindowAttrs( window, WA_InnerWidth, width, WA_InnerHeight, height, TAG_DONE); if (ret) { dprintf("GetWindowAttrs() returned %d\n", ret); } } static void OS4_WaitForResize(_GLFWwindow* window, int * width, int * height) { int counter = 0; int activeWidth, activeHeight; int w = 0; int h = 0; _glfwGetWindowSizeOS4(window, &activeWidth, &activeHeight); while (counter++ < 100) { OS4_GetWindowSize(window->os4.handle, &w, &h); if (w == activeWidth && h == activeHeight) { break; } dprintf("Waiting for Intuition %d\n", counter); dprintf("System window size (%d * %d), GLFW window size (%d * %d)\n", w, h, activeWidth, activeHeight); usleep(1000); } if (width) { *width = w; } if (height) { *height = h; } } static void OS4_ResizeWindow(_GLFWwindow* window, int width, int height, int posx, int posy) { if (width > 0 && height > 0) { LONG ret = IIntuition->SetWindowAttrs(window->os4.handle, WA_InnerWidth, width, WA_InnerHeight, height, WA_Left, posx, WA_Top, posy, TAG_DONE); if (ret) { dprintf("SetWindowAttrs() returned %d\n", ret); } OS4_WaitForResize(window, NULL, NULL); #if 0 if (window->os4.glwindow->context.gl.glContext) { OS4_ResizeGlContext(window); } #endif } else { dprintf("Invalid width %d or height %d\n", width, height); } } static uint32 OS4_GetIDCMPFlags(_GLFWwindow* window, GLFWbool fullscreen) { uint32 IDCMPFlags = IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_DELTAMOVE | IDCMP_RAWKEY | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW | IDCMP_INTUITICKS | IDCMP_EXTENDEDMOUSE; dprintf("Called\n"); if (!fullscreen) { if (window->decorated) { IDCMPFlags |= IDCMP_CLOSEWINDOW | IDCMP_GADGETUP | IDCMP_CHANGEWINDOW; } if (window->resizable) { //IDCMPFlags |= IDCMP_SIZEVERIFY; no handling so far IDCMPFlags |= IDCMP_NEWSIZE; } } return IDCMPFlags; } static struct Screen * OS4_GetScreenForWindow(_GLFWwindow* window) { if (window->os4.screen) { dprintf("Fullscreen\n"); return window->os4.screen; } else { dprintf("Window mode (public screen)\n"); return _glfw.os4.publicScreen; } } static void OS4_DefineWindowBox(_GLFWwindow* window, const _GLFWwndconfig *wndconfig, struct Screen * screen, GLFWbool fullscreen, struct IBox *box) { if (fullscreen && screen) { box->Left = 0; box->Top = 0; box->Width = screen->Width; box->Height = screen->Height; } else { box->Left = window->os4.xpos; box->Top = window->os4.ypos; box->Width = wndconfig->width; box->Height = wndconfig->height; } } void OS4_CloseScreen(struct Screen* screen) { if (screen) { if (screen != _glfw.os4.publicScreen) { dprintf("Closing screen %p\n", screen); if (IIntuition->CloseScreen(screen) == FALSE) { dprintf("Screen has open window(s), cannot close\n"); } else { dprintf("Screen closed successfully\n"); } } else { dprintf("Public screen, not closing\n"); } } else { dprintf("NULL pointer\n"); } } static ULONG OS4_MapCursorIdToNative(int id) { switch (id) { case GLFW_ARROW_CURSOR: return POINTERTYPE_NORMAL; case GLFW_IBEAM_CURSOR: return POINTERTYPE_SELECT; //54.21 //case SDL_SYSTEM_CURSOR_WAITARROW: //case SDL_SYSTEM_CURSOR_WAIT: return POINTERTYPE_BUSY; case GLFW_CROSSHAIR_CURSOR: return POINTERTYPE_CROSS; case GLFW_RESIZE_NWSE_CURSOR: return POINTERTYPE_NORTHWESTSOUTHEASTRESIZE; case GLFW_RESIZE_NESW_CURSOR: return POINTERTYPE_NORTHEASTSOUTHWESTRESIZE; case GLFW_RESIZE_EW_CURSOR: return POINTERTYPE_EASTWESTRESIZE; case GLFW_RESIZE_NS_CURSOR: return POINTERTYPE_NORTHSOUTHRESIZE; case GLFW_NOT_ALLOWED_CURSOR: return POINTERTYPE_NOTALLOWED; case GLFW_POINTING_HAND_CURSOR: return POINTERTYPE_HAND; // case GLFW_RESIZE_ALL_CURSOR: default: dprintf("Unknown mapping from type %d\n", id); return POINTERTYPE_NORMAL; } } static void OS4_HandleAppWindow(struct AppMessage *msg) { _GLFWwindow *window = (_GLFWwindow *) msg->am_UserData; int count = msg->am_NumArgs; if (count > 0) { int i; char** paths = _glfw_calloc(count, sizeof(char*)); for (i = 0; i < count; i++) { const size_t maxPathLen = 255; char buf[maxPathLen]; if (IDOS->NameFromLock(msg->am_ArgList[i].wa_Lock, buf, sizeof(buf))) { if (IDOS->AddPart(buf, msg->am_ArgList[i].wa_Name, sizeof(buf))) { paths[i] = _glfw_strdup(buf); dprintf("%s - %s\n", buf, paths[i]); } } } _glfwInputDrop(window, count, (const char**) paths); for (i = 0; i < count; i++) _glfw_free(paths[i]); _glfw_free(paths); } } static void applySizeLimits(_GLFWwindow* window, int* width, int* height) { if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) { const float ratio = (float) window->numer / (float) window->denom; *height = (int) (*width / ratio); } if (window->minwidth != GLFW_DONT_CARE && *width < window->minwidth) *width = window->minwidth; else if (window->maxwidth != GLFW_DONT_CARE && *width > window->maxwidth) *width = window->maxwidth; if (window->minheight != GLFW_DONT_CARE && *height < window->minheight) *height = window->minheight; else if (window->maxheight != GLFW_DONT_CARE && *height > window->maxheight) *height = window->maxheight; OS4_SetWindowLimits(window); } static void fitToMonitor(_GLFWwindow* window) { GLFWvidmode mode; _glfwGetVideoModeOS4(window->monitor, &mode); _glfwGetMonitorPosOS4(window->monitor, &window->os4.xpos, &window->os4.ypos); window->os4.width = mode.width; window->os4.height = mode.height; IIntuition->SetWindowAttrs(window->os4.handle, WA_Left, 0, WA_Top, 0, WA_Width, mode.width, WA_Height, mode.height, TAG_DONE); } static void acquireMonitor(_GLFWwindow* window) { _glfwInputMonitorWindow(window->monitor, window); } static void releaseMonitor(_GLFWwindow* window) { if (window->monitor->window != window) return; _glfwInputMonitorWindow(window->monitor, NULL); } // Apply disabled cursor mode to a focused window // static void disableCursor(_GLFWwindow* window) { _glfw.os4.disabledCursorWindow = window; } // Exit disabled cursor mode for the specified window // static void enableCursor(_GLFWwindow* window) { _glfw.os4.disabledCursorWindow = NULL; } // Updates the cursor image according to its cursor mode // static void updateCursorImage(_GLFWwindow* window, _GLFWcursor* cursor) { if (!window) return; if (cursor && cursor->os4.handle) { if (cursor->os4.handle != window->cursor->os4.currentHandle) { printf("handle: %p\n", window->cursor->os4.handle); IIntuition->SetWindowPointer( window->os4.handle, WA_Pointer, window->cursor->os4.handle, TAG_DONE); window->cursor->os4.currentHandle = cursor->os4.handle; } } else { if (cursor != NULL) { IIntuition->SetWindowPointer( window->os4.handle, WA_PointerType, cursor->os4.id, TAG_DONE); } else { IIntuition->SetWindowPointer( window->os4.handle, WA_PointerType, POINTERTYPE_NORMAL, TAG_DONE); } } } static int createNativeWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig, int windowType) { window->autoIconify = GLFW_FALSE; if (window->monitor) { GLFW_DisplayModeData *data = (GLFW_DisplayModeData *) window->monitor->userPointer; IIntuition->OpenScreenTags(NULL, SA_Width, window->monitor->currentMode.width, SA_Height, window->monitor->currentMode.height, SA_Depth, data->depth, SA_DisplayID, data->modeid, SA_Quiet, TRUE, SA_Title, wndconfig->title, SA_ShowTitle, FALSE, SA_LikeWorkbench, TRUE, SA_Compositing, FALSE, TAG_DONE); dprintf("fitToMonitor\n"); fitToMonitor(window); window->os4.fullscreen = GLFW_TRUE; } else { int x = 0, y = 0; if (_glfw.os4.publicScreen) { x = (_glfw.os4.publicScreen->Width - wndconfig->width) / 2; y = (_glfw.os4.publicScreen->Height - wndconfig->height) / 2; } window->os4.fullscreen = GLFW_FALSE; window->os4.xpos = x; window->os4.ypos = y; window->os4.width = wndconfig->width; window->os4.height = wndconfig->height; } window->os4.visible = wndconfig->visible; window->os4.decorated = wndconfig->decorated; window->os4.maximized = wndconfig->maximized; window->os4.floating = wndconfig->floating; if (fbconfig != NULL) window->os4.transparent = fbconfig->transparent; else window->os4.transparent = 0; window->os4.opacity = 1.f; window->os4.windowType = windowType; uint32_t windowFlags = OS4_GetWindowFlags(window, window->os4.fullscreen); uint32 IDCMPFlags = OS4_GetIDCMPFlags(window, window->os4.fullscreen); struct Screen *screen = OS4_GetScreenForWindow(window); OS4_BackFillHook.h_Data = IGraphics; // Smuggle interface ptr for the hook struct IBox box; OS4_DefineWindowBox(window, wndconfig, screen, window->os4.fullscreen, &box); window->os4.handle = IIntuition->OpenWindowTags(NULL, WA_PubScreen, screen, WA_Left, box.Left, WA_Top, box.Top, WA_InnerWidth, box.Width, WA_InnerHeight, box.Height, WA_Title, window->os4.fullscreen ? NULL: wndconfig->title, WA_ScreenTitle, wndconfig->title, WA_MaxWidth, _glfw.os4.publicScreen->Width, WA_MaxHeight, _glfw.os4.publicScreen->Height, WA_Flags, windowFlags, WA_Activate, TRUE, WA_IDCMP, IDCMPFlags, WA_Hidden, !wndconfig->visible, WA_UserPort, _glfw.os4.userPort, WA_BackFill, &OS4_BackFillHook, TAG_DONE); /* If we have a valid handle return GLFW_TRUE */ if (window->os4.handle) { window->os4.title = _glfw_strdup(wndconfig->title); window->maxwidth = _glfw.os4.publicScreen->Width; window->maxheight = _glfw.os4.publicScreen->Height; _glfwGetWindowPosOS4(window, &window->os4.xpos, &window->os4.ypos); _glfwGetWindowSizeOS4(window, &window->os4.width, &window->os4.height); window->os4.oldxpos = window->os4.xpos; window->os4.oldypos = window->os4.ypos; if (wndconfig->decorated && wndconfig->width > 99 && wndconfig->height ) { OS4_CreateIconifyGadget(window); } window->os4.appWin = IWorkbench->AddAppWindow(0, (ULONG) window, window->os4.handle, _glfw.os4.appMsgPort, TAG_DONE); #if 0 IWorkbench->AddAppWindowDropZone(window->os4.appWin, DROPZONE_Icon, 0, WBDZA_Box, &box, TAG_DONE); #endif _glfwWindowFocusedOS4(window); dprintf("Window Created\n"); return GLFW_TRUE; } else return GLFW_FALSE; } ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwCreateWindowOS4(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { dprintf("_glfwCreateWindowOS4 enter\n"); if (!createNativeWindow(window, wndconfig, fbconfig, ctxconfig->client)) { dprintf("Cannot create native window\n"); return GLFW_FALSE; } if (ctxconfig->client != GLFW_NO_API) { dprintf("Creating context\n"); if (!_glfwCreateContextGL(window, ctxconfig, fbconfig)) { dprintf("Error creating context\n"); return GLFW_FALSE; } if (!_glfwRefreshContextAttribs(window, ctxconfig)) return GLFW_FALSE; dprintf("Context created\n"); } _glfwShowWindowOS4(window); _glfwFocusWindowOS4(window); if (window->monitor) { acquireMonitor(window); } dprintf("_glfwCreateWindowOS4 exit\n"); return GLFW_TRUE; } void _glfwDestroyWindowOS4(_GLFWwindow* window) { if (window->os4.appWin) { IWorkbench->RemoveAppWindow(window->os4.appWin); window->os4.appWin = NULL; } if (window->os4.appIcon) { IWorkbench->RemoveAppIcon(window->os4.appIcon); window->os4.appIcon = NULL; } if (window->context.destroy) window->context.destroy(window); struct Screen *screen = window->os4.handle->WScreen; IIntuition->CloseWindow(window->os4.handle); OS4_CloseScreen(screen); if (window->os4.gadget) { IIntuition->DisposeObject((Object *)window->os4.gadget); window->os4.gadget = NULL; } if (window->os4.image) { IIntuition->DisposeObject((Object *)window->os4.image); window->os4.image = NULL; } if (window->monitor) releaseMonitor(window); if (_glfw.os4.focusedWindow == window) _glfw.os4.focusedWindow = NULL; } void _glfwSetWindowTitleOS4(_GLFWwindow* window, const char* title) { char* copy = _glfw_strdup(title); if (window->os4.title) _glfw_free(window->os4.title); window->os4.title = copy; IIntuition->SetWindowTitles(window->os4.handle, copy, copy); } void _glfwSetWindowIconOS4(_GLFWwindow* window, int count, const GLFWimage* images) { // We don't have window's icon } void _glfwSetWindowMonitorOS4(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate) { if (monitor && window->monitor == monitor) { _glfwSetWindowPosOS4(window, xpos, ypos); _glfwSetWindowSizeOS4(window, width, height); return; } if (window->monitor) releaseMonitor(window); _glfwInputWindowMonitor(window, monitor); if (window->monitor) { window->os4.visible = GLFW_TRUE; acquireMonitor(window); fitToMonitor(window); } else { _glfwSetWindowPosOS4(window, xpos, ypos); _glfwSetWindowSizeOS4(window, width, height); } } void _glfwGetWindowPosOS4(_GLFWwindow* window, int* xpos, int* ypos) { if (xpos) *xpos = window->os4.xpos; if (ypos) *ypos = window->os4.ypos; } void _glfwSetWindowPosOS4(_GLFWwindow* window, int xpos, int ypos) { if (window->monitor) return; if (window->os4.xpos != xpos || window->os4.ypos != ypos) { window->os4.oldxpos = window->os4.xpos; window->os4.oldypos = window->os4.ypos; window->os4.xpos = xpos; window->os4.ypos = ypos; _glfwInputWindowPos(window, xpos, ypos); IIntuition->SetWindowAttrs(window->os4.handle, WA_Left, xpos, WA_Top, ypos, TAG_DONE); } } void _glfwGetWindowSizeOS4(_GLFWwindow* window, int* width, int* height) { if (width) *width = window->os4.width; if (height) *height = window->os4.height; } void _glfwSetWindowSizeOS4(_GLFWwindow* window, int width, int height) { if (window->monitor) return; if (window->os4.width != width || window->os4.height != height) { window->os4.width = width; window->os4.height = height; _glfwInputWindowSize(window, width, height); _glfwInputFramebufferSize(window, width, height); IIntuition->SetWindowAttrs(window->os4.handle, WA_Width, width, WA_Height, height, TAG_DONE); } } void _glfwSetWindowSizeLimitsOS4(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { int width = window->os4.width; int height = window->os4.height; applySizeLimits(window, &width, &height); _glfwSetWindowSizeOS4(window, width, height); } void _glfwSetWindowAspectRatioOS4(_GLFWwindow* window, int n, int d) { int width = window->os4.width; int height = window->os4.height; applySizeLimits(window, &width, &height); _glfwSetWindowSizeOS4(window, width, height); } void _glfwGetFramebufferSizeOS4(_GLFWwindow* window, int* width, int* height) { //printf("window->os4.width = %d - window->os4.height = %d\n", window->os4.width, window->os4.height); if (width) *width = window->os4.width; if (height) *height = window->os4.height; } void _glfwGetWindowFrameSizeOS4(_GLFWwindow* window, int* left, int* top, int* right, int* bottom) { if (window->os4.decorated && !window->monitor) { if (left) *left = 1; if (top) *top = 10; if (right) *right = 1; if (bottom) *bottom = 1; } else { if (left) *left = 0; if (top) *top = 0; if (right) *right = 0; if (bottom) *bottom = 0; } } void _glfwGetWindowContentScaleOS4(_GLFWwindow* window, float* xscale, float* yscale) { if (xscale) *xscale = 1.f; if (yscale) *yscale = 1.f; } void _glfwIconifyWindowOS4(_GLFWwindow* window) { printf("_glfwIconifyWindowOS4\n"); if (_glfw.os4.focusedWindow == window) { printf("_glfwIconifyWindowOS4 1\n"); _glfw.os4.focusedWindow = NULL; _glfwInputWindowFocus(window, GLFW_FALSE); } if (!window->os4.iconified) { OS4_IconifyWindow(window); printf("_glfwIconifyWindowOS4 2\n"); window->os4.iconified = GLFW_TRUE; _glfwInputWindowIconify(window, GLFW_TRUE); if (window->monitor) releaseMonitor(window); } } void _glfwRestoreWindowOS4(_GLFWwindow* window) { if (window->os4.iconified) { OS4_UniconifyWindow(window); window->os4.iconified = GLFW_FALSE; _glfwInputWindowIconify(window, GLFW_FALSE); if (window->monitor) acquireMonitor(window); } else if (window->os4.maximized) { OS4_ResizeWindow(window, window->os4.oldwidth, window->os4.oldheight, window->os4.oldxpos, window->os4.oldypos); window->os4.maximized = GLFW_FALSE; _glfwInputWindowMaximize(window, GLFW_FALSE); } } void _glfwMaximizeWindowOS4(_GLFWwindow* window) { if (!window->os4.maximized) { window->os4.oldxpos = window->os4.xpos; window->os4.oldypos = window->os4.ypos; window->os4.oldwidth = window->os4.width; window->os4.oldheight = window->os4.height; printf("%d %d %d %d\n", window->os4.oldwidth, window->os4.oldheight, window->os4.oldxpos, window->os4.oldypos); OS4_ResizeWindow(window, window->maxwidth, window->maxheight, 0, 0); window->os4.maximized = GLFW_TRUE; _glfwInputWindowMaximize(window, GLFW_TRUE); } } int _glfwWindowMaximizedOS4(_GLFWwindow* window) { return window->os4.maximized; } int _glfwWindowHoveredOS4(_GLFWwindow* window) { return window->os4.lastCursorPosX >= window->os4.xpos && window->os4.lastCursorPosY >= window->os4.ypos && window->os4.lastCursorPosX <= window->os4.xpos + window->os4.width - 1 && window->os4.lastCursorPosY <= window->os4.ypos + window->os4.height - 1; } int _glfwFramebufferTransparentOS4(_GLFWwindow* window) { return window->os4.transparent; } void _glfwSetWindowResizableOS4(_GLFWwindow* window, GLFWbool enabled) { window->os4.resizable = enabled; } void _glfwSetWindowDecoratedOS4(_GLFWwindow* window, GLFWbool enabled) { window->os4.decorated = enabled; } void _glfwSetWindowFloatingOS4(_GLFWwindow* window, GLFWbool enabled) { window->os4.floating = enabled; } void _glfwSetWindowMousePassthroughOS4(_GLFWwindow* window, GLFWbool enabled) { } float _glfwGetWindowOpacityOS4(_GLFWwindow* window) { return window->os4.opacity; } void _glfwSetWindowOpacityOS4(_GLFWwindow* window, float opacity) { window->os4.opacity = opacity; int iOpacity = (int) (opacity * 255); if (iOpacity < 30) { iOpacity = 30; window->os4.opacity = (float) 0.11; } IIntuition->SetWindowAttrs(window->os4.handle, WA_Opaqueness, iOpacity, TAG_DONE); } void _glfwSetRawMouseMotionOS4(_GLFWwindow *window, GLFWbool enabled) { } GLFWbool _glfwRawMouseMotionSupportedOS4(void) { return GLFW_TRUE; } void _glfwShowWindowOS4(_GLFWwindow* window) { window->os4.visible = GLFW_TRUE; IIntuition->ShowWindow(window->os4.handle, NULL); } void _glfwRequestWindowAttentionOS4(_GLFWwindow* window) { } void _glfwHideWindowOS4(_GLFWwindow* window) { if (_glfw.os4.focusedWindow == window) { _glfw.os4.focusedWindow = NULL; _glfwInputWindowFocus(window, GLFW_FALSE); } window->os4.visible = GLFW_FALSE; IIntuition->HideWindow(window->os4.handle); } void _glfwFocusWindowOS4(_GLFWwindow* window) { _GLFWwindow* previous; if (_glfw.os4.focusedWindow == window) return; if (!window->os4.visible) return; previous = _glfw.os4.focusedWindow; _glfw.os4.focusedWindow = window; if (previous) { _glfwInputWindowFocus(previous, GLFW_FALSE); if (!previous->monitor && previous->autoIconify) _glfwIconifyWindowOS4(previous); } _glfwInputWindowFocus(window, GLFW_TRUE); } int _glfwWindowFocusedOS4(_GLFWwindow* window) { return _glfw.os4.focusedWindow == window; } int _glfwWindowIconifiedOS4(_GLFWwindow* window) { return window->os4.iconified; } int _glfwWindowVisibleOS4(_GLFWwindow* window) { return window->os4.visible; } void _glfwPollEventsOS4(void) { struct IntuiMessage *imsg; struct MyIntuiMessage msg; memset(&msg, 0, sizeof(struct MyIntuiMessage)); while ((imsg = (struct IntuiMessage *)IExec->GetMsg(_glfw.os4.userPort))) { OS4_CopyIdcmpMessage(imsg, &msg); _GLFWwindow* window = OS4_FindWindow(imsg->IDCMPWindow); IExec->ReplyMsg((struct Message *) imsg); switch (msg.Class) { case IDCMP_MOUSEMOVE: window->os4.lastCursorPosX = msg.WindowMouseX; window->os4.lastCursorPosY = msg.WindowMouseY; _glfwInputCursorPos(window, msg.WindowMouseX, msg.WindowMouseY); break; case IDCMP_RAWKEY: uint8_t rawkey = msg.Code & 0x7F; dprintf("RAWKEY = 0x%x\n", rawkey); int key = _glfw.os4.keycodes[rawkey]; int mods = OS4_TranslateState(msg.Qualifier); const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); if (imsg->Code < 0x80) { char text[5] ={0}; const uint32 unicode = OS4_TranslateUnicode(msg.Code, msg.Qualifier); if (unicode) { UCS4ToUTF8(unicode, text); _glfwInputKey(window, key, rawkey, GLFW_PRESS, mods); for (int i = 0; i < 4; i++) { if (text[0] != '\0') _glfwInputChar(window, text[i], mods, plain); } } else { text[0] = OS4_TranslateUnicode(msg.Code, msg.Qualifier); text[1] = '\0'; _glfwInputKey(window, key, rawkey, GLFW_PRESS, mods); if (text[0] && text[0] < 0x80) _glfwInputChar(window, text[0], mods, plain); } } else { _glfwInputKey(window, key, rawkey, GLFW_RELEASE, mods); } break; case IDCMP_MOUSEBUTTONS: int button = OS4_GetButton(imsg->Code); int state = OS4_GetButtonState(imsg->Code); int bmods = OS4_TranslateState(msg.Qualifier); _glfwInputMouseClick(window, button, state, bmods); break; case IDCMP_EXTENDEDMOUSE: struct IntuiWheelData *data = (struct IntuiWheelData *)msg.Gadget; if (data->WheelY < 0) { _glfwInputScroll(window, 0.0, 1.0); } else if (data->WheelY > 0) { _glfwInputScroll(window, 0.0, -1.0); } if (data->WheelX < 0) { _glfwInputScroll(window, 1.0, 0.0); } else if (data->WheelX > 0) { _glfwInputScroll(window, -1.0, 0.0); } break; case IDCMP_NEWSIZE: if (window != NULL) { window->os4.width = msg.Width; window->os4.height = msg.Height; } _glfwInputWindowSize(window, msg.Width, msg.Height); //OS4_HandleResize(_this, &msg); break; case IDCMP_CHANGEWINDOW: if (window != NULL) { window->os4.xpos = imsg->IDCMPWindow->LeftEdge; window->os4.ypos = imsg->IDCMPWindow->TopEdge; } //dprintf("w: %d - h: %d - x =%d - y = %d\n", msg.Width, msg.Height, window->os4.xpos, window->os4.ypos); _glfwInputWindowPos(window, window->os4.xpos, window->os4.ypos); //OS4_HandleMove(_this, &msg); //OS4_HandleResize(_this, &msg); break; case IDCMP_ACTIVEWINDOW: if (window->cursorMode == GLFW_CURSOR_DISABLED) disableCursor(window); _glfwInputWindowFocus(window, GLFW_TRUE); //OS4_HandleActivation(_this, &msg, SDL_TRUE); break; case IDCMP_INACTIVEWINDOW: //OS4_HandleActivation(_this, &msg, SDL_FALSE); if (window->cursorMode == GLFW_CURSOR_DISABLED) enableCursor(window); if (!window->monitor && window->autoIconify) { OS4_IconifyWindow(window); } _glfwInputWindowFocus(window, GLFW_FALSE); break; case IDCMP_CLOSEWINDOW: if (window != NULL) { _glfwInputWindowCloseRequest(window); } break; case IDCMP_INTUITICKS: //OS4_HandleTicks(_this, &msg); break; case IDCMP_GADGETUP: OS4_IconifyWindow(window); break; default: dprintf("Unknown event received class %d, code %d\n", msg.Class, msg.Code); break; } } struct AppMessage *amsg; while ((amsg = (struct AppMessage *)IExec->GetMsg(_glfw.os4.appMsgPort))) { switch (amsg->am_Type) { case AMTYPE_APPWINDOW: OS4_HandleAppWindow(amsg); break; case AMTYPE_APPICON: OS4_HandleAppIcon(amsg); break; default: dprintf("Unknown AppMsg %d %p\n", amsg->am_Type, (APTR)amsg->am_UserData); break; } IExec->ReplyMsg((struct Message *) amsg); } } void _glfwWaitEventsOS4(void) { _glfwPollEventsOS4(); } void _glfwWaitEventsTimeoutOS4(double timeout) { _glfwPollEventsOS4(); } void _glfwPostEmptyEventOS4(void) { } void _glfwGetCursorPosOS4(_GLFWwindow* window, double* xpos, double* ypos) { if (xpos) *xpos = window->os4.lastCursorPosX; if (ypos) *ypos = window->os4.lastCursorPosY; } void _glfwSetCursorPosOS4(_GLFWwindow* window, double x, double y) { window->os4.lastCursorPosX = window->os4.xpos + (int) x; window->os4.lastCursorPosY = window->os4.ypos + (int) y; } void _glfwSetCursorModeOS4(_GLFWwindow* window, int mode) { if (mode == GLFW_CURSOR_DISABLED) { if (_glfwWindowFocusedOS4(window)) disableCursor(window); } else if (_glfw.os4.disabledCursorWindow == window) enableCursor(window); else updateCursorImage(window, NULL); } int _glfwCreateCursorOS4(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot) { if (image->width > 64 || image->height > 64) { dprintf("Invalid pointer size w:%d h:%d\n", image->width, image->height, xhot, yhot); } else { uint32_t *buffer = OS4_CopyImageData(image); /* We need to pass some compatibility parameters even though we are going to use just ARGB pointer */ cursor->os4.handle = IIntuition->NewObject( NULL, POINTERCLASS, POINTERA_BitMap, &fallbackPointerBitMap, POINTERA_XOffset, xhot, POINTERA_YOffset, yhot, POINTERA_WordWidth, 1, POINTERA_XResolution, POINTERXRESN_SCREENRES, POINTERA_YResolution, POINTERYRESN_SCREENRES, POINTERA_ImageData, buffer, POINTERA_Width, image->width, POINTERA_Height, image->height, TAG_DONE); if (cursor->os4.handle) { dprintf("cursor created\n"); cursor->os4.imageData = buffer; cursor->os4.id = -1; return GLFW_TRUE; } } dprintf("error creating cursor\n"); return GLFW_FALSE; } int _glfwCreateStandardCursorOS4(_GLFWcursor* cursor, int shape) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); if (window) { int id = OS4_MapCursorIdToNative(shape); cursor->os4.id = id; dprintf("_glfwCreateStandardCursorOS4 %02x %d\n", shape, id); return GLFW_TRUE; } return GLFW_FALSE; } void _glfwDestroyCursorOS4(_GLFWcursor* cursor) { if (cursor->os4.handle) { IIntuition->DisposeObject(cursor->os4.handle); if (cursor->os4.imageData) free(cursor->os4.imageData); cursor->os4.imageData = NULL; cursor->os4.handle = NULL; } } void _glfwSetCursorOS4(_GLFWwindow* window, _GLFWcursor* cursor) { if (cursor != window->os4.currentCursor) { dprintf("_glfwSetCursorOS4\n"); updateCursorImage(window, cursor); window->os4.currentCursor = cursor; } } void _glfwSetClipboardStringOS4(const char* string) { char* copy = _glfw_strdup(string); _glfw_free(_glfw.os4.clipboardString); _glfw.os4.clipboardString = copy; ITextClip->WriteClipVector(string, strlen(string)); } const char* _glfwGetClipboardStringOS4(void) { STRPTR from; ULONG size; LONG result = ITextClip->ReadClipVector(&from, &size); if (result) { if (size) { _glfw.os4.clipboardString = _glfw_calloc( ++size, 1 ); if (_glfw.os4.clipboardString) { strlcpy(_glfw.os4.clipboardString, from, size); } else { dprintf("Failed to allocate memory\n"); } } else { _glfw.os4.clipboardString = strdup(""); } ITextClip->DisposeClipVector(from); } return _glfw.os4.clipboardString; } const char* _glfwGetScancodeNameOS4(int scancode) { if (scancode < GLFW_KEY_SPACE || scancode > GLFW_KEY_LAST) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid OS4 scancode %i", scancode); return NULL; } return _glfw.os4.keynames[scancode]; } int _glfwGetKeyScancodeOS4(int key) { return _glfw.os4.scancodes[key]; } void _glfwGetRequiredInstanceExtensionsOS4(char** extensions) { } int _glfwGetPhysicalDevicePresentationSupportOS4(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { return GLFW_FALSE; } VkResult _glfwCreateWindowSurfaceOS4(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface) { // This seems like the most appropriate error to return here return VK_ERROR_EXTENSION_NOT_PRESENT; } EGLenum _glfwGetEGLPlatformOS4(EGLint** attribs) { if (_glfw.egl.ANGLE_platform_angle) { int type = 0; if (_glfw.egl.ANGLE_platform_angle_opengl) { if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL) type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE; else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGLES) type = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE; } if (type) { *attribs = _glfw_calloc(3, sizeof(EGLint)); (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE; (*attribs)[1] = type; (*attribs)[2] = EGL_NONE; return EGL_PLATFORM_ANGLE_ANGLE; } } return 0; } EGLNativeDisplayType _glfwGetEGLNativeDisplayOS4(void) { return EGL_DEFAULT_DISPLAY; } EGLNativeWindowType _glfwGetEGLNativeWindowOS4(_GLFWwindow* window) { if (_glfw.egl.platform) return &window->os4.handle; else return (EGLNativeWindowType) window->os4.handle; } /**********************************************************************************************/ /******************************************** PRIVATE METHODS *********************************/ /**********************************************************************************************/ static _GLFWwindow * OS4_FindWindow(struct Window * syswin) { _GLFWwindow *glfwWin; glfwWin = _glfw.windowListHead; while (glfwWin) { if (glfwWin->os4.handle == syswin) return glfwWin; glfwWin = glfwWin->next; } dprintf("No window found\n"); return NULL; } static void OS4_CopyIdcmpMessage(struct IntuiMessage * src, struct MyIntuiMessage * dst) { // Copy relevant fields. This makes it safer if the window goes away during // this loop (re-open due to keystroke) dst->Class = src->Class; dst->Code = src->Code; dst->Qualifier = src->Qualifier; dst->Gadget = (struct Gadget *) src->IAddress; dst->RelativeMouseX = src->MouseX; dst->RelativeMouseY = src->MouseY; dst->IDCMPWindow = src->IDCMPWindow; if (src->IDCMPWindow) { dst->WindowMouseX = src->IDCMPWindow->MouseX - src->IDCMPWindow->BorderLeft; dst->WindowMouseY = src->IDCMPWindow->MouseY - src->IDCMPWindow->BorderTop; dst->ScreenMouseX = src->IDCMPWindow->WScreen->MouseX; dst->ScreenMouseY = src->IDCMPWindow->WScreen->MouseY; dst->Width = src->IDCMPWindow->Width - src->IDCMPWindow->BorderLeft - src->IDCMPWindow->BorderRight; dst->Height = src->IDCMPWindow->Height - src->IDCMPWindow->BorderTop - src->IDCMPWindow->BorderBottom; } } static uint32_t* OS4_CopyImageData(const GLFWimage *surface) { const size_t bytesPerRow = surface->width * sizeof(uint32_t); uint32_t* buffer = malloc(bytesPerRow * surface->height); dprintf("Copying cursor data %d*%d from surface %p to buffer %p\n", surface->width, surface->height, surface, buffer); if (buffer) { uint8_t* source = surface->pixels; uint32_t* destination = buffer; int y; for (y = 0; y < surface->height; y++) { memcpy(destination, source, bytesPerRow); destination += surface->width; source += 4; } } else { dprintf("Failed to allocate memory\n"); } return buffer; } static int OS4_GetButtonState(uint16_t code) { return (code & IECODE_UP_PREFIX) ? GLFW_RELEASE : GLFW_PRESS; } static int OS4_GetButton(uint16_t code) { switch (code & ~IECODE_UP_PREFIX) { case IECODE_LBUTTON: return GLFW_MOUSE_BUTTON_LEFT; case IECODE_RBUTTON: return GLFW_MOUSE_BUTTON_RIGHT; case IECODE_MBUTTON: return GLFW_MOUSE_BUTTON_MIDDLE; default: return 0; } } static char OS4_TranslateUnicode(uint16_t code, uint32_t qualifier) { struct InputEvent ie; uint16_t res; char buffer[10]; ie.ie_Class = IECLASS_RAWKEY; ie.ie_SubClass = 0; ie.ie_Code = code & ~(IECODE_UP_PREFIX); ie.ie_Qualifier = qualifier; ie.ie_EventAddress = NULL; res = IKeymap->MapRawKey(&ie, buffer, sizeof(buffer), 0); if (res != 1) return 0; else return buffer[0]; } static int OS4_TranslateState(int state) { int mods = 0; if (state & IEQUALIFIER_LSHIFT || state & IEQUALIFIER_RSHIFT) mods |= GLFW_MOD_SHIFT; if (state & IEQUALIFIER_CONTROL) mods |= GLFW_MOD_CONTROL; if (state & IEQUALIFIER_LALT || state & IEQUALIFIER_RALT) mods |= GLFW_MOD_ALT; if (state & IEQUALIFIER_LCOMMAND || state & IEQUALIFIER_RCOMMAND) mods |= GLFW_MOD_SUPER; if (state & IEQUALIFIER_CAPSLOCK) mods |= GLFW_MOD_CAPS_LOCK; return mods; } static uint32_t OS4_GetWindowFlags(_GLFWwindow* window, GLFWbool fullscreen) { uint32_t windowFlags = WFLG_ACTIVATE | WFLG_REPORTMOUSE | WFLG_RMBTRAP | WFLG_SMART_REFRESH | WFLG_NOCAREREFRESH; if (fullscreen) { windowFlags |= WFLG_BORDERLESS | WFLG_BACKDROP; } else { windowFlags |= WFLG_NEWLOOKMENUS; if (!window->decorated) { windowFlags |= WFLG_BORDERLESS; } else { windowFlags |= WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET; if (window->resizable) { windowFlags |= WFLG_SIZEGADGET | WFLG_SIZEBBOTTOM; } } } return windowFlags; } static void OS4_SetWindowLimits(_GLFWwindow * window) { struct Window * syswin = window->os4.handle; const int minW = window->minwidth ? MAX(MIN_WINDOW_SIZE, window->minwidth) : MIN_WINDOW_SIZE; const int minH = window->minheight ? MAX(MIN_WINDOW_SIZE, window->minheight) : MIN_WINDOW_SIZE; const int maxW = window->maxwidth != GLFW_DONT_CARE ? window->maxwidth : GLFW_DONT_CARE; const int maxH = window->maxheight != GLFW_DONT_CARE ? window->maxheight : GLFW_DONT_CARE; dprintf("Window min size %d*%d, max size %d*%d\n", minW, minH, maxW, maxH); const int borderWidth = syswin->BorderLeft + syswin->BorderRight; const int borderHeight = syswin->BorderTop + syswin->BorderBottom; BOOL ret = IIntuition->WindowLimits(syswin, minW + borderWidth, minH + borderHeight, maxW != GLFW_DONT_CARE ? (maxW + borderWidth) : GLFW_DONT_CARE, maxH != GLFW_DONT_CARE ? (maxH + borderHeight) : GLFW_DONT_CARE); if (!ret) { dprintf("Setting window limits failed\n"); } } static void OS4_CreateIconifyGadget(_GLFWwindow * window) { struct DrawInfo *di = IIntuition->GetScreenDrawInfo(_glfw.os4.publicScreen); if (di) { window->os4.image = (struct Image *)IIntuition->NewObject(NULL, SYSICLASS, SYSIA_Which, ICONIFYIMAGE, SYSIA_DrawInfo, di, TAG_DONE); if (window->os4.image) { window->os4.gadget = (struct Gadget *)IIntuition->NewObject(NULL, BUTTONGCLASS, GA_Image, window->os4.image, GA_ID, GID_ICONIFY, GA_TopBorder, TRUE, GA_RelRight, TRUE, GA_Titlebar, TRUE, GA_RelVerify, TRUE, TAG_DONE); if (window->os4.gadget) { struct Window *syswin = window->os4.handle; IIntuition->AddGadget(syswin, window->os4.gadget, -1); } else { dprintf("Failed to create button class\n"); } } else { dprintf("Failed to create image class\n"); } IIntuition->FreeScreenDrawInfo(_glfw.os4.publicScreen, di); } else { dprintf("Failed to get screen draw info\n"); } } static struct DiskObject* OS4_GetDiskObject() { struct DiskObject *diskObject = NULL; if (_glfw.os4.appName) { BPTR oldDir = IDOS->SetCurrentDir(IDOS->GetProgramDir()); diskObject = IIcon->GetDiskObject(_glfw.os4.appName); IDOS->SetCurrentDir(oldDir); } if (!diskObject) { CONST_STRPTR fallbackIconName = "ENVARC:Sys/def_window"; dprintf("Falling back to '%s'\n", fallbackIconName); diskObject = IIcon->GetDiskObjectNew(fallbackIconName); } return diskObject; } void OS4_IconifyWindow(_GLFWwindow *window) { if (window->os4.iconified) { dprintf("Window '%s' is already iconified\n", window->os4.title); } else { struct DiskObject *diskObject = OS4_GetDiskObject(); if (diskObject) { diskObject->do_CurrentX = NO_ICON_POSITION; diskObject->do_CurrentY = NO_ICON_POSITION; window->os4.appIcon = IWorkbench->AddAppIcon( 0, (ULONG)window, _glfw.os4.appName, _glfw.os4.appMsgPort, 0, diskObject, TAG_DONE); if (!window->os4.appIcon) { dprintf("Failed to add AppIcon\n"); } else { dprintf("Iconifying '%s'\n", window->os4.title); IIntuition->HideWindow(window->os4.handle); window->os4.iconified = TRUE; //SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0); } IIcon->FreeDiskObject(diskObject); } else { dprintf("Failed to load icon\n"); } } } void OS4_UniconifyWindow(_GLFWwindow* window) { if (window->os4.iconified) { dprintf("Restoring '%s'\n", window->os4.title); if (window->os4.appIcon) { IWorkbench->RemoveAppIcon(window->os4.appIcon); window->os4.appIcon = NULL; } IIntuition->SetWindowAttrs(window->os4.handle, WA_Hidden, FALSE, WA_Activate, TRUE, TAG_DONE); window->os4.iconified = FALSE; } } static void OS4_HandleAppIcon(struct AppMessage * msg) { _GLFWwindow *window = (_GLFWwindow *)msg->am_UserData; dprintf("Window ptr = %p\n", window); OS4_UniconifyWindow(window); } static ULONG OS4_BackFill(const struct Hook *hook, struct RastPort *rastport, struct BackFillMessage *message) { struct Rectangle *rect = &message->Bounds; struct GraphicsIFace *igfx = hook->h_Data; struct RastPort bfRastport; igfx->InitRastPort(&bfRastport); bfRastport.BitMap = rastport->BitMap; igfx->RectFillColor(&bfRastport, rect->MinX, rect->MinY, rect->MaxX, rect->MaxY, 0xFF000000); return 0; } static char *UCS4ToUTF8(uint32_t ch, char *dst) { uint8_t *p = (uint8_t *)dst; if (ch <= 0x7F) { *p = (uint8_t)ch; ++dst; } else if (ch <= 0x7FF) { p[0] = 0xC0 | (uint8_t)((ch >> 6) & 0x1F); p[1] = 0x80 | (uint8_t)(ch & 0x3F); dst += 2; } else if (ch <= 0xFFFF) { p[0] = 0xE0 | (uint8_t)((ch >> 12) & 0x0F); p[1] = 0x80 | (uint8_t)((ch >> 6) & 0x3F); p[2] = 0x80 | (uint8_t)(ch & 0x3F); dst += 3; } else { p[0] = 0xF0 | (uint8_t)((ch >> 18) & 0x07); p[1] = 0x80 | (uint8_t)((ch >> 12) & 0x3F); p[2] = 0x80 | (uint8_t)((ch >> 6) & 0x3F); p[3] = 0x80 | (uint8_t)(ch & 0x3F); dst += 4; } return dst; }