show tasks button when user task started

This commit is contained in:
nakst 2021-09-03 10:24:28 +01:00
parent ce01df7c59
commit c80e762d86
6 changed files with 126 additions and 29 deletions

View File

@ -61,6 +61,7 @@ struct EnumString { const char *cName; int value; };
#define DESKTOP_MSG_SYSTEM_CONFIGURATION_GET (13)
#define DESKTOP_MSG_FILE_TYPES_GET (14)
#define DESKTOP_MSG_UNHANDLED_KEY_EVENT (15)
#define DESKTOP_MSG_START_USER_TASK (16)
struct EsFileStore {
#define FILE_STORE_HANDLE (1)
@ -1550,6 +1551,7 @@ const void *EsEmbeddedFileGet(const char *_name, ptrdiff_t nameBytes, size_t *by
struct UserTask {
EsUserTaskCallbackFunction callback;
EsGeneric data;
EsHandle taskHandle;
};
void UserTaskThread(EsGeneric _task) {
@ -1558,23 +1560,48 @@ void UserTaskThread(EsGeneric _task) {
EsMessageMutexAcquire();
api.openInstanceCount--;
// TODO Send ES_MSG_APPLICATION_EXIT if needed.
// TODO Tell Desktop the task is complete.
EsMessageMutexRelease();
EsSyscall(ES_SYSCALL_WINDOW_CLOSE, task->taskHandle, 0, 0, 0);
EsHandleClose(task->taskHandle);
EsHeapFree(task);
}
EsError EsUserTaskStart(EsUserTaskCallbackFunction callback, EsGeneric data) {
EsMessageMutexCheck();
UserTask *task = (UserTask *) EsHeapAllocate(sizeof(UserTask), true);
if (!task) return ES_ERROR_INSUFFICIENT_RESOURCES;
if (!task) {
return ES_ERROR_INSUFFICIENT_RESOURCES;
}
uint8_t m = DESKTOP_MSG_START_USER_TASK;
EsBuffer response = { .canGrow = true };
MessageDesktop(&m, 1, ES_INVALID_HANDLE, &response);
EsHandle handle;
EsBufferReadInto(&response, &handle, sizeof(handle));
EsHeapFree(response.out);
if (!handle) {
EsHeapFree(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++;
task->taskHandle = handle;
EsThreadInformation information;
EsError error = EsThreadCreate(UserTaskThread, &information, task);
if (error == ES_SUCCESS) EsHandleClose(information.handle);
else EsHeapFree(task);
if (error == ES_SUCCESS) {
EsHandleClose(information.handle);
api.openInstanceCount++;
} else {
EsSyscall(ES_SYSCALL_WINDOW_CLOSE, task->taskHandle, 0, 0, 0);
EsHandleClose(task->taskHandle);
EsHeapFree(task);
}
return error;
}

View File

@ -137,7 +137,7 @@ struct BlankTabInstance : CommonDesktopInstance {
struct ApplicationInstance {
// User interface.
WindowTab *tab; // nullptr for notRespondingInstance.
WindowTab *tab; // nullptr for notRespondingInstance and user tasks.
EsObjectID embeddedWindowID;
EsHandle embeddedWindowHandle;
@ -145,8 +145,9 @@ struct ApplicationInstance {
InstalledApplication *application;
EsObjectID documentID, processID;
EsHandle processHandle;
bool isUserTask;
// Tab information.
// Metadata.
char title[128];
size_t titleBytes;
uint32_t iconID;
@ -182,6 +183,7 @@ struct {
TaskBar taskBar;
EsWindow *wallpaperWindow;
EsButton *tasksButton;
bool shutdownWindowOpen;
bool setupDesktopUIComplete;
@ -729,12 +731,12 @@ int TaskBarMessage(EsElement *element, EsMessage *message) {
return 0;
}
int TaskBarTasksButtonMessage(EsElement *element, EsMessage *message) {
int TaskBarTasksButtonMessage(EsElement *, EsMessage *message) {
if (message->type == ES_MSG_GET_WIDTH) {
message->measure.width = GetConstantNumber("taskBarTasksButtonWidth");
return ES_HANDLED;
} else if (message->type == ES_MSG_PAINT_ICON) {
float progress = 0.33f;
float progress = 0.0f; // TODO.
uint32_t color1 = GetConstantNumber("taskBarTasksButtonWheelColor1");
uint32_t color2 = GetConstantNumber("taskBarTasksButtonWheelColor2");
@ -1200,8 +1202,10 @@ void ApplicationInstanceCrashed(EsMessage *message) {
ApplicationInstance *instance = desktop.allApplicationInstances[i];
if (instance->processID == message->crash.pid) {
ApplicationInstanceStart(APPLICATION_ID_DESKTOP_CRASHED, nullptr, instance);
WindowTabActivate(instance->tab, true);
if (instance->tab) {
ApplicationInstanceStart(APPLICATION_ID_DESKTOP_CRASHED, nullptr, instance);
WindowTabActivate(instance->tab, true);
}
}
}
@ -1884,8 +1888,8 @@ void DesktopSetup() {
desktop.taskBar.taskList.Initialise(panel, ES_CELL_FILL, ReorderListMessage, nullptr);
desktop.taskBar.taskList.cName = "task list";
EsButton *tasksButton = EsButtonCreate(panel, ES_ELEMENT_HIDDEN, ES_STYLE_TASK_BAR_BUTTON, "Copying files" ELLIPSIS, -1);
tasksButton->messageUser = TaskBarTasksButtonMessage;
desktop.tasksButton = EsButtonCreate(panel, ES_ELEMENT_HIDDEN, ES_STYLE_TASK_BAR_BUTTON, "Copying files" ELLIPSIS, -1);
desktop.tasksButton->messageUser = TaskBarTasksButtonMessage;
EsButton *shutdownButton = EsButtonCreate(panel, ES_FLAGS_DEFAULT, ES_STYLE_TASK_BAR_EXTRA);
EsButtonSetIcon(shutdownButton, ES_ICON_SYSTEM_SHUTDOWN_SYMBOLIC);
@ -1953,7 +1957,7 @@ void DesktopSetup() {
desktop.setupDesktopUIComplete = true;
}
void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
ApplicationInstance *instance = ApplicationInstanceFindByWindowID(message->desktop.windowID);
if (buffer[0] == DESKTOP_MSG_START_APPLICATION) {
@ -2045,6 +2049,57 @@ void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
if (application && (application->permissions & APPLICATION_PERMISSION_ALL_FILES)) {
InstanceAnnouncePathMoved(application, buffer, message->desktop.bytes);
}
} else if (buffer[0] == DESKTOP_MSG_START_USER_TASK && pipe) {
InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
if (!application) {
return;
}
// HACK User tasks use an embedded window object for IPC.
// This allows us to basically treat them like other instances.
EsHandle processHandle = EsProcessOpen(message->desktop.processID);
EsHandle windowHandle = EsSyscall(ES_SYSCALL_WINDOW_CREATE, ES_WINDOW_NORMAL, 0, 0, 0);
ApplicationInstance *instance = (ApplicationInstance *) EsHeapAllocate(sizeof(ApplicationInstance), true);
bool added = false;
if (processHandle && windowHandle && instance) {
added = desktop.allApplicationInstances.Add(instance);
}
if (!processHandle || !windowHandle || !instance || !added) {
if (processHandle) EsHandleClose(processHandle);
if (windowHandle) EsHandleClose(windowHandle);
if (instance) EsHeapFree(instance);
EsHandle invalid = ES_INVALID_HANDLE;
EsBufferWrite(pipe, &invalid, sizeof(invalid));
return;
}
instance->title[0] = ' ';
instance->titleBytes = 1;
instance->isUserTask = true;
instance->embeddedWindowHandle = windowHandle;
instance->embeddedWindowID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, windowHandle, 0, 0, 0);
instance->processHandle = processHandle;
instance->processID = message->desktop.processID;
instance->application = application;
if (application->singleProcessHandle) {
EsAssert(application->openInstanceCount);
application->openInstanceCount++;
}
EsHandle targetWindowHandle = EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, windowHandle, processHandle, 0, ES_WINDOW_PROPERTY_EMBED_OWNER);
EsBufferWrite(pipe, &targetWindowHandle, sizeof(targetWindowHandle));
if (EsElementIsHidden(desktop.tasksButton)) {
EsPanelStartMovementAnimation((EsPanel *) EsElementGetLayoutParent(desktop.tasksButton), 1.5f /* duration scale */);
EsElementStartTransition(desktop.tasksButton, ES_TRANSITION_FADE_IN, ES_ELEMENT_TRANSITION_ENTRANCE, 1.5f);
EsElementSetHidden(desktop.tasksButton, false);
}
} else if (!instance) {
// -------------------------------------------------
// | Messages below here require a valid instance. |
@ -2059,10 +2114,12 @@ void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
}
}
instance->tab->Repaint(true);
if (instance->tab) {
instance->tab->Repaint(true);
if (instance->tab == instance->tab->container->active) {
instance->tab->container->taskBarButton->Repaint(true);
if (instance->tab == instance->tab->container->active) {
instance->tab->container->taskBarButton->Repaint(true);
}
}
} else if (buffer[0] == DESKTOP_MSG_REQUEST_SAVE) {
ApplicationInstanceRequestSave(instance, (const char *) buffer + 1, message->desktop.bytes - 1);
@ -2201,7 +2258,7 @@ void DesktopMessage(EsMessage *message) {
if (buffer) {
EsConstantBufferRead(message->desktop.buffer, buffer);
EsBuffer pipe = { .canGrow = true };
DesktopMessage2(message, buffer, &pipe);
DesktopSyscall(message, buffer, &pipe);
if (message->desktop.pipe) EsPipeWrite(message->desktop.pipe, pipe.out, pipe.position);
EsHeapFree(pipe.out);
EsHeapFree(buffer);

View File

@ -321,6 +321,7 @@ struct ScrollPane {
struct PanelMovementItem {
EsElement *element;
EsRectangle oldBounds;
bool wasHidden;
};
struct EsPanel : EsElement {
@ -1903,15 +1904,19 @@ void PanelMoveChild(EsElement *element, int width, int height, int offsetX, int
continue;
}
int oldWidth = Width(item->oldBounds);
int oldHeight = Height(item->oldBounds);
int oldOffsetX = item->oldBounds.l;
int oldOffsetY = item->oldBounds.t;
if (item->wasHidden) {
break;
} else {
int oldWidth = Width(item->oldBounds);
int oldHeight = Height(item->oldBounds);
int oldOffsetX = item->oldBounds.l;
int oldOffsetY = item->oldBounds.t;
element->InternalMove(LinearInterpolate(oldWidth, width, progress),
LinearInterpolate(oldHeight, height, progress),
LinearInterpolate(oldOffsetX, offsetX, progress),
LinearInterpolate(oldOffsetY, offsetY, progress));
element->InternalMove(LinearInterpolate(oldWidth, width, progress),
LinearInterpolate(oldHeight, height, progress),
LinearInterpolate(oldOffsetX, offsetX, progress),
LinearInterpolate(oldOffsetY, offsetY, progress));
}
return;
}
@ -3471,6 +3476,7 @@ void EsPanelStartMovementAnimation(EsPanel *panel, float timeMultiplier) {
item.element = element;
item.oldBounds = ES_RECT_4(element->offsetX, element->offsetX + element->width,
element->offsetY, element->offsetY + element->height);
item.wasHidden = element->flags & ES_ELEMENT_HIDDEN;
panel->movementItems.Add(item);
}
@ -5643,6 +5649,11 @@ void EsElementSetHidden(EsElement *element, bool hidden) {
UIMaybeRemoveFocusedElement(element->window);
}
bool EsElementIsHidden(EsElement *element) {
EsMessageMutexCheck();
return element->flags & ES_ELEMENT_HIDDEN;
}
void EsElementSetDisabled(EsElement *element, bool disabled) {
EsMessageMutexCheck();

View File

@ -2285,6 +2285,7 @@ function void EsElementFocus(EsElement *element, uint32_t flags = ES_FLAGS_DEFAU
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, EsUICallbackFunction 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.

View File

@ -717,7 +717,7 @@ size_t EsGameControllerStatePoll(EsGameControllerState *buffer) {
return EsSyscall(ES_SYSCALL_GAME_CONTROLLER_STATE_POLL, (uintptr_t) buffer, 0, 0, 0);
}
void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe);
void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe);
void MessageDesktop(void *message, size_t messageBytes, EsHandle embeddedWindow = ES_INVALID_HANDLE, EsBuffer *responseBuffer = nullptr) {
if (api.startupInformation->isDesktop) {
@ -726,7 +726,7 @@ void MessageDesktop(void *message, size_t messageBytes, EsHandle embeddedWindow
m.desktop.windowID = embeddedWindow ? EsSyscall(ES_SYSCALL_WINDOW_GET_ID, embeddedWindow, 0, 0, 0) : 0;
m.desktop.processID = EsProcessGetID(ES_CURRENT_PROCESS);
m.desktop.bytes = messageBytes;
DesktopMessage2(&m, (uint8_t *) message, responseBuffer);
DesktopSyscall(&m, (uint8_t *) message, responseBuffer);
} else {
EsHandle pipeRead = ES_INVALID_HANDLE, pipeWrite = ES_INVALID_HANDLE;

View File

@ -433,3 +433,4 @@ EsFileCopy=431
EsListViewSelectNone=432
EsElementIsFocused=433
EsUserTaskStart=434
EsElementIsHidden=435