From 81007a2debffebc97c230cd810fb1bf10760180f Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sun, 19 Sep 2021 13:28:58 +0300 Subject: Refactoring Window to split off MainWindow MainWindow represents (one of) the main windows of the app, while the basic Window will be a used for popups. Only MainWindow supports split view modes. --- src/app.c | 122 +++++------ src/ui/documentwidget.c | 2 +- src/ui/paint.c | 3 + src/ui/root.c | 10 +- src/ui/uploadwidget.c | 2 +- src/ui/util.c | 2 +- src/ui/widget.c | 4 +- src/ui/window.c | 557 +++++++++++++++++++++++++----------------------- src/ui/window.h | 135 ++++++++---- 9 files changed, 462 insertions(+), 375 deletions(-) (limited to 'src') diff --git a/src/app.c b/src/app.c index e06a32ce..91b3a06d 100644 --- a/src/app.c +++ b/src/app.c @@ -117,7 +117,7 @@ struct Impl_App { iGmCerts * certs; iVisited * visited; iBookmarks * bookmarks; - iWindow * window; + iMainWindow *window; iSortedArray tickers; /* per-frame callbacks, used for animations */ uint32_t lastTickerTime; uint32_t elapsedSinceLastTicker; @@ -188,7 +188,7 @@ static iString *serializePrefs_App_(const iApp *d) { /* On macOS, maximization should be applied at creation time or the window will take a moment to animate to its maximized size. */ #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) - if (snap_Window(d->window)) { + if (snap_MainWindow(d->window)) { if (~SDL_GetWindowFlags(d->window->win) & SDL_WINDOW_MINIMIZED) { /* Save the actual visible window position, too, because snapped windows may still be resized/moved without affecting normalRect. */ @@ -196,17 +196,17 @@ static iString *serializePrefs_App_(const iApp *d) { SDL_GetWindowSize(d->window->win, &w, &h); appendFormat_String( str, "~window.setrect snap:%d width:%d height:%d coord:%d %d\n", - snap_Window(d->window), w, h, x, y); + snap_MainWindow(d->window), w, h, x, y); } } #elif !defined (iPlatformApple) - if (snap_Window(d->window) == maximized_WindowSnap) { + if (snap_MainWindow(d->window) == maximized_WindowSnap) { appendFormat_String(str, "~window.maximize\n"); } #endif } appendFormat_String(str, "uilang id:%s\n", cstr_String(&d->prefs.uiLanguage)); - appendFormat_String(str, "uiscale arg:%f\n", uiScale_Window(d->window)); + appendFormat_String(str, "uiscale arg:%f\n", uiScale_Window(as_Window(d->window))); appendFormat_String(str, "prefs.dialogtab arg:%d\n", d->prefs.dialogTab); appendFormat_String(str, "font.set arg:%d\n", d->prefs.font); appendFormat_String(str, "font.user path:%s\n", cstr_String(&d->prefs.symbolFontPath)); @@ -414,8 +414,8 @@ static iBool loadState_App_(iApp *d) { const int splitMode = read32_File(f); const int keyRoot = read32_File(f); d->window->pendingSplitMode = splitMode; - setSplitMode_Window(d->window, splitMode | noEvents_WindowSplit); - d->window->keyRoot = d->window->roots[keyRoot]; + setSplitMode_MainWindow(d->window, splitMode | noEvents_WindowSplit); + d->window->base.keyRoot = d->window->base.roots[keyRoot]; } else if (!memcmp(magic, magicSidebar_App_, 4)) { const uint16_t bits = readU16_File(f); @@ -426,7 +426,7 @@ static iBool loadState_App_(iApp *d) { }; const uint8_t rootIndex = bits & 0xff; const uint8_t flags = bits >> 8; - iRoot *root = d->window->roots[rootIndex]; + iRoot *root = d->window->base.roots[rootIndex]; if (root) { iSidebarWidget *sidebar = findChild_Widget(root->widget, "sidebar"); iSidebarWidget *sidebar2 = findChild_Widget(root->widget, "sidebar2"); @@ -443,10 +443,10 @@ static iBool loadState_App_(iApp *d) { else if (!memcmp(magic, magicTabDocument_App_, 4)) { const int8_t flags = read8_File(f); int rootIndex = flags & rootIndex1_DocumentStateFlag ? 1 : 0; - if (rootIndex > numRoots_Window(d->window) - 1) { + if (rootIndex > numRoots_Window(as_Window(d->window)) - 1) { rootIndex = 0; } - setCurrent_Root(d->window->roots[rootIndex]); + setCurrent_Root(d->window->base.roots[rootIndex]); if (isFirstTab[rootIndex]) { isFirstTab[rootIndex] = iFalse; /* There is one pre-created tab in each root. */ @@ -469,7 +469,7 @@ static iBool loadState_App_(iApp *d) { } if (d->window->splitMode) { /* Update root placement. */ - resize_Window(d->window, -1, -1); + resize_MainWindow(d->window, -1, -1); } iForIndices(i, current) { postCommandf_Root(NULL, "tabs.switch page:%p", current[i]); @@ -483,7 +483,7 @@ static iBool loadState_App_(iApp *d) { static void saveState_App_(const iApp *d) { iUnused(d); trimCache_App(); - iWindow *win = d->window; + iMainWindow *win = d->window; /* UI state is saved in binary because it is quite complex (e.g., navigation history, cached content) and depends closely on the widget tree. The data is largely not reorderable and should not be modified @@ -495,11 +495,11 @@ static void saveState_App_(const iApp *d) { /* Begin with window state. */ { writeData_File(f, magicWindow_App_, 4); writeU32_File(f, win->splitMode); - writeU32_File(f, win->keyRoot == win->roots[0] ? 0 : 1); + writeU32_File(f, win->base.keyRoot == win->base.roots[0] ? 0 : 1); } /* State of UI elements. */ { - iForIndices(i, win->roots) { - const iRoot *root = win->roots[i]; + iForIndices(i, win->base.roots) { + const iRoot *root = win->base.roots[i]; if (root) { writeData_File(f, magicSidebar_App_, 4); const iSidebarWidget *sidebar = findChild_Widget(root->widget, "sidebar"); @@ -520,7 +520,7 @@ static void saveState_App_(const iApp *d) { const iWidget *widget = constAs_Widget(i.object); writeData_File(f, magicTabDocument_App_, 4); int8_t flags = (document_Root(widget->root) == i.object ? current_DocumentStateFlag : 0); - if (widget->root == win->roots[1]) { + if (widget->root == win->base.roots[1]) { flags |= rootIndex1_DocumentStateFlag; } write8_File(f, flags); @@ -801,7 +801,7 @@ static void init_App_(iApp *d, int argc, char **argv) { d->initialWindowRect.size.y = toInt_String(value_CommandLineArg(arg, 0)); } } - d->window = new_Window(d->initialWindowRect); + d->window = new_MainWindow(d->initialWindowRect); load_Visited(d->visited, dataDir_App_()); load_Bookmarks(d->bookmarks, dataDir_App_()); load_MimeHooks(d->mimehooks, dataDir_App_()); @@ -848,7 +848,7 @@ static void init_App_(iApp *d, int argc, char **argv) { fetchRemote_Bookmarks(d->bookmarks); if (deviceType_App() != desktop_AppDeviceType) { /* HACK: Force a resize so widgets update their state. */ - resize_Window(d->window, -1, -1); + resize_MainWindow(d->window, -1, -1); } } @@ -871,7 +871,7 @@ static void deinit_App(iApp *d) { delete_GmCerts(d->certs); save_MimeHooks(d->mimehooks); delete_MimeHooks(d->mimehooks); - delete_Window(d->window); + delete_MainWindow(d->window); d->window = NULL; deinit_CommandLine(&d->args); iRelease(d->launchCommands); @@ -1110,7 +1110,7 @@ void processEvents_App(enum iAppEventMode eventMode) { clearCache_App_(); break; case SDL_APP_WILLENTERFOREGROUND: - invalidate_Window(d->window); + invalidate_Window(as_Window(d->window)); break; case SDL_APP_DIDENTERFOREGROUND: gotEvents = iTrue; @@ -1125,17 +1125,17 @@ void processEvents_App(enum iAppEventMode eventMode) { #if defined (iPlatformAppleMobile) updateNowPlayingInfo_iOS(); #endif - setFreezeDraw_Window(d->window, iTrue); + setFreezeDraw_Window(as_Window(d), iTrue); savePrefs_App_(d); saveState_App_(d); break; case SDL_APP_TERMINATING: - setFreezeDraw_Window(d->window, iTrue); + setFreezeDraw_Window(as_Window(d), iTrue); savePrefs_App_(d); saveState_App_(d); break; case SDL_DROPFILE: { - iBool wasUsed = processEvent_Window(d->window, &ev); + iBool wasUsed = processEvent_MainWindow(d->window, &ev); if (!wasUsed) { iBool newTab = iFalse; if (elapsedSeconds_Time(&d->lastDropTime) < 0.1) { @@ -1177,10 +1177,10 @@ void processEvents_App(enum iAppEventMode eventMode) { #endif if (ev.type == SDL_USEREVENT && ev.user.code == arrange_UserEventCode) { printf("[App] rearrange\n"); - resize_Window(d->window, -1, -1); - iForIndices(i, d->window->roots) { - if (d->window->roots[i]) { - d->window->roots[i]->pendingArrange = iFalse; + resize_MainWindow(d->window, -1, -1); + iForIndices(i, d->window->base.roots) { + if (d->window->base.roots[i]) { + d->window->base.roots[i]->pendingArrange = iFalse; } } // if (ev.user.data2 == d->window->roots[0]) { @@ -1209,8 +1209,8 @@ void processEvents_App(enum iAppEventMode eventMode) { if (ev.wheel.which == 0) { /* Trackpad with precise scrolling w/inertia (points). */ setPerPixel_MouseWheelEvent(&ev.wheel, iTrue); - ev.wheel.x *= -d->window->pixelRatio; - ev.wheel.y *= d->window->pixelRatio; + ev.wheel.x *= -d->window->base.pixelRatio; + ev.wheel.y *= d->window->base.pixelRatio; /* Only scroll on one axis at a time. */ if (iAbs(ev.wheel.x) > iAbs(ev.wheel.y)) { ev.wheel.y = 0; @@ -1268,8 +1268,8 @@ void processEvents_App(enum iAppEventMode eventMode) { } } #endif - d->window->lastHover = d->window->hover; - iBool wasUsed = processEvent_Window(d->window, &ev); + d->window->base.lastHover = d->window->base.hover; + iBool wasUsed = processEvent_MainWindow(d->window, &ev); if (!wasUsed) { /* There may be a key bindings for this. */ wasUsed = processEvent_Keys(&ev); @@ -1289,8 +1289,8 @@ void processEvents_App(enum iAppEventMode eventMode) { handleCommand_MacOS(command_UserEvent(&ev)); #endif if (isMetricsChange_UserEvent(&ev)) { - iForIndices(i, d->window->roots) { - iRoot *root = d->window->roots[i]; + iForIndices(i, d->window->base.roots) { + iRoot *root = d->window->base.roots[i]; if (root) { arrange_Widget(root->widget); } @@ -1304,9 +1304,9 @@ void processEvents_App(enum iAppEventMode eventMode) { free(ev.user.data1); } /* Update when hover has changed. */ - if (d->window->lastHover != d->window->hover) { - refresh_Widget(d->window->lastHover); - refresh_Widget(d->window->hover); + if (d->window->base.lastHover != d->window->base.hover) { + refresh_Widget(d->window->base.lastHover); + refresh_Widget(d->window->base.hover); } break; } @@ -1362,15 +1362,16 @@ static int resizeWatcher_(void *user, SDL_Event *event) { dispatchEvent_Window(d->window, &u); } #endif - drawWhileResizing_Window(d->window, winev->data1, winev->data2); + drawWhileResizing_MainWindow(d->window, winev->data1, winev->data2); } return 0; } static int run_App_(iApp *d) { - iForIndices(i, d->window->roots) { - if (d->window->roots[i]) { - arrange_Widget(d->window->roots[i]->widget); + /* Initial arrangement. */ + iForIndices(i, d->window->base.roots) { + if (d->window->base.roots[i]) { + arrange_Widget(d->window->base.roots[i]->widget); } } d->isRunning = iTrue; @@ -1384,7 +1385,7 @@ static int run_App_(iApp *d) { runTickers_App_(d); refresh_App(); /* Change the widget tree while we are not iterating through it. */ - checkPendingSplit_Window(d->window); + checkPendingSplit_MainWindow(d->window); recycle_Garbage(); } SDL_DelEventWatch(resizeWatcher_, d); @@ -1393,8 +1394,8 @@ static int run_App_(iApp *d) { void refresh_App(void) { iApp *d = &app_; - iForIndices(i, d->window->roots) { - iRoot *root = d->window->roots[i]; + iForIndices(i, d->window->base.roots) { + iRoot *root = d->window->base.roots[i]; if (root) { destroyPending_Root(root); } @@ -1409,7 +1410,7 @@ void refresh_App(void) { } // iTime draw; // initCurrent_Time(&draw); - draw_Window(d->window); + draw_MainWindow(d->window); // printf("draw: %lld \u03bcs\n", (long long) (elapsedSeconds_Time(&draw) * 1000000)); // fflush(stdout); if (d->warmupFrames > 0) { @@ -1545,7 +1546,7 @@ void postCommandf_App(const char *command, ...) { } void rootOrder_App(iRoot *roots[2]) { - const iWindow *win = app_.window; + const iWindow *win = as_Window(app_.window); roots[0] = win->keyRoot; roots[1] = (roots[0] == win->roots[0] ? win->roots[1] : win->roots[0]); } @@ -1979,7 +1980,7 @@ const iString *searchQueryUrl_App(const iString *queryStringUnescaped) { iBool handleCommand_App(const char *cmd) { iApp *d = &app_; - const iBool isFrozen = !d->window || d->window->isDrawFrozen; + const iBool isFrozen = !d->window || d->window->base.isDrawFrozen; if (equal_Command(cmd, "config.error")) { makeSimpleMessage_Widget(uiTextCaution_ColorEscape "CONFIG ERROR", format_CStr("Error in config file: %s\n" @@ -2011,13 +2012,13 @@ iBool handleCommand_App(const char *cmd) { } else if (equal_Command(cmd, "ui.split")) { if (argLabel_Command(cmd, "swap")) { - swapRoots_Window(d->window); + swapRoots_MainWindow(d->window); return iTrue; } d->window->pendingSplitMode = (argLabel_Command(cmd, "axis") ? vertical_WindowSplit : 0) | (arg_Command(cmd) << 1); const char *url = suffixPtr_Command(cmd, "url"); - setCStr_String(get_Window()->pendingSplitUrl, url ? url : ""); + setCStr_String(d->window->pendingSplitUrl, url ? url : ""); postRefresh_App(); return iTrue; } @@ -2031,17 +2032,17 @@ iBool handleCommand_App(const char *cmd) { } else if (equal_Command(cmd, "window.maximize")) { if (!argLabel_Command(cmd, "toggle")) { - setSnap_Window(d->window, maximized_WindowSnap); + setSnap_MainWindow(d->window, maximized_WindowSnap); } else { - setSnap_Window(d->window, snap_Window(d->window) == maximized_WindowSnap ? 0 : + setSnap_MainWindow(d->window, snap_MainWindow(d->window) == maximized_WindowSnap ? 0 : maximized_WindowSnap); } return iTrue; } else if (equal_Command(cmd, "window.fullscreen")) { - const iBool wasFull = snap_Window(d->window) == fullscreen_WindowSnap; - setSnap_Window(d->window, wasFull ? 0 : fullscreen_WindowSnap); + const iBool wasFull = snap_MainWindow(d->window) == fullscreen_WindowSnap; + setSnap_MainWindow(d->window, wasFull ? 0 : fullscreen_WindowSnap); postCommandf_App("window.fullscreen.changed arg:%d", !wasFull); return iTrue; } @@ -2210,7 +2211,7 @@ iBool handleCommand_App(const char *cmd) { equal_Command(cmd, "prefs.mono.gopher.changed")) { const iBool isSet = (arg_Command(cmd) != 0); if (!isFrozen) { - setFreezeDraw_Window(d->window, iTrue); + setFreezeDraw_Window(as_Window(d->window), iTrue); } if (startsWith_CStr(cmd, "prefs.mono.gemini")) { d->prefs.monospaceGemini = isSet; @@ -2405,8 +2406,8 @@ iBool handleCommand_App(const char *cmd) { iRoot *root = get_Root(); iRoot *oldRoot = root; if (newTab & otherRoot_OpenTabFlag) { - root = otherRoot_Window(d->window, root); - setKeyRoot_Window(d->window, root); + root = otherRoot_Window(as_Window(d->window), root); + setKeyRoot_Window(as_Window(d->window), root); setCurrent_Root(root); /* need to change for widget creation */ } iDocumentWidget *doc = document_Command(cmd); @@ -2560,7 +2561,8 @@ iBool handleCommand_App(const char *cmd) { return iTrue; } else if (equal_Command(cmd, "keyroot.next")) { - if (setKeyRoot_Window(d->window, otherRoot_Window(d->window, d->window->keyRoot))) { + if (setKeyRoot_Window(as_Window(d->window), + otherRoot_Window(as_Window(d->window), d->window->base.keyRoot))) { setFocus_Widget(NULL); } return iTrue; @@ -2592,7 +2594,7 @@ iBool handleCommand_App(const char *cmd) { format_CStr("returnkey.set arg:%d", d->prefs.returnKey)); setToggle_Widget(findChild_Widget(dlg, "prefs.retainwindow"), d->prefs.retainWindowSize); setText_InputWidget(findChild_Widget(dlg, "prefs.uiscale"), - collectNewFormat_String("%g", uiScale_Window(d->window))); + collectNewFormat_String("%g", uiScale_Window(as_Window(d->window)))); setFlags_Widget(findChild_Widget(dlg, format_CStr("prefs.font.%d", d->prefs.font)), selected_WidgetFlag, iTrue); @@ -2749,7 +2751,7 @@ iBool handleCommand_App(const char *cmd) { /* Set of open tabs has changed. */ postCommand_App("document.openurls.changed"); if (deviceType_App() == phone_AppDeviceType) { - showToolbar_Root(d->window->roots[0], iTrue); + showToolbar_Root(d->window->base.roots[0], iTrue); } return iFalse; } @@ -2825,8 +2827,8 @@ iBool handleCommand_App(const char *cmd) { } else if (equal_Command(cmd, "ipc.signal")) { if (argLabel_Command(cmd, "raise")) { - if (d->window && d->window->win) { - SDL_RaiseWindow(d->window->win); + if (d->window && d->window->base.win) { + SDL_RaiseWindow(d->window->base.win); } } signal_Ipc(arg_Command(cmd)); diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 8ea695d5..ed9e41d6 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -934,7 +934,7 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { iString *text = collect_String(joinCStr_StringArray(title, " \u2014 ")); if (setWindow) { /* Longest version for the window title, and omit the icon. */ - setTitle_Window(get_Window(), text); + setTitle_MainWindow(get_MainWindow(), text); setWindow = iFalse; } const iChar siteIcon = siteIcon_GmDocument(d->doc); diff --git a/src/ui/paint.c b/src/ui/paint.c index a3ee32c6..5506f845 100644 --- a/src/ui/paint.c +++ b/src/ui/paint.c @@ -152,6 +152,9 @@ void drawSoftShadow_Paint(const iPaint *d, iRect inner, int thickness, int color addv_I2(&inner.pos, origin_Paint); SDL_Renderer *render = renderer_Paint_(d); SDL_Texture *shadow = get_Window()->borderShadow; + if (!shadow) { + return; + } const iInt2 size = size_SDLTexture(shadow); const iRect outer = expanded_Rect(inner, init1_I2(thickness)); const iColor clr = get_Color(color); diff --git a/src/ui/root.c b/src/ui/root.c index 6ea5f521..52a08eca 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -383,18 +383,18 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) { else if (equal_Command(cmd, "window.setrect")) { const int snap = argLabel_Command(cmd, "snap"); if (snap) { - iWindow *window = get_Window(); + iMainWindow *window = get_MainWindow(); iInt2 coord = coord_Command(cmd); iInt2 size = init_I2(argLabel_Command(cmd, "width"), argLabel_Command(cmd, "height")); - SDL_SetWindowPosition(window->win, coord.x, coord.y); - SDL_SetWindowSize(window->win, size.x, size.y); + SDL_SetWindowPosition(window->base.win, coord.x, coord.y); + SDL_SetWindowSize(window->base.win, size.x, size.y); window->place.snap = snap; return iTrue; } } else if (equal_Command(cmd, "window.restore")) { - setSnap_Window(get_Window(), none_WindowSnap); + setSnap_MainWindow(get_MainWindow(), none_WindowSnap); return iTrue; } else if (equal_Command(cmd, "window.minimize")) { @@ -1525,5 +1525,5 @@ iRect safeRect_Root(const iRoot *d) { } iInt2 visibleSize_Root(const iRoot *d) { - return addY_I2(size_Root(d), -get_Window()->keyboardHeight); + return addY_I2(size_Root(d), -get_MainWindow()->keyboardHeight); } diff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c index 72608851..ba7545fd 100644 --- a/src/ui/uploadwidget.c +++ b/src/ui/uploadwidget.c @@ -97,7 +97,7 @@ static void updateInputMaxHeight_UploadWidget_(iUploadWidget *d) { height_Widget(findChild_Widget(w, "dialogbuttons")) + 12 * gap_UI); const int avail = bottom_Rect(safeRect_Root(w->root)) - footerHeight - - get_Window()->keyboardHeight; + get_MainWindow()->keyboardHeight; setLineLimits_InputWidget(d->input, minLines_InputWidget(d->input), iMaxi(minLines_InputWidget(d->input), diff --git a/src/ui/util.c b/src/ui/util.c index 01939e66..721aed2d 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -1222,7 +1222,7 @@ static void updateValueInputWidth_(iWidget *dlg) { iMin(rootSize.x, iMaxi(iMaxi(100 * gap_UI, title->rect.size.x), prompt->rect.size.x)); } /* Adjust the maximum number of visible lines. */ - int footer = 6 * gap_UI + get_Window()->keyboardHeight; + int footer = 6 * gap_UI + get_MainWindow()->keyboardHeight; iWidget *buttons = findChild_Widget(dlg, "dialogbuttons"); if (buttons) { footer += height_Widget(buttons); diff --git a/src/ui/widget.c b/src/ui/widget.c index c1fb9e95..23c19315 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -1088,7 +1088,7 @@ void scrollInfo_Widget(const iWidget *d, iWidgetScrollInfo *info) { iRect bounds = boundsWithoutVisualOffset_Widget(d); const iRect winRect = adjusted_Rect(safeRect_Root(d->root), zero_I2(), - init_I2(0, -get_Window()->keyboardHeight)); + init_I2(0, -get_MainWindow()->keyboardHeight)); info->height = bounds.size.y; info->avail = height_Rect(winRect); if (info->avail >= info->height) { @@ -1109,7 +1109,7 @@ iBool scrollOverflow_Widget(iWidget *d, int delta) { iRect bounds = boundsWithoutVisualOffset_Widget(d); const iRect winRect = adjusted_Rect(safeRect_Root(d->root), zero_I2(), - init_I2(0, -get_Window()->keyboardHeight)); + init_I2(0, -get_MainWindow()->keyboardHeight)); const int yTop = top_Rect(winRect); const int yBottom = bottom_Rect(winRect); if (top_Rect(bounds) >= yTop && bottom_Rect(bounds) < yBottom) { diff --git a/src/ui/window.c b/src/ui/window.c index b8198636..92125d81 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -67,7 +67,7 @@ static float initialUiScale_ = 1.1f; static iBool isOpenGLRenderer_; -iDefineTypeConstructionArgs(Window, (iRect rect), rect) +iDefineTypeConstructionArgs(MainWindow, (iRect rect), rect) /* TODO: Define menus per platform. */ @@ -169,17 +169,17 @@ int numRoots_Window(const iWindow *d) { return num; } -static void windowSizeChanged_Window_(iWindow *d) { - const int numRoots = numRoots_Window(d); - const iInt2 rootSize = d->size; +static void windowSizeChanged_MainWindow_(iMainWindow *d) { + const int numRoots = numRoots_Window(as_Window(d)); + const iInt2 rootSize = d->base.size; const int weights[2] = { - d->roots[0] ? (d->splitMode & twoToOne_WindowSplit ? 2 : 1) : 0, - d->roots[1] ? (d->splitMode & oneToTwo_WindowSplit ? 2 : 1) : 0, + d->base.roots[0] ? (d->splitMode & twoToOne_WindowSplit ? 2 : 1) : 0, + d->base.roots[1] ? (d->splitMode & oneToTwo_WindowSplit ? 2 : 1) : 0, }; const int totalWeight = weights[0] + weights[1]; int w = 0; - iForIndices(i, d->roots) { - iRoot *root = d->roots[i]; + iForIndices(i, d->base.roots) { + iRoot *root = d->base.roots[i]; if (root) { iRect *rect = &root->widget->rect; /* Horizontal split frame. */ @@ -199,26 +199,26 @@ static void windowSizeChanged_Window_(iWindow *d) { } } -static void setupUserInterface_Window(iWindow *d) { +static void setupUserInterface_MainWindow(iMainWindow *d) { #if defined (iHaveNativeMenus) insertMacMenus_(); #endif /* One root is created by default. */ - d->roots[0] = new_Root(); - setCurrent_Root(d->roots[0]); - createUserInterface_Root(d->roots[0]); + d->base.roots[0] = new_Root(); + setCurrent_Root(d->base.roots[0]); + createUserInterface_Root(d->base.roots[0]); setCurrent_Root(NULL); /* One of the roots always has keyboard input focus. */ - d->keyRoot = d->roots[0]; + d->base.keyRoot = d->base.roots[0]; } -static void updateSize_Window_(iWindow *d, iBool notifyAlways) { - iInt2 *size = &d->size; +static void updateSize_MainWindow_(iMainWindow *d, iBool notifyAlways) { + iInt2 *size = &d->base.size; const iInt2 oldSize = *size; - SDL_GetRendererOutputSize(d->render, &size->x, &size->y); + SDL_GetRendererOutputSize(d->base.render, &size->x, &size->y); size->y -= d->keyboardHeight; if (notifyAlways || !isEqual_I2(oldSize, *size)) { - windowSizeChanged_Window_(d); + windowSizeChanged_MainWindow_(d); if (!isEqual_I2(*size, d->place.lastNotifiedSize)) { const iBool isHoriz = (d->place.lastNotifiedSize.x != size->x); const iBool isVert = (d->place.lastNotifiedSize.y != size->y); @@ -234,8 +234,8 @@ static void updateSize_Window_(iWindow *d, iBool notifyAlways) { } } -void drawWhileResizing_Window(iWindow *d, int w, int h) { - draw_Window(d); +void drawWhileResizing_MainWindow(iMainWindow *d, int w, int h) { + draw_MainWindow(d); } static float pixelRatio_Window_(const iWindow *d) { @@ -308,7 +308,7 @@ static iRoot *rootAt_Window_(const iWindow *d, iInt2 coord) { } #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) -static SDL_HitTestResult hitTest_Window_(SDL_Window *win, const SDL_Point *pos, void *data) { +static SDL_HitTestResult hitTest_MainWindow_(SDL_Window *win, const SDL_Point *pos, void *data) { iWindow *d = data; iAssert(d->win == win); if (SDL_GetWindowFlags(d->win) & (SDL_WINDOW_MOUSE_CAPTURE | SDL_WINDOW_FULLSCREEN_DESKTOP)) { @@ -361,19 +361,22 @@ SDL_HitTestResult hitTest_Window(const iWindow *d, iInt2 pos) { #endif iBool create_Window_(iWindow *d, iRect rect, uint32_t flags) { - flags |= SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN; + flags |= SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN; + if (d->type == main_WindowType) { + flags |= SDL_WINDOW_RESIZABLE; #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) - if (prefs_App()->customFrame) { - /* We are drawing a custom frame so hide the default one. */ - flags |= SDL_WINDOW_BORDERLESS; - } + if (prefs_App()->customFrame) { + /* We are drawing a custom frame so hide the default one. */ + flags |= SDL_WINDOW_BORDERLESS; + } #endif + } if (SDL_CreateWindowAndRenderer( width_Rect(rect), height_Rect(rect), flags, &d->win, &d->render)) { return iFalse; } #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) - if (prefs_App()->customFrame) { + if (type_Window(d) == main_WindowType && prefs_App()->customFrame) { /* Register a handler for window hit testing (drag, resize). */ SDL_SetWindowHitTest(d->win, hitTest_Window_, d); SDL_SetWindowResizable(d->win, SDL_TRUE); @@ -397,40 +400,28 @@ static SDL_Surface *loadImage_(const iBlock *data, int resized) { pixels, w, h, 8 * num, w * num, SDL_PIXELFORMAT_RGBA32); } -void init_Window(iWindow *d, iRect rect) { - theWindow_ = d; - d->win = NULL; - d->size = zero_I2(); /* will be updated below */ - iZap(d->roots); - d->splitMode = d->pendingSplitMode = 0; - d->pendingSplitUrl = new_String(); - d->hover = NULL; - d->lastHover = NULL; - d->mouseGrab = NULL; - d->focus = NULL; - iZap(d->cursors); - d->place.initialPos = rect.pos; - d->place.normalRect = rect; - d->place.lastNotifiedSize = zero_I2(); - d->place.snap = 0; +void init_Window(iWindow *d, enum iWindowType type, iRect rect, uint32_t flags) { + d->type = type; + d->win = NULL; + d->size = zero_I2(); /* will be updated below */ + d->hover = NULL; + d->lastHover = NULL; + d->mouseGrab = NULL; + d->focus = NULL; d->pendingCursor = NULL; - d->isDrawFrozen = iTrue; - d->isExposed = iFalse; - d->isMinimized = iFalse; + d->isDrawFrozen = iTrue; + d->isExposed = iFalse; + d->isMinimized = iFalse; d->isInvalidated = iFalse; /* set when posting event, to avoid repeated events */ - d->isMouseInside = iTrue; - d->ignoreClick = iFalse; + d->isMouseInside = iTrue; + d->ignoreClick = iFalse; d->focusGainedAt = 0; - d->keyboardHeight = 0; - uint32_t flags = 0; -#if defined (iPlatformAppleDesktop) - SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl"); -#elif defined (iPlatformAppleMobile) - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal"); -#else - flags |= SDL_WINDOW_OPENGL; -#endif - SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"); + d->presentTime = 0.0; + d->frameTime = SDL_GetTicks(); + d->keyRoot = NULL; + d->borderShadow = NULL; + iZap(d->roots); + iZap(d->cursors); /* First try SDL's default renderer that should be the best option. */ if (forceSoftwareRender_App() || !create_Window_(d, rect, flags)) { /* No luck, maybe software only? This should always work as long as there is a display. */ @@ -443,40 +434,74 @@ void init_Window(iWindow *d, iRect rect) { if (left_Rect(rect) >= 0 || top_Rect(rect) >= 0) { SDL_SetWindowPosition(d->win, left_Rect(rect), top_Rect(rect)); } -#if defined (iPlatformMobile) + SDL_GetRendererOutputSize(d->render, &d->size.x, &d->size.y); + drawBlank_Window_(d); + d->pixelRatio = pixelRatio_Window_(d); /* point/pixel conversion */ + d->displayScale = displayScale_Window_(d); + d->uiScale = initialUiScale_; + /* TODO: Ratios, scales, and metrics must be window-specific, not global. */ + setScale_Metrics(d->pixelRatio * d->displayScale * d->uiScale); +} + +void deinit_Window(iWindow *d) { + SDL_DestroyRenderer(d->render); + SDL_DestroyWindow(d->win); + iForIndices(i, d->cursors) { + if (d->cursors[i]) { + SDL_FreeCursor(d->cursors[i]); + } + } +} + +void init_MainWindow(iMainWindow *d, iRect rect) { + theWindow_ = &d->base; + uint32_t flags = 0; +#if defined (iPlatformAppleDesktop) + SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl"); +#elif defined (iPlatformAppleMobile) + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal"); +#else + flags |= SDL_WINDOW_OPENGL; +#endif + SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"); + init_Window(&d->base, main_WindowType, rect, flags); + d->splitMode = d->pendingSplitMode = 0; + d->pendingSplitUrl = new_String(); + d->place.initialPos = rect.pos; + d->place.normalRect = rect; + d->place.lastNotifiedSize = zero_I2(); + d->place.snap = 0; + d->keyboardHeight = 0; +#if defined(iPlatformMobile) const iInt2 minSize = zero_I2(); /* windows aren't independently resizable */ #else const iInt2 minSize = init_I2(425, 325); #endif - SDL_SetWindowMinimumSize(d->win, minSize.x, minSize.y); - SDL_SetWindowTitle(d->win, "Lagrange"); + SDL_SetWindowMinimumSize(d->base.win, minSize.x, minSize.y); + SDL_SetWindowTitle(d->base.win, "Lagrange"); /* Some info. */ { SDL_RendererInfo info; - SDL_GetRendererInfo(d->render, &info); + SDL_GetRendererInfo(d->base.render, &info); isOpenGLRenderer_ = !iCmpStr(info.name, "opengl"); - printf("[window] renderer: %s%s\n", info.name, + printf("[window] renderer: %s%s\n", + info.name, info.flags & SDL_RENDERER_ACCELERATED ? " (accelerated)" : ""); -#if !defined (NDEBUG) +#if !defined(NDEBUG) printf("[window] max texture size: %d x %d\n", info.max_texture_width, info.max_texture_height); for (size_t i = 0; i < info.num_texture_formats; ++i) { - printf("[window] supported texture format: %s\n", SDL_GetPixelFormatName( - info.texture_formats[i])); + printf("[window] supported texture format: %s\n", + SDL_GetPixelFormatName(info.texture_formats[i])); } #endif } - drawBlank_Window_(d); - d->pixelRatio = pixelRatio_Window_(d); /* point/pixel conversion */ - d->displayScale = displayScale_Window_(d); - d->uiScale = initialUiScale_; - setScale_Metrics(d->pixelRatio * d->displayScale * d->uiScale); -#if defined (iPlatformMsys) - SDL_SetWindowMinimumSize(d->win, minSize.x * d->displayScale, minSize.y * d->displayScale); - useExecutableIconResource_SDLWindow(d->win); +#if defined(iPlatformMsys) + SDL_SetWindowMinimumSize(d->win, minSize.x * d->base.displayScale, minSize.y * d->base.displayScale); + useExecutableIconResource_SDLWindow(d->base.win); #endif #if defined (iPlatformLinux) - SDL_SetWindowMinimumSize(d->win, minSize.x * d->pixelRatio, minSize.y * d->pixelRatio); + SDL_SetWindowMinimumSize(d->win, minSize.x * d->base.pixelRatio, minSize.y * d->base.pixelRatio); /* Load the window icon. */ { SDL_Surface *surf = loadImage_(&imageLagrange64_Embedded, 0); SDL_SetWindowIcon(d->win, surf); @@ -487,18 +512,14 @@ void init_Window(iWindow *d, iRect rect) { #if defined (iPlatformAppleMobile) setupWindow_iOS(d); #endif - d->presentTime = 0.0; - d->frameTime = SDL_GetTicks(); - d->loadAnimTimer = 0; - init_Text(d->render); - SDL_GetRendererOutputSize(d->render, &d->size.x, &d->size.y); - setupUserInterface_Window(d); + init_Text(d->base.render); + SDL_GetRendererOutputSize(d->base.render, &d->base.size.x, &d->base.size.y); + setupUserInterface_MainWindow(d); postCommand_App("~bindings.changed"); /* update from bindings */ - //updateSize_Window_(d, iFalse); /* Load the border shadow texture. */ { SDL_Surface *surf = loadImage_(&imageShadow_Embedded, 0); - d->borderShadow = SDL_CreateTextureFromSurface(d->render, surf); - SDL_SetTextureBlendMode(d->borderShadow, SDL_BLENDMODE_BLEND); + d->base.borderShadow = SDL_CreateTextureFromSurface(d->base.render, surf); + SDL_SetTextureBlendMode(d->base.borderShadow, SDL_BLENDMODE_BLEND); free(surf->pixels); SDL_FreeSurface(surf); } @@ -508,7 +529,7 @@ void init_Window(iWindow *d, iRect rect) { if (prefs_App()->customFrame) { SDL_Surface *surf = loadImage_(&imageLagrange64_Embedded, appIconSize_Root()); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); - d->appIcon = SDL_CreateTextureFromSurface(d->render, surf); + d->appIcon = SDL_CreateTextureFromSurface(d->base.render, surf); free(surf->pixels); SDL_FreeSurface(surf); /* We need to observe non-client-area events. */ @@ -517,7 +538,7 @@ void init_Window(iWindow *d, iRect rect) { #endif } -void deinit_Window(iWindow *d) { +static void deinitRoots_Window_(iWindow *d) { iRecycle(); iForIndices(i, d->roots) { if (d->roots[i]) { @@ -525,19 +546,17 @@ void deinit_Window(iWindow *d) { deinit_Root(d->roots[i]); } } - if (theWindow_ == d) { + setCurrent_Root(NULL); +} + +void deinit_MainWindow(iMainWindow *d) { + deinitRoots_Window_(as_Window(d)); + if (theWindow_ == as_Window(d)) { theWindow_ = NULL; } - setCurrent_Root(NULL); delete_String(d->pendingSplitUrl); deinit_Text(); - SDL_DestroyRenderer(d->render); - SDL_DestroyWindow(d->win); - iForIndices(i, d->cursors) { - if (d->cursors[i]) { - SDL_FreeCursor(d->cursors[i]); - } - } + deinit_Window(&d->base); } SDL_Renderer *renderer_Window(const iWindow *d) { @@ -550,8 +569,8 @@ iInt2 maxTextureSize_Window(const iWindow *d) { return init_I2(info.max_texture_width, info.max_texture_height); } -iBool isFullscreen_Window(const iWindow *d) { - return snap_Window(d) == fullscreen_WindowSnap; +iBool isFullscreen_MainWindow(const iMainWindow *d) { + return snap_MainWindow(d) == fullscreen_WindowSnap; } iRoot *findRoot_Window(const iWindow *d, const iWidget *widget) { @@ -570,36 +589,41 @@ iRoot *otherRoot_Window(const iWindow *d, iRoot *root) { return root == d->roots[0] && d->roots[1] ? d->roots[1] : d->roots[0]; } -static void invalidate_Window_(iWindow *d, iBool forced) { - if (d && (!d->isInvalidated || forced)) { - d->isInvalidated = iTrue; +static void invalidate_MainWindow_(iMainWindow *d, iBool forced) { + if (d && (!d->base.isInvalidated || forced)) { + d->base.isInvalidated = iTrue; resetFonts_Text(); postCommand_App("theme.changed auto:1"); /* forces UI invalidation */ } } -void invalidate_Window(iWindow *d) { - invalidate_Window_(d, iFalse); +void invalidate_Window(iAnyWindow *d) { + if (type_Window(d) == main_WindowType) { + invalidate_MainWindow_(as_MainWindow(d), iFalse); + } + else { + iAssert(type_Window(d) == main_WindowType); + } } -static iBool isNormalPlacement_Window_(const iWindow *d) { - if (d->isDrawFrozen) return iFalse; +static iBool isNormalPlacement_MainWindow_(const iMainWindow *d) { + if (d->base.isDrawFrozen) return iFalse; #if defined (iPlatformApple) /* Maximized mode is not special on macOS. */ - if (snap_Window(d) == maximized_WindowSnap) { + if (snap_MainWindow(d) == maximized_WindowSnap) { return iTrue; } #endif - if (snap_Window(d)) return iFalse; - return !(SDL_GetWindowFlags(d->win) & SDL_WINDOW_MINIMIZED); + if (snap_MainWindow(d)) return iFalse; + return !(SDL_GetWindowFlags(d->base.win) & SDL_WINDOW_MINIMIZED); } -static iBool unsnap_Window_(iWindow *d, const iInt2 *newPos) { +static iBool unsnap_MainWindow_(iMainWindow *d, const iInt2 *newPos) { #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) if (!prefs_App()->customFrame) { return iFalse; } - const int snap = snap_Window(d); + const int snap = snap_MainWindow(d); if (snap == yMaximized_WindowSnap || snap == left_WindowSnap || snap == right_WindowSnap) { if (!newPos || (d->place.lastHit == SDL_HITTEST_RESIZE_LEFT || d->place.lastHit == SDL_HITTEST_RESIZE_RIGHT)) { @@ -607,21 +631,21 @@ static iBool unsnap_Window_(iWindow *d, const iInt2 *newPos) { } if (newPos) { SDL_Rect usable; - SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->win), &usable); + SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->base.win), &usable); /* Snap to top. */ if (snap == yMaximized_WindowSnap && iAbs(newPos->y - usable.y) < lineHeight_Text(uiContent_FontId) * 2) { - setSnap_Window(d, redo_WindowSnap | yMaximized_WindowSnap); + setSnap_MainWindow(d, redo_WindowSnap | yMaximized_WindowSnap); return iFalse; } } } if (snap && snap != fullscreen_WindowSnap) { - if (snap_Window(d) == yMaximized_WindowSnap && newPos) { + if (snap_MainWindow(d) == yMaximized_WindowSnap && newPos) { d->place.normalRect.pos = *newPos; } //printf("unsnap\n"); fflush(stdout); - setSnap_Window(d, none_WindowSnap); + setSnap_MainWindow(d, none_WindowSnap); return iTrue; } #endif @@ -652,109 +676,110 @@ static void checkPixelRatioChange_Window_(iWindow *d) { } } -static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) { +static iBool handleWindowEvent_MainWindow_(iMainWindow *d, const SDL_WindowEvent *ev) { switch (ev->event) { -#if defined (iPlatformDesktop) +#if defined(iPlatformDesktop) case SDL_WINDOWEVENT_EXPOSED: - if (!d->isExposed) { - drawBlank_Window_(d); /* avoid showing system-provided contents */ - d->isExposed = iTrue; + if (!d->base.isExposed) { + drawBlank_Window_(as_Window(d)); /* avoid showing system-provided contents */ + d->base.isExposed = iTrue; } /* Since we are manually controlling when to redraw the window, we are responsible - for ensuring that window contents get redrawn after expose events. Under certain - circumstances (e.g., under openbox), not doing this would mean that the window - is missing contents until other events trigger a refresh. */ + for ensuring that window contents get redrawn after expose events. Under certain + circumstances (e.g., under openbox), not doing this would mean that the window + is missing contents until other events trigger a refresh. */ postRefresh_App(); -#if defined (LAGRANGE_ENABLE_WINDOWPOS_FIX) +#if defined(LAGRANGE_ENABLE_WINDOWPOS_FIX) if (d->place.initialPos.x >= 0) { int bx, by; SDL_GetWindowBordersSize(d->win, &by, &bx, NULL, NULL); - SDL_SetWindowPosition(d->win, d->place.initialPos.x + bx, d->place.initialPos.y + by); + SDL_SetWindowPosition( + d->win, d->place.initialPos.x + bx, d->place.initialPos.y + by); d->place.initialPos = init1_I2(-1); } #endif return iFalse; case SDL_WINDOWEVENT_MOVED: { - if (d->isMinimized) { + if (d->base.isMinimized) { return iFalse; } - checkPixelRatioChange_Window_(d); + checkPixelRatioChange_Window_(as_Window(d)); const iInt2 newPos = init_I2(ev->data1, ev->data2); if (isEqual_I2(newPos, init1_I2(-32000))) { /* magic! */ /* Maybe minimized? Seems like a Windows constant of some kind. */ - d->isMinimized = iTrue; + d->base.isMinimized = iTrue; return iFalse; } -#if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) +#if defined(LAGRANGE_ENABLE_CUSTOM_FRAME) /* Set the snap position depending on where the mouse cursor is. */ if (prefs_App()->customFrame) { SDL_Rect usable; - iInt2 mouse = cursor_Win32(); /* SDL is unaware of the current cursor pos */ - SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->win), &usable); - const iBool isTop = iAbs(mouse.y - usable.y) < gap_UI * 20; + iInt2 mouse = cursor_Win32(); /* SDL is unaware of the current cursor pos */ + SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->base.win), &usable); + const iBool isTop = iAbs(mouse.y - usable.y) < gap_UI * 20; const iBool isBottom = iAbs(usable.y + usable.h - mouse.y) < gap_UI * 20; if (iAbs(mouse.x - usable.x) < gap_UI) { - setSnap_Window(d, - redo_WindowSnap | left_WindowSnap | - (isTop ? topBit_WindowSnap : 0) | - (isBottom ? bottomBit_WindowSnap : 0)); + setSnap_MainWindow(d, + redo_WindowSnap | left_WindowSnap | + (isTop ? topBit_WindowSnap : 0) | + (isBottom ? bottomBit_WindowSnap : 0)); return iTrue; } if (iAbs(mouse.x - usable.x - usable.w) < gap_UI) { - setSnap_Window(d, - redo_WindowSnap | right_WindowSnap | - (isTop ? topBit_WindowSnap : 0) | - (isBottom ? bottomBit_WindowSnap : 0)); + setSnap_MainWindow(d, + redo_WindowSnap | right_WindowSnap | + (isTop ? topBit_WindowSnap : 0) | + (isBottom ? bottomBit_WindowSnap : 0)); return iTrue; } if (iAbs(mouse.y - usable.y) < 2) { - setSnap_Window(d, - redo_WindowSnap | (d->place.lastHit == SDL_HITTEST_RESIZE_TOP - ? yMaximized_WindowSnap - : maximized_WindowSnap)); + setSnap_MainWindow(d, + redo_WindowSnap | (d->place.lastHit == SDL_HITTEST_RESIZE_TOP + ? yMaximized_WindowSnap + : maximized_WindowSnap)); return iTrue; } } #endif /* defined LAGRANGE_ENABLE_CUSTOM_FRAME */ - if (unsnap_Window_(d, &newPos)) { + if (unsnap_MainWindow_(d, &newPos)) { return iTrue; } - if (isNormalPlacement_Window_(d)) { + if (isNormalPlacement_MainWindow_(d)) { d->place.normalRect.pos = newPos; - //printf("normal rect set (move)\n"); fflush(stdout); + // printf("normal rect set (move)\n"); fflush(stdout); iInt2 border = zero_I2(); -#if !defined (iPlatformApple) +#if !defined(iPlatformApple) SDL_GetWindowBordersSize(d->win, &border.y, &border.x, NULL, NULL); #endif - d->place.normalRect.pos = max_I2(zero_I2(), sub_I2(d->place.normalRect.pos, border)); + d->place.normalRect.pos = + max_I2(zero_I2(), sub_I2(d->place.normalRect.pos, border)); } return iTrue; } case SDL_WINDOWEVENT_RESIZED: - if (d->isMinimized) { - //updateSize_Window_(d, iTrue); + if (d->base.isMinimized) { + // updateSize_Window_(d, iTrue); return iTrue; } - if (unsnap_Window_(d, NULL)) { + if (unsnap_MainWindow_(d, NULL)) { return iTrue; } - if (isNormalPlacement_Window_(d)) { + if (isNormalPlacement_MainWindow_(d)) { d->place.normalRect.size = init_I2(ev->data1, ev->data2); - //printf("normal rect set (resize)\n"); fflush(stdout); + // printf("normal rect set (resize)\n"); fflush(stdout); } - checkPixelRatioChange_Window_(d); - //updateSize_Window_(d, iTrue /* we were already redrawing during the resize */); + checkPixelRatioChange_Window_(as_Window(d)); postRefresh_App(); return iTrue; case SDL_WINDOWEVENT_RESTORED: case SDL_WINDOWEVENT_SHOWN: - updateSize_Window_(d, iTrue); - invalidate_Window_(d, iTrue); - d->isMinimized = iFalse; + updateSize_MainWindow_(d, iTrue); + invalidate_MainWindow_(d, iTrue); + d->base.isMinimized = iFalse; postRefresh_App(); return iTrue; case SDL_WINDOWEVENT_MINIMIZED: - d->isMinimized = iTrue; + d->base.isMinimized = iTrue; return iTrue; #else /* if defined (!iPlatformDesktop) */ case SDL_WINDOWEVENT_RESIZED: @@ -765,19 +790,19 @@ static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) { #endif case SDL_WINDOWEVENT_LEAVE: unhover_Widget(); - d->isMouseInside = iFalse; + d->base.isMouseInside = iFalse; postCommand_App("window.mouse.exited"); return iTrue; case SDL_WINDOWEVENT_ENTER: - d->isMouseInside = iTrue; + d->base.isMouseInside = iTrue; postCommand_App("window.mouse.entered"); return iTrue; case SDL_WINDOWEVENT_FOCUS_GAINED: - d->focusGainedAt = SDL_GetTicks(); + d->base.focusGainedAt = SDL_GetTicks(); setCapsLockDown_Keys(iFalse); postCommand_App("window.focus.gained"); - d->isExposed = iTrue; -#if !defined (iPlatformDesktop) + d->base.isExposed = iTrue; +#if !defined(iPlatformDesktop) /* Returned to foreground, may have lost buffered content. */ invalidate_Window_(d, iTrue); postCommand_App("window.unfreeze"); @@ -785,12 +810,12 @@ static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) { return iFalse; case SDL_WINDOWEVENT_FOCUS_LOST: postCommand_App("window.focus.lost"); -#if !defined (iPlatformDesktop) +#if !defined(iPlatformDesktop) setFreezeDraw_Window(d, iTrue); #endif return iFalse; case SDL_WINDOWEVENT_TAKE_FOCUS: - SDL_SetWindowInputFocus(d->win); + SDL_SetWindowInputFocus(d->base.win); postRefresh_App(); return iTrue; default: @@ -806,7 +831,8 @@ static void applyCursor_Window_(iWindow *d) { } } -iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { +iBool processEvent_MainWindow(iMainWindow *d, const SDL_Event *ev) { + iWindow *w = as_Window(d); switch (ev->type) { #if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) case SDL_SYSWMEVENT: { @@ -819,19 +845,19 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { } #endif case SDL_WINDOWEVENT: { - return handleWindowEvent_Window_(d, &ev->window); + return handleWindowEvent_MainWindow_(d, &ev->window); } case SDL_RENDER_TARGETS_RESET: case SDL_RENDER_DEVICE_RESET: { - invalidate_Window_(d, iTrue /* force full reset */); + invalidate_MainWindow_(d, iTrue /* force full reset */); break; } default: { SDL_Event event = *ev; if (event.type == SDL_USEREVENT && isCommand_UserEvent(ev, "window.unfreeze")) { - d->isDrawFrozen = iFalse; - if (SDL_GetWindowFlags(d->win) & SDL_WINDOW_HIDDEN) { - SDL_ShowWindow(d->win); + d->base.isDrawFrozen = iFalse; + if (SDL_GetWindowFlags(w->win) & SDL_WINDOW_HIDDEN) { + SDL_ShowWindow(w->win); } postRefresh_App(); postCommand_App("media.player.update"); /* in case a player needs updating */ @@ -840,35 +866,35 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { if (processEvent_Touch(&event)) { return iTrue; } - if (event.type == SDL_KEYDOWN && SDL_GetTicks() - d->focusGainedAt < 10) { + if (event.type == SDL_KEYDOWN && SDL_GetTicks() - d->base.focusGainedAt < 10) { /* Suspiciously close to when input focus was received. For example under openbox, closing xterm with Ctrl+D will cause the keydown event to "spill" over to us. As a workaround, ignore these events. */ return iTrue; /* won't go to bindings, either */ } - if (event.type == SDL_MOUSEBUTTONDOWN && d->ignoreClick) { - d->ignoreClick = iFalse; + if (event.type == SDL_MOUSEBUTTONDOWN && d->base.ignoreClick) { + d->base.ignoreClick = iFalse; return iTrue; } /* Map mouse pointer coordinate to our coordinate system. */ if (event.type == SDL_MOUSEMOTION) { - setCursor_Window(d, SDL_SYSTEM_CURSOR_ARROW); /* default cursor */ - const iInt2 pos = coord_Window(d, event.motion.x, event.motion.y); + setCursor_Window(w, SDL_SYSTEM_CURSOR_ARROW); /* default cursor */ + const iInt2 pos = coord_Window(w, event.motion.x, event.motion.y); event.motion.x = pos.x; event.motion.y = pos.y; } else if (event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEBUTTONDOWN) { - const iInt2 pos = coord_Window(d, event.button.x, event.button.y); + const iInt2 pos = coord_Window(w, event.button.x, event.button.y); event.button.x = pos.x; event.button.y = pos.y; if (event.type == SDL_MOUSEBUTTONDOWN) { /* Button clicks will change keyroot. */ - if (numRoots_Window(d) > 1) { + if (numRoots_Window(w) > 1) { const iInt2 click = init_I2(event.button.x, event.button.y); - iForIndices(i, d->roots) { - iRoot *root = d->roots[i]; - if (root != d->keyRoot && contains_Rect(rect_Root(root), click)) { - setKeyRoot_Window(d, root); + iForIndices(i, w->roots) { + iRoot *root = w->roots[i]; + if (root != w->keyRoot && contains_Rect(rect_Root(root), click)) { + setKeyRoot_Window(w, root); break; } } @@ -883,13 +909,13 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEBUTTONDOWN) { if (mouseGrab_Widget()) { iWidget *grabbed = mouseGrab_Widget(); - setCurrent_Root(findRoot_Window(d, grabbed)); + setCurrent_Root(findRoot_Window(w, grabbed)); wasUsed = dispatchEvent_Widget(grabbed, &event); } } /* Dispatch the event to the tree of widgets. */ if (!wasUsed) { - wasUsed = dispatchEvent_Window(d, &event); + wasUsed = dispatchEvent_Window(w, &event); } if (!wasUsed) { /* As a special case, clicking the middle mouse button can be used for pasting @@ -902,17 +928,17 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { paste.key.keysym.mod = KMOD_PRIMARY; paste.key.state = SDL_PRESSED; paste.key.timestamp = SDL_GetTicks(); - wasUsed = dispatchEvent_Window(d, &paste); + wasUsed = dispatchEvent_Window(w, &paste); } if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_RIGHT) { - if (postContextClick_Window(d, &event.button)) { + if (postContextClick_Window(w, &event.button)) { wasUsed = iTrue; } } } if (isMetricsChange_UserEvent(&event)) { - iForIndices(i, d->roots) { - updateMetrics_Root(d->roots[i]); + iForIndices(i, w->roots) { + updateMetrics_Root(w->roots[i]); } } if (isCommand_UserEvent(&event, "lang.changed")) { @@ -921,16 +947,16 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { removeMacMenus_(); insertMacMenus_(); #endif - invalidate_Window(d); - iForIndices(i, d->roots) { - if (d->roots[i]) { - updatePreferencesLayout_Widget(findChild_Widget(d->roots[i]->widget, "prefs")); - arrange_Widget(d->roots[i]->widget); + invalidate_Window(w); + iForIndices(i, w->roots) { + if (w->roots[i]) { + updatePreferencesLayout_Widget(findChild_Widget(w->roots[i]->widget, "prefs")); + arrange_Widget(w->roots[i]->widget); } } } if (event.type == SDL_MOUSEMOTION) { - applyCursor_Window_(d); + applyCursor_Window_(w); } return wasUsed; } @@ -1018,25 +1044,26 @@ iBool postContextClick_Window(iWindow *d, const SDL_MouseButtonEvent *ev) { return iFalse; } -void draw_Window(iWindow *d) { - if (d->isDrawFrozen) { +void draw_MainWindow(iMainWindow *d) { + iWindow *w = as_Window(d); + if (w->isDrawFrozen) { return; } /* Check if root needs resizing. */ { iInt2 renderSize; - SDL_GetRendererOutputSize(d->render, &renderSize.x, &renderSize.y); - if (!isEqual_I2(renderSize, d->size)) { - updateSize_Window_(d, iTrue); + SDL_GetRendererOutputSize(w->render, &renderSize.x, &renderSize.y); + if (!isEqual_I2(renderSize, w->size)) { + updateSize_MainWindow_(d, iTrue); processEvents_App(postedEventsOnly_AppEventMode); } } - const int winFlags = SDL_GetWindowFlags(d->win); + const int winFlags = SDL_GetWindowFlags(d->base.win); const iBool gotFocus = (winFlags & SDL_WINDOW_INPUT_FOCUS) != 0; iPaint p; init_Paint(&p); /* Clear the window. The clear color is visible as a border around the window when the custom frame is being used. */ { - setCurrent_Root(d->roots[0]); + setCurrent_Root(w->roots[0]); #if defined (iPlatformMobile) iColor back = get_Color(uiBackground_ColorId); if (deviceType_App() == phone_AppDeviceType) { @@ -1050,16 +1077,16 @@ void draw_Window(iWindow *d) { : uiSeparator_ColorId); #endif unsetClip_Paint(&p); /* update clip to full window */ - SDL_SetRenderDrawColor(d->render, back.r, back.g, back.b, 255); - SDL_RenderClear(d->render); + SDL_SetRenderDrawColor(w->render, back.r, back.g, back.b, 255); + SDL_RenderClear(w->render); } /* Draw widgets. */ - d->frameTime = SDL_GetTicks(); - if (isExposed_Window(d)) { - d->isInvalidated = iFalse; + w->frameTime = SDL_GetTicks(); + if (isExposed_Window(w)) { + w->isInvalidated = iFalse; extern int drawCount_; - iForIndices(i, d->roots) { - iRoot *root = d->roots[i]; + iForIndices(i, w->roots) { + iRoot *root = w->roots[i]; if (root) { setCurrent_Root(root); unsetClip_Paint(&p); /* update clip to current root */ @@ -1076,14 +1103,14 @@ void draw_Window(iWindow *d) { SDL_SetTextureColorMod(d->appIcon, iconColor.r, iconColor.g, iconColor.b); SDL_SetTextureAlphaMod(d->appIcon, gotFocus || !isLight ? 255 : 92); SDL_RenderCopy( - d->render, + w->render, d->appIcon, NULL, &(SDL_Rect){ left_Rect(rect) + gap_UI * 1.25f, mid.y - size / 2, size, size }); } #endif /* Root separator and keyboard focus indicator. */ - if (numRoots_Window(d) > 1){ + if (numRoots_Window(w) > 1){ const iRect bounds = bounds_Widget(root->widget); if (i == 1) { fillRect_Paint(&p, (iRect){ @@ -1091,7 +1118,7 @@ void draw_Window(iWindow *d) { init_I2(gap_UI / 4, height_Rect(bounds)) }, uiSeparator_ColorId); } - if (root == d->keyRoot) { + if (root == w->keyRoot) { const iBool isDark = isDark_ColorTheme(colorTheme_App()); fillRect_Paint(&p, (iRect){ topLeft_Rect(bounds), @@ -1104,7 +1131,7 @@ void draw_Window(iWindow *d) { } setCurrent_Root(NULL); #if !defined (NDEBUG) - draw_Text(defaultBold_FontId, safeRect_Root(d->roots[0]).pos, red_ColorId, "%d", drawCount_); + draw_Text(defaultBold_FontId, safeRect_Root(w->roots[0]).pos, red_ColorId, "%d", drawCount_); drawCount_ = 0; #endif } @@ -1116,21 +1143,21 @@ void draw_Window(iWindow *d) { SDL_RenderCopy(d->render, glyphCache_Text(), NULL, &rect); } #endif - SDL_RenderPresent(d->render); + SDL_RenderPresent(w->render); } -void resize_Window(iWindow *d, int w, int h) { +void resize_MainWindow(iMainWindow *d, int w, int h) { if (w > 0 && h > 0) { - SDL_SetWindowSize(d->win, w, h); - updateSize_Window_(d, iFalse); + SDL_SetWindowSize(d->base.win, w, h); + updateSize_MainWindow_(d, iFalse); } else { - updateSize_Window_(d, iTrue); /* notify always */ + updateSize_MainWindow_(d, iTrue); /* notify always */ } } -void setTitle_Window(iWindow *d, const iString *title) { - SDL_SetWindowTitle(d->win, cstr_String(title)); +void setTitle_MainWindow(iMainWindow *d, const iString *title) { + SDL_SetWindowTitle(d->base.win, cstr_String(title)); iLabelWidget *bar = findChild_Widget(get_Root()->widget, "winbar.title"); if (bar) { updateText_LabelWidget(bar, title); @@ -1204,11 +1231,15 @@ iWindow *get_Window(void) { return theWindow_; } +iMainWindow *get_MainWindow(void) { + return as_MainWindow(theWindow_); +} + iBool isOpenGLRenderer_Window(void) { return isOpenGLRenderer_; } -void setKeyboardHeight_Window(iWindow *d, int height) { +void setKeyboardHeight_MainWindow(iMainWindow *d, int height) { if (d->keyboardHeight != height) { d->keyboardHeight = height; postCommandf_App("keyboard.changed arg:%d", height); @@ -1216,47 +1247,49 @@ void setKeyboardHeight_Window(iWindow *d, int height) { } } -void checkPendingSplit_Window(iWindow *d) { +void checkPendingSplit_MainWindow(iMainWindow *d) { if (d->splitMode != d->pendingSplitMode) { - setSplitMode_Window(d, d->pendingSplitMode); + setSplitMode_MainWindow(d, d->pendingSplitMode); } } -void swapRoots_Window(iWindow *d) { - if (numRoots_Window(d) == 2) { - iSwap(iRoot *, d->roots[0], d->roots[1]); - updateSize_Window_(d, iTrue); +void swapRoots_MainWindow(iMainWindow *d) { + iWindow *w = as_Window(d); + if (numRoots_Window(w) == 2) { + iSwap(iRoot *, w->roots[0], w->roots[1]); + updateSize_MainWindow_(d, iTrue); } } -void setSplitMode_Window(iWindow *d, int splitFlags) { +void setSplitMode_MainWindow(iMainWindow *d, int splitFlags) { const int splitMode = splitFlags & mode_WindowSplit; if (deviceType_App() == phone_AppDeviceType) { /* There isn't enough room on the phone. */ /* TODO: Maybe in landscape only? */ return; } + iWindow *w = as_Window(d); iAssert(current_Root() == NULL); if (d->splitMode != splitMode) { - int oldCount = numRoots_Window(d); - setFreezeDraw_Window(d, iTrue); + int oldCount = numRoots_Window(w); + setFreezeDraw_Window(w, iTrue); if (oldCount == 2 && splitMode == 0) { /* Keep references to the tabs of the second root. */ - const iDocumentWidget *curPage = document_Root(d->keyRoot); + const iDocumentWidget *curPage = document_Root(w->keyRoot); if (!curPage) { /* All tabs closed on that side. */ - curPage = document_Root(otherRoot_Window(d, d->keyRoot)); + curPage = document_Root(otherRoot_Window(w, w->keyRoot)); } - iObjectList *tabs = listDocuments_App(d->roots[1]); + iObjectList *tabs = listDocuments_App(w->roots[1]); iForEach(ObjectList, i, tabs) { - setRoot_Widget(i.object, d->roots[0]); + setRoot_Widget(i.object, w->roots[0]); } setFocus_Widget(NULL); - delete_Root(d->roots[1]); - d->roots[1] = NULL; - d->keyRoot = d->roots[0]; + delete_Root(w->roots[1]); + w->roots[1] = NULL; + w->keyRoot = w->roots[0]; /* Move the deleted root's tabs to the first root. */ - setCurrent_Root(d->roots[0]); + setCurrent_Root(w->roots[0]); iWidget *docTabs = findWidget_Root("doctabs"); iForEach(ObjectList, j, tabs) { appendTabPage_Widget(docTabs, j.object, "", 0, 0); @@ -1268,38 +1301,38 @@ void setSplitMode_Window(iWindow *d, int splitFlags) { } else if (splitMode && oldCount == 1) { /* Add a second root. */ - iDocumentWidget *moved = document_Root(d->roots[0]); - iAssert(d->roots[1] == NULL); + iDocumentWidget *moved = document_Root(w->roots[0]); + iAssert(w->roots[1] == NULL); const iBool addToLeft = (prefs_App()->pinSplit == 2); size_t newRootIndex = 1; if (addToLeft) { - iSwap(iRoot *, d->roots[0], d->roots[1]); + iSwap(iRoot *, w->roots[0], w->roots[1]); newRootIndex = 0; } - d->roots[newRootIndex] = new_Root(); - d->keyRoot = d->roots[newRootIndex]; - setCurrent_Root(d->roots[newRootIndex]); - createUserInterface_Root(d->roots[newRootIndex]); + w->roots[newRootIndex] = new_Root(); + w->keyRoot = w->roots[newRootIndex]; + setCurrent_Root(w->roots[newRootIndex]); + createUserInterface_Root(w->roots[newRootIndex]); if (!isEmpty_String(d->pendingSplitUrl)) { - postCommandf_Root(d->roots[newRootIndex], "open url:%s", + postCommandf_Root(w->roots[newRootIndex], "open url:%s", cstr_String(d->pendingSplitUrl)); clear_String(d->pendingSplitUrl); } else if (~splitFlags & noEvents_WindowSplit) { - iWidget *docTabs0 = findChild_Widget(d->roots[newRootIndex ^ 1]->widget, "doctabs"); - iWidget *docTabs1 = findChild_Widget(d->roots[newRootIndex]->widget, "doctabs"); + iWidget *docTabs0 = findChild_Widget(w->roots[newRootIndex ^ 1]->widget, "doctabs"); + iWidget *docTabs1 = findChild_Widget(w->roots[newRootIndex]->widget, "doctabs"); /* If the old root has multiple tabs, move the current one to the new split. */ if (tabCount_Widget(docTabs0) >= 2) { int movedIndex = tabPageIndex_Widget(docTabs0, moved); removeTabPage_Widget(docTabs0, movedIndex); showTabPage_Widget(docTabs0, tabPage_Widget(docTabs0, iMax(movedIndex - 1, 0))); iRelease(removeTabPage_Widget(docTabs1, 0)); /* delete the default tab */ - setRoot_Widget(as_Widget(moved), d->roots[newRootIndex]); + setRoot_Widget(as_Widget(moved), w->roots[newRootIndex]); prependTabPage_Widget(docTabs1, iClob(moved), "", 0, 0); postCommandf_App("tabs.switch page:%p", moved); } else { - postCommand_Root(d->roots[newRootIndex], "navigate.home"); + postCommand_Root(w->roots[newRootIndex], "navigate.home"); } } setCurrent_Root(NULL); @@ -1328,26 +1361,26 @@ void setSplitMode_Window(iWindow *d, int splitFlags) { } #endif if (~splitFlags & noEvents_WindowSplit) { - updateSize_Window_(d, iTrue); + updateSize_MainWindow_(d, iTrue); postCommand_App("window.unfreeze"); } } } -void setSnap_Window(iWindow *d, int snapMode) { +void setSnap_MainWindow(iMainWindow *d, int snapMode) { if (!prefs_App()->customFrame) { if (snapMode == maximized_WindowSnap) { - SDL_MaximizeWindow(d->win); + SDL_MaximizeWindow(d->base.win); } else if (snapMode == fullscreen_WindowSnap) { - SDL_SetWindowFullscreen(d->win, SDL_WINDOW_FULLSCREEN_DESKTOP); + SDL_SetWindowFullscreen(d->base.win, SDL_WINDOW_FULLSCREEN_DESKTOP); } else { - if (snap_Window(d) == fullscreen_WindowSnap) { - SDL_SetWindowFullscreen(d->win, 0); + if (snap_MainWindow(d) == fullscreen_WindowSnap) { + SDL_SetWindowFullscreen(d->base.win, 0); } else { - SDL_RestoreWindow(d->win); + SDL_RestoreWindow(d->base.win); } } return; @@ -1359,9 +1392,9 @@ void setSnap_Window(iWindow *d, int snapMode) { const int snapDist = gap_UI * 4; iRect newRect = zero_Rect(); SDL_Rect usable; - SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->win), &usable); + SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->base.win), &usable); if (d->place.snap == fullscreen_WindowSnap) { - SDL_SetWindowFullscreen(d->win, 0); + SDL_SetWindowFullscreen(d->base.win, 0); } d->place.snap = snapMode & ~redo_WindowSnap; switch (snapMode & mask_WindowSnap) { @@ -1382,8 +1415,8 @@ void setSnap_Window(iWindow *d, int snapMode) { case yMaximized_WindowSnap: newRect.pos.y = 0; newRect.size.y = usable.h; - SDL_GetWindowSize(d->win, &newRect.size.x, NULL); - SDL_GetWindowPosition(d->win, &newRect.pos.x, NULL); + SDL_GetWindowSize(d->base.win, &newRect.size.x, NULL); + SDL_GetWindowPosition(d->base.win, &newRect.pos.x, NULL); /* Snap the window to left/right edges, if close by. */ if (iAbs(right_Rect(newRect) - (usable.x + usable.w)) < snapDist) { newRect.pos.x = usable.x + usable.w - width_Rect(newRect); @@ -1393,7 +1426,7 @@ void setSnap_Window(iWindow *d, int snapMode) { } break; case fullscreen_WindowSnap: - SDL_SetWindowFullscreen(d->win, SDL_WINDOW_FULLSCREEN_DESKTOP); + SDL_SetWindowFullscreen(d->base.win, SDL_WINDOW_FULLSCREEN_DESKTOP); break; } if (snapMode & (topBit_WindowSnap | bottomBit_WindowSnap)) { @@ -1425,9 +1458,9 @@ void setSnap_Window(iWindow *d, int snapMode) { #endif /* defined (LAGRANGE_ENABLE_CUSTOM_FRAME) */ } -int snap_Window(const iWindow *d) { +int snap_MainWindow(const iMainWindow *d) { if (!prefs_App()->customFrame) { - const int flags = SDL_GetWindowFlags(d->win); + const int flags = SDL_GetWindowFlags(d->base.win); if (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) { return fullscreen_WindowSnap; } diff --git a/src/ui/window.h b/src/ui/window.h index 282e1682..73e92391 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -29,8 +29,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include +iDeclareType(MainWindow) iDeclareType(Window) -iDeclareTypeConstructionArgs(Window, iRect rect) +iDeclareTypeConstructionArgs(MainWindow, iRect rect) + +typedef iAny iAnyWindow; enum iWindowSnap { none_WindowSnap = 0, @@ -68,9 +71,14 @@ enum iWindowSplit { noEvents_WindowSplit = iBit(11), }; +enum iWindowType { + main_WindowType, + popup_WindowType, +}; + struct Impl_Window { + enum iWindowType type; SDL_Window * win; - iWindowPlacement place; iBool isDrawFrozen; /* avoids premature draws while restoring window state */ iBool isExposed; iBool isMinimized; @@ -80,11 +88,6 @@ struct Impl_Window { uint32_t focusGainedAt; SDL_Renderer *render; iInt2 size; - int splitMode; - int pendingSplitMode; - iString * pendingSplitUrl; /* URL to open in a newly opened split */ - iRoot * roots[2]; /* root widget and UI state; second one is for split mode */ - iRoot * keyRoot; /* root that has the current keyboard input focus */ iWidget * hover; iWidget * lastHover; /* cleared if deleted */ iWidget * mouseGrab; @@ -94,56 +97,102 @@ struct Impl_Window { float uiScale; uint32_t frameTime; double presentTime; - SDL_Texture * appIcon; - SDL_Texture * borderShadow; SDL_Cursor * cursors[SDL_NUM_SYSTEM_CURSORS]; SDL_Cursor * pendingCursor; - int loadAnimTimer; - int keyboardHeight; /* mobile software keyboards */ + iRoot * roots[2]; /* root widget and UI state; second one is for split mode */ + iRoot * keyRoot; /* root that has the current keyboard input focus */ + SDL_Texture * borderShadow; +}; + +struct Impl_MainWindow { + iWindow base; + iWindowPlacement place; + int splitMode; + int pendingSplitMode; + iString * pendingSplitUrl; /* URL to open in a newly opened split */ + SDL_Texture * appIcon; + int keyboardHeight; /* mobile software keyboards */ }; -iBool processEvent_Window (iWindow *, const SDL_Event *); +iLocalDef enum iWindowType type_Window(const iAnyWindow *d) { + return ((const iWindow *) d)->type; +} + +uint32_t id_Window (const iWindow *); +iInt2 size_Window (const iWindow *); +iInt2 maxTextureSize_Window (const iWindow *); +float uiScale_Window (const iWindow *); +iInt2 coord_Window (const iWindow *, int x, int y); +iInt2 mouseCoord_Window (const iWindow *, int whichDevice); +iAnyObject * hitChild_Window (const iWindow *, iInt2 coord); +uint32_t frameTime_Window (const iWindow *); +SDL_Renderer * renderer_Window (const iWindow *); +int numRoots_Window (const iWindow *); +iRoot * findRoot_Window (const iWindow *, const iWidget *widget); +iRoot * otherRoot_Window (const iWindow *, iRoot *root); + iBool dispatchEvent_Window (iWindow *, const SDL_Event *); -void invalidate_Window (iWindow *); /* discard all cached graphics */ +void invalidate_Window (iAnyWindow *); /* discard all cached graphics */ void draw_Window (iWindow *); -void drawWhileResizing_Window(iWindow *d, int w, int h); /* workaround for SDL bug */ -void resize_Window (iWindow *, int w, int h); -void setTitle_Window (iWindow *, const iString *title); void setUiScale_Window (iWindow *, float uiScale); void setFreezeDraw_Window (iWindow *, iBool freezeDraw); -iBool setKeyRoot_Window (iWindow *, iRoot *root); void setCursor_Window (iWindow *, int cursor); -void setSnap_Window (iWindow *, int snapMode); -void setKeyboardHeight_Window(iWindow *, int height); -void setSplitMode_Window (iWindow *, int splitMode); -void showToolbars_Window (iWindow *, iBool show); +iBool setKeyRoot_Window (iWindow *, iRoot *root); iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *); -void checkPendingSplit_Window(iWindow *); -void swapRoots_Window (iWindow *); - -uint32_t id_Window (const iWindow *); -iInt2 size_Window (const iWindow *); -iInt2 maxTextureSize_Window (const iWindow *); -float uiScale_Window (const iWindow *); -iInt2 coord_Window (const iWindow *, int x, int y); -iInt2 mouseCoord_Window (const iWindow *, int whichDevice); -iAnyObject *hitChild_Window (const iWindow *, iInt2 coord); -uint32_t frameTime_Window (const iWindow *); -SDL_Renderer *renderer_Window (const iWindow *); -int snap_Window (const iWindow *); -iBool isFullscreen_Window (const iWindow *); -int numRoots_Window (const iWindow *); -iRoot * findRoot_Window (const iWindow *, const iWidget *widget); -iRoot * otherRoot_Window (const iWindow *, iRoot *root); -iWindow * get_Window (void); +iWindow * get_Window (void); iBool isOpenGLRenderer_Window (void); -#if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) -SDL_HitTestResult hitTest_Window(const iWindow *d, iInt2 pos); -#endif - iLocalDef iBool isExposed_Window(const iWindow *d) { iAssert(d); return d->isExposed; } + +iLocalDef iWindow *as_Window(iAnyWindow *d) { + iAssert(type_Window(d) == main_WindowType || type_Window(d) == popup_WindowType); + return (iWindow *) d; +} + +iLocalDef const iWindow *constAs_Window(const iAnyWindow *d) { + iAssert(type_Window(d) == main_WindowType || type_Window(d) == popup_WindowType); + return (const iWindow *) d; +} + +/*----------------------------------------------------------------------------------------------*/ + +iLocalDef iWindow *asWindow_MainWindow(iMainWindow *d) { + iAssert(type_Window(d) == main_WindowType); + return &d->base; +} + +void setTitle_MainWindow (iMainWindow *, const iString *title); +void setSnap_MainWindow (iMainWindow *, int snapMode); +void setKeyboardHeight_MainWindow (iMainWindow *, int height); +void setSplitMode_MainWindow (iMainWindow *, int splitMode); +void checkPendingSplit_MainWindow (iMainWindow *); +void swapRoots_MainWindow (iMainWindow *); +void showToolbars_MainWindow (iMainWindow *, iBool show); +void resize_MainWindow (iMainWindow *, int w, int h); + +iBool processEvent_MainWindow (iMainWindow *, const SDL_Event *); +void draw_MainWindow (iMainWindow *); +void drawWhileResizing_MainWindow (iMainWindow *, int w, int h); /* workaround for SDL bug */ + +int snap_MainWindow (const iMainWindow *); +iBool isFullscreen_Window (const iMainWindow *); + +#if defined (LAGRANGE_ENABLE_CUSTOM_FRAME) +SDL_HitTestResult hitTest_MainWindow(const iMainWindow *d, iInt2 pos); +#endif + +iMainWindow * get_MainWindow (void); + +iLocalDef iMainWindow *as_MainWindow(iAnyWindow *d) { + iAssert(type_Window(d) == main_WindowType); + return (iMainWindow *) d; +} + +iLocalDef const iMainWindow *constAs_MainWindow(const iAnyWindow *d) { + iAssert(type_Window(d) == main_WindowType); + return (const iMainWindow *) d; +} -- cgit v1.2.3