add basic clock to task bar

This commit is contained in:
nakst 2021-10-15 17:43:03 +01:00
parent 8ee9b564a9
commit 3c22769e70
13 changed files with 96 additions and 15 deletions

View File

@ -907,6 +907,17 @@ void WriteNewConfiguration() {
} else if (!s.sectionClassBytes && 0 == EsStringCompareRaw(s.section, s.sectionBytes, EsLiteral("general"))
&& 0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("installation_state"))) {
EsBufferFormat(&buffer, "installation_state=0\n");
} else if (!s.sectionClassBytes && 0 == EsStringCompareRaw(s.section, s.sectionBytes, EsLiteral("general"))
&& 0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("clock_offset_ms"))) {
EsAssert(false);
} else if (!s.sectionClassBytes && 0 == EsStringCompareRaw(s.section, s.sectionBytes, EsLiteral("general"))
&& 0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("user_name"))) {
EsAssert(false);
} else if (!s.sectionClassBytes && 0 == EsStringCompareRaw(s.section, s.sectionBytes, EsLiteral("general")) && !s.keyBytes) {
size_t userNameBytes;
char *userName = EsTextboxGetContents(userNameTextbox, &userNameBytes);
EsBufferFormat(&buffer, "[general]\nclock_offset_ms=%d\nuser_name=%s\n", clockOffsetMs, userNameBytes, userName);
EsHeapFree(userName);
} else {
size_t lineBytes = EsINIFormat(&s, lineBuffer, lineBufferBytes);
EsBufferWrite(&buffer, lineBuffer, lineBytes);

View File

@ -428,6 +428,8 @@ void SystemConfigurationUnload() {
}
void SystemConfigurationLoad(const char *file, size_t fileBytes) {
// TODO Detecting duplicate keys?
EsINIState s = {};
s.buffer = (char *) file;
s.bytes = fileBytes;

View File

@ -218,6 +218,8 @@ struct {
bool inShutdown;
bool inspectorOpen;
EsHandle clockReady;
} desktop;
int TaskBarButtonMessage(EsElement *element, EsMessage *message);
@ -1217,6 +1219,40 @@ int TaskBarTasksButtonMessage(EsElement *element, EsMessage *message) {
return ES_HANDLED;
}
void TaskBarClockUpdateThread(EsGeneric _clock) {
EsWaitSingle(desktop.clockReady);
EsButton *clock = (EsButton *) _clock.p;
static EsDateComponents previousTime = {};
while (true) {
// TODO Use the local time zone.
EsDateComponents currentTime;
EsDateNowUTC(&currentTime);
uint8_t secondsUntilNextMinuteChange = 60 - currentTime.second;
currentTime.second = 0;
currentTime.millisecond = 0;
if (0 == EsMemoryCompare(&currentTime, &previousTime, sizeof(EsDateComponents))) {
// The minute or hour hasn't changed. Wait for the next change.
EsSleep((secondsUntilNextMinuteChange + 1) * 1000);
} else {
// Update the clock's label.
// TODO Proper clock formatting.
char label[32];
size_t labelBytes = EsStringFormat(label, sizeof(label), "%d%d:%d%d",
currentTime.hour / 10, currentTime.hour % 10, currentTime.minute / 10, currentTime.minute % 10);
EsMessageMutexAcquire();
EsButtonSetLabel(clock, label, labelBytes);
EsMessageMutexRelease();
EsMemoryCopy(&previousTime, &currentTime, sizeof(EsDateComponents));
}
}
}
void Shutdown(uintptr_t action) {
// TODO This doesn't wait for Desktop instances.
@ -1771,6 +1807,7 @@ ApplicationInstance *ApplicationInstanceCreate(int64_t id, _EsApplicationStartup
return instance;
} else {
if (!hidden) WindowTabDestroy(tab); // TODO Test this.
desktop.allApplicationInstances.FindAndDeleteSwap(instance, true);
EsHeapFree(instance);
return nullptr;
}
@ -2513,6 +2550,14 @@ void DesktopSetup() {
desktop.tasksButton = EsButtonCreate(panel, ES_ELEMENT_HIDDEN, ES_STYLE_TASK_BAR_BUTTON);
desktop.tasksButton->messageUser = TaskBarTasksButtonMessage;
EsButton *clockButton = EsButtonCreate(panel, ES_BUTTON_TABULAR | ES_BUTTON_COMPACT, ES_STYLE_TASK_BAR_EXTRA);
clockButton->cName = "current time";
EsThreadCreate(TaskBarClockUpdateThread, nullptr, clockButton);
EsButtonOnCommand(clockButton, [] (EsInstance *, EsElement *, EsCommand *) {
ApplicationInstanceCreate(APPLICATION_ID_DESKTOP_SETTINGS, nullptr, nullptr);
});
EsButton *shutdownButton = EsButtonCreate(panel, ES_FLAGS_DEFAULT, ES_STYLE_TASK_BAR_EXTRA);
EsButtonSetIcon(shutdownButton, ES_ICON_SYSTEM_SHUTDOWN_SYMBOLIC);
@ -2948,7 +2993,10 @@ void DesktopMessage(EsMessage *message) {
if (ES_SUCCESS == EsDeviceControl(handle, ES_DEVICE_CONTROL_CLOCK_READ, &reading, &linear)) {
// TODO Scheduler timer is not particularly accurate, so we should periodically resynchronize with the clock.
api.global->schedulerTimeOffset = (linear ?: DateToLinear(&reading)) - api.global->schedulerTimeMs;
api.global->schedulerTimeOffset = (linear ?: DateToLinear(&reading))
- api.global->schedulerTimeMs
+ EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("clock_offset_ms"), 0);
EsEventSet(desktop.clockReady);
}
}
} else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM || message->type == ES_MSG_DEVICE_DISCONNECTED) {
@ -2993,6 +3041,8 @@ void DesktopMessage(EsMessage *message) {
void DesktopEntry() {
ConfigurationLoadApplications();
desktop.clockReady = EsEventCreate(false);
EsMessage m = { MSG_SETUP_DESKTOP_UI };
EsMessagePost(nullptr, &m);

View File

@ -3926,7 +3926,8 @@ int ProcessButtonMessage(EsElement *element, EsMessage *message) {
EsDrawContent(message->painter, element,
ES_RECT_2S(message->painter->width, message->painter->height),
button->label, button->labelBytes, button->iconID,
(button->flags & ES_BUTTON_DROPDOWN) ? ES_DRAW_CONTENT_MARKER_DOWN_ARROW : ES_FLAGS_DEFAULT);
((button->flags & ES_BUTTON_DROPDOWN) ? ES_DRAW_CONTENT_MARKER_DOWN_ARROW : 0)
| ((button->flags & ES_BUTTON_TABULAR) ? ES_DRAW_CONTENT_TABULAR : 0));
} else if (message->type == ES_MSG_PAINT_ICON) {
if (button->imageDisplay) {
EsRectangle imageSize = ES_RECT_2S(button->imageDisplay->width, button->imageDisplay->height);
@ -4099,6 +4100,15 @@ EsButton *EsButtonCreate(EsElement *parent, uint64_t flags, const EsStyle *style
return button;
}
void EsButtonSetLabel(EsButton *button, const char *label, ptrdiff_t labelBytes) {
EsMessageMutexCheck();
if (labelBytes == -1) labelBytes = EsCStringLength(label);
HeapDuplicate((void **) &button->label, &button->labelBytes, label, labelBytes);
button->Repaint(true);
button->state &= ~UI_STATE_USE_MEASUREMENT_CACHE;
EsElementUpdateContentSize(button->parent);
}
void EsButtonSetIcon(EsButton *button, uint32_t iconID) {
EsMessageMutexCheck();

View File

@ -514,6 +514,7 @@ define ES_BUTTON_CHECKBOX (1 << 10)
define ES_BUTTON_RADIOBOX (1 << 11)
define ES_BUTTON_CANCEL (1 << 12)
define ES_BUTTON_PUSH (1 << 13)
define ES_BUTTON_TABULAR (1 << 14) // Use tabular text figures.
define ES_MENU_ITEM_CHECKED (ES_CHECK_CHECKED)
define ES_COLOR_WELL_HAS_OPACITY (1 << 0)
@ -2468,7 +2469,6 @@ private function void _EsUISetFont(EsFontFamily id);
// Buttons.
function EsButton *EsButtonCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL, STRING label = BLANK_STRING);
function void EsButtonSetIcon(EsButton *button, uint32_t iconID);
function void EsButtonSetIconFromBits(EsButton *button, const uint32_t *bits, size_t width, size_t height, size_t stride);
function void EsButtonSetCheck(EsButton *button, EsCheckState checkState = ES_CHECK_CHECKED, bool sendUpdatedMessage = true);

View File

@ -1883,7 +1883,7 @@ void UIStyle::PaintText(EsPainter *painter, EsElement *element, EsRectangle rect
EsRectangle bounds = Translate(EsRectangleAddBorder(rectangle, insets), painter->offsetX, painter->offsetY);
EsRectangle textBounds = bounds;
EsRectangle oldClip = painter->clip;
EsRectangleClip(painter->clip, bounds, &painter->clip);
EsRectangleClip(painter->clip, Translate(rectangle, painter->offsetX, painter->offsetY), &painter->clip);
EsRectangle iconBounds = EsRectangleSplit(&textBounds, metrics->iconSize, metrics->layoutVertical ? 't' : 'l', gapMinor);
EsPainter iconPainter = *painter;

Binary file not shown.

Binary file not shown.

View File

@ -1638,7 +1638,7 @@ void LoadImage(const void *path, ptrdiff_t pathBytes, void *destination, int des
for (int i = 0; i < destinationWidth; i++, pixel++) {
if (i - cx < 0 || i - cx >= width || j - cy < 0 || j - cy >= height) {
*pixel = 0x738393;
*pixel = 0x77B9F9;
} else {
*pixel = image[i - cx + (j - cy) * width];
}

View File

@ -1119,6 +1119,17 @@ void DoCommand(const char *l) {
fwrite(&uncompressed, 1, sizeof(uncompressed), f);
fwrite(&crc64, 1, sizeof(crc64), f);
fclose(f);
} else if (0 == strcmp(l, "make-installer-root")) {
DoCommand("make-installer-archive");
CallSystem("util/uefi_compile.sh");
CallSystem("cp bin/mbr root/mbr.dat");
CallSystem("cp bin/stage1 root/stage1.dat");
CallSystem("cp bin/stage2 root/stage2.dat");
CallSystem("cp bin/uefi root/uefi1.dat");
CallSystem("cp bin/uefi_loader root/uefi2.dat");
CallSystem("cp LICENSE.md root/installer_licenses.txt");
CallSystem("mv bin/installer_archive.dat root");
CallSystem("mv bin/installer_metadata.dat root");
} else if (0 == strcmp(l, "config")) {
BuildUtilities();
CallSystem("bin/config_editor");

View File

@ -10,11 +10,7 @@
set -e
# Duplicated in uefi_to_device.sh.
CC="clang -target x86_64-unknown-windows -ffreestanding -fshort-wchar -mno-red-zone -I ports/efitoolkit/inc -c -Wall -Wextra"
LINK="clang -target x86_64-unknown-windows -nostdlib -Wl,-entry:efi_main -Wl,-subsystem:efi_application -fuse-ld=lld-link"
$CC -o bin/uefi.o boot/x86/uefi.c
$LINK -o bin/uefi bin/uefi.o
util/uefi_compile.sh
mkdir -p mount
sudo losetup --offset `fdisk -l bin/uefi_drive | grep 'EFI System' | awk '{print 512*$2}'` --sizelimit `fdisk -l bin/uefi_drive | grep 'EFI System' | awk '{print 512*$4}'` /dev/loop0 bin/uefi_drive

5
util/uefi_compile.sh Executable file
View File

@ -0,0 +1,5 @@
set -e
CC="clang -target x86_64-unknown-windows -ffreestanding -fshort-wchar -mno-red-zone -I ports/efitoolkit/inc -c -Wall -Wextra"
LINK="clang -target x86_64-unknown-windows -nostdlib -Wl,-entry:efi_main -Wl,-subsystem:efi_application -fuse-ld=lld-link"
$CC -o bin/uefi.o boot/x86/uefi.c
$LINK -o bin/uefi bin/uefi.o

View File

@ -4,11 +4,7 @@
set -e
# Duplicated from uefi.sh.
CC="clang -target x86_64-unknown-windows -ffreestanding -fshort-wchar -mno-red-zone -I ports/efitoolkit/inc -c -Wall -Wextra"
LINK="clang -target x86_64-unknown-windows -nostdlib -Wl,-entry:efi_main -Wl,-subsystem:efi_application -fuse-ld=lld-link"
$CC -o bin/uefi.o boot/x86/uefi.c
$LINK -o bin/uefi bin/uefi.o
util/uefi_compile.sh
mkdir -p mount
mount $1 mount