4#ifndef IMGUI_DEFINE_MATH_OPERATORS
5#define IMGUI_DEFINE_MATH_OPERATORS
14#include "absl/strings/str_format.h"
29#if defined(__APPLE__) && defined(__MACH__)
31#include <TargetConditionals.h>
33#import <CoreText/CoreText.h>
35#if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1
38#elif TARGET_OS_MAC == 1
40#import <Cocoa/Cocoa.h>
42#if defined(YAZE_HTTP_API_ENABLED)
57T* Autoreleased(T*
object) {
58#if __has_feature(objc_arc)
61 return [
object autorelease];
67 if (!app.IsReady() || app.GetController() ==
nullptr) {
70 return app.GetController()->editor_manager();
76class EditorManagerMenuHost final :
public nm::NativeMenuHost {
79 auto* manager = CurrentEditorManager();
80 return manager ? manager->shortcut_manager() :
nullptr;
83 bool HasLoadedRom()
const override {
84 auto* manager = CurrentEditorManager();
85 if (manager ==
nullptr) {
88 auto* rom = manager->GetCurrentRom();
89 return rom !=
nullptr && rom->
is_loaded();
92 bool HasCurrentEditor()
const override {
93 auto* manager = CurrentEditorManager();
94 return manager !=
nullptr && manager->GetCurrentEditor() !=
nullptr;
102 bool CanUndo()
const override {
return HasCurrentEditor(); }
103 bool CanRedo()
const override {
return HasCurrentEditor(); }
105 bool WantsTextInput()
const override {
106 return ImGui::GetCurrentContext() !=
nullptr &&
107 ImGui::GetIO().WantTextInput;
110 void Defer(std::function<
void()> action)
override {
111 if (
auto* manager = CurrentEditorManager()) {
112 manager->QueueDeferredAction(std::move(action));
116 void InjectCommandChord(ImGuiKey key)
override {
117 if (ImGui::GetCurrentContext() ==
nullptr) {
120 ImGuiIO& io = ImGui::GetIO();
123 const ImGuiKey mod = io.ConfigMacOSXBehaviors ? ImGuiMod_Super : ImGuiMod_Ctrl;
124 io.AddKeyEvent(mod,
true);
125 io.AddKeyEvent(key,
true);
126 io.AddKeyEvent(key,
false);
127 io.AddKeyEvent(mod,
false);
130 void RunHostAction(nm::MenuAction action)
override {
131 auto* manager = CurrentEditorManager();
132 if (manager ==
nullptr) {
135 manager->QueueDeferredAction([action]() {
136 auto* m = CurrentEditorManager();
141 case nm::MenuAction::kAbout:
142 if (
auto* popups = m->popup_manager()) {
146 case nm::MenuAction::kSettings:
149 case nm::MenuAction::kQuit:
152 case nm::MenuAction::kOpenRom:
155 case nm::MenuAction::kOpenProject:
156 (void)m->OpenProject();
158 case nm::MenuAction::kSave: {
159 const auto status = m->SaveCurrentSession();
160 if (!status.ok() && !absl::IsCancelled(status)) {
161 m->toast_manager()->Show(
162 absl::StrFormat(
"Failed to save: %s", status.message()),
167 case nm::MenuAction::kSaveAs: {
168 const auto status = m->SaveCurrentSessionAs();
169 if (!status.ok() && !absl::IsCancelled(status)) {
170 m->toast_manager()->Show(
171 absl::StrFormat(
"Failed to save a copy: %s", status.message()),
176 case nm::MenuAction::kCloseRom:
177 m->CloseCurrentSession();
179 case nm::MenuAction::kUndo:
180 if (
auto* editor = m->GetCurrentEditor()) {
181 (void)editor->Undo();
184 case nm::MenuAction::kRedo:
185 if (
auto* editor = m->GetCurrentEditor()) {
186 (void)editor->Redo();
189 case nm::MenuAction::kToggleSidebar:
190 m->window_manager().ToggleSidebarVisibility();
192 case nm::MenuAction::kKeyboardShortcuts:
193 if (
auto* ui = m->ui_coordinator()) {
194 ui->ShowShortcutsBrowser();
203 std::vector<std::string> RecentFiles()
const override {
207 void OpenRecentFile(
const std::string& path)
override {
209 if (
auto* m = CurrentEditorManager()) {
210 (void)m->OpenRomOrProject(path);
215 void ClearRecentFiles()
override {
222EditorManagerMenuHost& MenuHost() {
223 static EditorManagerMenuHost host;
227NSEventModifierFlags ModifierFlagsForChord(
const nm::KeyChord& chord) {
228 NSEventModifierFlags flags = 0;
229 if (chord.command) flags |= NSEventModifierFlagCommand;
230 if (chord.shift) flags |= NSEventModifierFlagShift;
231 if (chord.option) flags |= NSEventModifierFlagOption;
232 if (chord.control) flags |= NSEventModifierFlagControl;
236nm::KeyChord ChordFromNSEvent(NSEvent* event) {
238 if (event.type != NSEventTypeKeyDown) {
241 NSString* chars = nil;
242 if (@available(macOS 10.15, *)) {
243 chars = [
event charactersByApplyingModifiers:0];
245 if (chars.length == 0) {
246 chars =
event.charactersIgnoringModifiers;
248 if (chars.length != 1) {
251 const unichar c = [chars.lowercaseString characterAtIndex:0];
252 if (c < 0x20 || c > 0x7e) {
255 const NSEventModifierFlags flags =
event.modifierFlags;
256 chord.key =
static_cast<char>(c);
257 chord.command = (flags & NSEventModifierFlagCommand) != 0;
258 chord.shift = (flags & NSEventModifierFlagShift) != 0;
259 chord.option = (flags & NSEventModifierFlagOption) != 0;
260 chord.control = (flags & NSEventModifierFlagControl) != 0;
264void ApplyChordToItem(NSMenuItem* item,
const nm::ResolvedItem& resolved) {
265 if (!resolved.chord.valid()) {
266 item.keyEquivalent =
@"";
267 item.keyEquivalentModifierMask = 0;
270 item.keyEquivalent = [NSString stringWithFormat:
@"%c", resolved.chord.key];
271 item.keyEquivalentModifierMask = ModifierFlagsForChord(resolved.chord);
275SDL_EventFilter g_prev_sdl_filter =
nullptr;
276void* g_prev_sdl_filter_userdata =
nullptr;
278nm::KeyChord ChordFromSdlKey(
const SDL_KeyboardEvent& key) {
280 const SDL_Keycode sym = key.keysym.sym;
281 if (sym < 0x20 || sym > 0x7e) {
284 const Uint16 mod = key.keysym.mod;
285 chord.key =
static_cast<char>(sym >=
'A' && sym <=
'Z' ? sym -
'A' +
'a' : sym);
286 chord.command = (mod & KMOD_GUI) != 0;
287 chord.shift = (mod & KMOD_SHIFT) != 0;
288 chord.option = (mod & KMOD_ALT) != 0;
289 chord.control = (mod & KMOD_CTRL) != 0;
297int YazeNativeMenuSdlFilter(
void* userdata, SDL_Event* event) {
299 if (event !=
nullptr &&
300 (event->type == SDL_KEYDOWN || event->type == SDL_KEYUP)) {
301 const nm::KeyChord chord = ChordFromSdlKey(event->key);
303 nm::IsNativeOwnedChord(MenuHost().shortcut_manager(), chord)) {
307 if (g_prev_sdl_filter !=
nullptr) {
308 return g_prev_sdl_filter(g_prev_sdl_filter_userdata, event);
318@interface YazeMainMenu : NSMenu
321@implementation YazeMainMenu
322- (BOOL)performKeyEquivalent:(NSEvent*)event {
323 const nm::KeyChord chord = ChordFromNSEvent(event);
324 if (!nm::ShouldMenuPerformKeyEquivalent(MenuHost().shortcut_manager(),
328 return [
super performKeyEquivalent:event];
332@interface YazeMenuController : NSObject <NSMenuDelegate, NSMenuItemValidation>
333@property(nonatomic, assign) NSMenu* openRecentMenu;
334- (void)performMenuAction:(NSMenuItem*)sender;
335- (void)openRecentFile:(NSMenuItem*)sender;
336- (void)clearRecentFiles:(NSMenuItem*)sender;
339@implementation YazeMenuController
341- (void)performMenuAction:(NSMenuItem*)sender {
342 nm::PerformAction(MenuHost(),
static_cast<nm::MenuAction
>(sender.tag));
345- (void)openRecentFile:(NSMenuItem*)sender {
346 NSString* path = sender.representedObject;
347 if (path.length > 0) {
348 MenuHost().OpenRecentFile(path.UTF8String);
352- (void)clearRecentFiles:(NSMenuItem*)sender {
354 MenuHost().ClearRecentFiles();
357- (BOOL)validateMenuItem:(NSMenuItem*)item {
358 if (item.action ==
@selector(performMenuAction:)) {
359 const auto action =
static_cast<nm::MenuAction
>(item.tag);
360 if (action == nm::MenuAction::kUndo || action == nm::MenuAction::kRedo) {
361 std::string title = action == nm::MenuAction::kUndo ?
"Undo" :
"Redo";
362 if (
auto* manager = CurrentEditorManager()) {
363 if (
auto* editor = manager->GetCurrentEditor()) {
364 const std::string desc = action == nm::MenuAction::kUndo
365 ? editor->GetUndoDescription()
366 : editor->GetRedoDescription();
372 item.title = [NSString stringWithUTF8String:title.c_str()];
374 return nm::IsActionEnabled(MenuHost(), action) ? YES : NO;
376 if (item.action ==
@selector(openRecentFile:)) {
377 return CurrentEditorManager() !=
nullptr;
379 if (item.action ==
@selector(clearRecentFiles:)) {
380 return !MenuHost().RecentFiles().empty();
385- (void)rebuildOpenRecent:(NSMenu*)menu {
386 [menu removeAllItems];
387 const std::vector<std::string> files = MenuHost().RecentFiles();
388 for (
const std::string& path : files) {
389 NSString* nsPath = [NSString stringWithUTF8String:path.c_str()];
390 NSString* label = [NSString
391 stringWithUTF8String:nm::RecentFileLabel(path).c_str()];
392 if (nsPath == nil || label == nil) {
395 NSMenuItem* item = Autoreleased([[NSMenuItem alloc] initWithTitle:label
396 action:@selector(openRecentFile:)
399 item.representedObject = nsPath;
400 item.toolTip = nsPath;
403 if (!files.empty()) {
404 [menu addItem:[NSMenuItem separatorItem]];
406 NSMenuItem* clear = Autoreleased([[NSMenuItem alloc] initWithTitle:
@"Clear Menu"
407 action:@selector(clearRecentFiles:)
410 [menu addItem:clear];
415- (void)menuNeedsUpdate:(NSMenu*)menu {
416 if (menu == self.openRecentMenu) {
417 [
self rebuildOpenRecent:menu];
420 auto* shortcuts = MenuHost().shortcut_manager();
421 for (NSMenuItem* item in menu.itemArray) {
422 if (item.isSeparatorItem || item.hasSubmenu || item.tag < 0 ||
423 item.tag >=
static_cast<NSInteger
>(nm::MenuAction::kCount)) {
426 ApplyChordToItem(item, nm::ResolveItem(
427 shortcuts,
static_cast<nm::MenuAction
>(item.tag)));
435YazeMenuController* g_menu_controller = nil;
437SEL CocoaSelectorFor(nm::MenuAction action) {
439 case nm::MenuAction::kHide:
440 return @selector(hide:);
441 case nm::MenuAction::kHideOthers:
442 return @selector(hideOtherApplications:);
443 case nm::MenuAction::kShowAll:
444 return @selector(unhideAllApplications:);
445 case nm::MenuAction::kToggleFullScreen:
446 return @selector(toggleFullScreen:);
447 case nm::MenuAction::kMinimize:
448 return @selector(performMiniaturize:);
449 case nm::MenuAction::kZoom:
450 return @selector(performZoom:);
451 case nm::MenuAction::kBringAllToFront:
452 return @selector(arrangeInFront:);
458NSMenuItem* AddActionItem(NSMenu* menu, nm::MenuAction action) {
459 const nm::ActionSpec* spec = nm::FindSpec(action);
460 NSString* title = [NSString stringWithUTF8String:spec ? spec->title : "?"];
461 const nm::ResolvedItem resolved =
462 nm::ResolveItem(MenuHost().shortcut_manager(), action);
463 NSMenuItem* item = nil;
464 if (spec !=
nullptr && spec->dispatch == nm::Dispatch::kCocoa) {
467 item = Autoreleased([[NSMenuItem alloc] initWithTitle:title
468 action:CocoaSelectorFor(action)
471 item = Autoreleased([[NSMenuItem alloc] initWithTitle:title
472 action:@selector(performMenuAction:)
474 item.target = g_menu_controller;
476 item.tag =
static_cast<NSInteger
>(action);
477 ApplyChordToItem(item, resolved);
482NSMenu* AddTopLevelMenu(NSMenu* mainMenu, NSString* title) {
483 NSMenu* menu = Autoreleased([[NSMenu alloc] initWithTitle:title]);
484 menu.delegate = g_menu_controller;
485 NSMenuItem* holder = Autoreleased([[NSMenuItem alloc] initWithTitle:title
488 holder.submenu = menu;
489 [mainMenu addItem:holder];
497void InstallNativeMainMenu() {
498 if (g_menu_controller == nil) {
499 g_menu_controller = [[YazeMenuController alloc] init];
501 YazeMainMenu* mainMenu = Autoreleased([[YazeMainMenu alloc] initWithTitle:
@"MainMenu"]);
504 NSMenu* appMenu = AddTopLevelMenu(mainMenu,
@"yaze");
505 AddActionItem(appMenu, nm::MenuAction::kAbout);
506 [appMenu addItem:[NSMenuItem separatorItem]];
507 AddActionItem(appMenu, nm::MenuAction::kSettings);
508 [appMenu addItem:[NSMenuItem separatorItem]];
509 NSMenu* servicesMenu = Autoreleased([[NSMenu alloc] initWithTitle:
@"Services"]);
510 NSMenuItem* servicesItem = Autoreleased([[NSMenuItem alloc] initWithTitle:
@"Services"
513 servicesItem.submenu = servicesMenu;
514 servicesItem.tag = -1;
515 [appMenu addItem:servicesItem];
516 [NSApp setServicesMenu:servicesMenu];
517 [appMenu addItem:[NSMenuItem separatorItem]];
518 AddActionItem(appMenu, nm::MenuAction::kHide);
519 AddActionItem(appMenu, nm::MenuAction::kHideOthers);
520 AddActionItem(appMenu, nm::MenuAction::kShowAll);
521 [appMenu addItem:[NSMenuItem separatorItem]];
522 AddActionItem(appMenu, nm::MenuAction::kQuit);
524 NSMenu* fileMenu = AddTopLevelMenu(mainMenu,
@"File");
525 AddActionItem(fileMenu, nm::MenuAction::kOpenRom);
526 AddActionItem(fileMenu, nm::MenuAction::kOpenProject);
527 NSMenu* recentMenu = Autoreleased([[NSMenu alloc] initWithTitle:
@"Open Recent"]);
528 recentMenu.delegate = g_menu_controller;
529 g_menu_controller.openRecentMenu = recentMenu;
530 NSMenuItem* recentItem = Autoreleased([[NSMenuItem alloc] initWithTitle:
@"Open Recent"
533 recentItem.submenu = recentMenu;
535 [fileMenu addItem:recentItem];
536 [g_menu_controller rebuildOpenRecent:recentMenu];
537 [fileMenu addItem:[NSMenuItem separatorItem]];
538 AddActionItem(fileMenu, nm::MenuAction::kSave);
539 AddActionItem(fileMenu, nm::MenuAction::kSaveAs);
540 [fileMenu addItem:[NSMenuItem separatorItem]];
541 AddActionItem(fileMenu, nm::MenuAction::kCloseRom);
543 NSMenu* editMenu = AddTopLevelMenu(mainMenu,
@"Edit");
544 AddActionItem(editMenu, nm::MenuAction::kUndo);
545 AddActionItem(editMenu, nm::MenuAction::kRedo);
546 [editMenu addItem:[NSMenuItem separatorItem]];
547 AddActionItem(editMenu, nm::MenuAction::kCut);
548 AddActionItem(editMenu, nm::MenuAction::kCopy);
549 AddActionItem(editMenu, nm::MenuAction::kPaste);
550 AddActionItem(editMenu, nm::MenuAction::kSelectAll);
552 NSMenu* viewMenu = AddTopLevelMenu(mainMenu,
@"View");
553 AddActionItem(viewMenu, nm::MenuAction::kToggleSidebar);
554 [viewMenu addItem:[NSMenuItem separatorItem]];
555 AddActionItem(viewMenu, nm::MenuAction::kToggleFullScreen);
557 NSMenu* windowMenu = AddTopLevelMenu(mainMenu,
@"Window");
558 AddActionItem(windowMenu, nm::MenuAction::kMinimize);
559 AddActionItem(windowMenu, nm::MenuAction::kZoom);
560 [windowMenu addItem:[NSMenuItem separatorItem]];
561 AddActionItem(windowMenu, nm::MenuAction::kBringAllToFront);
563 NSMenu* helpMenu = AddTopLevelMenu(mainMenu,
@"Help");
564 AddActionItem(helpMenu, nm::MenuAction::kKeyboardShortcuts);
566 [NSApp setMainMenu:mainMenu];
569 [NSApp setWindowsMenu:windowMenu];
570 [NSApp setHelpMenu:helpMenu];
573 SDL_EventFilter existing =
nullptr;
574 void* existing_userdata =
nullptr;
575 if (SDL_GetEventFilter(&existing, &existing_userdata) &&
576 existing != YazeNativeMenuSdlFilter) {
577 g_prev_sdl_filter = existing;
578 g_prev_sdl_filter_userdata = existing_userdata;
580 SDL_SetEventFilter(YazeNativeMenuSdlFilter,
nullptr);
584std::string DescribeChord(
const nm::KeyChord& chord) {
585 if (!chord.valid()) {
589 if (chord.control) out += "Ctrl+";
590 if (chord.option) out += "Opt+";
591 if (chord.shift) out += "Shift+";
592 if (chord.command) out += "
Cmd+";
597const char* OwnerName(nm::ChordOwner owner) {
599 case nm::ChordOwner::kImGui:
601 case nm::ChordOwner::kNative:
612void DumpNativeMenu(
const char* phase) {
613 const char* path = std::getenv(
"YAZE_NATIVE_MENU_DUMP");
614 if (path ==
nullptr || path[0] ==
'\0') {
617 FILE* out = std::fopen(path,
"a");
618 if (out ==
nullptr) {
621 auto* shortcuts = MenuHost().shortcut_manager();
622 std::fprintf(out,
"== phase=%s shortcut_manager=%s rom_loaded=%d\n", phase,
623 shortcuts ?
"yes" :
"no", MenuHost().HasLoadedRom() ? 1 : 0);
624 NSMenu* mainMenu = [NSApp mainMenu];
625 std::fprintf(out,
"mainMenu class=%s items=%ld\n",
626 mainMenu ? NSStringFromClass([mainMenu
class]).UTF8String :
"nil",
627 static_cast<long>(mainMenu.numberOfItems));
628 for (NSMenuItem* top in mainMenu.itemArray) {
629 NSMenu* sub = top.submenu;
631 if (sub.delegate != nil &&
632 [sub.delegate respondsToSelector:@selector(menuNeedsUpdate:)]) {
633 [sub.delegate menuNeedsUpdate:sub];
635 std::fprintf(out,
"[%s]\n", top.title.UTF8String);
636 for (NSMenuItem* item in sub.itemArray) {
637 if (item.isSeparatorItem) {
638 std::fprintf(out,
" ---\n");
641 std::string owner =
"n/a";
642 std::string resolved_chord =
"-";
644 item.tag <
static_cast<NSInteger
>(nm::MenuAction::kCount)) {
645 const auto r = nm::ResolveItem(
646 shortcuts,
static_cast<nm::MenuAction
>(item.tag));
647 owner = OwnerName(r.owner);
648 resolved_chord = DescribeChord(r.chord);
651 id target = item.target;
653 [target respondsToSelector:@selector(validateMenuItem:)]) {
654 enabled = [target validateMenuItem:item];
657 " %-24s key='%s' mods=0x%lx chord=%s owner=%s "
658 "action=%s enabled=%d%s%s\n",
659 item.title.UTF8String, item.keyEquivalent.UTF8String,
660 static_cast<unsigned long>(item.keyEquivalentModifierMask),
661 resolved_chord.c_str(), owner.c_str(),
662 item.action ? NSStringFromSelector(item.action).UTF8String
664 enabled ? 1 : 0, item.hasSubmenu ?
" [submenu]" :
"",
665 item.isHidden ?
" [hidden]" :
"");
666 if (item.hasSubmenu) {
667 for (NSMenuItem* child in item.submenu.itemArray) {
668 std::fprintf(out,
" - %s\n",
669 child.isSeparatorItem ?
"---" : child.title.UTF8String);
680 unsigned short key_code;
681 NSEventModifierFlags flags;
683 const Probe probes[] = {
684 {
"Cmd+S",
@"s", 1, NSEventModifierFlagCommand},
685 {
"Cmd+Z",
@"z", 6, NSEventModifierFlagCommand},
686 {
"Cmd+W",
@"w", 13, NSEventModifierFlagCommand},
687 {
"Cmd+Q",
@"q", 12, NSEventModifierFlagCommand},
689 for (
const Probe& probe : probes) {
690 NSEvent* ev = [NSEvent keyEventWithType:NSEventTypeKeyDown
692 modifierFlags:probe.flags
696 characters:probe.chars
697 charactersIgnoringModifiers:probe.chars
699 keyCode:probe.key_code];
700 const nm::KeyChord chord = ChordFromNSEvent(ev);
703 if (nm::ShouldMenuPerformKeyEquivalent(shortcuts, chord)) {
704 std::fprintf(out,
"selfcheck nsmenu %s gate=native (not probed)\n",
708 const BOOL performed = [mainMenu performKeyEquivalent:ev];
709 std::fprintf(out,
"selfcheck nsmenu %s gate=imgui performed=%d\n",
710 probe.label, performed ? 1 : 0);
721 const SdlProbe sdl_probes[] = {
722 {
"Cmd+S", SDLK_s, KMOD_LGUI},
723 {
"Cmd+Q", SDLK_q, KMOD_LGUI},
724 {
"Cmd+W", SDLK_w, KMOD_LGUI},
725 {
"Cmd+,", SDLK_COMMA, KMOD_LGUI},
726 {
"Cmd+M", SDLK_m, KMOD_LGUI},
727 {
"Ctrl+Cmd+F", SDLK_f,
static_cast<Uint16
>(KMOD_LGUI | KMOD_LCTRL)},
728 {
"Opt+Cmd+H", SDLK_h,
static_cast<Uint16
>(KMOD_LGUI | KMOD_LALT)},
729 {
"Cmd+H", SDLK_h, KMOD_LGUI},
731 for (
const SdlProbe& probe : sdl_probes) {
733 ev.type = SDL_KEYDOWN;
734 ev.key.keysym.sym = probe.sym;
735 ev.key.keysym.mod = probe.mod;
736 const int keep = YazeNativeMenuSdlFilter(
nullptr, &ev);
737 std::fprintf(out,
"selfcheck sdlfilter %s keep=%d\n", probe.label, keep);
745@interface AppDelegate : NSObject <NSApplicationDelegate>
750- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
756 [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSQuitAlwaysKeepsWindows"];
760 [[NSUserDefaults standardUserDefaults] setBool:NO
761 forKey:@"NSFullScreenMenuItemEverywhere"];
764- (NSApplicationTerminateReply)applicationShouldTerminate:
765 (NSApplication *)sender {
768 if (!app.IsReady() || app.GetController() ==
nullptr ||
769 app.GetController()->editor_manager() ==
nullptr) {
770 return NSTerminateNow;
778 app.GetController()->editor_manager()->Quit();
779 return NSTerminateCancel;
784extern "C" void yaze_initialize_cocoa() {
787 [NSApplication sharedApplication];
788 [NSApp setDelegate:delegate];
789 [NSApp finishLaunching];
793extern "C" int yaze_run_cocoa_app_delegate(
const yaze::AppConfig& config) {
794 yaze_initialize_cocoa();
806#if defined(YAZE_HTTP_API_ENABLED)
808 auto api_server = yaze::app::SetupEditorHttpServer(config);
811 LOG_WARN(
"App",
"HTTP API requested but unavailable in this build");
817 InstallNativeMainMenu();
818 DumpNativeMenu(
"install");
822 const auto started = std::chrono::steady_clock::now();
823 bool late_dump_done =
false;
824 while (app.IsReady() && app.GetController()->IsActive()) {
827 if (!late_dump_done &&
828 std::chrono::steady_clock::now() - started > std::chrono::seconds(10)) {
829 late_dump_done =
true;
830 DumpNativeMenu(
"late");
835#if defined(YAZE_HTTP_API_ENABLED)
836 if (api_server) api_server->Stop();
static Application & Instance()
void Initialize(const AppConfig &config)
The EditorManager controls the main editor window and manages the various editor classes.
static RecentFilesManager & GetInstance()
const std::vector< std::string > & GetRecentFiles() const
#define LOG_WARN(category, format,...)
Configuration options for the application startup.