[1mdiff --git a/src/app.c b/src/app.c[m
[1mindex 91b3a06d..c1c1da27 100644[m
[1m--- a/src/app.c[m
[1m+++ b/src/app.c[m
[36m@@ -118,6 +118,7 @@[m [mstruct Impl_App {[m
iVisited * visited;[m
iBookmarks * bookmarks;[m
iMainWindow *window;[m
[32m+[m[32m iPtrArray popupWindows;[m
iSortedArray tickers; /* per-frame callbacks, used for animations */[m
uint32_t lastTickerTime;[m
uint32_t elapsedSinceLastTicker;[m
[36m@@ -801,6 +802,7 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m
d->initialWindowRect.size.y = toInt_String(value_CommandLineArg(arg, 0));[m
}[m
}[m
[32m+[m[32m init_PtrArray(&d->popupWindows);[m
d->window = new_MainWindow(d->initialWindowRect);[m
load_Visited(d->visited, dataDir_App_());[m
load_Bookmarks(d->bookmarks, dataDir_App_());[m
[36m@@ -853,6 +855,11 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m
}[m
[m
static void deinit_App(iApp *d) {[m
[32m+[m[32m iReverseForEach(PtrArray, i, &d->popupWindows) {[m
[32m+[m[32m delete_Window(i.ptr);[m
[32m+[m[32m }[m
[32m+[m[32m iAssert(isEmpty_PtrArray(&d->popupWindows));[m
[32m+[m[32m deinit_PtrArray(&d->popupWindows);[m
#if defined (LAGRANGE_ENABLE_IDLE_SLEEP)[m
SDL_RemoveTimer(d->sleepTimer);[m
#endif[m
[36m@@ -1086,6 +1093,15 @@[m [mstatic iBool nextEvent_App_(iApp *d, enum iAppEventMode eventMode, SDL_Event *ev[m
return SDL_PollEvent(event);[m
}[m
[m
[32m+[m[32mstatic const iPtrArray *listWindows_App_(const iApp *d) {[m
[32m+[m[32m iPtrArray *list = collectNew_PtrArray();[m
[32m+[m[32m iReverseConstForEach(PtrArray, i, &d->popupWindows) {[m
[32m+[m[32m pushBack_PtrArray(list, i.ptr);[m
[32m+[m[32m }[m
[32m+[m[32m pushBack_PtrArray(list, d->window);[m
[32m+[m[32m return list;[m
[32m+[m[32m}[m
[32m+[m
void processEvents_App(enum iAppEventMode eventMode) {[m
iApp *d = &app_;[m
iRoot *oldCurrentRoot = current_Root(); /* restored afterwards */[m
[36m@@ -1125,17 +1141,17 @@[m [mvoid processEvents_App(enum iAppEventMode eventMode) {[m
#if defined (iPlatformAppleMobile)[m
updateNowPlayingInfo_iOS();[m
#endif[m
[31m- setFreezeDraw_Window(as_Window(d), iTrue);[m
[32m+[m[32m setFreezeDraw_MainWindow(d->window, iTrue);[m
savePrefs_App_(d);[m
saveState_App_(d);[m
break;[m
case SDL_APP_TERMINATING:[m
[31m- setFreezeDraw_Window(as_Window(d), iTrue);[m
[32m+[m[32m setFreezeDraw_MainWindow(d->window, iTrue);[m
savePrefs_App_(d);[m
saveState_App_(d);[m
break;[m
case SDL_DROPFILE: {[m
[31m- iBool wasUsed = processEvent_MainWindow(d->window, &ev);[m
[32m+[m[32m iBool wasUsed = processEvent_Window(as_Window(d->window), &ev);[m
if (!wasUsed) {[m
iBool newTab = iFalse;[m
if (elapsedSeconds_Time(&d->lastDropTime) < 0.1) {[m
[36m@@ -1175,23 +1191,6 @@[m [mvoid processEvents_App(enum iAppEventMode eventMode) {[m
}[m
d->isIdling = iFalse;[m
#endif[m
[31m- if (ev.type == SDL_USEREVENT && ev.user.code == arrange_UserEventCode) {[m
[31m- printf("[App] rearrange\n");[m
[31m- resize_MainWindow(d->window, -1, -1);[m
[31m- iForIndices(i, d->window->base.roots) {[m
[31m- if (d->window->base.roots[i]) {[m
[31m- d->window->base.roots[i]->pendingArrange = iFalse;[m
[31m- }[m
[31m- }[m
[31m-// if (ev.user.data2 == d->window->roots[0]) {[m
[31m-// arrange_Widget(d->window->roots[0]->widget);[m
[31m-// }[m
[31m-// else if (d->window->roots[1]) {[m
[31m-// arrange_Widget(d->window->roots[1]->widget);[m
[31m-// }[m
[31m-// postRefresh_App();[m
[31m- continue;[m
[31m- }[m
gotEvents = iTrue;[m
/* Keyboard modifier mapping. */[m
if (ev.type == SDL_KEYDOWN || ev.type == SDL_KEYUP) {[m
[36m@@ -1268,10 +1267,22 @@[m [mvoid processEvents_App(enum iAppEventMode eventMode) {[m
}[m
}[m
#endif[m
[31m- d->window->base.lastHover = d->window->base.hover;[m
[31m- iBool wasUsed = processEvent_MainWindow(d->window, &ev);[m
[32m+[m[32m /* Per-window processing. */[m
[32m+[m[32m iBool wasUsed = iFalse;[m
[32m+[m[32m const iPtrArray *windows = listWindows_App_(d);[m
[32m+[m[32m iConstForEach(PtrArray, iter, windows) {[m
[32m+[m[32m iWindow *window = iter.ptr;[m
[32m+[m[32m setCurrent_Window(window);[m
[32m+[m[32m window->lastHover = window->hover;[m
[32m+[m[32m wasUsed = processEvent_Window(window, &ev);[m
[32m+[m[32m if (ev.type == SDL_MOUSEMOTION) {[m
[32m+[m[32m break;[m
[32m+[m[32m }[m
[32m+[m[32m if (wasUsed) break;[m
[32m+[m[32m }[m
[32m+[m[32m setCurrent_Window(d->window);[m
if (!wasUsed) {[m
[31m- /* There may be a key bindings for this. */[m
[32m+[m[32m /* There may be a key binding for this. */[m
wasUsed = processEvent_Keys(&ev);[m
}[m
if (!wasUsed) {[m
[36m@@ -1289,24 +1300,32 @@[m [mvoid processEvents_App(enum iAppEventMode eventMode) {[m
handleCommand_MacOS(command_UserEvent(&ev));[m
#endif[m
if (isMetricsChange_UserEvent(&ev)) {[m
[31m- iForIndices(i, d->window->base.roots) {[m
[31m- iRoot *root = d->window->base.roots[i];[m
[31m- if (root) {[m
[31m- arrange_Widget(root->widget);[m
[31m- }[m
[32m+[m[32m iConstForEach(PtrArray, iter, windows) {[m
[32m+[m[32m iWindow *window = iter.ptr;[m
[32m+[m[32m iForIndices(i, window->roots) {[m
[32m+[m[32m iRoot *root = window->roots[i];[m
[32m+[m[32m if (root) {[m
[32m+[m[32m arrange_Widget(root->widget);[m
[32m+[m[32m }[m
[32m+[m[32m }[m[41m [m
}[m
}[m
if (!wasUsed) {[m
/* No widget handled the command, so we'll do it. */[m
[32m+[m[32m setCurrent_Window(d->window);[m
handleCommand_App(ev.user.data1);[m
}[m
/* Allocated by postCommand_Apps(). */[m
free(ev.user.data1);[m
}[m
[31m- /* Update when hover has changed. */[m
[31m- if (d->window->base.lastHover != d->window->base.hover) {[m
[31m- refresh_Widget(d->window->base.lastHover);[m
[31m- refresh_Widget(d->window->base.hover);[m
[32m+[m[32m /* Refresh after hover changes. */ {[m
[32m+[m[32m iConstForEach(PtrArray, iter, windows) {[m
[32m+[m[32m iWindow *window = iter.ptr;[m
[32m+[m[32m if (window->lastHover != window->hover) {[m
[32m+[m[32m refresh_Widget(window->lastHover);[m
[32m+[m[32m refresh_Widget(window->hover);[m
[32m+[m[32m }[m
[32m+[m[32m }[m
}[m
break;[m
}[m
[36m@@ -1394,25 +1413,46 @@[m [mstatic int run_App_(iApp *d) {[m
[m
void refresh_App(void) {[m
iApp *d = &app_;[m
[31m- iForIndices(i, d->window->base.roots) {[m
[31m- iRoot *root = d->window->base.roots[i];[m
[31m- if (root) {[m
[31m- destroyPending_Root(root);[m
[31m- }[m
[31m- }[m
#if defined (LAGRANGE_ENABLE_IDLE_SLEEP)[m
if (d->warmupFrames == 0 && d->isIdling) {[m
return;[m
}[m
#endif[m
[32m+[m[32m const iPtrArray *windows = listWindows_App_(d);[m
[32m+[m[32m /* Destroy pending widgets. */ {[m
[32m+[m[32m iConstForEach(PtrArray, j, windows) {[m[41m [m
[32m+[m[32m iWindow *win = j.ptr;[m
[32m+[m[32m setCurrent_Window(win);[m
[32m+[m[32m iForIndices(i, win->roots) {[m
[32m+[m[32m iRoot *root = win->roots[i];[m
[32m+[m[32m if (root) {[m
[32m+[m[32m destroyPending_Root(root);[m
[32m+[m[32m }[m
[32m+[m[32m }[m
[32m+[m[32m }[m
[32m+[m[32m }[m
[32m+[m[32m /* TODO: Pending refresh is window-specific. */[m
if (!exchange_Atomic(&d->pendingRefresh, iFalse)) {[m
return;[m
}[m
[31m-// iTime draw;[m
[31m-// initCurrent_Time(&draw);[m
[31m- draw_MainWindow(d->window);[m
[31m-// printf("draw: %lld \u03bcs\n", (long long) (elapsedSeconds_Time(&draw) * 1000000));[m
[31m-// fflush(stdout);[m
[32m+[m[32m /* Draw each window. */ {[m
[32m+[m[32m iConstForEach(PtrArray, j, windows) {[m
[32m+[m[32m iWindow *win = j.ptr;[m
[32m+[m[32m setCurrent_Window(win);[m
[32m+[m[32m switch (win->type) {[m
[32m+[m[32m case main_WindowType:[m
[32m+[m[32m // iTime draw;[m
[32m+[m[32m // initCurrent_Time(&draw);[m
[32m+[m[32m draw_MainWindow(as_MainWindow(win));[m
[32m+[m[32m // printf("draw: %lld \u03bcs\n", (long long) (elapsedSeconds_Time(&draw) * 1000000));[m
[32m+[m[32m // fflush(stdout);[m
[32m+[m[32m break;[m
[32m+[m[32m default:[m
[32m+[m[32m draw_Window(win);[m
[32m+[m[32m break;[m[41m [m
[32m+[m[32m }[m
[32m+[m[32m }[m
[32m+[m[32m }[m
if (d->warmupFrames > 0) {[m
d->warmupFrames--;[m
}[m
[36m@@ -1485,12 +1525,6 @@[m [mvoid postRefresh_App(void) {[m
}[m
}[m
[m
[31m-void postImmediateRefresh_App(void) {[m
[31m- SDL_Event ev = { .type = SDL_USEREVENT };[m
[31m- ev.user.code = immediateRefresh_UserEventCode;[m
[31m- SDL_PushEvent(&ev);[m
[31m-}[m
[31m-[m
void postCommand_Root(iRoot *d, const char *command) {[m
iAssert(command);[m
if (strlen(command) == 0) {[m
[36m@@ -1546,7 +1580,7 @@[m [mvoid postCommandf_App(const char *command, ...) {[m
}[m
[m
void rootOrder_App(iRoot *roots[2]) {[m
[31m- const iWindow *win = as_Window(app_.window);[m
[32m+[m[32m const iWindow *win = get_Window();[m
roots[0] = win->keyRoot;[m
roots[1] = (roots[0] == win->roots[0] ? win->roots[1] : win->roots[0]);[m
}[m
[36m@@ -1583,6 +1617,16 @@[m [mvoid removeTicker_App(iTickerFunc ticker, iAny *context) {[m
remove_SortedArray(&d->tickers, &(iTicker){ context, NULL, ticker });[m
}[m
[m
[32m+[m[32mvoid addPopup_App(iWindow *popup) {[m
[32m+[m[32m iApp *d = &app_;[m
[32m+[m[32m pushBack_PtrArray(&d->popupWindows, popup);[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mvoid removePopup_App(iWindow *popup) {[m
[32m+[m[32m iApp *d = &app_;[m
[32m+[m[32m removeOne_PtrArray(&d->popupWindows, popup);[m
[32m+[m[32m}[m
[32m+[m
iMimeHooks *mimeHooks_App(void) {[m
return app_.mimehooks;[m
}[m
[36m@@ -1836,8 +1880,10 @@[m [miDocumentWidget *newTab_App(const iDocumentWidget *duplicateOf, iBool switchToNe[m
static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) {[m
iApp *d = &app_;[m
if (equal_Command(cmd, "ident.showmore")) {[m
[31m- iForEach(ObjectList, i,[m
[31m- children_Widget(findChild_Widget(dlg, isUsingPanelLayout_Mobile() ? "panel.top" : "headings"))) {[m
[32m+[m[32m iForEach(ObjectList,[m
[32m+[m[32m i,[m
[32m+[m[32m children_Widget(findChild_Widget([m
[32m+[m[32m dlg, isUsingPanelLayout_Mobile() ? "panel.top" : "headings"))) {[m
if (flags_Widget(i.object) & collapse_WidgetFlag) {[m
setFlags_Widget(i.object, hidden_WidgetFlag, iFalse);[m
}[m
[36m@@ -1978,9 +2024,15 @@[m [mconst iString *searchQueryUrl_App(const iString *queryStringUnescaped) {[m
return collectNewFormat_String("%s?%s", cstr_String(&d->prefs.searchUrl), cstr_String(escaped));[m
}[m
[m
[32m+[m[32mstatic void resetFonts_App_(iApp *d) {[m
[32m+[m[32m iConstForEach(PtrArray, win, listWindows_App_(d)) {[m
[32m+[m[32m resetFonts_Text(text_Window(win.ptr));[m
[32m+[m[32m }[m[41m [m
[32m+[m[32m}[m
[32m+[m
iBool handleCommand_App(const char *cmd) {[m
iApp *d = &app_;[m
[31m- const iBool isFrozen = !d->window || d->window->base.isDrawFrozen;[m
[32m+[m[32m const iBool isFrozen = !d->window || d->window->isDrawFrozen;[m
if (equal_Command(cmd, "config.error")) {[m
makeSimpleMessage_Widget(uiTextCaution_ColorEscape "CONFIG ERROR",[m
format_CStr("Error in config file: %s\n"[m
[36m@@ -2047,18 +2099,18 @@[m [miBool handleCommand_App(const char *cmd) {[m
return iTrue;[m
}[m
else if (equal_Command(cmd, "font.reset")) {[m
[31m- resetFonts_Text();[m
[32m+[m[32m resetFonts_App_(d);[m
return iTrue;[m
}[m
else if (equal_Command(cmd, "font.user")) {[m
const char *path = suffixPtr_Command(cmd, "path");[m
if (cmp_String(&d->prefs.symbolFontPath, path)) {[m
if (!isFrozen) {[m
[31m- setFreezeDraw_Window(get_Window(), iTrue);[m
[32m+[m[32m setFreezeDraw_MainWindow(get_MainWindow(), iTrue);[m
}[m
setCStr_String(&d->prefs.symbolFontPath, path);[m
loadUserFonts_Text();[m
[31m- resetFonts_Text();[m
[32m+[m[32m resetFonts_App_(d);[m
if (!isFrozen) {[m
postCommand_App("font.changed");[m
postCommand_App("window.unfreeze");[m
[36m@@ -2068,10 +2120,10 @@[m [miBool handleCommand_App(const char *cmd) {[m
}[m
else if (equal_Command(cmd, "font.set")) {[m
if (!isFrozen) {[m
[31m- setFreezeDraw_Window(get_Window(), iTrue);[m
[32m+[m[32m setFreezeDraw_MainWindow(get_MainWindow(), iTrue);[m
}[m
d->prefs.font = arg_Command(cmd);[m
[31m- setContentFont_Text(d->prefs.font);[m
[32m+[m[32m setContentFont_Text(text_Window(d->window), d->prefs.font);[m
if (!isFrozen) {[m
postCommand_App("font.changed");[m
postCommand_App("window.unfreeze");[m
[36m@@ -2080,10 +2132,10 @@[m [miBool handleCommand_App(const char *cmd) {[m
}[m
else if (equal_Command(cmd, "headingfont.set")) {[m
if (!isFrozen) {[m
[31m- setFreezeDraw_Window(get_Window(), iTrue);[m
[32m+[m[32m setFreezeDraw_MainWindow(get_MainWindow(), iTrue);[m
}[m
d->prefs.headingFont = arg_Command(cmd);[m
[31m- setHeadingFont_Text(d->prefs.headingFont);[m
[32m+[m[32m setHeadingFont_Text(text_Window(d->window), d->prefs.headingFont);[m
if (!isFrozen) {[m
postCommand_App("font.changed");[m
postCommand_App("window.unfreeze");[m
[36m@@ -2092,10 +2144,10 @@[m [miBool handleCommand_App(const char *cmd) {[m
}[m
else if (equal_Command(cmd, "zoom.set")) {[m
if (!isFrozen) {[m
[31m- setFreezeDraw_Window(get_Window(), iTrue); /* no intermediate draws before docs updated */[m
[32m+[m[32m setFreezeDraw_MainWindow(get_MainWindow(), iTrue); /* no intermediate draws before docs updated */[m
}[m
d->prefs.zoomPercent = arg_Command(cmd);[m
[31m- setContentFontSize_Text((float) d->prefs.zoomPercent / 100.0f);[m
[32m+[m[32m setContentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f);[m
if (!isFrozen) {[m
postCommand_App("font.changed");[m
postCommand_App("window.unfreeze");[m
[36m@@ -2104,14 +2156,14 @@[m [miBool handleCommand_App(const char *cmd) {[m
}[m
else if (equal_Command(cmd, "zoom.delta")) {[m
if (!isFrozen) {[m
[31m- setFreezeDraw_Window(get_Window(), iTrue); /* no intermediate draws before docs updated */[m
[32m+[m[32m setFreezeDraw_MainWindow(get_MainWindow(), iTrue); /* no intermediate draws before docs updated */[m
}[m
int delta = arg_Command(cmd);[m
if (d->prefs.zoomPercent < 100 || (delta < 0 && d->prefs.zoomPercent == 100)) {[m
delta /= 2;[m
}[m
d->prefs.zoomPercent = iClamp(d->prefs.zoomPercent + delta, 50, 200);[m
[31m- setContentFontSize_Text((float) d->prefs.zoomPercent / 100.0f);[m
[32m+[m[32m setContentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f);[m
if (!isFrozen) {[m
postCommand_App("font.changed");[m
postCommand_App("window.unfreeze");[m
[36m@@ -2211,7 +2263,7 @@[m [miBool handleCommand_App(const char *cmd) {[m
equal_Command(cmd, "prefs.mono.gopher.changed")) {[m
const iBool isSet = (arg_Command(cmd) != 0);[m
if (!isFrozen) {[m
[31m- setFreezeDraw_Window(as_Window(d->window), iTrue);[m
[32m+[m[32m setFreezeDraw_MainWindow(get_MainWindow(), iTrue);[m
}[m
if (startsWith_CStr(cmd, "prefs.mono.gemini")) {[m
d->prefs.monospaceGemini = isSet;[m
[36m@@ -2936,3 +2988,7 @@[m [miStringSet *listOpenURLs_App(void) {[m
iRelease(docs);[m
return set;[m
}[m
[32m+[m
[32m+[m[32miMainWindow *mainWindow_App(void) {[m
[32m+[m[32m return app_.window;[m
[32m+[m[32m}[m
[1mdiff --git a/src/app.h b/src/app.h[m
[1mindex 08589000..8966e8c7 100644[m
[1m--- a/src/app.h[m
[1m+++ b/src/app.h[m
[36m@@ -22,8 +22,6 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
[m
#pragma once[m
[m
[31m-/* Application core: event loop, base event processing, audio synth. */[m
[31m-[m
#include <the_Foundation/objectlist.h>[m
#include <the_Foundation/string.h>[m
#include <the_Foundation/stringset.h>[m
[36m@@ -35,6 +33,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
iDeclareType(Bookmarks)[m
iDeclareType(DocumentWidget)[m
iDeclareType(GmCerts)[m
[32m+[m[32miDeclareType(MainWindow)[m
iDeclareType(MimeHooks)[m
iDeclareType(Periodic)[m
iDeclareType(Root)[m
[36m@@ -61,14 +60,12 @@[m [menum iAppEventMode {[m
enum iUserEventCode {[m
command_UserEventCode = 1,[m
refresh_UserEventCode,[m
[31m- arrange_UserEventCode,[m
asleep_UserEventCode,[m
/* The start of a potential touch tap event is notified via a custom event because[m
sending SDL_MOUSEBUTTONDOWN would be premature: we don't know how long the tap will[m
take, it could turn into a tap-and-hold for example. */[m
widgetTapBegins_UserEventCode,[m
widgetTouchEnds_UserEventCode, /* finger lifted, but momentum may continue */[m
[31m- immediateRefresh_UserEventCode, /* refresh even though more events are pending */[m
};[m
[m
const iString *execPath_App (void);[m
[36m@@ -119,8 +116,9 @@[m [miAny * findWidget_App (const char *id);[m
void addTicker_App (iTickerFunc ticker, iAny *context);[m
void addTickerRoot_App (iTickerFunc ticker, iRoot *root, iAny *context);[m
void removeTicker_App (iTickerFunc ticker, iAny *context);[m
[32m+[m[32mvoid addPopup_App (iWindow *popup);[m
[32m+[m[32mvoid removePopup_App (iWindow *popup);[m
void postRefresh_App (void);[m
[31m-void postImmediateRefresh_App(void);[m
void postCommand_Root (iRoot *, const char *command);[m
void postCommandf_Root (iRoot *, const char *command, ...);[m
void postCommandf_App (const char *command, ...);[m
[36m@@ -138,3 +136,5 @@[m [miDocumentWidget * document_Command (const char *cmd);[m
[m
void openInDefaultBrowser_App (const iString *url);[m
void revealPath_App (const iString *path);[m
[32m+[m
[32m+[m[32miMainWindow *mainWindow_App(void);[m
[1mdiff --git a/src/ios.m b/src/ios.m[m
[1mindex 3fb0af48..b46fb8dc 100644[m
[1m--- a/src/ios.m[m
[1m+++ b/src/ios.m[m
[36m@@ -247,14 +247,14 @@[m [mdidPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {[m
UIView *view = [viewController_(get_Window()) view];[m
CGRect keyboardFrame = [view convertRect:rawFrame fromView:nil];[m
// NSLog(@"keyboardFrame: %@", NSStringFromCGRect(keyboardFrame));[m
[31m- iWindow *window = get_Window();[m
[31m- const iInt2 rootSize = size_Root(window->roots[0]);[m
[31m- const int keyTop = keyboardFrame.origin.y * window->pixelRatio;[m
[31m- setKeyboardHeight_Window(window, rootSize.y - keyTop);[m
[32m+[m[32m iMainWindow *window = get_MainWindow();[m
[32m+[m[32m const iInt2 rootSize = size_Root(window->base.roots[0]);[m
[32m+[m[32m const int keyTop = keyboardFrame.origin.y * window->base.pixelRatio;[m
[32m+[m[32m setKeyboardHeight_MainWindow(window, rootSize.y - keyTop);[m
}[m
[m
-(void)keyboardOffScreen:(NSNotification *)notification {[m
[31m- setKeyboardHeight_Window(get_Window(), 0);[m
[32m+[m[32m setKeyboardHeight_MainWindow(get_MainWindow(), 0);[m
}[m
@end[m
[m
[1mdiff --git a/src/macos.h b/src/macos.h[m
[1mindex 0d3f097a..20b95943 100644[m
[1m--- a/src/macos.h[m
[1m+++ b/src/macos.h[m
[36m@@ -24,6 +24,8 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
[m
#include "ui/util.h"[m
[m
[32m+[m[32miDeclareType(Window)[m
[32m+[m
/* Platform-specific functionality for macOS */[m
[m
iBool shouldDefaultToMetalRenderer_MacOS (void);[m
[36m@@ -31,6 +33,7 @@[m [miBool shouldDefaultToMetalRenderer_MacOS (void);[m
void enableMomentumScroll_MacOS (void);[m
void registerURLHandler_MacOS (void);[m
void setupApplication_MacOS (void);[m
[32m+[m[32mvoid hideTitleBar_MacOS (iWindow *window);[m
void insertMenuItems_MacOS (const char *menuLabel, int atIndex, const iMenuItem *items, size_t count);[m
void removeMenu_MacOS (int atIndex);[m
void enableMenu_MacOS (const char *menuLabel, iBool enable);[m
[1mdiff --git a/src/macos.m b/src/macos.m[m
[1mindex d588fa4a..298db0f8 100644[m
[1m--- a/src/macos.m[m
[1m+++ b/src/macos.m[m
[36m@@ -30,6 +30,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
#include "ui/window.h"[m
[m
#include <SDL_timer.h>[m
[32m+[m[32m#include <SDL_syswm.h>[m
[m
#import <AppKit/AppKit.h>[m
[m
[36m@@ -51,6 +52,16 @@[m [mstatic iInt2 macVer_(void) {[m
return init_I2(10, 10);[m
}[m
[m
[32m+[m[32mstatic NSWindow *nsWindow_(SDL_Window *window) {[m
[32m+[m[32m SDL_SysWMinfo wm;[m
[32m+[m[32m SDL_VERSION(&wm.version);[m
[32m+[m[32m if (SDL_GetWindowWMInfo(window, &wm)) {[m
[32m+[m[32m return wm.info.cocoa.window;[m
[32m+[m[32m }[m
[32m+[m[32m iAssert(false);[m
[32m+[m[32m return nil;[m
[32m+[m[32m}[m
[32m+[m
static NSString *currentSystemAppearance_(void) {[m
/* This API does not exist on 10.13. */[m
if ([NSApp respondsToSelector:@selector(effectiveAppearance)]) {[m
[36m@@ -370,6 +381,11 @@[m [mvoid setupApplication_MacOS(void) {[m
windowCloseItem.action = @selector(closeTab);[m
}[m
[m
[32m+[m[32mvoid hideTitleBar_MacOS(iWindow *window) {[m
[32m+[m[32m NSWindow *w = nsWindow_(window->win);[m
[32m+[m[32m w.styleMask = 0; /* borderless */[m
[32m+[m[32m}[m
[32m+[m
void enableMenu_MacOS(const char *menuLabel, iBool enable) {[m
menuLabel = translateCStr_Lang(menuLabel);[m
NSApplication *app = [NSApplication sharedApplication];[m
[36m@@ -377,7 +393,6 @@[m [mvoid enableMenu_MacOS(const char *menuLabel, iBool enable) {[m
NSString *label = [NSString stringWithUTF8String:menuLabel];[m
NSMenuItem *menuItem = [appMenu itemAtIndex:[appMenu indexOfItemWithTitle:label]];[m
[menuItem setEnabled:enable];[m
[31m- [label release];[m
}[m
[m
void enableMenuItem_MacOS(const char *menuItemCommand, iBool enable) {[m
[1mdiff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c[m
[1mindex ed9e41d6..6f9824de 100644[m
[1m--- a/src/ui/documentwidget.c[m
[1m+++ b/src/ui/documentwidget.c[m
[36m@@ -750,7 +750,7 @@[m [mstatic uint32_t mediaUpdateInterval_DocumentWidget_(const iDocumentWidget *d) {[m
if (document_App() != d) {[m
return 0;[m
}[m
[31m- if (get_Window()->isDrawFrozen) {[m
[32m+[m[32m if (as_MainWindow(window_Widget(d))->isDrawFrozen) {[m
return 0;[m
}[m
static const uint32_t invalidInterval_ = ~0u;[m
[1mdiff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c[m
[1mindex a561d5bd..f02bf408 100644[m
[1m--- a/src/ui/inputwidget.c[m
[1m+++ b/src/ui/inputwidget.c[m
[36m@@ -2352,7 +2352,7 @@[m [mstatic void draw_InputWidget_(const iInputWidget *d) {[m
}[m
/* Draw the insertion point. */[m
if (isFocused && d->cursorVis && contains_Range(&visLines, d->cursor.y) &&[m
[31m- isEmpty_Range(&d->mark)) {[m
[32m+[m[32m (deviceType_App() == desktop_AppDeviceType || isEmpty_Range(&d->mark))) {[m
iInt2 curSize;[m
iRangecc cursorChar = iNullRange;[m
int visWrapsAbove = 0;[m
[1mdiff --git a/src/ui/root.c b/src/ui/root.c[m
[1mindex 52a08eca..9e290b05 100644[m
[1m--- a/src/ui/root.c[m
[1m+++ b/src/ui/root.c[m
[36m@@ -298,16 +298,6 @@[m [mvoid destroyPending_Root(iRoot *d) {[m
setCurrent_Root(oldRoot);[m
}[m
[m
[31m-void postArrange_Root(iRoot *d) {[m
[31m- if (!d->pendingArrange) {[m
[31m- d->pendingArrange = iTrue;[m
[31m- SDL_Event ev = { .type = SDL_USEREVENT };[m
[31m- ev.user.code = arrange_UserEventCode;[m
[31m- ev.user.data2 = d;[m
[31m- SDL_PushEvent(&ev);[m
[31m- }[m
[31m-}[m
[31m-[m
iPtrArray *onTop_Root(iRoot *d) {[m
if (!d->onTop) {[m
d->onTop = new_PtrArray();[m
[1mdiff --git a/src/ui/root.h b/src/ui/root.h[m
[1mindex 740e97c9..04dd5e16 100644[m
[1m--- a/src/ui/root.h[m
[1m+++ b/src/ui/root.h[m
[36m@@ -9,6 +9,7 @@[m [miDeclareType(Root)[m
[m
struct Impl_Root {[m
iWidget * widget;[m
[32m+[m[32m iWindow * window;[m
iPtrArray *onTop; /* order is important; last one is topmost */[m
iPtrSet * pendingDestruction;[m
iBool pendingArrange;[m
[36m@@ -29,7 +30,6 @@[m [miAnyObject *findWidget_Root (const char id); / under curre[m
[m
iPtrArray * onTop_Root (iRoot *);[m
void destroyPending_Root (iRoot *);[m
[31m-void postArrange_Root (iRoot *);[m
[m
void updateMetrics_Root (iRoot *);[m
void updatePadding_Root (iRoot ); / TODO: is part of metrics? */[m
[1mdiff --git a/src/ui/text.c b/src/ui/text.c[m
[1mindex f7fff4bc..bf71b0e9 100644[m
[1m--- a/src/ui/text.c[m
[1m+++ b/src/ui/text.c[m
[36m@@ -290,7 +290,9 @@[m [mstruct Impl_Text {[m
iRegExp * ansiEscape;[m
};[m
[m
[31m-static iText text_;[m
[32m+[m[32miDefineTypeConstructionArgs(Text, (SDL_Renderer *render), render)[m
[32m+[m
[32m+[m[32mstatic iText *activeText_;[m
static iBlock *userFont_;[m
[m
static void initFonts_Text_(iText *d) {[m
[36m@@ -501,8 +503,7 @@[m [mvoid loadUserFonts_Text(void) {[m
}[m
}[m
[m
[31m-void init_Text(SDL_Renderer *render) {[m
[31m- iText *d = &text_;[m
[32m+[m[32mvoid init_Text(iText *d, SDL_Renderer *render) {[m
loadUserFonts_Text();[m
d->contentFont = nunito_TextFont;[m
d->headingFont = nunito_TextFont;[m
[36m@@ -521,8 +522,7 @@[m [mvoid init_Text(SDL_Renderer *render) {[m
initFonts_Text_(d);[m
}[m
[m
[31m-void deinit_Text(void) {[m
[31m- iText *d = &text_;[m
[32m+[m[32mvoid deinit_Text(iText *d) {[m
SDL_FreePalette(d->grayscale);[m
deinitFonts_Text_(d);[m
deinitCache_Text_(d);[m
[36m@@ -530,30 +530,34 @@[m [mvoid deinit_Text(void) {[m
iRelease(d->ansiEscape);[m
}[m
[m
[32m+[m[32mvoid setCurrent_Text(iText *d) {[m
[32m+[m[32m activeText_ = d;[m
[32m+[m[32m}[m
[32m+[m
void setOpacity_Text(float opacity) {[m
[31m- SDL_SetTextureAlphaMod(text_.cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f);[m
[32m+[m[32m SDL_SetTextureAlphaMod(activeText_->cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f);[m
}[m
[m
[31m-void setContentFont_Text(enum iTextFont font) {[m
[31m- if (text_.contentFont != font) {[m
[31m- text_.contentFont = font;[m
[31m- resetFonts_Text();[m
[32m+[m[32mvoid setContentFont_Text(iText *d, enum iTextFont font) {[m
[32m+[m[32m if (d->contentFont != font) {[m
[32m+[m[32m d->contentFont = font;[m
[32m+[m[32m resetFonts_Text(d);[m
}[m
}[m
[m
[31m-void setHeadingFont_Text(enum iTextFont font) {[m
[31m- if (text_.headingFont != font) {[m
[31m- text_.headingFont = font;[m
[31m- resetFonts_Text();[m
[32m+[m[32mvoid setHeadingFont_Text(iText *d, enum iTextFont font) {[m
[32m+[m[32m if (d->headingFont != font) {[m
[32m+[m[32m d->headingFont = font;[m
[32m+[m[32m resetFonts_Text(d);[m
}[m
}[m
[m
[31m-void setContentFontSize_Text(float fontSizeFactor) {[m
[32m+[m[32mvoid setContentFontSize_Text(iText *d, float fontSizeFactor) {[m
fontSizeFactor *= contentScale_Text_;[m
iAssert(fontSizeFactor > 0);[m
[31m- if (iAbs(text_.contentFontSize - fontSizeFactor) > 0.001f) {[m
[31m- text_.contentFontSize = fontSizeFactor;[m
[31m- resetFonts_Text();[m
[32m+[m[32m if (iAbs(d->contentFontSize - fontSizeFactor) > 0.001f) {[m
[32m+[m[32m d->contentFontSize = fontSizeFactor;[m
[32m+[m[32m resetFonts_Text(d);[m
}[m
}[m
[m
[36m@@ -565,8 +569,7 @@[m [mstatic void resetCache_Text_(iText *d) {[m
initCache_Text_(d);[m
}[m
[m
[31m-void resetFonts_Text(void) {[m
[31m- iText *d = &text_;[m
[32m+[m[32mvoid resetFonts_Text(iText *d) {[m
deinitFonts_Text_(d);[m
deinitCache_Text_(d);[m
initCache_Text_(d);[m
[36m@@ -574,7 +577,7 @@[m [mvoid resetFonts_Text(void) {[m
}[m
[m
iLocalDef iFont *font_Text_(enum iFontId id) {[m
[31m- return &text_.fonts[id & mask_FontId];[m
[32m+[m[32m return &activeText_->fonts[id & mask_FontId];[m
}[m
[m
static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, float xShift) {[m
[36m@@ -584,7 +587,7 @@[m [mstatic SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, fl[m
SDL_Surface *surface8 =[m
SDL_CreateRGBSurfaceWithFormatFrom(bmp, w, h, 8, w, SDL_PIXELFORMAT_INDEX8);[m
SDL_SetSurfaceBlendMode(surface8, SDL_BLENDMODE_NONE);[m
[31m- SDL_SetSurfacePalette(surface8, text_.grayscale);[m
[32m+[m[32m SDL_SetSurfacePalette(surface8, activeText_->grayscale);[m
#if LAGRANGE_RASTER_DEPTH != 8[m
/* Convert to the cache format. */[m
SDL_Surface *surf = SDL_ConvertSurfaceFormat(surface8, LAGRANGE_RASTER_FORMAT, 0);[m
[36m@@ -631,7 +634,7 @@[m [mstatic void allocate_Font_(iFont *d, iGlyph *glyph, int hoff) {[m
&d->font, index_Glyph_(glyph), d->xScale, d->yScale, hoff * 0.5f, 0.0f, &x0, &y0, &x1, &y1);[m
glRect->size = init_I2(x1 - x0, y1 - y0);[m
/* Determine placement in the glyph cache texture, advancing in rows. */[m
[31m- glRect->pos = assignCachePos_Text_(&text_, glRect->size);[m
[32m+[m[32m glRect->pos = assignCachePos_Text_(activeText_, glRect->size);[m
glyph->d[hoff] = init_I2(x0, y0);[m
glyph->d[hoff].y += d->vertOffset;[m
if (hoff == 0) { /* hoff==1 uses same metrics as `glyph` */[m
[36m@@ -737,11 +740,11 @@[m [mstatic iGlyph *glyphByIndex_Font_(iFont *d, uint32_t glyphIndex) {[m
}[m
else {[m
/* If the cache is running out of space, clear it and we'll recache what's needed currently. */[m
[31m- if (text_.cacheBottom > text_.cacheSize.y - maxGlyphHeight_Text_(&text_)) {[m
[32m+[m[32m if (activeText_->cacheBottom > activeText_->cacheSize.y - maxGlyphHeight_Text_(activeText_)) {[m
#if !defined (NDEBUG)[m
printf("[Text] glyph cache is full, clearing!\n"); fflush(stdout);[m
#endif[m
[31m- resetCache_Text_(&text_);[m
[32m+[m[32m resetCache_Text_(activeText_);[m
}[m
glyph = new_Glyph(glyphIndex);[m
glyph->font = d;[m
[36m@@ -858,7 +861,7 @@[m [mstatic void finishRun_AttributedText_(iAttributedText *d, iAttributedRun *run, i[m
}[m
[m
static enum iFontId fontId_Text_(const iFont *font) {[m
[31m- return (enum iFontId) (font - text_.fonts);[m
[32m+[m[32m return (enum iFontId) (font - activeText_->fonts);[m
}[m
[m
static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iChar overrideChar) {[m
[36m@@ -949,7 +952,7 @@[m [mstatic void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh[m
/* Do a regexp match in the source text. */[m
iRegExpMatch m;[m
init_RegExpMatch(&m);[m
[31m- if (match_RegExp(text_.ansiEscape, srcPos, d->source.end - srcPos, &m)) {[m
[32m+[m[32m if (match_RegExp(activeText_->ansiEscape, srcPos, d->source.end - srcPos, &m)) {[m
finishRun_AttributedText_(d, &run, pos - 1);[m
run.fgColor = ansiForeground_Color(capturedRange_RegExpMatch(&m, 1),[m
tmParagraph_ColorId);[m
[36m@@ -1082,9 +1085,9 @@[m [mstatic void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) {[m
while (index < size_Array(glyphIndices)) {[m
for (; index < size_Array(glyphIndices); index++) {[m
const uint32_t glyphIndex = constValue_Array(glyphIndices, index, uint32_t);[m
[31m- const int lastCacheBottom = text_.cacheBottom;[m
[32m+[m[32m const int lastCacheBottom = activeText_->cacheBottom;[m
iGlyph *glyph = glyphByIndex_Font_(d, glyphIndex);[m
[31m- if (text_.cacheBottom < lastCacheBottom) {[m
[32m+[m[32m if (activeText_->cacheBottom < lastCacheBottom) {[m
/* The cache was reset due to running out of space. We need to restart from[m
the beginning! */[m
bufX = 0;[m
[36m@@ -1103,7 +1106,7 @@[m [mstatic void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) {[m
LAGRANGE_RASTER_DEPTH,[m
LAGRANGE_RASTER_FORMAT);[m
SDL_SetSurfaceBlendMode(buf, SDL_BLENDMODE_NONE);[m
[31m- SDL_SetSurfacePalette(buf, text_.grayscale);[m
[32m+[m[32m SDL_SetSurfacePalette(buf, activeText_->grayscale);[m
}[m
SDL_Surface *surfaces[2] = {[m
!isRasterized_Glyph_(glyph, 0) ?[m
[36m@@ -1147,19 +1150,19 @@[m [mstatic void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) {[m
}[m
/* Finished or the buffer is full, copy the glyphs to the cache texture. */[m
if (!isEmpty_Array(rasters)) {[m
[31m- SDL_Texture *bufTex = SDL_CreateTextureFromSurface(text_.render, buf);[m
[32m+[m[32m SDL_Texture *bufTex = SDL_CreateTextureFromSurface(activeText_->render, buf);[m
SDL_SetTextureBlendMode(bufTex, SDL_BLENDMODE_NONE);[m
if (!isTargetChanged) {[m
isTargetChanged = iTrue;[m
[31m- oldTarget = SDL_GetRenderTarget(text_.render);[m
[31m- SDL_SetRenderTarget(text_.render, text_.cache);[m
[32m+[m[32m oldTarget = SDL_GetRenderTarget(activeText_->render);[m
[32m+[m[32m SDL_SetRenderTarget(activeText_->render, activeText_->cache);[m
}[m
// printf("copying %zu rasters from %p\n", size_Array(rasters), bufTex); fflush(stdout);[m
iConstForEach(Array, i, rasters) {[m
const iRasterGlyph *rg = i.value;[m
// iAssert(isEqual_I2(rg->rect.size, rg->glyph->rect[rg->hoff].size));[m
const iRect *glRect = &rg->glyph->rect[rg->hoff];[m
[31m- SDL_RenderCopy(text_.render,[m
[32m+[m[32m SDL_RenderCopy(activeText_->render,[m
bufTex,[m
(const SDL_Rect *) &rg->rect,[m
(const SDL_Rect *) glRect);[m
[36m@@ -1179,7 +1182,7 @@[m [mstatic void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) {[m
SDL_FreeSurface(buf);[m
}[m
if (isTargetChanged) {[m
[31m- SDL_SetRenderTarget(text_.render, oldTarget);[m
[32m+[m[32m SDL_SetRenderTarget(activeText_->render, oldTarget);[m
}[m
}[m
[m
[36m@@ -1706,9 +1709,9 @@[m [mstatic iRect run_Font_(iFont *d, const iRunArgs *args) {[m
}[m
if (~mode & permanentColorFlag_RunMode) {[m
const iColor clr = run->fgColor;[m
[31m- SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b);[m
[32m+[m[32m SDL_SetTextureColorMod(activeText_->cache, clr.r, clr.g, clr.b);[m
if (args->mode & fillBackground_RunMode) {[m
[31m- SDL_SetRenderDrawColor(text_.render, clr.r, clr.g, clr.b, 0);[m
[32m+[m[32m SDL_SetRenderDrawColor(activeText_->render, clr.r, clr.g, clr.b, 0);[m
}[m
}[m
SDL_Rect src;[m
[36m@@ -1719,9 +1722,9 @@[m [mstatic iRect run_Font_(iFont *d, const iRunArgs *args) {[m
/* Alpha blending looks much better if the RGB components don't change in[m
the partially transparent pixels. */[m
/* TODO: Backgrounds of all glyphs should be cleared before drawing anything else. */[m
[31m- SDL_RenderFillRect(text_.render, &dst);[m
[32m+[m[32m SDL_RenderFillRect(activeText_->render, &dst);[m
}[m
[31m- SDL_RenderCopy(text_.render, text_.cache, &src, &dst);[m
[32m+[m[32m SDL_RenderCopy(activeText_->render, activeText_->cache, &src, &dst);[m
#if 0[m
/* Show spaces and direction. */[m
if (logicalText[logPos] == 0x20) {[m
[36m@@ -1863,7 +1866,7 @@[m [miTextMetrics measureN_Text(int fontId, const char *text, size_t n) {[m
}[m
[m
static void drawBoundedN_Text_(int fontId, iInt2 pos, int xposBound, int color, iRangecc text, size_t maxLen) {[m
[31m- iText * d = &text_;[m
[32m+[m[32m iText * d = activeText_;[m
iFont * font = font_Text_(fontId);[m
const iColor clr = get_Color(color & mask_ColorId);[m
SDL_SetTextureColorMod(d->cache, clr.r, clr.g, clr.b);[m
[36m@@ -2057,7 +2060,7 @@[m [miTextMetrics draw_WrapText(iWrapText *d, int fontId, iInt2 pos, int color) {[m
}[m
[m
SDL_Texture *glyphCache_Text(void) {[m
[31m- return text_.cache;[m
[32m+[m[32m return activeText_->cache;[m
}[m
[m
static void freeBitmap_(void *ptr) {[m
[36m@@ -2170,7 +2173,7 @@[m [miString *renderBlockChars_Text(const iBlock *fontData, int height, enum iTextBlo[m
iDefineTypeConstructionArgs(TextBuf, (iWrapText *wrapText, int font, int color), wrapText, font, color)[m
[m
void init_TextBuf(iTextBuf *d, iWrapText *wrapText, int font, int color) {[m
[31m- SDL_Renderer *render = text_.render;[m
[32m+[m[32m SDL_Renderer *render = activeText_->render;[m
d->size = measure_WrapText(wrapText, font).bounds.size;[m
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");[m
if (d->size.x * d->size.y) {[m
[36m@@ -2191,9 +2194,9 @@[m [mvoid init_TextBuf(iTextBuf *d, iWrapText *wrapText, int font, int color) {[m
SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE);[m
SDL_SetRenderDrawColor(render, 255, 255, 255, 0);[m
SDL_RenderClear(render);[m
[31m- SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_NONE); /* blended when TextBuf is drawn */[m
[32m+[m[32m SDL_SetTextureBlendMode(activeText_->cache, SDL_BLENDMODE_NONE); /* blended when TextBuf is drawn */[m
draw_WrapText(wrapText, font, zero_I2(), color | fillBackground_ColorId);[m
[31m- SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_BLEND);[m
[32m+[m[32m SDL_SetTextureBlendMode(activeText_->cache, SDL_BLENDMODE_BLEND);[m
SDL_SetRenderTarget(render, oldTarget);[m
origin_Paint = oldOrigin;[m
SDL_SetTextureBlendMode(d->texture, SDL_BLENDMODE_BLEND);[m
[36m@@ -2212,7 +2215,7 @@[m [mvoid draw_TextBuf(const iTextBuf *d, iInt2 pos, int color) {[m
addv_I2(&pos, origin_Paint);[m
const iColor clr = get_Color(color);[m
SDL_SetTextureColorMod(d->texture, clr.r, clr.g, clr.b);[m
[31m- SDL_RenderCopy(text_.render,[m
[32m+[m[32m SDL_RenderCopy(activeText_->render,[m
d->texture,[m
&(SDL_Rect){ 0, 0, d->size.x, d->size.y },[m
&(SDL_Rect){ pos.x, pos.y, d->size.x, d->size.y });[m
[1mdiff --git a/src/ui/text.h b/src/ui/text.h[m
[1mindex ac6cc1c1..1da43818 100644[m
[1m--- a/src/ui/text.h[m
[1m+++ b/src/ui/text.h[m
[36m@@ -139,15 +139,20 @@[m [menum iTextFont {[m
[m
extern int gap_Text; /* affected by content font size */[m
[m
[31m-void init_Text (SDL_Renderer *);[m
[31m-void deinit_Text (void);[m
[32m+[m[32miDeclareType(Text)[m
[32m+[m[32miDeclareTypeConstructionArgs(Text, SDL_Renderer *)[m
[32m+[m
[32m+[m[32mvoid init_Text (iText *, SDL_Renderer *);[m
[32m+[m[32mvoid deinit_Text (iText *);[m
[32m+[m
[32m+[m[32mvoid setCurrent_Text (iText *);[m
[m
void loadUserFonts_Text (void); /* based on Prefs */[m
[m
[31m-void setContentFont_Text (enum iTextFont font);[m
[31m-void setHeadingFont_Text (enum iTextFont font);[m
[31m-void setContentFontSize_Text (float fontSizeFactor); /* affects all except default*
fonts */[m
[31m-void resetFonts_Text (void);[m
[32m+[m[32mvoid setContentFont_Text (iText *, enum iTextFont font);[m
[32m+[m[32mvoid setHeadingFont_Text (iText *, enum iTextFont font);[m
[32m+[m[32mvoid setContentFontSize_Text (iText , float fontSizeFactor); / affects all except default*
fonts */[m
[32m+[m[32mvoid resetFonts_Text (iText *);[m
[m
int lineHeight_Text (int fontId);[m
iRect visualBounds_Text (int fontId, iRangecc text);[m
[1mdiff --git a/src/ui/text_simple.c b/src/ui/text_simple.c[m
[1mindex bf33b4be..8b1de64a 100644[m
[1m--- a/src/ui/text_simple.c[m
[1m+++ b/src/ui/text_simple.c[m
[36m@@ -92,7 +92,7 @@[m [mstatic iRect runSimple_Font_(iFont *d, const iRunArgs *args) {[m
}[m
if (args->mode & fillBackground_RunMode) {[m
const iColor initial = get_Color(args->color);[m
[31m- SDL_SetRenderDrawColor(text_.render, initial.r, initial.g, initial.b, 0);[m
[32m+[m[32m SDL_SetRenderDrawColor(activeText_->render, initial.r, initial.g, initial.b, 0);[m
}[m
/* Text rendering is not very straightforward! Let's dive in... */[m
iChar prevCh = 0;[m
[36m@@ -114,14 +114,14 @@[m [mstatic iRect runSimple_Font_(iFont *d, const iRunArgs *args) {[m
chPos++;[m
iRegExpMatch m;[m
init_RegExpMatch(&m);[m
[31m- if (match_RegExp(text_.ansiEscape, chPos, args->text.end - chPos, &m)) {[m
[32m+[m[32m if (match_RegExp(activeText_->ansiEscape, chPos, args->text.end - chPos, &m)) {[m
if (mode & draw_RunMode && ~mode & permanentColorFlag_RunMode) {[m
/* Change the color. */[m
const iColor clr =[m
ansiForeground_Color(capturedRange_RegExpMatch(&m, 1), tmParagraph_ColorId);[m
[31m- SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b);[m
[32m+[m[32m SDL_SetTextureColorMod(activeText_->cache, clr.r, clr.g, clr.b);[m
if (args->mode & fillBackground_RunMode) {[m
[31m- SDL_SetRenderDrawColor(text_.render, clr.r, clr.g, clr.b, 0);[m
[32m+[m[32m SDL_SetRenderDrawColor(activeText_->render, clr.r, clr.g, clr.b, 0);[m
}[m
}[m
chPos = end_RegExpMatch(&m);[m
[36m@@ -205,9 +205,9 @@[m [mstatic iRect runSimple_Font_(iFont *d, const iRunArgs *args) {[m
}[m
if (mode & draw_RunMode && ~mode & permanentColorFlag_RunMode) {[m
const iColor clr = get_Color(colorNum);[m
[31m- SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b);[m
[32m+[m[32m SDL_SetTextureColorMod(activeText_->cache, clr.r, clr.g, clr.b);[m
if (args->mode & fillBackground_RunMode) {[m
[31m- SDL_SetRenderDrawColor(text_.render, clr.r, clr.g, clr.b, 0);[m
[32m+[m[32m SDL_SetRenderDrawColor(activeText_->render, clr.r, clr.g, clr.b, 0);[m
}[m
}[m
prevCh = 0;[m
[36m@@ -311,9 +311,9 @@[m [mstatic iRect runSimple_Font_(iFont *d, const iRunArgs *args) {[m
if (args->mode & fillBackground_RunMode) {[m
/* Alpha blending looks much better if the RGB components don't change in[m
the partially transparent pixels. */[m
[31m- SDL_RenderFillRect(text_.render, &dst);[m
[32m+[m[32m SDL_RenderFillRect(activeText_->render, &dst);[m
}[m
[31m- SDL_RenderCopy(text_.render, text_.cache, &src, &dst);[m
[32m+[m[32m SDL_RenderCopy(activeText_->render, activeText_->cache, &src, &dst);[m
}[m
xpos += advance;[m
if (!isSpace_Char(ch)) {[m
[1mdiff --git a/src/ui/util.c b/src/ui/util.c[m
[1mindex 721aed2d..38977b96 100644[m
[1m--- a/src/ui/util.c[m
[1m+++ b/src/ui/util.c[m
[36m@@ -613,6 +613,8 @@[m [miBool isAction_Widget(const iWidget *d) {[m
/-----------------------------------------------------------------------------------------------/[m
[m
static iBool isCommandIgnoredByMenus_(const char *cmd) {[m
[32m+[m[32m if (equal_Command(cmd, "window.focus.lost") ||[m
[32m+[m[32m equal_Command(cmd, "window.focus.gained")) return iTrue;[m
/* TODO: Perhaps a common way of indicating which commands are notifications and should not[m
be reacted to by menus? */[m
return equal_Command(cmd, "media.updated") ||[m
[36m@@ -810,6 +812,10 @@[m [mstatic void updateMenuItemFonts_Widget_(iWidget *d) {[m
}[m
}[m
[m
[32m+[m[32miLocalDef iBool isUsingMenuPopupWindows_(void) {[m
[32m+[m[32m return deviceType_App() == desktop_AppDeviceType;[m
[32m+[m[32m}[m
[32m+[m
void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) {[m
const iRect rootRect = rect_Root(d->root);[m
const iInt2 rootSize = rootRect.size;[m
[36m@@ -822,6 +828,26 @@[m [mvoid openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) {[m
processEvents_App(postedEventsOnly_AppEventMode);[m
setFlags_Widget(d, hidden_WidgetFlag, iFalse);[m
setFlags_Widget(d, commandOnMouseMiss_WidgetFlag, iTrue);[m
[32m+[m[32m if (isUsingMenuPopupWindows_()) {[m
[32m+[m[32m if (postCommands) {[m
[32m+[m[32m postCommand_Widget(d, "menu.opened");[m
[32m+[m[32m }[m
[32m+[m[32m updateMenuItemFonts_Widget_(d);[m
[32m+[m[32m iRoot *oldRoot = current_Root();[m
[32m+[m[32m setFlags_Widget(d, keepOnTop_WidgetFlag, iFalse);[m
[32m+[m[32m setUserData_Object(d, parent_Widget(d));[m
[32m+[m[32m removeChild_Widget(parent_Widget(d), d); /* we'll borrow the widget for a while */[m
[32m+[m[32m iInt2 mousePos;[m
[32m+[m[32m SDL_GetGlobalMouseState(&mousePos.x, &mousePos.y);[m
[32m+[m[32m iWindow *win = newPopup_Window(sub_I2(mousePos, divi_I2(gap2_UI, 2)), d);[m
[32m+[m[32m SDL_SetWindowTitle(win->win, "Menu");[m
[32m+[m[32m addPopup_App(win); /* window takes the widget */[m
[32m+[m[32m SDL_ShowWindow(win->win);[m
[32m+[m[32m draw_Window(win);[m
[32m+[m[32m setCurrent_Window(mainWindow_App());[m
[32m+[m[32m setCurrent_Root(oldRoot);[m
[32m+[m[32m return;[m
[32m+[m[32m }[m
raise_Widget(d);[m
setFlags_Widget(findChild_Widget(d, "menu.cancel"), disabled_WidgetFlag, iFalse);[m
if (isPortraitPhone) {[m
[36m@@ -836,7 +862,7 @@[m [mvoid openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) {[m
arrange_Widget(d);[m
if (isPortraitPhone) {[m
if (isSlidePanel) {[m
[31m- d->rect.pos = zero_I2(); //neg_I2(bounds_Widget(parent_Widget(d)).pos);[m
[32m+[m[32m d->rect.pos = zero_I2();[m
}[m
else {[m
d->rect.pos = init_I2(0, rootSize.y);[m
[36m@@ -856,7 +882,7 @@[m [mvoid openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) {[m
float l, t, r, b;[m
safeAreaInsets_iOS(&l, &t, &r, &b);[m
topExcess += t;[m
[31m- bottomExcess += iMax(b, get_Window()->keyboardHeight);[m
[32m+[m[32m bottomExcess += iMax(b, get_MainWindow()->keyboardHeight);[m
leftExcess += l;[m
rightExcess += r;[m
}[m
[36m@@ -884,6 +910,18 @@[m [mvoid closeMenu_Widget(iWidget *d) {[m
if (d == NULL || flags_Widget(d) & hidden_WidgetFlag) {[m
return; /* Already closed. */[m
}[m
[32m+[m[32m if (isUsingMenuPopupWindows_()) {[m
[32m+[m[32m iWindow *win = window_Widget(d);[m
[32m+[m[32m iAssert(type_Window(win) == popup_WindowType);[m
[32m+[m[32m iWidget *originalParent = userData_Object(d);[m
[32m+[m[32m setUserData_Object(d, NULL);[m
[32m+[m[32m win->roots[0]->widget = NULL;[m
[32m+[m[32m setRoot_Widget(d, originalParent->root);[m
[32m+[m[32m addChild_Widget(originalParent, d);[m
[32m+[m[32m setFlags_Widget(d, keepOnTop_WidgetFlag, iTrue);[m
[32m+[m[32m SDL_HideWindow(win->win);[m
[32m+[m[32m collect_Garbage(win, (iDeleteFunc) delete_Window); /* get rid of it after event processing */[m
[32m+[m[32m }[m
setFlags_Widget(d, hidden_WidgetFlag, iTrue);[m
setFlags_Widget(findChild_Widget(d, "menu.cancel"), disabled_WidgetFlag, iTrue);[m
postRefresh_App();[m
[1mdiff --git a/src/ui/widget.c b/src/ui/widget.c[m
[1mindex 23c19315..7b33a752 100644[m
[1m--- a/src/ui/widget.c[m
[1m+++ b/src/ui/widget.c[m
[36m@@ -271,6 +271,10 @@[m [miWidget *root_Widget(const iWidget *d) {[m
return d ? d->root->widget : NULL;[m
}[m
[m
[32m+[m[32miWindow *window_Widget(const iAnyObject *d) {[m
[32m+[m[32m return constAs_Widget(d)->root->window;[m
[32m+[m[32m}[m
[32m+[m
void showCollapsed_Widget(iWidget *d, iBool show) {[m
const iBool isVisible = !(d->flags & hidden_WidgetFlag);[m
if ((isVisible && !show) || (!isVisible && show)) {[m
[36m@@ -979,11 +983,10 @@[m [mvoid unhover_Widget(void) {[m
}[m
[m
iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {[m
[31m- //iAssert(d->root == get_Root());[m
if (!d->parent) {[m
[31m- if (get_Window()->focus && get_Window()->focus->root == d->root && isKeyboardEvent_(ev)) {[m
[32m+[m[32m if (window_Widget(d)->focus && window_Widget(d)->focus->root == d->root && isKeyboardEvent_(ev)) {[m
/* Root dispatches keyboard events directly to the focused widget. */[m
[31m- if (dispatchEvent_Widget(get_Window()->focus, ev)) {[m
[32m+[m[32m if (dispatchEvent_Widget(window_Widget(d)->focus, ev)) {[m
return iTrue;[m
}[m
}[m
[36m@@ -1012,7 +1015,8 @@[m [miBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {[m
}[m
}[m
else if (ev->type == SDL_MOUSEMOTION &&[m
[31m- (!get_Window()->hover || hasParent_Widget(d, get_Window()->hover)) &&[m
[32m+[m[32m ev->motion.windowID == SDL_GetWindowID(window_Widget(d)->win) &&[m
[32m+[m[32m (!window_Widget(d)->hover || hasParent_Widget(d, window_Widget(d)->hover)) &&[m
flags_Widget(d) & hover_WidgetFlag && ~flags_Widget(d) & hidden_WidgetFlag &&[m
~flags_Widget(d) & disabled_WidgetFlag) {[m
if (contains_Widget(d, init_I2(ev->motion.x, ev->motion.y))) {[m
[36m@@ -1031,11 +1035,11 @@[m [miBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {[m
iReverseForEach(ObjectList, i, d->children) {[m
iWidget *child = as_Widget(i.object);[m
//iAssert(child->root == d->root);[m
[31m- if (child == get_Window()->focus && isKeyboardEvent_(ev)) {[m
[32m+[m[32m if (child == window_Widget(d)->focus && isKeyboardEvent_(ev)) {[m
continue; /* Already dispatched. */[m
}[m
if (isVisible_Widget(child) && child->flags & keepOnTop_WidgetFlag) {[m
[31m- /* Already dispatched. */[m
[32m+[m[32m /* Already dispatched. */[m
continue;[m
}[m
if (dispatchEvent_Widget(child, ev)) {[m
[36m@@ -1050,7 +1054,7 @@[m [miBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {[m
#endif[m
#if 0[m
if (ev->type == SDL_MOUSEMOTION) {[m
[31m- printf("[%p] %s:'%s' (on top) ate the motion\n",[m
[32m+[m[32m printf("[%p] %s:'%s' ate the motion\n",[m
child, class_Widget(child)->name,[m
cstr_String(id_Widget(child)));[m
fflush(stdout);[m
[36m@@ -1246,7 +1250,7 @@[m [miBool processEvent_Widget(iWidget *d, const SDL_Event *ev) {[m
ev->button.x,[m
ev->button.y);[m
}[m
[31m- setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW);[m
[32m+[m[32m setCursor_Window(window_Widget(d), SDL_SYSTEM_CURSOR_ARROW);[m
return iTrue;[m
}[m
return iFalse;[m
[36m@@ -1270,6 +1274,7 @@[m [miLocalDef iBool isDrawn_Widget_(const iWidget *d) {[m
void drawLayerEffects_Widget(const iWidget *d) {[m
/* Layered effects are not buffered, so they are drawn here separately. */[m
iAssert(isDrawn_Widget_(d));[m
[32m+[m[32m iAssert(window_Widget(d) == get_Window());[m
iBool shadowBorder = (d->flags & keepOnTop_WidgetFlag && ~d->flags & mouseModal_WidgetFlag) != 0;[m
iBool fadeBackground = (d->bgColor >= 0 || d->frameColor >= 0) && d->flags & mouseModal_WidgetFlag;[m
if (deviceType_App() == phone_AppDeviceType) {[m
[36m@@ -1539,6 +1544,7 @@[m [mstatic void endBufferDraw_Widget_(const iWidget *d) {[m
}[m
[m
void draw_Widget(const iWidget *d) {[m
[32m+[m[32m iAssert(window_Widget(d) == get_Window());[m
if (!isDrawn_Widget_(d)) {[m
if (d->drawBuf) {[m
// printf("[%p] drawBuffer released\n", d);[m
[36m@@ -1820,7 +1826,17 @@[m [miBool equalWidget_Command(const char *cmd, const iWidget *widget, const char *ch[m
if (equal_Command(cmd, checkCommand)) {[m
const iWidget *src = pointer_Command(cmd);[m
iAssert(!src || strstr(cmd, " ptr:"));[m
[31m- return src == widget || hasParent_Widget(src, widget);[m
[32m+[m[32m if (src == widget || hasParent_Widget(src, widget)) {[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m }[m
[32m+[m[32m// if (src && type_Window(window_Widget(src)) == popup_WindowType) {[m
[32m+[m[32m// /* Special case: command was emitted from a popup widget. The popup root widget actually[m
[32m+[m[32m// belongs to someone else. */[m
[32m+[m[32m// iWidget *realParent = userData_Object(src->root->widget);[m
[32m+[m[32m// iAssert(realParent);[m
[32m+[m[32m// iAssert(isInstance_Object(realParent, &Class_Widget));[m
[32m+[m[32m// return realParent == widget || hasParent_Widget(realParent, widget);[m
[32m+[m[32m// }[m
}[m
return iFalse;[m
}[m
[36m@@ -1962,6 +1978,10 @@[m [mvoid postCommand_Widget(const iAnyObject *d, const char *cmd, ...) {[m
}[m
if (!isGlobal) {[m
iAssert(isInstance_Object(d, &Class_Widget));[m
[32m+[m[32m if (type_Window(window_Widget(d)) == popup_WindowType) {[m
[32m+[m[32m postCommandf_Root(((const iWidget *) d)->root, "cancel popup:1 ptr:%p", d);[m
[32m+[m[32m d = userData_Object(root_Widget(d));[m
[32m+[m[32m }[m
appendFormat_String(&str, " ptr:%p", d);[m
}[m
postCommandString_Root(((const iWidget *) d)->root, &str);[m
[1mdiff --git a/src/ui/widget.h b/src/ui/widget.h[m
[1mindex 7491cb79..0eab69c1 100644[m
[1m--- a/src/ui/widget.h[m
[1m+++ b/src/ui/widget.h[m
[36m@@ -34,7 +34,8 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
#include <the_Foundation/string.h>[m
#include <SDL_events.h>[m
[m
[31m-iDeclareType(Root) /* each widget is associated with a Root */[m
[32m+[m[32miDeclareType(Root) /* each widget is associated with a Root */[m
[32m+[m[32miDeclareType(Window) /* each Root is inside a Window */[m
[m
#define iDeclareWidgetClass(className) \[m
iDeclareType(className); \[m
[36m@@ -185,6 +186,7 @@[m [mvoid releaseChildren_Widget (iWidget *);[m
- inner: 0,0 is at the top left corner of the widget */[m
[m
iWidget * root_Widget (const iWidget *);[m
[32m+[m[32miWindow * window_Widget (const iAnyObject *);[m
const iString * id_Widget (const iWidget *);[m
int64_t flags_Widget (const iWidget *);[m
iRect bounds_Widget (const iWidget ); / outer bounds */[m
[1mdiff --git a/src/ui/window.c b/src/ui/window.c[m
[1mindex 92125d81..e9a34ace 100644[m
[1m--- a/src/ui/window.c[m
[1m+++ b/src/ui/window.c[m
[36m@@ -57,7 +57,8 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
#include "stb_image.h"[m
#include "stb_image_resize.h"[m
[m
[31m-static iWindow *theWindow_ = NULL;[m
[32m+[m[32mstatic iWindow * theWindow_;[m
[32m+[m[32mstatic iMainWindow *theMainWindow_;[m
[m
#if defined (iPlatformApple) || defined (iPlatformLinux) || defined (iPlatformOther)[m
static float initialUiScale_ = 1.0f;[m
[36m@@ -67,6 +68,9 @@[m [mstatic float initialUiScale_ = 1.1f;[m
[m
static iBool isOpenGLRenderer_;[m
[m
[32m+[m[32miDefineTypeConstructionArgs(Window,[m
[32m+[m[32m (enum iWindowType type, iRect rect, uint32_t flags),[m
[32m+[m[32m type, rect, flags)[m
iDefineTypeConstructionArgs(MainWindow, (iRect rect), rect)[m
[m
/* TODO: Define menus per platform. */[m
[36m@@ -205,6 +209,7 @@[m [mstatic void setupUserInterface_MainWindow(iMainWindow *d) {[m
#endif[m
/* One root is created by default. */[m
d->base.roots[0] = new_Root();[m
[32m+[m[32m d->base.roots[0]->window = as_Window(d);[m
setCurrent_Root(d->base.roots[0]);[m
createUserInterface_Root(d->base.roots[0]);[m
setCurrent_Root(NULL);[m
[36m@@ -409,7 +414,6 @@[m [mvoid init_Window(iWindow *d, enum iWindowType type, iRect rect, uint32_t flags)[m
d->mouseGrab = NULL;[m
d->focus = NULL;[m
d->pendingCursor = NULL;[m
[31m- d->isDrawFrozen = iTrue;[m
d->isExposed = iFalse;[m
d->isMinimized = iFalse;[m
d->isInvalidated = iFalse; /* set when posting event, to avoid repeated events */[m
[36m@@ -441,9 +445,27 @@[m [mvoid init_Window(iWindow *d, enum iWindowType type, iRect rect, uint32_t flags)[m
d->uiScale = initialUiScale_;[m
/* TODO: Ratios, scales, and metrics must be window-specific, not global. */[m
setScale_Metrics(d->pixelRatio * d->displayScale * d->uiScale);[m
[32m+[m[32m d->text = new_Text(d->render);[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mstatic void deinitRoots_Window_(iWindow *d) {[m
[32m+[m[32m iRecycle();[m
[32m+[m[32m iForIndices(i, d->roots) {[m
[32m+[m[32m if (d->roots[i]) {[m
[32m+[m[32m setCurrent_Root(d->roots[i]);[m
[32m+[m[32m delete_Root(d->roots[i]);[m
[32m+[m[32m d->roots[i] = NULL;[m
[32m+[m[32m }[m
[32m+[m[32m }[m
[32m+[m[32m setCurrent_Root(NULL);[m
}[m
[m
void deinit_Window(iWindow *d) {[m
[32m+[m[32m if (d->type == popup_WindowType) {[m
[32m+[m[32m removePopup_App(d);[m
[32m+[m[32m }[m
[32m+[m[32m deinitRoots_Window_(d);[m
[32m+[m[32m delete_Text(d->text);[m
SDL_DestroyRenderer(d->render);[m
SDL_DestroyWindow(d->win);[m
iForIndices(i, d->cursors) {[m
[36m@@ -455,6 +477,7 @@[m [mvoid deinit_Window(iWindow *d) {[m
[m
void init_MainWindow(iMainWindow *d, iRect rect) {[m
theWindow_ = &d->base;[m
[32m+[m[32m theMainWindow_ = d;[m
uint32_t flags = 0;[m
#if defined (iPlatformAppleDesktop)[m
SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl");[m
[36m@@ -465,13 +488,15 @@[m [mvoid init_MainWindow(iMainWindow *d, iRect rect) {[m
#endif[m
SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");[m
init_Window(&d->base, main_WindowType, rect, flags);[m
[31m- d->splitMode = d->pendingSplitMode = 0;[m
[31m- d->pendingSplitUrl = new_String();[m
[31m- d->place.initialPos = rect.pos;[m
[31m- d->place.normalRect = rect;[m
[32m+[m[32m d->isDrawFrozen = iTrue;[m
[32m+[m[32m d->splitMode = 0;[m
[32m+[m[32m d->pendingSplitMode = 0;[m
[32m+[m[32m d->pendingSplitUrl = new_String();[m
[32m+[m[32m d->place.initialPos = rect.pos;[m
[32m+[m[32m d->place.normalRect = rect;[m
d->place.lastNotifiedSize = zero_I2();[m
[31m- d->place.snap = 0;[m
[31m- d->keyboardHeight = 0;[m
[32m+[m[32m d->place.snap = 0;[m
[32m+[m[32m d->keyboardHeight = 0;[m
#if defined(iPlatformMobile)[m
const iInt2 minSize = zero_I2(); /* windows aren't independently resizable */[m
#else[m
[36m@@ -510,9 +535,9 @@[m [mvoid init_MainWindow(iMainWindow *d, iRect rect) {[m
}[m
#endif[m
#if defined (iPlatformAppleMobile)[m
[31m- setupWindow_iOS(d);[m
[32m+[m[32m setupWindow_iOS(as_Window(d));[m
#endif[m
[31m- init_Text(d->base.render);[m
[32m+[m[32m setCurrent_Text(d->base.text);[m
SDL_GetRendererOutputSize(d->base.render, &d->base.size.x, &d->base.size.y); [m
setupUserInterface_MainWindow(d);[m
postCommand_App("~bindings.changed"); /* update from bindings */[m
[36m@@ -538,24 +563,15 @@[m [mvoid init_MainWindow(iMainWindow *d, iRect rect) {[m
#endif[m
}[m
[m
[31m-static void deinitRoots_Window_(iWindow *d) {[m
[31m- iRecycle();[m
[31m- iForIndices(i, d->roots) {[m
[31m- if (d->roots[i]) {[m
[31m- setCurrent_Root(d->roots[i]);[m
[31m- deinit_Root(d->roots[i]);[m
[31m- }[m
[31m- }[m
[31m- setCurrent_Root(NULL);[m
[31m-}[m
[31m-[m
void deinit_MainWindow(iMainWindow *d) {[m
deinitRoots_Window_(as_Window(d));[m
if (theWindow_ == as_Window(d)) {[m
theWindow_ = NULL;[m
}[m
[32m+[m[32m if (theMainWindow_ == d) {[m
[32m+[m[32m theMainWindow_ = NULL;[m
[32m+[m[32m }[m
delete_String(d->pendingSplitUrl);[m
[31m- deinit_Text();[m
deinit_Window(&d->base);[m
}[m
[m
[36m@@ -592,7 +608,7 @@[m [miRoot *otherRoot_Window(const iWindow *d, iRoot *root) {[m
static void invalidate_MainWindow_(iMainWindow *d, iBool forced) {[m
if (d && (!d->base.isInvalidated || forced)) {[m
d->base.isInvalidated = iTrue;[m
[31m- resetFonts_Text();[m
[32m+[m[32m resetFonts_Text(text_Window(d));[m
postCommand_App("theme.changed auto:1"); /* forces UI invalidation */[m
}[m
}[m
[36m@@ -607,7 +623,7 @@[m [mvoid invalidate_Window(iAnyWindow *d) {[m
}[m
[m
static iBool isNormalPlacement_MainWindow_(const iMainWindow *d) {[m
[31m- if (d->base.isDrawFrozen) return iFalse;[m
[32m+[m[32m if (d->isDrawFrozen) return iFalse;[m
#if defined (iPlatformApple)[m
/* Maximized mode is not special on macOS. */[m
if (snap_MainWindow(d) == maximized_WindowSnap) {[m
[36m@@ -655,7 +671,7 @@[m [mstatic iBool unsnap_MainWindow_(iMainWindow *d, const iInt2 *newPos) {[m
static void notifyMetricsChange_Window_(const iWindow *d) {[m
/* Dynamic UI metrics change. Widgets need to update themselves. */[m
setScale_Metrics(d->pixelRatio * d->displayScale * d->uiScale);[m
[31m- resetFonts_Text();[m
[32m+[m[32m resetFonts_Text(d->text);[m
postCommand_App("metrics.changed");[m
}[m
[m
[36m@@ -676,6 +692,41 @@[m [mstatic void checkPixelRatioChange_Window_(iWindow *d) {[m
}[m
}[m
[m
[32m+[m[32mstatic iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) {[m
[32m+[m[32m if (ev->windowID != SDL_GetWindowID(d->win)) {[m
[32m+[m[32m return iFalse;[m
[32m+[m[32m }[m
[32m+[m[32m switch (ev->event) {[m
[32m+[m[32m case SDL_WINDOWEVENT_EXPOSED:[m
[32m+[m[32m d->isExposed = iTrue;[m
[32m+[m[32m postRefresh_App();[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m case SDL_WINDOWEVENT_RESTORED:[m
[32m+[m[32m case SDL_WINDOWEVENT_SHOWN:[m
[32m+[m[32m postRefresh_App();[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m case SDL_WINDOWEVENT_FOCUS_LOST:[m
[32m+[m[32m /* Popup windows are currently only used for menus. */[m
[32m+[m[32m closeMenu_Widget(d->roots[0]->widget);[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m case SDL_WINDOWEVENT_LEAVE:[m
[32m+[m[32m unhover_Widget();[m
[32m+[m[32m d->isMouseInside = iFalse;[m
[32m+[m[32m //postCommand_App("window.mouse.exited");[m
[32m+[m[32m// SDL_SetWindowInputFocus(mainWindow_App()->base.win);[m
[32m+[m[32m printf("mouse leaves popup\n"); fflush(stdout);[m
[32m+[m[32m //SDL_RaiseWindow(mainWindow_App()->base.win);[m
[32m+[m[32m postRefresh_App();[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m case SDL_WINDOWEVENT_ENTER:[m
[32m+[m[32m d->isMouseInside = iTrue;[m
[32m+[m[32m //postCommand_App("window.mouse.entered");[m
[32m+[m[32m printf("mouse enters popup\n"); fflush(stdout);[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m }[m
[32m+[m[32m return iFalse;[m
[32m+[m[32m}[m
[32m+[m
static iBool handleWindowEvent_MainWindow_(iMainWindow *d, const SDL_WindowEvent *ev) {[m
switch (ev->event) {[m
#if defined(iPlatformDesktop)[m
[36m@@ -795,6 +846,7 @@[m [mstatic iBool handleWindowEvent_MainWindow_(iMainWindow *d, const SDL_WindowEvent[m
return iTrue;[m
case SDL_WINDOWEVENT_ENTER:[m
d->base.isMouseInside = iTrue;[m
[32m+[m[32m SDL_SetWindowInputFocus(d->base.win);[m
postCommand_App("window.mouse.entered");[m
return iTrue;[m
case SDL_WINDOWEVENT_FOCUS_GAINED:[m
[36m@@ -802,16 +854,16 @@[m [mstatic iBool handleWindowEvent_MainWindow_(iMainWindow *d, const SDL_WindowEvent[m
setCapsLockDown_Keys(iFalse);[m
postCommand_App("window.focus.gained");[m
d->base.isExposed = iTrue;[m
[31m-#if !defined(iPlatformDesktop)[m
[32m+[m[32m#if !defined (iPlatformDesktop)[m
/* Returned to foreground, may have lost buffered content. */[m
[31m- invalidate_Window_(d, iTrue);[m
[32m+[m[32m invalidate_MainWindow_(d, iTrue);[m
postCommand_App("window.unfreeze");[m
#endif[m
return iFalse;[m
case SDL_WINDOWEVENT_FOCUS_LOST:[m
postCommand_App("window.focus.lost");[m
[31m-#if !defined(iPlatformDesktop)[m
[31m- setFreezeDraw_Window(d, iTrue);[m
[32m+[m[32m#if !defined (iPlatformDesktop)[m
[32m+[m[32m setFreezeDraw_MainWindow(d, iTrue);[m
#endif[m
return iFalse;[m
case SDL_WINDOWEVENT_TAKE_FOCUS:[m
[36m@@ -831,8 +883,8 @@[m [mstatic void applyCursor_Window_(iWindow *d) {[m
}[m
}[m
[m
[31m-iBool processEvent_MainWindow(iMainWindow *d, const SDL_Event *ev) {[m
[31m- iWindow *w = as_Window(d);[m
[32m+[m[32miBool processEvent_Window(iWindow *d, const SDL_Event *ev) {[m
[32m+[m[32m iMainWindow *mw = (type_Window(d) == main_WindowType ? as_MainWindow(d) : NULL);[m
switch (ev->type) {[m
#if defined (LAGRANGE_ENABLE_CUSTOM_FRAME)[m
case SDL_SYSWMEVENT: {[m
[36m@@ -845,19 +897,26 @@[m [miBool processEvent_MainWindow(iMainWindow *d, const SDL_Event *ev) {[m
}[m
#endif[m
case SDL_WINDOWEVENT: {[m
[31m- return handleWindowEvent_MainWindow_(d, &ev->window);[m
[32m+[m[32m if (mw) {[m
[32m+[m[32m return handleWindowEvent_MainWindow_(mw, &ev->window);[m
[32m+[m[32m }[m
[32m+[m[32m else {[m
[32m+[m[32m return handleWindowEvent_Window_(d, &ev->window);[m
[32m+[m[32m }[m
}[m
case SDL_RENDER_TARGETS_RESET:[m
case SDL_RENDER_DEVICE_RESET: {[m
[31m- invalidate_MainWindow_(d, iTrue /* force full reset */);[m
[32m+[m[32m if (mw) {[m
[32m+[m[32m invalidate_MainWindow_(mw, iTrue /* force full reset */);[m
[32m+[m[32m }[m
break;[m
}[m
default: {[m
SDL_Event event = *ev;[m
if (event.type == SDL_USEREVENT && isCommand_UserEvent(ev, "window.unfreeze")) {[m
[31m- d->base.isDrawFrozen = iFalse;[m
[31m- if (SDL_GetWindowFlags(w->win) & SDL_WINDOW_HIDDEN) {[m
[31m- SDL_ShowWindow(w->win);[m
[32m+[m[32m mw->isDrawFrozen = iFalse;[m
[32m+[m[32m if (SDL_GetWindowFlags(d->win) & SDL_WINDOW_HIDDEN) {[m
[32m+[m[32m SDL_ShowWindow(d->win);[m
}[m
postRefresh_App();[m
postCommand_App("media.player.update"); /* in case a player needs updating */[m
[36m@@ -866,35 +925,35 @@[m [miBool processEvent_MainWindow(iMainWindow *d, const SDL_Event *ev) {[m
if (processEvent_Touch(&event)) {[m
return iTrue;[m
}[m
[31m- if (event.type == SDL_KEYDOWN && SDL_GetTicks() - d->base.focusGainedAt < 10) {[m
[32m+[m[32m if (event.type == SDL_KEYDOWN && SDL_GetTicks() - d->focusGainedAt < 10) {[m
/* Suspiciously close to when input focus was received. For example under openbox,[m
closing xterm with Ctrl+D will cause the keydown event to "spill" over to us.[m
As a workaround, ignore these events. */[m
return iTrue; /* won't go to bindings, either */[m
}[m
[31m- if (event.type == SDL_MOUSEBUTTONDOWN && d->base.ignoreClick) {[m
[31m- d->base.ignoreClick = iFalse;[m
[32m+[m[32m if (event.type == SDL_MOUSEBUTTONDOWN && d->ignoreClick) {[m
[32m+[m[32m d->ignoreClick = iFalse;[m
return iTrue;[m
}[m
/* Map mouse pointer coordinate to our coordinate system. */[m
if (event.type == SDL_MOUSEMOTION) {[m
[31m- setCursor_Window(w, SDL_SYSTEM_CURSOR_ARROW); /* default cursor */[m
[31m- const iInt2 pos = coord_Window(w, event.motion.x, event.motion.y);[m
[32m+[m[32m setCursor_Window(d, SDL_SYSTEM_CURSOR_ARROW); /* default cursor */[m
[32m+[m[32m const iInt2 pos = coord_Window(d, event.motion.x, event.motion.y);[m
event.motion.x = pos.x;[m
event.motion.y = pos.y;[m
}[m
else if (event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEBUTTONDOWN) {[m
[31m- const iInt2 pos = coord_Window(w, event.button.x, event.button.y);[m
[32m+[m[32m const iInt2 pos = coord_Window(d, event.button.x, event.button.y);[m
event.button.x = pos.x;[m
event.button.y = pos.y;[m
if (event.type == SDL_MOUSEBUTTONDOWN) {[m
/* Button clicks will change keyroot. */[m
[31m- if (numRoots_Window(w) > 1) {[m
[32m+[m[32m if (numRoots_Window(d) > 1) {[m
const iInt2 click = init_I2(event.button.x, event.button.y);[m
[31m- iForIndices(i, w->roots) {[m
[31m- iRoot *root = w->roots[i];[m
[31m- if (root != w->keyRoot && contains_Rect(rect_Root(root), click)) {[m
[31m- setKeyRoot_Window(w, root);[m
[32m+[m[32m iForIndices(i, d->roots) {[m
[32m+[m[32m iRoot *root = d->roots[i];[m
[32m+[m[32m if (root != d->keyRoot && contains_Rect(rect_Root(root), click)) {[m
[32m+[m[32m setKeyRoot_Window(d, root);[m
break;[m
}[m
}[m
[36m@@ -909,13 +968,13 @@[m [miBool processEvent_MainWindow(iMainWindow *d, const SDL_Event *ev) {[m
event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEBUTTONDOWN) {[m
if (mouseGrab_Widget()) {[m
iWidget *grabbed = mouseGrab_Widget();[m
[31m- setCurrent_Root(findRoot_Window(w, grabbed));[m
[32m+[m[32m setCurrent_Root(findRoot_Window(d, grabbed));[m
wasUsed = dispatchEvent_Widget(grabbed, &event);[m
}[m
}[m
/* Dispatch the event to the tree of widgets. */[m
if (!wasUsed) {[m
[31m- wasUsed = dispatchEvent_Window(w, &event);[m
[32m+[m[32m wasUsed = dispatchEvent_Window(d, &event);[m
}[m
if (!wasUsed) {[m
/* As a special case, clicking the middle mouse button can be used for pasting[m
[36m@@ -928,35 +987,35 @@[m [miBool processEvent_MainWindow(iMainWindow *d, const SDL_Event *ev) {[m
paste.key.keysym.mod = KMOD_PRIMARY;[m
paste.key.state = SDL_PRESSED;[m
paste.key.timestamp = SDL_GetTicks();[m
[31m- wasUsed = dispatchEvent_Window(w, &paste);[m
[32m+[m[32m wasUsed = dispatchEvent_Window(d, &paste);[m
}[m
if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_RIGHT) {[m
[31m- if (postContextClick_Window(w, &event.button)) {[m
[32m+[m[32m if (postContextClick_Window(d, &event.button)) {[m
wasUsed = iTrue;[m
}[m
}[m
}[m
if (isMetricsChange_UserEvent(&event)) {[m
[31m- iForIndices(i, w->roots) {[m
[31m- updateMetrics_Root(w->roots[i]);[m
[32m+[m[32m iForIndices(i, d->roots) {[m
[32m+[m[32m updateMetrics_Root(d->roots[i]);[m
}[m
}[m
[31m- if (isCommand_UserEvent(&event, "lang.changed")) {[m
[32m+[m[32m if (isCommand_UserEvent(&event, "lang.changed") && mw) {[m
#if defined (iHaveNativeMenus)[m
/* Retranslate the menus. */[m
removeMacMenus_();[m
insertMacMenus_();[m
#endif[m
[31m- invalidate_Window(w);[m
[31m- iForIndices(i, w->roots) {[m
[31m- if (w->roots[i]) {[m
[31m- updatePreferencesLayout_Widget(findChild_Widget(w->roots[i]->widget, "prefs"));[m
[31m- arrange_Widget(w->roots[i]->widget);[m
[32m+[m[32m invalidate_Window(d);[m
[32m+[m[32m iForIndices(i, d->roots) {[m
[32m+[m[32m if (d->roots[i]) {[m
[32m+[m[32m updatePreferencesLayout_Widget(findChild_Widget(d->roots[i]->widget, "prefs"));[m
[32m+[m[32m arrange_Widget(d->roots[i]->widget);[m
}[m
}[m
}[m
if (event.type == SDL_MOUSEMOTION) {[m
[31m- applyCursor_Window_(w);[m
[32m+[m[32m applyCursor_Window_(d);[m
}[m
return wasUsed;[m
}[m
[36m@@ -1003,6 +1062,9 @@[m [miBool dispatchEvent_Window(iWindow *d, const SDL_Event *ev) {[m
coord_MouseWheelEvent(&ev->wheel))) {[m
continue; /* Only process the event in the relevant split. */[m
}[m
[32m+[m[32m if (!root->widget) {[m
[32m+[m[32m continue;[m
[32m+[m[32m }[m
setCurrent_Root(root);[m
const iBool wasUsed = dispatchEvent_Widget(root->widget, ev);[m
if (wasUsed) {[m
[36m@@ -1044,11 +1106,40 @@[m [miBool postContextClick_Window(iWindow *d, const SDL_MouseButtonEvent *ev) {[m
return iFalse;[m
}[m
[m
[32m+[m[32mvoid draw_Window(iWindow *d) {[m
[32m+[m[32m if (SDL_GetWindowFlags(d->win) & SDL_WINDOW_HIDDEN) {[m
[32m+[m[32m return;[m
[32m+[m[32m }[m
[32m+[m[32m iPaint p;[m
[32m+[m[32m init_Paint(&p);[m
[32m+[m[32m iRoot *root = d->roots[0];[m
[32m+[m[32m setCurrent_Root(root);[m
[32m+[m[32m unsetClip_Paint(&p); /* update clip to full window */[m
[32m+[m[32m const iColor back = get_Color(uiBackground_ColorId);[m
[32m+[m[32m SDL_SetRenderDrawColor(d->render, back.r, back.g, back.b, 255);[m
[32m+[m[32m SDL_RenderClear(d->render);[m
[32m+[m[32m d->frameTime = SDL_GetTicks();[m
[32m+[m[32m if (isExposed_Window(d)) {[m
[32m+[m[32m d->isInvalidated = iFalse;[m
[32m+[m[32m extern int drawCount_;[m
[32m+[m[32m drawRoot_Widget(root->widget);[m
[32m+[m[32m#if !defined (NDEBUG)[m
[32m+[m[32m draw_Text(defaultBold_FontId, safeRect_Root(root).pos, red_ColorId, "%d", drawCount_);[m
[32m+[m[32m drawCount_ = 0;[m
[32m+[m[32m#endif[m[41m [m
[32m+[m[32m }[m
[32m+[m[32m// drawRectThickness_Paint(&p, (iRect){ zero_I2(), sub_I2(d->size, one_I2()) }, gap_UI / 4, uiSeparator_ColorId);[m
[32m+[m[32m setCurrent_Root(NULL);[m
[32m+[m[32m SDL_RenderPresent(d->render);[m
[32m+[m[32m}[m
[32m+[m
void draw_MainWindow(iMainWindow *d) {[m
[32m+[m[32m /* TODO: Try to make this a specialization of draw_Window
? */[m
iWindow *w = as_Window(d);[m
[31m- if (w->isDrawFrozen) {[m
[32m+[m[32m if (d->isDrawFrozen) {[m
return;[m
}[m
[32m+[m[32m setCurrent_Text(d->base.text);[m
/* Check if root needs resizing. */ {[m
iInt2 renderSize;[m
SDL_GetRendererOutputSize(w->render, &renderSize.x, &renderSize.y);[m
[36m@@ -1180,7 +1271,7 @@[m [mvoid setUiScale_Window(iWindow *d, float uiScale) {[m
}[m
}[m
[m
[31m-void setFreezeDraw_Window(iWindow *d, iBool freezeDraw) {[m
[32m+[m[32mvoid setFreezeDraw_MainWindow(iMainWindow *d, iBool freezeDraw) {[m
d->isDrawFrozen = freezeDraw;[m
}[m
[m
[36m@@ -1231,8 +1322,23 @@[m [miWindow *get_Window(void) {[m
return theWindow_;[m
}[m
[m
[32m+[m[32mvoid setCurrent_Window(iAnyWindow *d) {[m
[32m+[m[32m theWindow_ = d;[m
[32m+[m[32m if (type_Window(d) == main_WindowType) {[m
[32m+[m[32m theMainWindow_ = d;[m
[32m+[m[32m }[m
[32m+[m[32m if (d) {[m
[32m+[m[32m setCurrent_Text(theWindow_->text);[m
[32m+[m[32m setCurrent_Root(theWindow_->keyRoot);[m
[32m+[m[32m }[m
[32m+[m[32m else {[m
[32m+[m[32m setCurrent_Text(NULL);[m
[32m+[m[32m setCurrent_Root(NULL);[m
[32m+[m[32m }[m
[32m+[m[32m}[m
[32m+[m
iMainWindow *get_MainWindow(void) {[m
[31m- return as_MainWindow(theWindow_);[m
[32m+[m[32m return theMainWindow_;[m
}[m
[m
iBool isOpenGLRenderer_Window(void) {[m
[36m@@ -1272,7 +1378,7 @@[m [mvoid setSplitMode_MainWindow(iMainWindow *d, int splitFlags) {[m
iAssert(current_Root() == NULL);[m
if (d->splitMode != splitMode) {[m
int oldCount = numRoots_Window(w);[m
[31m- setFreezeDraw_Window(w, iTrue);[m
[32m+[m[32m setFreezeDraw_MainWindow(d, iTrue);[m
if (oldCount == 2 && splitMode == 0) {[m
/* Keep references to the tabs of the second root. */[m
const iDocumentWidget *curPage = document_Root(w->keyRoot);[m
[36m@@ -1311,6 +1417,7 @@[m [mvoid setSplitMode_MainWindow(iMainWindow *d, int splitFlags) {[m
}[m
w->roots[newRootIndex] = new_Root();[m
w->keyRoot = w->roots[newRootIndex];[m
[32m+[m[32m w->keyRoot->window = w;[m
setCurrent_Root(w->roots[newRootIndex]);[m
createUserInterface_Root(w->roots[newRootIndex]);[m
if (!isEmpty_String(d->pendingSplitUrl)) {[m
[36m@@ -1471,3 +1578,25 @@[m [mint snap_MainWindow(const iMainWindow *d) {[m
}[m
return d->place.snap;[m
}[m
[32m+[m
[32m+[m[32m/----------------------------------------------------------------------------------------------/[m
[32m+[m
[32m+[m[32miWindow *newPopup_Window(iInt2 screenPos, iWidget *rootWidget) {[m
[32m+[m[32m arrange_Widget(rootWidget);[m
[32m+[m[32m iWindow *win =[m
[32m+[m[32m new_Window(popup_WindowType,[m
[32m+[m[32m (iRect){ screenPos, divf_I2(rootWidget->rect.size, get_Window()->pixelRatio) },[m
[32m+[m[32m SDL_WINDOW_ALWAYS_ON_TOP |[m
[32m+[m[32m SDL_WINDOW_POPUP_MENU |[m
[32m+[m[32m SDL_WINDOW_SKIP_TASKBAR);[m
[32m+[m[32m#if defined (iPlatformAppleDesktop)[m
[32m+[m[32m hideTitleBar_MacOS(win); /* make it a borderless window */[m
[32m+[m[32m#endif[m
[32m+[m[32m iRoot *root = new_Root();[m
[32m+[m[32m win->roots[0] = root;[m
[32m+[m[32m win->keyRoot = root;[m
[32m+[m[32m root->widget = rootWidget;[m
[32m+[m[32m root->window = win;[m
[32m+[m[32m setRoot_Widget(rootWidget, root);[m
[32m+[m[32m return win;[m
[32m+[m[32m}[m
[1mdiff --git a/src/ui/window.h b/src/ui/window.h[m
[1mindex 73e92391..f1827931 100644[m
[1m--- a/src/ui/window.h[m
[1m+++ b/src/ui/window.h[m
[36m@@ -29,8 +29,16 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
#include <SDL_render.h>[m
#include <SDL_video.h>[m
[m
[32m+[m[32menum iWindowType {[m
[32m+[m[32m main_WindowType,[m
[32m+[m[32m popup_WindowType,[m
[32m+[m[32m};[m
[32m+[m
iDeclareType(MainWindow)[m
[32m+[m[32miDeclareType(Text)[m
iDeclareType(Window)[m
[32m+[m[41m [m
[32m+[m[32miDeclareTypeConstructionArgs(Window, enum iWindowType type, iRect rect, uint32_t flags)[m
iDeclareTypeConstructionArgs(MainWindow, iRect rect)[m
[m
typedef iAny iAnyWindow;[m
[36m@@ -71,15 +79,9 @@[m [menum iWindowSplit {[m
noEvents_WindowSplit = iBit(11),[m
};[m
[m
[31m-enum iWindowType {[m
[31m- main_WindowType,[m
[31m- popup_WindowType,[m
[31m-};[m
[31m-[m
struct Impl_Window {[m
enum iWindowType type;[m
SDL_Window * win;[m
[31m- iBool isDrawFrozen; /* avoids premature draws while restoring window state */[m
iBool isExposed;[m
iBool isMinimized;[m
iBool isMouseInside;[m
[36m@@ -102,11 +104,13 @@[m [mstruct Impl_Window {[m
iRoot * roots[2]; /* root widget and UI state; second one is for split mode */[m
iRoot * keyRoot; /* root that has the current keyboard input focus */[m
SDL_Texture * borderShadow;[m
[32m+[m[32m iText * text;[m
};[m
[m
struct Impl_MainWindow {[m
iWindow base;[m
iWindowPlacement place;[m
[32m+[m[32m iBool isDrawFrozen; /* avoids premature draws while restoring window state */[m
int splitMode;[m
int pendingSplitMode;[m
iString * pendingSplitUrl; /* URL to open in a newly opened split */[m
[36m@@ -115,7 +119,10 @@[m [mstruct Impl_MainWindow {[m
};[m
[m
iLocalDef enum iWindowType type_Window(const iAnyWindow *d) {[m
[31m- return ((const iWindow *) d)->type;[m
[32m+[m[32m if (d) {[m
[32m+[m[32m return ((const iWindow *) d)->type;[m
[32m+[m[32m }[m
[32m+[m[32m return main_WindowType;[m
}[m
[m
uint32_t id_Window (const iWindow *);[m
[36m@@ -131,11 +138,11 @@[m [mint numRoots_Window (const iWindow *);[m
iRoot * findRoot_Window (const iWindow *, const iWidget *widget);[m
iRoot * otherRoot_Window (const iWindow *, iRoot *root);[m
[m
[32m+[m[32miBool processEvent_Window (iWindow *, const SDL_Event *);[m
iBool dispatchEvent_Window (iWindow *, const SDL_Event *);[m
void invalidate_Window (iAnyWindow ); / discard all cached graphics */[m
void draw_Window (iWindow *);[m
void setUiScale_Window (iWindow *, float uiScale);[m
[31m-void setFreezeDraw_Window (iWindow *, iBool freezeDraw);[m
void setCursor_Window (iWindow *, int cursor);[m
iBool setKeyRoot_Window (iWindow *, iRoot *root);[m
iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *);[m
[36m@@ -143,6 +150,8 @@[m [miBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *);[m
iWindow * get_Window (void);[m
iBool isOpenGLRenderer_Window (void);[m
[m
[32m+[m[32mvoid setCurrent_Window (iAnyWindow *);[m
[32m+[m
iLocalDef iBool isExposed_Window(const iWindow *d) {[m
iAssert(d);[m
return d->isExposed;[m
[36m@@ -158,6 +167,10 @@[m [miLocalDef const iWindow *constAs_Window(const iAnyWindow *d) {[m
return (const iWindow *) d;[m
}[m
[m
[32m+[m[32miLocalDef iText *text_Window(const iAnyWindow *d) {[m
[32m+[m[32m return constAs_Window(d)->text;[m
[32m+[m[32m}[m
[32m+[m
/----------------------------------------------------------------------------------------------/[m
[m
iLocalDef iWindow *asWindow_MainWindow(iMainWindow *d) {[m
[36m@@ -167,6 +180,7 @@[m [miLocalDef iWindow *asWindow_MainWindow(iMainWindow *d) {[m
[m
void setTitle_MainWindow (iMainWindow *, const iString *title);[m
void setSnap_MainWindow (iMainWindow *, int snapMode);[m
[32m+[m[32mvoid setFreezeDraw_MainWindow (iMainWindow *, iBool freezeDraw);[m
void setKeyboardHeight_MainWindow (iMainWindow *, int height);[m
void setSplitMode_MainWindow (iMainWindow *, int splitMode);[m
void checkPendingSplit_MainWindow (iMainWindow *);[m
[36m@@ -196,3 +210,7 @@[m [miLocalDef const iMainWindow *constAs_MainWindow(const iAnyWindow *d) {[m
iAssert(type_Window(d) == main_WindowType);[m
return (const iMainWindow *) d;[m
}[m
[32m+[m
[32m+[m[32m/----------------------------------------------------------------------------------------------/[m
[32m+[m
[32m+[m[32miWindow * newPopup_Window (iInt2 screenPos, iWidget *rootWidget);[m
text/plain
This content has been proxied by September (ba2dc).