instance callbacks; bugfixes

This commit is contained in:
nakst 2021-12-16 19:06:08 +00:00
parent 2b1e81b772
commit ba4b0318e7
23 changed files with 540 additions and 450 deletions

View File

@ -495,6 +495,30 @@ void LoadSettings() {
}
}
int InstanceCallback(Instance *instance, EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_CLOSE) {
EsAssert(!instance->closed);
instance->closed = true;
instance->list = nullptr;
instance->placesView = nullptr;
instance->breadcrumbBar = nullptr;
instance->newFolderButton = nullptr;
instance->status = nullptr;
instance->blockingDialog = nullptr;
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
EsApplicationStartupRequest request = EsInstanceGetStartupRequest(instance);
if (request.flags & ES_APPLICATION_STARTUP_BACKGROUND_SERVICE) {
// No cleanup to do.
} else {
InstanceDestroy(instance);
instances.FindAndDeleteSwap(instance, true);
}
}
return 0;
}
void _start() {
_init();
@ -514,6 +538,7 @@ void _start() {
if (message->type == ES_MSG_INSTANCE_CREATE) {
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(FileManagerTitle));
instance->callback = InstanceCallback;
EsApplicationStartupRequest request = EsInstanceGetStartupRequest(instance);
@ -523,26 +548,6 @@ void _start() {
instances.Add(instance);
InstanceCreateUI(instance);
}
} else if (message->type == ES_MSG_INSTANCE_CLOSE) {
Instance *instance = message->instanceClose.instance;
EsAssert(!instance->closed);
instance->closed = true;
instance->list = nullptr;
instance->placesView = nullptr;
instance->breadcrumbBar = nullptr;
instance->newFolderButton = nullptr;
instance->status = nullptr;
instance->blockingDialog = nullptr;
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
Instance *instance = message->instanceDestroy.instance;
EsApplicationStartupRequest request = EsInstanceGetStartupRequest(instance);
if (request.flags & ES_APPLICATION_STARTUP_BACKGROUND_SERVICE) {
// No cleanup to do.
} else {
InstanceDestroy(instance);
instances.FindAndDeleteSwap(instance, true);
}
} else if (message->type == ES_MSG_APPLICATION_EXIT) {
#ifdef DEBUG_BUILD
for (uintptr_t i = 0; i < drives.Length(); i++) {

View File

@ -298,6 +298,62 @@ void BackCommand(Instance *instance, EsElement *, EsCommand *) {
EsWindowSwitchToolbar(instance->window, instance->fontListToolbar, ES_TRANSITION_SLIDE_DOWN);
}
int InstanceCallback(Instance *instance, EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_CLOSE) {
instance->switcher = nullptr;
instance->fontList = nullptr;
instance->fontSizeTextbox = nullptr;
instance->previewTextTextbox = nullptr;
instance->fontPreview = nullptr;
instance->fontListToolbar = nullptr;
instance->fontPreviewToolbar = nullptr;
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
SaveSettings(instance);
EsHeapFree(instance->previewText);
instance->fonts.Free();
// TODO Remove the font added to the font database.
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
if (!message->instanceOpen.update) {
EsFontInformation information = {};
information.availableWeightsNormal = 1 << 4 /* regular */;
instance->fontPreviewID = EsFontDatabaseInsertFile(&information, message->instanceOpen.file);
// TODO Check that the font is valid.
EsElementDestroyContents(instance->fontPreview);
EsPanel *titleRow = EsPanelCreate(instance->fontPreview, ES_CELL_H_CENTER | ES_PANEL_HORIZONTAL, &styleFontInformationRow);
EsIconDisplayCreate(titleRow, ES_FLAGS_DEFAULT, ES_STYLE_ICON_DISPLAY, ES_ICON_FONT_X_GENERIC);
EsTextDisplayCreate(titleRow, ES_FLAGS_DEFAULT, ES_STYLE_TEXT_HEADING0, message->instanceOpen.name, message->instanceOpen.nameBytes);
EsSpacerCreate(instance->fontPreview, ES_FLAGS_DEFAULT, 0, 0, 20);
int sizes[] = { 12, 18, 24, 36, 48, 60, 72, 0 };
for (uintptr_t i = 0; sizes[i]; i++) {
EsPanel *row = EsPanelCreate(instance->fontPreview, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &styleFontInformationRow);
char buffer[64];
EsTextDisplayCreate(row, ES_FLAGS_DEFAULT, 0, buffer, EsStringFormat(buffer, sizeof(buffer), "%d", sizes[i]));
EsTextDisplay *display = EsTextDisplayCreate(row, ES_TEXT_DISPLAY_NO_FONT_SUBSTITUTION);
const char *string = interfaceString_FontBookPreviewTextLongDefault;
EsTextRun runs[2] = {};
EsElementGetTextStyle(display, &runs[0].style);
runs[0].style.size = sizes[i];
runs[0].style.font.family = instance->fontPreviewID;
runs[1].offset = EsCStringLength(string);
EsTextDisplaySetStyledContents(display, string, runs, 1);
}
EsPanelSwitchTo(instance->switcher, instance->fontPreview, ES_TRANSITION_NONE);
EsWindowSwitchToolbar(instance->window, instance->fontPreviewToolbar, ES_TRANSITION_SLIDE_UP);
}
EsInstanceOpenComplete(instance, message->instanceOpen.file, true);
} else {
return 0;
}
return ES_HANDLED;
}
void _start() {
_init();
@ -306,6 +362,7 @@ void _start() {
if (message->type == ES_MSG_INSTANCE_CREATE) {
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(FontBookTitle));
instance->callback = InstanceCallback;
EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_FONTS);
EsPanel *rootPanel = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
@ -374,56 +431,6 @@ void _start() {
button->accessKey = 'B';
EsButtonSetIcon(button, ES_ICON_GO_PREVIOUS_SYMBOLIC);
EsButtonOnCommand(button, BackCommand);
} else if (message->type == ES_MSG_INSTANCE_CLOSE) {
Instance *instance = message->instanceClose.instance;
instance->switcher = nullptr;
instance->fontList = nullptr;
instance->fontSizeTextbox = nullptr;
instance->previewTextTextbox = nullptr;
instance->fontPreview = nullptr;
instance->fontListToolbar = nullptr;
instance->fontPreviewToolbar = nullptr;
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
if (!message->instanceOpen.update) {
Instance *instance = message->instanceOpen.instance;
EsFontInformation information = {};
information.availableWeightsNormal = 1 << 4 /* regular */;
instance->fontPreviewID = EsFontDatabaseInsertFile(&information, message->instanceOpen.file);
// TODO Check that the font is valid.
EsElementDestroyContents(instance->fontPreview);
EsPanel *titleRow = EsPanelCreate(instance->fontPreview, ES_CELL_H_CENTER | ES_PANEL_HORIZONTAL, &styleFontInformationRow);
EsIconDisplayCreate(titleRow, ES_FLAGS_DEFAULT, ES_STYLE_ICON_DISPLAY, ES_ICON_FONT_X_GENERIC);
EsTextDisplayCreate(titleRow, ES_FLAGS_DEFAULT, ES_STYLE_TEXT_HEADING0, message->instanceOpen.name, message->instanceOpen.nameBytes);
EsSpacerCreate(instance->fontPreview, ES_FLAGS_DEFAULT, 0, 0, 20);
int sizes[] = { 12, 18, 24, 36, 48, 60, 72, 0 };
for (uintptr_t i = 0; sizes[i]; i++) {
EsPanel *row = EsPanelCreate(instance->fontPreview, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &styleFontInformationRow);
char buffer[64];
EsTextDisplayCreate(row, ES_FLAGS_DEFAULT, 0, buffer, EsStringFormat(buffer, sizeof(buffer), "%d", sizes[i]));
EsTextDisplay *display = EsTextDisplayCreate(row, ES_TEXT_DISPLAY_NO_FONT_SUBSTITUTION);
const char *string = interfaceString_FontBookPreviewTextLongDefault;
EsTextRun runs[2] = {};
EsElementGetTextStyle(display, &runs[0].style);
runs[0].style.size = sizes[i];
runs[0].style.font.family = instance->fontPreviewID;
runs[1].offset = EsCStringLength(string);
EsTextDisplaySetStyledContents(display, string, runs, 1);
}
EsPanelSwitchTo(instance->switcher, instance->fontPreview, ES_TRANSITION_NONE);
EsWindowSwitchToolbar(instance->window, instance->fontPreviewToolbar, ES_TRANSITION_SLIDE_UP);
}
EsInstanceOpenComplete(message, true);
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
SaveSettings(message->instanceDestroy.instance);
EsHeapFree(message->instanceDestroy.instance->previewText);
message->instanceDestroy.instance->fonts.Free();
// TODO Remove the font added to the font database.
}
}
}

View File

@ -692,8 +692,111 @@ void MenuImage(Instance *instance, EsElement *element, EsCommand *) {
EsMenuShow(menu);
}
void WriteCallback(void *context, void *data, int size) {
EsBufferWrite((EsBuffer *) context, data, size);
}
void SwapRedAndBlueChannels(uint32_t *bits, size_t width, size_t height, size_t stride) {
for (uintptr_t i = 0; i < height; i++) {
for (uintptr_t j = 0; j < width; j++) {
uint32_t *pixel = &bits[i * stride / 4 + j];
*pixel = (*pixel & 0xFF00FF00) | (((*pixel >> 16) | (*pixel << 16)) & 0x00FF00FF);
}
}
}
int InstanceCallback(Instance *instance, EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_DESTROY) {
EsPaintTargetDestroy(instance->bitmap);
ImageDelete(instance->image);
} else if (message->type == ES_MSG_INSTANCE_SAVE) {
// TODO Error handling.
uintptr_t extensionOffset = message->instanceSave.nameBytes;
while (extensionOffset) {
if (message->instanceSave.name[extensionOffset - 1] == '.') {
break;
} else {
extensionOffset--;
}
}
const char *extension = extensionOffset ? message->instanceSave.name + extensionOffset : "png";
size_t extensionBytes = extensionOffset ? message->instanceSave.nameBytes - extensionOffset : 3;
uint32_t *bits;
size_t width, height, stride;
EsPaintTargetStartDirectAccess(instance->bitmap, &bits, &width, &height, &stride);
EsAssert(stride == width * 4); // TODO Other strides.
SwapRedAndBlueChannels(bits, width, height, stride); // stbi_write uses the other order. We swap back below.
size_t _bufferBytes = 262144;
uint8_t *_buffer = (uint8_t *) EsHeapAllocate(_bufferBytes, false);
EsBuffer buffer = { .out = _buffer, .bytes = _bufferBytes };
buffer.fileStore = message->instanceSave.file;
if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpg"))
|| 0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpeg"))) {
stbi_write_jpg_to_func(WriteCallback, &buffer, width, height, 4, bits, 90);
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("bmp"))) {
stbi_write_bmp_to_func(WriteCallback, &buffer, width, height, 4, bits);
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("tga"))) {
stbi_write_tga_to_func(WriteCallback, &buffer, width, height, 4, bits);
} else {
stbi_write_png_to_func(WriteCallback, &buffer, width, height, 4, bits, stride);
}
SwapRedAndBlueChannels(bits, width, height, stride); // Swap back.
EsBufferFlushToFileStore(&buffer);
EsHeapFree(_buffer);
EsPaintTargetEndDirectAccess(instance->bitmap);
EsInstanceSaveComplete(instance, message->instanceSave.file, true);
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
size_t fileSize;
uint8_t *file = (uint8_t *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
if (!file) {
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
return ES_HANDLED;
}
uint32_t width, height;
uint8_t *bits = EsImageLoad(file, fileSize, &width, &height, 4);
EsHeapFree(file);
if (!bits) {
EsInstanceOpenComplete(instance, message->instanceOpen.file, false, INTERFACE_STRING(ImageEditorUnsupportedFormat));
return ES_HANDLED;
}
EsPaintTargetDestroy(instance->bitmap);
ImageDelete(instance->image);
instance->bitmapWidth = width;
instance->bitmapHeight = height;
instance->bitmap = EsPaintTargetCreate(instance->bitmapWidth, instance->bitmapHeight, false);
EsPainter painter = {};
painter.clip = ES_RECT_4(0, instance->bitmapWidth, 0, instance->bitmapHeight);
painter.target = instance->bitmap;
EsDrawBitmap(&painter, painter.clip, (uint32_t *) bits, width * 4, 0xFF);
instance->image = ImageFork(instance, {}, instance->bitmapWidth, instance->bitmapHeight);
ImageCopyFromPaintTarget(instance, &instance->image, painter.clip);
EsElementRelayout(EsElementGetLayoutParent(instance->canvas));
EsHeapFree(bits);
EsInstanceOpenComplete(instance, message->instanceOpen.file, true);
} else {
return 0;
}
return ES_HANDLED;
}
void InstanceCreate(EsMessage *message) {
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(ImageEditorTitle));
instance->callback = InstanceCallback;
EsElement *toolbar = EsWindowGetToolbar(instance->window);
EsInstanceSetClassEditor(instance, &editorSettings);
@ -802,19 +905,6 @@ void InstanceCreate(EsMessage *message) {
ImageCopyFromPaintTarget(instance, &instance->image, painter.clip);
}
void WriteCallback(void *context, void *data, int size) {
EsBufferWrite((EsBuffer *) context, data, size);
}
void SwapRedAndBlueChannels(uint32_t *bits, size_t width, size_t height, size_t stride) {
for (uintptr_t i = 0; i < height; i++) {
for (uintptr_t j = 0; j < width; j++) {
uint32_t *pixel = &bits[i * stride / 4 + j];
*pixel = (*pixel & 0xFF00FF00) | (((*pixel >> 16) | (*pixel << 16)) & 0x00FF00FF);
}
}
}
void _start() {
_init();
@ -823,86 +913,6 @@ void _start() {
if (message->type == ES_MSG_INSTANCE_CREATE) {
InstanceCreate(message);
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
Instance *instance = message->instanceOpen.instance;
size_t fileSize;
uint8_t *file = (uint8_t *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
if (!file) {
EsInstanceOpenComplete(message, false);
continue;
}
uint32_t width, height;
uint8_t *bits = EsImageLoad(file, fileSize, &width, &height, 4);
EsHeapFree(file);
if (!bits) {
EsInstanceOpenComplete(message, false, INTERFACE_STRING(ImageEditorUnsupportedFormat));
continue;
}
EsPaintTargetDestroy(instance->bitmap);
ImageDelete(instance->image);
instance->bitmapWidth = width;
instance->bitmapHeight = height;
instance->bitmap = EsPaintTargetCreate(instance->bitmapWidth, instance->bitmapHeight, false);
EsPainter painter = {};
painter.clip = ES_RECT_4(0, instance->bitmapWidth, 0, instance->bitmapHeight);
painter.target = instance->bitmap;
EsDrawBitmap(&painter, painter.clip, (uint32_t *) bits, width * 4, 0xFF);
instance->image = ImageFork(instance, {}, instance->bitmapWidth, instance->bitmapHeight);
ImageCopyFromPaintTarget(instance, &instance->image, painter.clip);
EsElementRelayout(EsElementGetLayoutParent(instance->canvas));
EsHeapFree(bits);
EsInstanceOpenComplete(message, true);
} else if (message->type == ES_MSG_INSTANCE_SAVE) {
Instance *instance = message->instanceSave.instance;
uintptr_t extensionOffset = message->instanceSave.nameBytes;
while (extensionOffset) {
if (message->instanceSave.name[extensionOffset - 1] == '.') {
break;
} else {
extensionOffset--;
}
}
const char *extension = extensionOffset ? message->instanceSave.name + extensionOffset : "png";
size_t extensionBytes = extensionOffset ? message->instanceSave.nameBytes - extensionOffset : 3;
uint32_t *bits;
size_t width, height, stride;
EsPaintTargetStartDirectAccess(instance->bitmap, &bits, &width, &height, &stride);
EsAssert(stride == width * 4); // TODO Other strides.
SwapRedAndBlueChannels(bits, width, height, stride); // stbi_write uses the other order. We swap back below.
uint8_t _buffer[4096];
EsBuffer buffer = { .out = _buffer, .bytes = sizeof(_buffer) };
buffer.fileStore = message->instanceSave.file;
if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpg"))
|| 0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpeg"))) {
stbi_write_jpg_to_func(WriteCallback, &buffer, width, height, 4, bits, 90);
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("bmp"))) {
stbi_write_bmp_to_func(WriteCallback, &buffer, width, height, 4, bits);
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("tga"))) {
stbi_write_tga_to_func(WriteCallback, &buffer, width, height, 4, bits);
} else {
stbi_write_png_to_func(WriteCallback, &buffer, width, height, 4, bits, stride);
}
SwapRedAndBlueChannels(bits, width, height, stride); // Swap back.
EsBufferFlushToFileStore(&buffer);
EsPaintTargetEndDirectAccess(instance->bitmap);
EsInstanceSaveComplete(message, true);
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
Instance *instance = message->instanceDestroy.instance;
EsPaintTargetDestroy(instance->bitmap);
ImageDelete(instance->image);
}
}
}

