mirror of https://gitlab.com/nakst/essence
introduce CommandPasteTask and EsUserTaskStart
This commit is contained in:
parent
e8d219033e
commit
ce01df7c59
|
@ -62,7 +62,7 @@ void CommandRename(Instance *instance, EsElement *, EsCommand *) {
|
|||
size_t oldPathBytes;
|
||||
char *oldPath = EsStringAllocateAndFormat(&oldPathBytes, "%s%s", STRFMT(instance->folder->path), STRFMT(task->string2));
|
||||
|
||||
FolderPathMoved(instance, { .text = oldPath, .bytes = oldPathBytes }, { .text = newPath, .bytes = newPathBytes }, true);
|
||||
FolderPathMoved({ .text = oldPath, .bytes = oldPathBytes }, { .text = newPath, .bytes = newPathBytes }, true);
|
||||
|
||||
EsDirectoryChild information = {};
|
||||
EsPathQueryInformation(newPath, newPathBytes, &information);
|
||||
|
@ -229,11 +229,10 @@ EsError CommandPasteFile(String source, String destinationBase, void **copyBuffe
|
|||
}
|
||||
|
||||
if (error == ES_SUCCESS) {
|
||||
if (move) {
|
||||
FolderFileUpdatedAtPath(source, nullptr);
|
||||
}
|
||||
|
||||
EsMessageMutexAcquire();
|
||||
if (move) FolderFileUpdatedAtPath(source, nullptr);
|
||||
FolderFileUpdatedAtPath(destination, nullptr);
|
||||
EsMessageMutexRelease();
|
||||
}
|
||||
|
||||
done:;
|
||||
|
@ -251,62 +250,58 @@ struct PasteOperation {
|
|||
String source, destination;
|
||||
};
|
||||
|
||||
void CommandPaste(Instance *instance, EsElement *, EsCommand *) {
|
||||
if (EsClipboardHasFormat(ES_CLIPBOARD_PRIMARY, ES_CLIPBOARD_FORMAT_PATH_LIST)) {
|
||||
// TODO Background task.
|
||||
// TODO Reporting errors properly. Ask to retry or cancel.
|
||||
// TODO If the destination file already exists, ask to replace, skip, rename or cancel.
|
||||
// TODO Other namespace handlers.
|
||||
// TODO Undo.
|
||||
struct PasteTask {
|
||||
// Input:
|
||||
String destinationBase;
|
||||
bool move;
|
||||
char *pathList;
|
||||
size_t pathListBytes;
|
||||
};
|
||||
|
||||
void *copyBuffer = nullptr;
|
||||
void CommandPasteTask(EsGeneric _task) {
|
||||
// TODO Background task.
|
||||
// TODO Reporting errors properly. Ask to retry or cancel.
|
||||
// TODO If the destination file already exists, ask to replace, skip, rename or cancel.
|
||||
// TODO Other namespace handlers.
|
||||
// TODO Undo.
|
||||
|
||||
size_t bytes;
|
||||
uint32_t flags;
|
||||
char *pathList = EsClipboardReadText(ES_CLIPBOARD_PRIMARY, &bytes, &flags);
|
||||
PasteTask *task = (PasteTask *) _task.p;
|
||||
Array<PasteOperation> pasteOperations = {};
|
||||
EsError error = ES_SUCCESS;
|
||||
|
||||
bool move = flags & ES_CLIPBOARD_ADD_LAZY_CUT;
|
||||
String destinationBase = StringDuplicate(instance->folder->path);
|
||||
Array<PasteOperation> pasteOperations = {};
|
||||
void *copyBuffer = nullptr;
|
||||
const char *position = task->pathList;
|
||||
|
||||
bool success = true;
|
||||
while (task->pathListBytes) {
|
||||
const char *newline = (const char *) EsCRTmemchr(position, '\n', task->pathListBytes);
|
||||
if (!newline) break;
|
||||
|
||||
if (pathList) {
|
||||
const char *position = pathList;
|
||||
String source = StringFromLiteralWithSize(position, newline - position);
|
||||
String destination;
|
||||
error = CommandPasteFile(source, task->destinationBase, ©Buffer, task->move, &destination);
|
||||
if (error != ES_SUCCESS) break;
|
||||
|
||||
while (bytes) {
|
||||
const char *newline = (const char *) EsCRTmemchr(position, '\n', bytes);
|
||||
if (!newline) break;
|
||||
PasteOperation operation = { .source = StringDuplicate(source), .destination = destination };
|
||||
pasteOperations.Add(operation);
|
||||
|
||||
String source = StringFromLiteralWithSize(position, newline - position);
|
||||
String destination;
|
||||
position += source.bytes + 1;
|
||||
task->pathListBytes -= source.bytes + 1;
|
||||
}
|
||||
|
||||
if (ES_SUCCESS != CommandPasteFile(source, destinationBase, ©Buffer, move, &destination)) {
|
||||
goto encounteredError;
|
||||
}
|
||||
EsMessageMutexAcquire();
|
||||
|
||||
PasteOperation operation = { .source = StringDuplicate(source), .destination = destination };
|
||||
pasteOperations.Add(operation);
|
||||
size_t pathSectionCount = PathCountSections(task->destinationBase);
|
||||
FolderFileUpdatedAtPath(PathGetDrive(task->destinationBase), nullptr);
|
||||
|
||||
position += source.bytes + 1;
|
||||
bytes -= source.bytes + 1;
|
||||
}
|
||||
} else {
|
||||
encounteredError:;
|
||||
EsPoint point = EsListViewGetAnnouncementPointForSelection(instance->list);
|
||||
EsAnnouncementShow(instance->window, ES_FLAGS_DEFAULT, point.x, point.y, INTERFACE_STRING(CommonAnnouncementPasteErrorOther));
|
||||
success = false;
|
||||
}
|
||||
|
||||
size_t pathSectionCount = PathCountSections(destinationBase);
|
||||
|
||||
for (uintptr_t i = 0; i < pathSectionCount; i++) {
|
||||
String parent = PathGetParent(destinationBase, i + 1);
|
||||
FolderFileUpdatedAtPath(parent, nullptr);
|
||||
}
|
||||
for (uintptr_t i = 0; i < pathSectionCount; i++) {
|
||||
String parent = PathGetParent(task->destinationBase, i + 1);
|
||||
FolderFileUpdatedAtPath(parent, nullptr);
|
||||
}
|
||||
|
||||
if (task->move) {
|
||||
if (pasteOperations.Length()) {
|
||||
size_t pathSectionCount = PathCountSections(pasteOperations[0].source);
|
||||
FolderFileUpdatedAtPath(PathGetDrive(pasteOperations[0].source), nullptr);
|
||||
|
||||
for (uintptr_t i = 0; i < pathSectionCount; i++) {
|
||||
String parent = PathGetParent(pasteOperations[0].source, i + 1);
|
||||
|
@ -314,28 +309,61 @@ void CommandPaste(Instance *instance, EsElement *, EsCommand *) {
|
|||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
EsListViewSelectNone(instance->list);
|
||||
}
|
||||
|
||||
for (uintptr_t i = 0; i < pasteOperations.Length(); i++) {
|
||||
if (success) {
|
||||
InstanceSelectByName(instance, PathGetName(pasteOperations[i].destination), true, i == pasteOperations.Length() - 1);
|
||||
FolderPathMoved(pasteOperations[i].source, pasteOperations[i].destination, i == pasteOperations.Length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (move) {
|
||||
// TODO We must do this regardless of whether the instance has been destroyed during the operation.
|
||||
FolderPathMoved(instance, pasteOperations[i].source, pasteOperations[i].destination, i == pasteOperations.Length() - 1);
|
||||
for (uintptr_t i = 0; i < instances.Length(); i++) {
|
||||
Instance *instance = instances[i];
|
||||
|
||||
if (instance->issuedPasteTask == task) {
|
||||
instance->issuedPasteTask = nullptr;
|
||||
|
||||
if (error != ES_SUCCESS) {
|
||||
EsPoint point = EsListViewGetAnnouncementPointForSelection(instance->list);
|
||||
EsAnnouncementShow(instance->window, ES_FLAGS_DEFAULT, point.x, point.y, INTERFACE_STRING(CommonAnnouncementPasteErrorOther));
|
||||
} else {
|
||||
EsListViewSelectNone(instance->list);
|
||||
|
||||
for (uintptr_t i = 0; i < pasteOperations.Length(); i++) {
|
||||
String name = PathRemoveTrailingSlash(PathGetName(pasteOperations[i].destination));
|
||||
InstanceSelectByName(instance, name, true, i == pasteOperations.Length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
StringDestroy(&pasteOperations[i].source);
|
||||
StringDestroy(&pasteOperations[i].destination);
|
||||
}
|
||||
}
|
||||
|
||||
EsHeapFree(pathList);
|
||||
EsHeapFree(copyBuffer);
|
||||
StringDestroy(&destinationBase);
|
||||
pasteOperations.Free();
|
||||
EsMessageMutexRelease();
|
||||
|
||||
for (uintptr_t i = 0; i < pasteOperations.Length(); i++) {
|
||||
StringDestroy(&pasteOperations[i].source);
|
||||
StringDestroy(&pasteOperations[i].destination);
|
||||
}
|
||||
|
||||
pasteOperations.Free();
|
||||
EsHeapFree(copyBuffer);
|
||||
EsHeapFree(task->pathList);
|
||||
StringDestroy(&task->destinationBase);
|
||||
EsHeapFree(task);
|
||||
}
|
||||
|
||||
void CommandPaste(Instance *instance, EsElement *, EsCommand *) {
|
||||
if (EsClipboardHasFormat(ES_CLIPBOARD_PRIMARY, ES_CLIPBOARD_FORMAT_PATH_LIST)) {
|
||||
PasteTask *task = (PasteTask *) EsHeapAllocate(sizeof(PasteTask), true);
|
||||
uint32_t flags;
|
||||
task->pathList = EsClipboardReadText(ES_CLIPBOARD_PRIMARY, &task->pathListBytes, &flags);
|
||||
task->move = flags & ES_CLIPBOARD_ADD_LAZY_CUT;
|
||||
task->destinationBase = StringDuplicate(instance->folder->path);
|
||||
instance->issuedPasteTask = task;
|
||||
|
||||
if (ES_SUCCESS != EsUserTaskStart(CommandPasteTask, task)) {
|
||||
EsPoint point = EsListViewGetAnnouncementPointForSelection(instance->list);
|
||||
EsAnnouncementShow(instance->window, ES_FLAGS_DEFAULT, point.x, point.y, INTERFACE_STRING(CommonAnnouncementPasteErrorOther));
|
||||
EsHeapFree(task->pathList);
|
||||
StringDestroy(&task->destinationBase);
|
||||
EsHeapFree(task);
|
||||
}
|
||||
} else {
|
||||
// TODO Paste the data into a new file.
|
||||
}
|
||||
|
|
|
@ -469,8 +469,8 @@ void FolderFileUpdatedAtPath(String path, Instance *instance) {
|
|||
}
|
||||
}
|
||||
|
||||
void FolderPathMoved(Instance *instance, String oldPath, String newPath, bool saveConfiguration) {
|
||||
_EsPathAnnouncePathMoved(instance, STRING(oldPath), STRING(newPath));
|
||||
void FolderPathMoved(String oldPath, String newPath, bool saveConfiguration) {
|
||||
_EsPathAnnouncePathMoved(STRING(oldPath), STRING(newPath));
|
||||
|
||||
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
||||
Folder *folder = loadedFolders[i];
|
||||
|
|
|
@ -168,9 +168,11 @@ struct Instance : EsInstance {
|
|||
|
||||
FolderViewSettings viewSettings;
|
||||
|
||||
// Blocking task thread.
|
||||
// Tasks that block the use of the instance,
|
||||
// but display progress and can be (optionally) cancelled.
|
||||
// Asynchronous tasks.
|
||||
|
||||
struct PasteTask *issuedPasteTask;
|
||||
|
||||
// Tasks that block the use of the instance, but display progress and can be (optionally) cancelled.
|
||||
// Shows the dialog after some threshold.
|
||||
#define BLOCKING_TASK_DIALOG_THRESHOLD_MS (100)
|
||||
Task blockingTask;
|
||||
|
|
|
@ -192,6 +192,13 @@ String PathGetName(String path) {
|
|||
return path;
|
||||
}
|
||||
|
||||
String PathGetDrive(String path) {
|
||||
uintptr_t i = 0;
|
||||
while (i < path.bytes && path.text[i] != '/') i++;
|
||||
path.bytes = i;
|
||||
return path;
|
||||
}
|
||||
|
||||
bool PathHasPrefix(String path, String prefix) {
|
||||
prefix = PathRemoveTrailingSlash(prefix);
|
||||
return StringStartsWith(path, prefix) && path.bytes > prefix.bytes && path.text[prefix.bytes] == '/';
|
||||
|
|
|
@ -29,6 +29,8 @@ bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, i
|
|||
return true;
|
||||
}
|
||||
|
||||
instance->issuedPasteTask = nullptr;
|
||||
|
||||
InstanceRemoveContents(instance);
|
||||
FolderAttachInstance(instance, path, false);
|
||||
StringDestroy(&path);
|
||||
|
|
|
@ -133,6 +133,8 @@ struct {
|
|||
uintptr_t performanceTimerStackCount;
|
||||
|
||||
ThreadLocalStorage firstThreadLocalStorage;
|
||||
|
||||
size_t openInstanceCount; // Also counts user tasks.
|
||||
} api;
|
||||
|
||||
ptrdiff_t tlsStorageOffset;
|
||||
|
@ -244,6 +246,7 @@ MountPoint *NodeFindMountPoint(const char *prefix, size_t prefixBytes) {
|
|||
bool EsMountPointGetVolumeInformation(const char *prefix, size_t prefixBytes, EsVolumeInformation *information) {
|
||||
MountPoint *mountPoint = NodeFindMountPoint(prefix, prefixBytes);
|
||||
if (!mountPoint) return false;
|
||||
EsSyscall(ES_SYSCALL_VOLUME_GET_INFORMATION, mountPoint->base, (uintptr_t) &mountPoint->information, 0, 0);
|
||||
EsMemoryCopy(information, &mountPoint->information, sizeof(EsVolumeInformation));
|
||||
return true;
|
||||
}
|
||||
|
@ -513,7 +516,7 @@ int EsMessageSend(EsElement *element, EsMessage *message) {
|
|||
return response;
|
||||
}
|
||||
|
||||
void _EsPathAnnouncePathMoved(EsInstance *instance, const char *oldPath, ptrdiff_t oldPathBytes, const char *newPath, ptrdiff_t newPathBytes) {
|
||||
void _EsPathAnnouncePathMoved(const char *oldPath, ptrdiff_t oldPathBytes, const char *newPath, ptrdiff_t newPathBytes) {
|
||||
if (oldPathBytes == -1) oldPathBytes = EsCStringLength(oldPath);
|
||||
if (newPathBytes == -1) newPathBytes = EsCStringLength(newPath);
|
||||
size_t bufferBytes = 1 + sizeof(uintptr_t) * 2 + oldPathBytes + newPathBytes;
|
||||
|
@ -523,7 +526,7 @@ void _EsPathAnnouncePathMoved(EsInstance *instance, const char *oldPath, ptrdiff
|
|||
EsMemoryCopy(buffer + 1 + sizeof(uintptr_t), &newPathBytes, sizeof(uintptr_t));
|
||||
EsMemoryCopy(buffer + 1 + sizeof(uintptr_t) * 2, oldPath, oldPathBytes);
|
||||
EsMemoryCopy(buffer + 1 + sizeof(uintptr_t) * 2 + oldPathBytes, newPath, newPathBytes);
|
||||
MessageDesktop(buffer, bufferBytes, instance->window->handle);
|
||||
MessageDesktop(buffer, bufferBytes);
|
||||
EsHeapFree(buffer);
|
||||
}
|
||||
|
||||
|
@ -675,6 +678,7 @@ EsInstance *_EsInstanceCreate(size_t bytes, EsMessage *message, const char *appl
|
|||
APIInstance *apiInstance = InstanceSetup(instance);
|
||||
apiInstance->applicationName = applicationName;
|
||||
apiInstance->applicationNameBytes = applicationNameBytes;
|
||||
api.openInstanceCount++;
|
||||
|
||||
if (message && message->createInstance.data != ES_INVALID_HANDLE && message->createInstance.dataBytes > 1) {
|
||||
apiInstance->startupInformation = (EsApplicationStartupInformation *) EsHeapAllocate(message->createInstance.dataBytes, false);
|
||||
|
@ -781,9 +785,12 @@ EsMessage *EsMessageReceive() {
|
|||
} else if (message.message.type == ES_MSG_APPLICATION_EXIT) {
|
||||
EsProcessTerminateCurrent();
|
||||
} else if (message.message.type == ES_MSG_INSTANCE_DESTROY) {
|
||||
api.openInstanceCount--;
|
||||
|
||||
APIInstance *instance = (APIInstance *) message.message.instanceDestroy.instance->_private;
|
||||
|
||||
if (instance->startupInformation && (instance->startupInformation->flags & ES_APPLICATION_STARTUP_SINGLE_INSTANCE_IN_PROCESS)) {
|
||||
if (instance->startupInformation && (instance->startupInformation->flags & ES_APPLICATION_STARTUP_SINGLE_INSTANCE_IN_PROCESS)
|
||||
&& !api.openInstanceCount) {
|
||||
EsMessage m = { ES_MSG_APPLICATION_EXIT };
|
||||
EsMessagePost(nullptr, &m);
|
||||
}
|
||||
|
@ -1540,6 +1547,37 @@ const void *EsEmbeddedFileGet(const char *_name, ptrdiff_t nameBytes, size_t *by
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
struct UserTask {
|
||||
EsUserTaskCallbackFunction callback;
|
||||
EsGeneric data;
|
||||
};
|
||||
|
||||
void UserTaskThread(EsGeneric _task) {
|
||||
UserTask *task = (UserTask *) _task.p;
|
||||
task->callback(task->data);
|
||||
EsMessageMutexAcquire();
|
||||
api.openInstanceCount--;
|
||||
// TODO Send ES_MSG_APPLICATION_EXIT if needed.
|
||||
// TODO Tell Desktop the task is complete.
|
||||
EsMessageMutexRelease();
|
||||
EsHeapFree(task);
|
||||
}
|
||||
|
||||
EsError EsUserTaskStart(EsUserTaskCallbackFunction callback, EsGeneric data) {
|
||||
EsMessageMutexCheck();
|
||||
UserTask *task = (UserTask *) EsHeapAllocate(sizeof(UserTask), true);
|
||||
if (!task) return ES_ERROR_INSUFFICIENT_RESOURCES;
|
||||
task->callback = callback;
|
||||
task->data = data;
|
||||
// TODO Tell Desktop about the task. (This'll also prevent it sending ES_MSG_APPLICATION_EXIT in single process mode.)
|
||||
api.openInstanceCount++;
|
||||
EsThreadInformation information;
|
||||
EsError error = EsThreadCreate(UserTaskThread, &information, task);
|
||||
if (error == ES_SUCCESS) EsHandleClose(information.handle);
|
||||
else EsHeapFree(task);
|
||||
return error;
|
||||
}
|
||||
|
||||
void TimersThread(EsGeneric) {
|
||||
// TODO Maybe terminate this thread after ~10 seconds of no timers?
|
||||
|
||||
|
|
|
@ -1442,8 +1442,9 @@ void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *n
|
|||
EsMessagePostRemote(instance->processHandle, &m);
|
||||
}
|
||||
|
||||
void InstanceAnnouncePathMoved(ApplicationInstance *fromInstance, const uint8_t *buffer, size_t embedWindowMessageBytes) {
|
||||
void InstanceAnnouncePathMoved(InstalledApplication *fromApplication, const uint8_t *buffer, size_t embedWindowMessageBytes) {
|
||||
// TODO Update the location of installed applications and other things in the configuration.
|
||||
// TODO Replace fromApplication with something better.
|
||||
|
||||
uintptr_t oldPathBytes, newPathBytes;
|
||||
EsMemoryCopy(&oldPathBytes, buffer + 1, sizeof(uintptr_t));
|
||||
|
@ -1491,7 +1492,7 @@ void InstanceAnnouncePathMoved(ApplicationInstance *fromInstance, const uint8_t
|
|||
ApplicationInstance *instance = desktop.allApplicationInstances[i];
|
||||
|
||||
if (instance->documentID != documentID) continue;
|
||||
if (instance->application == fromInstance->application) continue;
|
||||
if (instance->application == fromApplication) continue;
|
||||
if (!instance->processHandle) continue;
|
||||
|
||||
EsMessage m = { ES_MSG_INSTANCE_DOCUMENT_RENAMED };
|
||||
|
@ -2038,6 +2039,12 @@ void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
|
|||
if (application && (application->permissions & APPLICATION_PERMISSION_VIEW_FILE_TYPES)) {
|
||||
ConfigurationWriteSectionsToBuffer("file_type", nullptr, false, pipe);
|
||||
}
|
||||
} else if (buffer[0] == DESKTOP_MSG_ANNOUNCE_PATH_MOVED && message->desktop.bytes > 1 + sizeof(uintptr_t) * 2) {
|
||||
InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
|
||||
|
||||
if (application && (application->permissions & APPLICATION_PERMISSION_ALL_FILES)) {
|
||||
InstanceAnnouncePathMoved(application, buffer, message->desktop.bytes);
|
||||
}
|
||||
} else if (!instance) {
|
||||
// -------------------------------------------------
|
||||
// | Messages below here require a valid instance. |
|
||||
|
@ -2072,10 +2079,6 @@ void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
|
|||
startupInformation.filePathBytes = document->pathBytes;
|
||||
ApplicationInstanceCreate(desktop.fileManager->id, &startupInformation, instance->tab->container);
|
||||
}
|
||||
} else if (buffer[0] == DESKTOP_MSG_ANNOUNCE_PATH_MOVED
|
||||
&& (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES)
|
||||
&& message->desktop.bytes > 1 + sizeof(uintptr_t) * 2) {
|
||||
InstanceAnnouncePathMoved(instance, buffer, message->desktop.bytes);
|
||||
} else if (buffer[0] == DESKTOP_MSG_RUN_TEMPORARY_APPLICATION) {
|
||||
if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_RUN_TEMPORARY_APPLICATION)) {
|
||||
InstalledApplication *application = (InstalledApplication *) EsHeapAllocate(sizeof(InstalledApplication), true);
|
||||
|
|
|
@ -1887,6 +1887,7 @@ function_pointer void EsUndoCallback(const void *item, EsUndoManager *manager, E
|
|||
function_pointer void EsMountPointEnumerationCallbackFunction(const char *prefix, size_t prefixBytes, EsGeneric context);
|
||||
function_pointer void EsListViewEnumerateVisibleItemsCallbackFunction(EsListView *view, EsElement *item, uint32_t group, EsGeneric index);
|
||||
function_pointer void EsFontEnumerationCallbackFunction(const EsFontInformation *information, EsGeneric context);
|
||||
function_pointer void EsUserTaskCallbackFunction(EsGeneric data);
|
||||
|
||||
// System.
|
||||
|
||||
|
@ -1958,7 +1959,7 @@ function void *EsFileStoreMap(EsFileStore *file, size_t *fileSize, uint32_t flag
|
|||
// Requires permission_all_files.
|
||||
function bool EsMountPointGetVolumeInformation(const char *prefix, size_t prefixBytes, EsVolumeInformation *information); // Returns false if the mount point does not exist.
|
||||
function void EsMountPointEnumerate(EsMountPointEnumerationCallbackFunction callback, EsGeneric context);
|
||||
function void _EsPathAnnouncePathMoved(EsInstance *instance, STRING oldPath, STRING newPath);
|
||||
function void _EsPathAnnouncePathMoved(STRING oldPath, STRING newPath);
|
||||
|
||||
// Processes and threads.
|
||||
|
||||
|
@ -2264,6 +2265,8 @@ function const EsApplicationStartupInformation *EsInstanceGetStartupInformation(
|
|||
function void EsInstanceOpenComplete(EsMessage *message, bool success, STRING errorText = BLANK_STRING);
|
||||
function void EsInstanceSaveComplete(EsMessage *message, bool success);
|
||||
|
||||
function EsError EsUserTaskStart(EsUserTaskCallbackFunction callback, EsGeneric data);
|
||||
|
||||
// Message processing.
|
||||
|
||||
function size_t EsMessageGetInputText(EsMessage *message, char *buffer); // The buffer should be 64 bytes in size.
|
||||
|
|
|
@ -432,3 +432,4 @@ EsClipboardHasData=430
|
|||
EsFileCopy=431
|
||||
EsListViewSelectNone=432
|
||||
EsElementIsFocused=433
|
||||
EsUserTaskStart=434
|
||||
|
|
Loading…
Reference in New Issue