View File

@ -445,18 +445,8 @@ int ParserText(MD_TEXTTYPE type, const MD_CHAR *text, MD_SIZE size, void *_insta
return 0;
}
void ProcessApplicationMessage(EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_CREATE) {
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(MarkdownViewerTitle));
EsInstanceSetClassViewer(instance, nullptr);
EsWindow *window = instance->window;
EsPanel *wrapper = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
EsPanel *background = EsPanelCreate(wrapper, ES_CELL_FILL | ES_PANEL_V_SCROLL_AUTO, &styleBackground);
instance->root = EsPanelCreate(background, ES_CELL_H_SHRINK, &styleRoot);
EsWindowSetIcon(window, ES_ICON_TEXT_MARKDOWN);
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
Instance *instance = message->instanceOpen.instance;
int InstanceCallback(Instance *instance, EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_OPEN) {
if (message->instanceOpen.update) {
EsElementStartTransition(instance->root, ES_TRANSITION_ZOOM_IN);
}
@ -467,8 +457,8 @@ void ProcessApplicationMessage(EsMessage *message) {
char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
if (!file || !EsUTF8IsValid(file, fileSize)) {
EsInstanceOpenComplete(message, false);
return;
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
return ES_HANDLED;
}
MD_PARSER parser = {};
@ -481,12 +471,29 @@ void ProcessApplicationMessage(EsMessage *message) {
instance->active = instance->root;
int result = md_parse(file, fileSize, &parser, instance);
if (result) EsElementDestroyContents(instance->root); // An error occurred.
EsInstanceOpenComplete(message, result == 0);
EsInstanceOpenComplete(instance, message->instanceOpen.file, result == 0);
EsHeapFree(file);
EsElementRelayout(instance->root);
instance->spans.Free();
instance->text.Free();
} else {
return 0;
}
return ES_HANDLED;
}
void ProcessApplicationMessage(EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_CREATE) {
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(MarkdownViewerTitle));
instance->callback = InstanceCallback;
EsInstanceSetClassViewer(instance, nullptr);
EsWindow *window = instance->window;
EsPanel *wrapper = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
EsPanel *background = EsPanelCreate(wrapper, ES_CELL_FILL | ES_PANEL_V_SCROLL_AUTO, &styleBackground);
instance->root = EsPanelCreate(background, ES_CELL_H_SHRINK, &styleRoot);
EsWindowSetIcon(window, ES_ICON_TEXT_MARKDOWN);
}
}

View File

@ -363,9 +363,18 @@ void TerminateProcess(Instance *instance, EsElement *, EsCommand *) {
}
}
int InstanceCallback(Instance *, EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_DESTROY) {
processes.Free();
}
return 0;
}
void ProcessApplicationMessage(EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_CREATE) {
Instance *instance = EsInstanceCreate(message, "System Monitor");
instance->callback = InstanceCallback;
EsCommandRegister(&instance->commandTerminateProcess, instance, EsLiteral("Terminate process"), TerminateProcess, 1, "Del", false);
@ -401,8 +410,6 @@ void ProcessApplicationMessage(EsMessage *message) {
EsSpacerCreate(buttonGroup, ES_CELL_V_FILL, ES_STYLE_TOOLBAR_BUTTON_GROUP_SEPARATOR);
AddTab(buttonGroup, DISPLAY_MEMORY, "Memory");
EsSpacerCreate(toolbar, ES_CELL_H_FILL);
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
processes.Free();
}
}

View File

@ -239,9 +239,52 @@ int TextboxDocumentMessage(EsElement *element, EsMessage *message) {
}
}
int InstanceCallback(Instance *instance, EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_SAVE) {
size_t byteCount;
char *contents = EsTextboxGetContents(instance->textboxDocument, &byteCount);
EsFileStoreWriteAll(message->instanceSave.file, contents, byteCount);
EsHeapFree(contents);
EsInstanceSaveComplete(instance, message->instanceSave.file, true);
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
size_t fileSize;
char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
if (!file) {
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
} else if (!EsUTF8IsValid(file, fileSize)) {
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
} else {
EsTextboxSelectAll(instance->textboxDocument);
EsTextboxInsert(instance->textboxDocument, file, fileSize);
EsTextboxSetSelection(instance->textboxDocument, 0, 0, 0, 0);
EsElementRelayout(instance->textboxDocument);
if (EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".c"), true)
|| EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".cpp"), true)
|| EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".h"), true)) {
SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_C);
} else if (EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".ini"), true)) {
SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_INI);
} else {
SetLanguage(instance, 0);
}
EsInstanceOpenComplete(instance, message->instanceOpen.file, true);
}
EsHeapFree(file);
} else {
return 0;
}
return ES_HANDLED;
}
void ProcessApplicationMessage(EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_CREATE) {
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(TextEditorTitle));
instance->callback = InstanceCallback;
EsInstanceSetClassEditor(instance, &editorSettings);
EsWindow *window = instance->window;
@ -357,43 +400,6 @@ void ProcessApplicationMessage(EsMessage *message) {
button = EsButtonCreate(buttonGroup, ES_FLAGS_DEFAULT, {}, INTERFACE_STRING(CommonSearchPrevious));
button->accessKey = 'P';
EsCommandAddButton(&instance->commandFindPrevious, button);
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
Instance *instance = message->instanceOpen.instance;
size_t fileSize;
char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
if (!file) {
EsInstanceOpenComplete(message, false);
} else if (!EsUTF8IsValid(file, fileSize)) {
EsInstanceOpenComplete(message, false);
} else {
EsTextboxSelectAll(instance->textboxDocument);
EsTextboxInsert(instance->textboxDocument, file, fileSize);
EsTextboxSetSelection(instance->textboxDocument, 0, 0, 0, 0);
EsElementRelayout(instance->textboxDocument);
if (EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".c"), true)
|| EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".cpp"), true)
|| EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".h"), true)) {
SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_C);
} else if (EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".ini"), true)) {
SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_INI);
} else {
SetLanguage(instance, 0);
}
EsInstanceOpenComplete(message, true);
}
EsHeapFree(file);
} else if (message->type == ES_MSG_INSTANCE_SAVE) {
Instance *instance = message->instanceSave.instance;
size_t byteCount;
char *contents = EsTextboxGetContents(instance->textboxDocument, &byteCount);
EsFileStoreWriteAll(message->instanceSave.file, contents, byteCount);
EsHeapFree(contents);
EsInstanceSaveComplete(message, true);
} else if (message->type == ES_MSG_APPLICATION_EXIT) {
EsBuffer buffer = {};
buffer.canGrow = true;

View File

@ -238,10 +238,6 @@ struct APIInstance {
bool closeAfterSaveCompletes;
// Do not propagate messages about this instance to the application.
// Currently only used for inspectors.
bool internalOnly;
union {
EsInstanceClassEditorSettings editorSettings;
EsInstanceClassViewerSettings viewerSettings;
@ -799,17 +795,6 @@ void InstanceCreateFileStore(APIInstance *instance, EsHandle handle) {
instance->fileStore = FileStoreCreateFromHandle(handle);
}
void InstancePostOpenMessage(EsInstance *_instance, bool update) {
APIInstance *instance = (APIInstance *) _instance->_private;
EsMessage m = { ES_MSG_INSTANCE_OPEN };
m.instanceOpen.instance = _instance;
m.instanceOpen.name = instance->startupInformation->filePath;
m.instanceOpen.nameBytes = instance->startupInformation->filePathBytes;
m.instanceOpen.file = instance->fileStore;
m.instanceOpen.update = update;
EsMessagePost(nullptr, &m);
}
APIInstance *InstanceSetup(EsInstance *instance) {
APIInstance *apiInstance = (APIInstance *) EsHeapAllocate(sizeof(APIInstance), true);
@ -886,9 +871,15 @@ EsInstance *_EsInstanceCreate(size_t bytes, EsMessage *message, const char *appl
if (apiInstance->startupInformation && apiInstance->startupInformation->readHandle) {
InstanceCreateFileStore(apiInstance, apiInstance->startupInformation->readHandle);
InstancePostOpenMessage(instance, false);
EsWindowSetTitle(instance->window, apiInstance->startupInformation->filePath, apiInstance->startupInformation->filePathBytes);
EsCommandSetDisabled(&apiInstance->commandShowInFileManager, false);
// HACK Delay sending the instance open message so that application has a chance to initialise the instance.
// TODO Change how this works!!
// TODO Can the posted message be raced by a ES_MSG_INSTANCE_DOCUMENT_UPDATED?
EsMessage m = { ES_MSG_INSTANCE_OPEN_DELAYED };
m._argument = instance;
EsMessagePost(nullptr, &m);
}
}
@ -922,19 +913,61 @@ void EsInstanceCloseReference(EsInstance *_instance) {
instance->referenceCount--;
if (!instance->referenceCount) {
EsMessage m = {};
m.type = ES_MSG_INSTANCE_DESTROY;
m.instanceDestroy.instance = _instance;
EsMessagePost(nullptr, &m);
if (_instance->callback) {
EsMessage m = {};
m.type = ES_MSG_INSTANCE_DESTROY;
_instance->callback(_instance, &m);
}
if (instance->startupInformation) {
EsHeapFree((void *) instance->startupInformation->filePath);
EsHeapFree((void *) instance->startupInformation->containingFolder);
}
EsHeapFree(instance->startupInformation);
EsHeapFree(instance->documentPath);
EsHeapFree(instance->newName);
for (uintptr_t i = 0; i < instance->commands.Count(); i++) {
EsCommand *command = instance->commands[i];
EsAssert(command->registered);
EsAssert(!ArrayLength(command->elements));
Array<EsElement *> elements = { command->elements };
elements.Free();
}
instance->commands.Free();
if (instance->fileStore) FileStoreCloseHandle(instance->fileStore);
EsHeapFree(instance);
EsHeapFree(_instance);
}
}
void EsInstanceClose(EsInstance *instance) {
EsMessageMutexCheck();
EsMessage m = {};
m.type = ES_MSG_INSTANCE_CLOSE;
m.instanceClose.instance = instance;
EsMessagePost(nullptr, &m);
if (instance->callback) {
EsMessage m = {};
m.type = ES_MSG_INSTANCE_CLOSE;
instance->callback(instance, &m);
}
InspectorWindow **inspector = &((APIInstance *) instance->_private)->attachedInspector;
if (*inspector) {
EsInstance *instance2 = *inspector;
UndoManagerDestroy(instance2->undoManager);
EsAssert(instance2->window->instance == instance2);
EsElementDestroy(instance2->window);
EsInstanceCloseReference(instance2);
instance2->window->InternalDestroy();
*inspector = nullptr;
}
UndoManagerDestroy(instance->undoManager);
EsAssert(instance->window->instance == instance);
EsElementDestroy(instance->window);
EsInstanceCloseReference(instance);
}
EsWindow *WindowFromWindowID(EsObjectID id) {
@ -952,6 +985,22 @@ EsInstance *InstanceFromWindowID(EsObjectID id) {
return window ? window->instance : nullptr;
}
void InstanceSendOpenMessage(EsInstance *instance, bool update) {
APIInstance *apiInstance = (APIInstance *) instance->_private;
EsMessage m = { .type = ES_MSG_INSTANCE_OPEN };
m.instanceOpen.name = apiInstance->startupInformation->filePath;
m.instanceOpen.nameBytes = apiInstance->startupInformation->filePathBytes;
m.instanceOpen.file = apiInstance->fileStore;
m.instanceOpen.update = update;
int response = instance->callback ? instance->callback(instance, &m) : 0;
if (!response) EsInstanceOpenComplete(instance, m.instanceOpen.file, true); // Ignored.
// TODO Support multithreaded file operations.
EsAssert(m.instanceOpen.file->operationComplete);
}
EsError GetMessage(_EsMessageWithObject *message) {
// Process posted messages first,
// so that messages like ES_MSG_WINDOW_DESTROYED are received last.
@ -980,13 +1029,6 @@ EsMessage *EsMessageReceive() {
if (message.message.createInstance.data != ES_INVALID_HANDLE) {
EsHandleClose(message.message.createInstance.data);
}
} else if (message.message.type == ES_MSG_INSTANCE_OPEN) {
// TODO Support multithreaded file operations.
EsAssert(message.message.instanceOpen.file->operationComplete);
} else if (message.message.type == ES_MSG_INSTANCE_SAVE) {
// TODO Support multithreaded file operations.
EsAssert(message.message.instanceSave.file->operationComplete);
FileStoreCloseHandle(message.message.instanceSave.file);
} else if (message.message.type == ES_MSG_APPLICATION_EXIT) {
if (api.startupInformation->isDesktop) {
// Desktop tracks the number of instances it owns, so it needs to know when it exits.
@ -1024,48 +1066,6 @@ EsMessage *EsMessageReceive() {
#endif
EsProcessTerminateCurrent();
}
} else if (message.message.type == ES_MSG_INSTANCE_DESTROY) {
APIInstance *instance = (APIInstance *) message.message.instanceDestroy.instance->_private;
if (instance->startupInformation) {
EsHeapFree((void *) instance->startupInformation->filePath);
EsHeapFree((void *) instance->startupInformation->containingFolder);
}
EsHeapFree(instance->startupInformation);
EsHeapFree(instance->documentPath);
EsHeapFree(instance->newName);
for (uintptr_t i = 0; i < instance->commands.Count(); i++) {
EsCommand *command = instance->commands[i];
EsAssert(command->registered);
EsAssert(!ArrayLength(command->elements));
Array<EsElement *> elements = { command->elements };
elements.Free();
}
instance->commands.Free();
if (instance->fileStore) FileStoreCloseHandle(instance->fileStore);
EsHeapFree(instance);
EsHeapFree(message.message.instanceDestroy.instance);
} else if (message.message.type == ES_MSG_INSTANCE_CLOSE) {
EsInstance *instance = message.message.instanceClose.instance;
InspectorWindow **inspector = &((APIInstance *) instance->_private)->attachedInspector;
if (*inspector) {
EsInstance *instance2 = *inspector;
UndoManagerDestroy(instance2->undoManager);
EsAssert(instance2->window->instance == instance2);
EsElementDestroy(instance2->window);
EsInstanceCloseReference(instance2);
instance2->window->InternalDestroy();
*inspector = nullptr;
}
UndoManagerDestroy(instance->undoManager);
EsAssert(instance->window->instance == instance);
EsElementDestroy(instance->window);
EsInstanceCloseReference(instance);
} else if (message.message.type == ES_MSG_UNREGISTER_FILE_SYSTEM) {
for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) {
if (api.mountPoints[i].information.id == message.message.unregisterFileSystem.id) {
@ -1132,34 +1132,37 @@ EsMessage *EsMessageReceive() {
InstanceClose(instance);
}
} else if (type == ES_MSG_INSTANCE_SAVE_RESPONSE) {
// TODO Support multithreaded file operations.
EsMessage m = {};
m.type = ES_MSG_INSTANCE_SAVE;
m.instanceSave.file = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore), true);
if (m.instanceSave.file) {
EsInstance *_instance = InstanceFromWindowID(message.message.tabOperation.id);
APIInstance *instance = (APIInstance *) _instance->_private;
m.instanceSave.file->error = message.message.tabOperation.error;
m.instanceSave.file->handle = message.message.tabOperation.handle;
m.instanceSave.file->type = FILE_STORE_HANDLE;
m.instanceSave.file->handles = 1;
m.instanceSave.instance = InstanceFromWindowID(message.message.tabOperation.id);
APIInstance *instance = (APIInstance *) m.instanceSave.instance->_private;
m.instanceSave.name = instance->startupInformation->filePath;
m.instanceSave.nameBytes = instance->startupInformation->filePathBytes;
if (m.instanceSave.file->error == ES_SUCCESS) {
EsMemoryCopy(&message.message, &m, sizeof(EsMessage));
return &message.message;
if (m.instanceSave.file->error == ES_SUCCESS && _instance->callback && _instance->callback(_instance, &m)) {
// The instance callback will have called EsInstanceSaveComplete.
} else {
EsInstanceSaveComplete(&m, false);
EsInstanceSaveComplete(_instance, m.instanceSave.file, false);
}
EsMemoryCopy(&message.message, &m, sizeof(EsMessage));
} else {
if (message.message.tabOperation.handle) {
EsHandleClose(message.message.tabOperation.handle);
}
}
EsAssert(m.instanceSave.file->operationComplete);
FileStoreCloseHandle(m.instanceSave.file);
} else if (type == ES_MSG_INSTANCE_RENAME_RESPONSE) {
EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id);
@ -1239,11 +1242,13 @@ EsMessage *EsMessageReceive() {
InstanceCreateFileStore(instance, message.message.tabOperation.handle);
if (!message.message.tabOperation.isSource) {
InstancePostOpenMessage(_instance, true);
InstanceSendOpenMessage(_instance, true);
}
} else {
EsHandleClose(message.message.tabOperation.handle);
}
} else if (type == ES_MSG_INSTANCE_OPEN_DELAYED) {
InstanceSendOpenMessage((EsInstance *) message.message._argument, false);
} else if (type == ES_MSG_PRIMARY_CLIPBOARD_UPDATED) {
EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id);
if (instance) UIRefreshPrimaryClipboard(instance->window);
@ -1314,12 +1319,6 @@ EsMessage *EsMessageReceive() {
return &message.message;
}
}
} else if (type == ES_MSG_INSTANCE_DESTROY || type == ES_MSG_INSTANCE_CLOSE) {
APIInstance *instance = (APIInstance *) message.message.instanceDestroy.instance->_private;
if (!instance->internalOnly) {
return &message.message;
}
} else {
return &message.message;
}
@ -1335,18 +1334,16 @@ void EsInstanceSetModified(EsInstance *instance, bool modified) {
MessageDesktop(m, 2, instance->window->handle);
}
void EsInstanceOpenComplete(EsMessage *message, bool success, const char *errorText, ptrdiff_t errorTextBytes) {
EsInstance *instance = message->instanceOpen.instance;
if (!success || message->instanceOpen.file->error != ES_SUCCESS) {
if (errorTextBytes) {
void EsInstanceOpenComplete(EsInstance *instance, EsFileStore *file, bool success, const char *errorText, ptrdiff_t errorTextBytes) {
if (!success || file->error != ES_SUCCESS) {
if (errorText && errorTextBytes) {
EsDialogShow(instance->window, INTERFACE_STRING(FileCannotOpen),
errorText, errorTextBytes,
ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON);
} else {
const char *errorMessage = interfaceString_FileLoadErrorUnknown;
switch (message->instanceOpen.file->error) {
switch (file->error) {
case ES_ERROR_DRIVE_ERROR_FILE_DAMAGED:
errorMessage = interfaceString_FileLoadErrorCorrupt;
break;
@ -1362,33 +1359,34 @@ void EsInstanceOpenComplete(EsMessage *message, bool success, const char *errorT
errorMessage, -1, ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON);
}
// TODO Close the instance.
// TODO Close the instance after the dialog is closed?
} else {
#if 0
if (!message->instanceOpen.update) {
EsUndoClear(instance->undoManager);
}
#endif
EsInstanceSetModified(instance, false);
}
EsAssert(!message->instanceOpen.file->operationComplete);
message->instanceOpen.file->operationComplete = true;
EsAssert(!file->operationComplete);
file->operationComplete = true;
}
void EsInstanceSaveComplete(EsMessage *message, bool success) {
if (message->instanceSave.file->error != ES_SUCCESS) {
void EsInstanceSaveComplete(EsInstance *instance, EsFileStore *file, bool success) {
if (file->error != ES_SUCCESS) {
success = false;
}
if (success) {
message->instanceSave.file->error = EsFileControl(message->instanceSave.file->handle, ES_FILE_CONTROL_FLUSH);
file->error = EsFileControl(file->handle, ES_FILE_CONTROL_FLUSH);
if (message->instanceSave.file->error != ES_SUCCESS) {
if (file->error != ES_SUCCESS) {
success = false;
}
}
EsInstance *instance = message->instanceSave.instance;
APIInstance *apiInstance = (APIInstance *) instance->_private;
if (instance) {
@ -1415,7 +1413,7 @@ void EsInstanceSaveComplete(EsMessage *message, bool success) {
const char *errorMessage = interfaceString_FileSaveErrorUnknown;
ptrdiff_t errorMessageBytes = -1;
switch (message->instanceSave.file->error) {
switch (file->error) {
case ES_ERROR_FILE_DOES_NOT_EXIST:
case ES_ERROR_NODE_DELETED:
case ES_ERROR_PERMISSION_NOT_GRANTED:
@ -1459,8 +1457,8 @@ void EsInstanceSaveComplete(EsMessage *message, bool success) {
}
}
EsAssert(!message->instanceSave.file->operationComplete);
message->instanceSave.file->operationComplete = true;
EsAssert(!file->operationComplete);
file->operationComplete = true;
}
uintptr_t EsSystemGetOptimalWorkQueueThreadCount() {
@ -2156,8 +2154,6 @@ void EsPOSIXInitialise(int *, char ***) {
EsInstance *instance = EsInstanceCreate(message, INTERFACE_STRING(POSIXTitle));
EsPanel *panel = EsPanelCreate((EsElement *) instance->window, ES_PANEL_VERTICAL | ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_BACKGROUND);
EsTextDisplayCreate(panel, ES_CELL_H_CENTER | ES_CELL_V_FILL | ES_TEXT_DISPLAY_RICH_TEXT, nullptr, INTERFACE_STRING(POSIXUnavailable));
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
EsInstanceOpenComplete(message, true);
}
}
}

View File

@ -131,14 +131,10 @@ struct InstalledApplication {
EsFileOffset totalSize; // 0 if uncalculated.
};
struct CommonDesktopInstance : EsInstance {
void (*destroy)(EsInstance *);
struct CrashedTabInstance : EsInstance {
};
struct CrashedTabInstance : CommonDesktopInstance {
};
struct BlankTabInstance : CommonDesktopInstance {
struct BlankTabInstance : EsInstance {
};
struct ApplicationProcess {
@ -3134,12 +3130,6 @@ void DesktopSendMessage(EsMessage *message) {
} else {
// The screen resolution will be correctly queried in DesktopSetup.
}
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
CommonDesktopInstance *instance = (CommonDesktopInstance *) message->instanceDestroy.instance;
if (instance->destroy) {
instance->destroy(instance);
}
} else if (message->type == ES_MSG_KEY_DOWN) {
ProcessGlobalKeyboardShortcuts(nullptr, message);
} else if (message->type == MSG_SETUP_DESKTOP_UI || message->type == ES_MSG_UI_SCALE_CHANGED) {

View File

@ -151,7 +151,7 @@ void InspectorNotifyElementContentChanged(EsElement *element);
#define UI_STATE_USE_MEASUREMENT_CACHE (1 << 21)
struct EsElement : EsElementPublic {
EsUICallback messageClass;
EsElementCallback messageClass;
EsElement *parent;
Array<EsElement *> children;
uint32_t state;
@ -262,7 +262,7 @@ struct EsElement : EsElementPublic {
void Repaint(bool all, EsRectangle region = ES_RECT_1(0) /* client coordinates */);
void Initialise(EsElement *_parent, uint64_t _flags, EsUICallback _classCallback, const EsStyle *style);
void Initialise(EsElement *_parent, uint64_t _flags, EsElementCallback _classCallback, const EsStyle *style);
};
struct MeasurementCache {
@ -6301,7 +6301,7 @@ void EsElementInsertAfter(EsElement *element) {
gui.insertAfter = element;
}
void EsElement::Initialise(EsElement *_parent, uint64_t _flags, EsUICallback _classCallback, const EsStyle *_style) {
void EsElement::Initialise(EsElement *_parent, uint64_t _flags, EsElementCallback _classCallback, const EsStyle *_style) {
EsMessageMutexCheck();
// EsPrint("New element '%z' %x with parent %x.\n", _debugName, this, _parent);
@ -6409,7 +6409,7 @@ float EsElementGetScaleFactor(EsElement *element) {
return theming.scale;
}
void EsElementSetCallback(EsElement *element, EsUICallback callback) {
void EsElementSetCallback(EsElement *element, EsElementCallback callback) {
EsMessageMutexCheck();
element->messageUser = callback;
}
@ -8090,7 +8090,6 @@ void InspectorSetup(EsWindow *window) {
EsInstanceOpenReference(inspector);
inspector->instance = window->instance;
((APIInstance *) inspector->_private)->internalOnly = true;
window->instance = inspector;
inspector->selectedElement = -1;

View File

@ -1757,6 +1757,7 @@ struct EsListView : EsElement {
secondaryCellStyle->CloseReference();
selectedCellStyle->CloseReference();
fixedItems.Free();
fixedItemIndices.Free();
visibleItems.Free();
groups.Free();
activeColumns.Free();

View File

@ -938,7 +938,9 @@ enum EsMessageType {
// It will be removed from the `children` later (but before the next ES_MSG_LAYOUT message is received).
ES_MSG_PRE_ADD_CHILD = 0x200D // An element has been created with this element as its parent, but is not yet added to the parent.
ES_MSG_HIT_TEST = 0x200E // For non-rectangular elements: test whether a pixel should be considered inside the element. Set response to ES_HANDLED.
ES_MSG_KEY_TYPED = 0x2011 // Sent to the focused element when a key is pressed. Only if ES_HANDLED is returned the message will not propagate; this allows messageUser to block input processing by returning ES_REJECTED.
ES_MSG_KEY_TYPED = 0x2011 // Sent to the focused element when a key is pressed.
// Only if ES_HANDLED is returned the message will not propagate;
// this allows messageUser to block input processing by returning ES_REJECTED.
ES_MSG_SCROLL_X = 0x2012 // The element has been horizontally scrolled.
ES_MSG_SCROLL_Y = 0x2013 // The element has been vertically scrolled.
ES_MSG_STRONG_FOCUS_END = 0x2014 // Sent once when the user 'clicks off' the element, even if a new element was not necessarily focused.
@ -963,6 +965,8 @@ enum EsMessageType {
ES_MSG_TRANSITION_COMPLETE = 0x202B // The transition started with EsElementStartTransition completed.
ES_MSG_PAINT_FOREGROUND = 0x202C // Paint the element's foreground. Sent after the children are painted.
// The width/height parameters of EsPainter may be larger than expected - this includes the 'non-client' area.
ES_MSG_PRIMARY_CLIPBOARD_UPDATED = 0x202D // Send to the focused element when the contents of the primary clipboard is changes.
// This message might be delayed if the window containing the element is inactive.
// State change messages: (causes a style refresh)
ES_MSG_STATE_CHANGE_MESSAGE_START = 0x2080
@ -984,39 +988,11 @@ enum EsMessageType {
ES_MSG_LIST_DISPLAY_GET_MARKER = 0x3004 // Get the string for a marker in an EsListDisplay. See message->getContent.
ES_MSG_SLIDER_MOVED = 0x3006 // The slider has been moved.
// Desktop messages:
ES_MSG_EMBEDDED_WINDOW_DESTROYED = 0x4802
ES_MSG_SET_SCREEN_RESOLUTION = 0x4803
ES_MSG_REGISTER_FILE_SYSTEM = 0x4804
ES_MSG_UNREGISTER_FILE_SYSTEM = 0x4805
ES_MSG_DESKTOP = 0x4806
ES_MSG_DEVICE_CONNECTED = 0x4807
ES_MSG_DEVICE_DISCONNECTED = 0x4808
// Messages sent from Desktop to application instances:
ES_MSG_TAB_INSPECT_UI = 0x4A01
ES_MSG_TAB_CLOSE_REQUEST = 0x4A02
ES_MSG_INSTANCE_SAVE_RESPONSE = 0x4A03 // Sent by Desktop after an application requested to save its document.
ES_MSG_INSTANCE_DOCUMENT_RENAMED = 0x4A04
ES_MSG_INSTANCE_DOCUMENT_UPDATED = 0x4A05
ES_MSG_PRIMARY_CLIPBOARD_UPDATED = 0x4A06
ES_MSG_INSTANCE_RENAME_RESPONSE = 0x4A07
// Debugger messages:
ES_MSG_APPLICATION_CRASH = 0x4C00
ES_MSG_PROCESS_TERMINATED = 0x4C01
// Undo item messages:
ES_MSG_UNDO_CANCEL = 0x4D00
ES_MSG_UNDO_INVOKE = 0x4D01
ES_MSG_UNDO_TO_STRING = 0x4D02
// Misc messages:
ES_MSG_EYEDROP_REPORT = 0x5001
ES_MSG_TIMER = 0x5003
ES_MSG_PING = 0x5004 // Sent by Desktop to check processes are processing messages.
ES_MSG_WAKEUP = 0x5005 // Sent to wakeup the message thread, so that it can process locally posted messages.
// File Manager messages:
ES_MSG_FILE_MANAGER_FILE_MODIFIED = 0x5100
ES_MSG_FILE_MANAGER_PATH_MOVED = 0x5101
@ -1057,12 +1033,22 @@ enum EsMessageType {
ES_MSG_REORDER_ITEM_MOVED = 0x5401
// Application messages:
ES_MSG_APPLICATION_EXIT = 0x7001
ES_MSG_INSTANCE_CREATE = 0x7002
ES_MSG_INSTANCE_OPEN = 0x7003
ES_MSG_INSTANCE_SAVE = 0x7004
ES_MSG_INSTANCE_DESTROY = 0x7005
ES_MSG_INSTANCE_CLOSE = 0x7006
ES_MSG_APPLICATION_EXIT = 0x6001
ES_MSG_INSTANCE_CREATE = 0x6002
ES_MSG_DEVICE_CONNECTED = 0x6003
ES_MSG_DEVICE_DISCONNECTED = 0x6004
ES_MSG_REGISTER_FILE_SYSTEM = 0x6005
ES_MSG_UNREGISTER_FILE_SYSTEM = 0x6006
// Instance messages:
ES_MSG_INSTANCE_OPEN = 0x6800
ES_MSG_INSTANCE_SAVE = 0x6801
ES_MSG_INSTANCE_DESTROY = 0x6802
ES_MSG_INSTANCE_CLOSE = 0x6803
// Messages for internal use by the system:
ES_MSG_SYSTEM_START = 0x7000
ES_MSG_SYSTEM_END = 0x7FFF
// User messages:
ES_MSG_USER_START = 0x8000
@ -1182,7 +1168,8 @@ enum EsDeviceControlType {
ES_DEVICE_CONTROL_CLOCK_READ = 0x2001
}
function_pointer int EsUICallback(struct EsElement *element, struct EsMessage *message);
function_pointer int EsElementCallback(struct EsElement *element, struct EsMessage *message);
function_pointer int EsInstanceCallback(ES_INSTANCE_TYPE *instance, struct EsMessage *message);
struct EsBuffer {
union { const uint8_t *in; uint8_t *out; };
@ -1193,7 +1180,7 @@ struct EsBuffer {
};
struct EsElementPublic {
EsUICallback messageUser;
EsElementCallback messageUser;
EsCString cName;
EsGeneric userData;
char accessKey; // Upper-case.
@ -1339,6 +1326,9 @@ struct EsInstance {
void *_private;
EsWindow *window;
EsUndoManager *undoManager;
// Read-write.
EsInstanceCallback callback;
};
struct EsPanelBand {
@ -1769,26 +1759,16 @@ struct EsMessageEndEdit {
// Instance messages.
struct EsMessageInstanceOpen {
ES_INSTANCE_TYPE *instance;
EsFileStore *file;
STRING name;
bool update;
};
struct EsMessageInstanceSave {
ES_INSTANCE_TYPE *instance;
EsFileStore *file;
STRING name;
};
struct EsMessageInstanceDestroy {
ES_INSTANCE_TYPE *instance;
};
struct EsMessageInstanceClose {
ES_INSTANCE_TYPE *instance;
};
// Internal system messages.
struct EsMessageProcessCrash {
@ -1902,8 +1882,6 @@ struct EsMessage {
// Instance messages:
EsMessageInstanceOpen instanceOpen;
EsMessageInstanceSave instanceSave;
EsMessageInstanceDestroy instanceDestroy;
EsMessageInstanceClose instanceClose;
// Internal messages:
void *_argument;
@ -2423,8 +2401,8 @@ function void EsInstanceSetActiveUndoManager(ES_INSTANCE_TYPE *instance, EsUndoM
function void EsInstanceSetClassEditor(ES_INSTANCE_TYPE *instance, const EsInstanceClassEditorSettings *settings);
function void EsInstanceSetClassViewer(ES_INSTANCE_TYPE *instance, const EsInstanceClassViewerSettings *settings);
function EsApplicationStartupRequest EsInstanceGetStartupRequest(ES_INSTANCE_TYPE *instance);
function void EsInstanceOpenComplete(EsMessage *message, bool success, STRING errorText = BLANK_STRING);
function void EsInstanceSaveComplete(EsMessage *message, bool success);
function void EsInstanceOpenComplete(ES_INSTANCE_TYPE *instance, EsFileStore *file, bool success, STRING errorText = BLANK_STRING);
function void EsInstanceSaveComplete(ES_INSTANCE_TYPE *instance, EsFileStore *file, bool success);
function void EsInstanceSetModified(ES_INSTANCE_TYPE *instance, bool modified);
function EsError EsUserTaskStart(EsUserTaskCallback callback, EsGeneric data, STRING title, uint32_t iconID);
@ -2450,7 +2428,7 @@ function bool EsElementIsFocused(EsElement *element);
function void EsElementSetDisabled(EsElement *element, bool disabled = true);
function void EsElementSetHidden(EsElement *element, bool hidden = true);
function bool EsElementIsHidden(EsElement *element);
function void EsElementSetCallback(EsElement *element, EsUICallback callback);
function void EsElementSetCallback(EsElement *element, EsElementCallback callback);
function void EsElementGetSize(EsElement *element, int *width, int *height);
function void EsElementRepaint(EsElement *element, const EsRectangle *region = ES_NULL); // Mark an element to be repainted. If region is null, then the whole element is repainted.
function void EsElementRepaintForScroll(EsElement *element, EsMessage *message, EsRectangle border); // Minimal repaint for ES_MSG_SCROLL_X/Y.

View File

@ -387,6 +387,30 @@ extern "C" void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writ
#define ES_THEME_CURSORS_WIDTH (264)
#define ES_THEME_CURSORS_HEIGHT (128)
// Desktop messages:
#define ES_MSG_EMBEDDED_WINDOW_DESTROYED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x001))
#define ES_MSG_SET_SCREEN_RESOLUTION ((EsMessageType) (ES_MSG_SYSTEM_START + 0x002))
#define ES_MSG_DESKTOP ((EsMessageType) (ES_MSG_SYSTEM_START + 0x005))
// Messages sent from Desktop to application instances:
#define ES_MSG_TAB_INSPECT_UI ((EsMessageType) (ES_MSG_SYSTEM_START + 0x101))
#define ES_MSG_TAB_CLOSE_REQUEST ((EsMessageType) (ES_MSG_SYSTEM_START + 0x102))
#define ES_MSG_INSTANCE_SAVE_RESPONSE ((EsMessageType) (ES_MSG_SYSTEM_START + 0x103)) // Sent by Desktop after an application requested to save its document.
#define ES_MSG_INSTANCE_DOCUMENT_RENAMED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x104))
#define ES_MSG_INSTANCE_DOCUMENT_UPDATED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x105))
#define ES_MSG_INSTANCE_RENAME_RESPONSE ((EsMessageType) (ES_MSG_SYSTEM_START + 0x107))
// Debugger messages:
#define ES_MSG_APPLICATION_CRASH ((EsMessageType) (ES_MSG_SYSTEM_START + 0x201))
#define ES_MSG_PROCESS_TERMINATED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x202))
// Misc messages:
#define ES_MSG_EYEDROP_REPORT ((EsMessageType) (ES_MSG_SYSTEM_START + 0x301))
#define ES_MSG_TIMER ((EsMessageType) (ES_MSG_SYSTEM_START + 0x302))
#define ES_MSG_PING ((EsMessageType) (ES_MSG_SYSTEM_START + 0x303)) // Sent by Desktop to check processes are processing messages.
#define ES_MSG_WAKEUP ((EsMessageType) (ES_MSG_SYSTEM_START + 0x304)) // Sent to wakeup the message thread, so that it can process locally posted messages.
#define ES_MSG_INSTANCE_OPEN_DELAYED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x305))
#endif
// --------- CRT function macros:

View File

@ -2,7 +2,7 @@
// It is released under the terms of the MIT license -- see LICENSE.md.
// Written by: nakst.
struct SettingsInstance : CommonDesktopInstance {
struct SettingsInstance : EsInstance {
EsPanel *switcher;
EsPanel *mainPage;
EsButton *undoButton, *backButton;
@ -885,7 +885,11 @@ void InstanceSettingsCreate(EsMessage *message) {
}
}
instance->destroy = [] (EsInstance *) {
ConfigurationWriteToFile();
instance->callback = [] (EsInstance *, EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_DESTROY) {
ConfigurationWriteToFile();
}
return 0;
};
}

View File

@ -2921,7 +2921,7 @@ struct EsTextbox : EsElement {
bool ensureCaretVisibleQueued;
EsUICallback overlayCallback;
EsElementCallback overlayCallback;
EsGeneric overlayData;
char *activeLine;
@ -3348,8 +3348,6 @@ void TextboxEnsureCaretVisibleActionCallback(EsElement *element, EsGeneric conte
bool verticallyCenter = context.u;
TextboxCaret caret = textbox->carets[1];
EsPrint("TextboxEnsureCaretVisibleActionCallback ------------\n");
for (uintptr_t i = 0; i < 3; i++) {
// ScrollPane::SetY causes ES_MSG_SCROLL_Y to get sent to the textbox.
// This causes a TextboxRefreshVisibleLines, which may cause new lines to added.

View File

@ -197,6 +197,8 @@ static bool ReadWrite(FSNode *file, uint64_t offset, uint64_t count, uint8_t *bu
ESFS_CHECK(data, "Read - Expected data attribute.");
if (data->indirection == ESFS_INDIRECTION_DIRECT) {
EsAssert(data->dataOffset + offset <= data->size && data->dataOffset + offset + count <= data->size);
if (write) {
EsMemoryCopy((uint8_t *) data + data->dataOffset + offset, buffer, count);
} else {
@ -1423,15 +1425,18 @@ static EsError RemoveDirectoryEntry(FSNode *file, uint8_t *blockBuffers /* super
// EsPrint("\tpositionOfLastEntry = %d\n\tThis node Reference = %d/%d\n", positionOfLastEntry, file->reference.block, file->reference.offsetIntoBlock);
ESFS_CHECK_TO_ERROR(AccessBlock(volume, file->reference.block, 1, blockBuffers, FS_BLOCK_ACCESS_CACHED, K_ACCESS_READ), "Remove - Could not load the container block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
ESFS_CHECK_TO_ERROR(AccessBlock(volume, file->reference.block, 1, blockBuffers, FS_BLOCK_ACCESS_CACHED, K_ACCESS_READ),
"Remove - Could not load the container block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
ESFS_CHECK_TO_ERROR(ReadWrite(directory, positionOfLastEntry & ~(superblock->blockSize - 1), superblock->blockSize,
blockBuffers + superblock->blockSize, false, false), "Remove - Could not load the last block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
ESFS_CHECK_TO_ERROR(0 == EsMemoryCompare(blockBuffers + file->reference.offsetIntoBlock, &file->entry, sizeof(DirectoryEntry)), "Remove - Inconsistent file entry.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
ESFS_CHECK_TO_ERROR(0 == EsMemoryCompare(blockBuffers + file->reference.offsetIntoBlock, &file->entry, sizeof(DirectoryEntry)),
"Remove - Inconsistent file entry.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
DirectoryEntry *movedEntry = (DirectoryEntry *) (blockBuffers + superblock->blockSize + (positionOfLastEntry & (superblock->blockSize - 1)));
DirectoryEntry *deletedEntry = (DirectoryEntry *) (blockBuffers + file->reference.offsetIntoBlock);
EsMemoryCopy(deletedEntry, movedEntry, sizeof(DirectoryEntry));
ESFS_CHECK_TO_ERROR(AccessBlock(volume, file->reference.block, 1, blockBuffers, FS_BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "Remove - Could not save the container block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
ESFS_CHECK_TO_ERROR(AccessBlock(volume, file->reference.block, 1, blockBuffers, FS_BLOCK_ACCESS_CACHED, K_ACCESS_WRITE),
"Remove - Could not save the container block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
// Step 2: Update the node for the moved entry.
@ -1450,7 +1455,8 @@ static EsError RemoveDirectoryEntry(FSNode *file, uint8_t *blockBuffers /* super
uint64_t key = CalculateCRC64(filename->filename, filename->length);
// EsPrint("\tModify index key for %s\n", filename->length, filename->filename);
ESFS_CHECK_TO_ERROR(IndexModifyKey(volume, key, file->reference, directoryAttribute->indexRootBlock, blockBuffers + superblock->blockSize), "Remove - Could not update index (2).", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
ESFS_CHECK_TO_ERROR(IndexModifyKey(volume, key, file->reference, directoryAttribute->indexRootBlock, blockBuffers + superblock->blockSize),
"Remove - Could not update index (2).", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
}
}

View File

@ -1094,6 +1094,7 @@ EsError CCSpaceAccess(CCSpace *cache, K_USER_BUFFER void *_buffer, EsFileOffset
KMutexRelease(&cache->cachedSectionsMutex);
if (error != ES_SUCCESS) {
CCActiveSectionReturnToLists(section, false);
return error;
}

View File

@ -913,8 +913,14 @@ EsError FSDirectoryEntryFound(KNode *_parent, KNodeMetadata *metadata,
nameBytes, name, parent);
}
if (update) {
EsMemoryCopy(existingEntry->thisItem + 1, driverData, driverDataBytes);
}
if (node) {
if (!update) {
// Only try to create a node for this directory entry if update is false.
if (existingEntry->thisItem->node) {
KernelPanic("FSDirectoryEntryFound - Entry exists and is created on file system.\n");
}
@ -927,9 +933,9 @@ EsError FSDirectoryEntryFound(KNode *_parent, KNodeMetadata *metadata,
}
*node = existingEntry->thisItem->node;
} else if (update) {
EsMemoryCopy(existingEntry->thisItem + 1, driverData, driverDataBytes);
} else if (EsMemoryCompare(existingEntry->thisItem + 1, driverData, driverDataBytes)) {
}
if (!node && !update && EsMemoryCompare(existingEntry->thisItem + 1, driverData, driverDataBytes)) {
// NOTE This can be caused by a directory containing an entry with the same name multiple times.
KernelLog(LOG_ERROR, "FS", "directory entry driverData changed", "FSDirectoryEntryFound - 'update' is false but driverData has changed.\n");
}

View File

@ -230,6 +230,26 @@ void SetDimensions(int width, int height) {
EsElementRepaint(instance->display);
}
int InstanceCallback(Instance *instance, EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_DESTROY) {
// TODO Tell the emulator to stop.
// unlink(configurationFile); (Do this on the POSIX thread.)
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
configurationFileData = (char *) EsFileStoreReadAll(message->instanceOpen.file, &configurationFileBytes);
if (!configurationFileData) {
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
} else {
EsEventSet(openEvent);
EsInstanceOpenComplete(instance, message->instanceOpen.file, true);
}
} else {
return 0;
}
return ES_HANDLED;
}
void MessageLoopThread(EsGeneric) {
EsPrint("Reached message loop thread...\n");
EsMessageMutexAcquire();
@ -239,24 +259,13 @@ void MessageLoopThread(EsGeneric) {
if (message->type == ES_MSG_INSTANCE_CREATE) {
instance = EsInstanceCreate(message, "Bochs");
instance->callback = InstanceCallback;
EsWindowSetTitle(instance->window, "Bochs", -1);
EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_DEVELOPMENT);
instance->display = EsCustomElementCreate(instance->window, ES_CELL_FILL | ES_ELEMENT_FOCUSABLE);
instance->display->messageUser = CanvasCallback;
EsElementFocus(instance->display);
SetDimensions(640, 480);
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
configurationFileData = (char *) EsFileStoreReadAll(message->instanceOpen.file, &configurationFileBytes);
if (!configurationFileData) {
EsInstanceOpenComplete(message, false);
} else {
EsEventSet(openEvent);
EsInstanceOpenComplete(message, true);
}
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
// TODO Tell the emulator to stop.
// unlink(configurationFile); (Do this on the POSIX thread.)
}
}
}

View File

@ -298,6 +298,19 @@ bool LoadModel(char *model, size_t modelBytes) {
return true;
}
int InstanceCallback(EsInstance *, EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_OPEN) {
size_t modelBytes;
void *model = EsFileStoreReadAll(message->instanceOpen.file, &modelBytes);
EsInstanceOpenComplete(message, LoadModel(model, modelBytes), NULL, 0);
EsHeapFree(model, 0, NULL);
loadedModel = true;
return ES_HANDLED;
}
return 0;
}
int main(int argc, char **argv) {
(void) argc;
(void) argv;
@ -436,16 +449,11 @@ int main(int argc, char **argv) {
if (message->type == ES_MSG_INSTANCE_CREATE) {
EsInstance *instance = EsInstanceCreate(message, "Object Viewer", -1);
instance->callback = InstanceCallback;
EsWindowSetIcon(instance->window, ES_ICON_MODEL);
EsElement *canvas = EsCustomElementCreate(instance->window, ES_CELL_FILL, 0);
canvas->messageUser = (EsUICallback) CanvasCallback;
EsElementStartAnimating(canvas);
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
size_t modelBytes;
void *model = EsFileStoreReadAll(message->instanceOpen.file, &modelBytes);
EsInstanceOpenComplete(message, LoadModel(model, modelBytes), NULL, 0);
EsHeapFree(model, 0, NULL);
loadedModel = true;
}
}

View File

@ -337,20 +337,28 @@ int CanvasMessage(EsElement *element, EsMessage *message) {
return ES_HANDLED;
}
int InstanceCallback(EsInstance *instance, EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_OPEN) {
size_t romBytes;
void *rom = EsFileStoreReadAll(message->instanceOpen.file, &romBytes);
EsInstanceOpenComplete(instance, message->instanceOpen.file, rom && Launch(rom, romBytes), NULL, 0);
EsHeapFree(rom, 0, NULL);
return ES_HANDLED;
}
return 0;
}
void _start() {
while (true) {
EsMessage *message = EsMessageReceive();
if (message->type == ES_MSG_INSTANCE_CREATE) {
EsInstance *instance = EsInstanceCreate(message, "Uxn Emulator", -1);
instance->callback = InstanceCallback;
canvas = EsCustomElementCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
canvas->messageUser = (EsUICallback) CanvasMessage;
canvas->messageUser = (EsElementCallback) CanvasMessage;
EsElementStartAnimating(canvas);
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
size_t romBytes;
void *rom = EsFileStoreReadAll(message->instanceOpen.file, &romBytes);
EsInstanceOpenComplete(message, rom && Launch(rom, romBytes), NULL, 0);
EsHeapFree(rom, 0, NULL);
}
}
}

View File

@ -1626,6 +1626,10 @@ uint8_t *EsImageLoad(const void *file, size_t fileSize, uint32_t *imageX, uint32
int unused;
uint32_t *image = (uint32_t *) stbi_load_from_memory((uint8_t *) file, fileSize, (int *) imageX, (int *) imageY, &unused, imageChannels);
if (!image) {
return nullptr;
}
for (uintptr_t j = 0; j < *imageY; j++) {
for (uintptr_t i = 0; i < *imageX; i++) {
uint32_t in = image[i + j * *imageX];
@ -2605,15 +2609,23 @@ void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writeBytes) {
return NULL;
#ifdef ES_API
} else if (buffer->fileStore) {
while (writeBytes && !buffer->error) {
if (buffer->position == buffer->bytes) {
EsBufferFlushToFileStore(buffer);
} else {
size_t bytesToWrite = writeBytes > buffer->bytes - buffer->position ? buffer->bytes - buffer->position : writeBytes;
EsMemoryCopy(buffer->out + buffer->position, source, bytesToWrite);
buffer->position += bytesToWrite;
writeBytes -= bytesToWrite;
source = (const uint8_t *) source + bytesToWrite;
if (writeBytes > buffer->bytes) {
EsBufferFlushToFileStore(buffer);
if (!buffer->error) {
buffer->error = !EsFileStoreAppend(buffer->fileStore, source, writeBytes);
}
} else {
while (writeBytes && !buffer->error) {
if (buffer->position == buffer->bytes) {
EsBufferFlushToFileStore(buffer);
} else {
size_t bytesToWrite = writeBytes > buffer->bytes - buffer->position ? buffer->bytes - buffer->position : writeBytes;
EsMemoryCopy(buffer->out + buffer->position, source, bytesToWrite);
buffer->position += bytesToWrite;
writeBytes -= bytesToWrite;
source = (const uint8_t *) source + bytesToWrite;
}
}
}

View File

@ -38,8 +38,6 @@
// Path boolean operations.
// Timeline editor for applying a given state change, with rows for possibly many different layers.
// Metrics: layoutVertical, textFigures.
// TODO Reorganize old theming data!
//////////////////////////////////////////////////////////////
@ -3760,19 +3758,25 @@ int main(int argc, char **argv) {
}
#ifdef OS_ESSENCE
void _UIMessageProcess(EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_OPEN) {
void _UIMessageProcess(EsMessage *message) {}
int _UIInstanceCallback(EsInstance *instance, EsMessage *message) {
if (message->type == ES_MSG_INSTANCE_SAVE) {
fileStore = message->instanceSave.file;
DocumentSave(nullptr);
EsInstanceSaveComplete(instance, fileStore, true);
fileStore = nullptr;
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
DocumentFree();
fileStore = message->instanceOpen.file;
DocumentLoad();
EsInstanceOpenComplete(instance, fileStore, true);
fileStore = nullptr;
EsInstanceOpenComplete(message, true);
} else if (message->type == ES_MSG_INSTANCE_SAVE) {
fileStore = message->instanceSave.file;
DocumentSave(nullptr);
fileStore = nullptr;
EsInstanceSaveComplete(message, true);
} else {
return 0;
}
return ES_HANDLED;
}
void _start() {

View File

@ -69,6 +69,9 @@
// Callback to allow the application to process messages.
void _UIMessageProcess(EsMessage *message);
// Callback for instances.
int _UIInstanceCallback(ES_INSTANCE_TYPE *instance, EsMessage *message);
#endif
#ifdef UI_DEBUG
@ -729,7 +732,7 @@ struct {
#endif
#ifdef UI_ESSENCE
EsInstance *instance;
ES_INSTANCE_TYPE *instance;
void *menuData[256]; // HACK This limits the number of menu items to 128.
uintptr_t menuIndex;
@ -5339,6 +5342,7 @@ void UIInitialise() {
if (message->type == ES_MSG_INSTANCE_CREATE) {
ui.instance = EsInstanceCreate(message, NULL, 0);
ui.instance->callback = _UIInstanceCallback;
break;
}
}