From 3c22769e7054b6c39f1e62880d96ea56c18556c2 Mon Sep 17 00:00:00 2001 From: nakst <> Date: Fri, 15 Oct 2021 17:43:03 +0100 Subject: [PATCH] add basic clock to task bar --- apps/installer.cpp | 11 +++++++++ desktop/api.cpp | 2 ++ desktop/desktop.cpp | 52 ++++++++++++++++++++++++++++++++++++++++- desktop/gui.cpp | 12 +++++++++- desktop/os.header | 2 +- desktop/theme.cpp | 2 +- res/Theme Source.dat | Bin 519760 -> 519800 bytes res/Theme.dat | Bin 29520 -> 29552 bytes shared/common.cpp | 2 +- util/build.c | 11 +++++++++ util/uefi.sh | 6 +---- util/uefi_compile.sh | 5 ++++ util/uefi_to_device.sh | 6 +---- 13 files changed, 96 insertions(+), 15 deletions(-) create mode 100755 util/uefi_compile.sh diff --git a/apps/installer.cpp b/apps/installer.cpp index fa06bfa..968231e 100644 --- a/apps/installer.cpp +++ b/apps/installer.cpp @@ -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); diff --git a/desktop/api.cpp b/desktop/api.cpp index bd649bd..e2402b0 100644 --- a/desktop/api.cpp +++ b/desktop/api.cpp @@ -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; diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp index 89a05d8..5b0710e 100644 --- a/desktop/desktop.cpp +++ b/desktop/desktop.cpp @@ -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(¤tTime); + + uint8_t secondsUntilNextMinuteChange = 60 - currentTime.second; + + currentTime.second = 0; + currentTime.millisecond = 0; + + if (0 == EsMemoryCompare(¤tTime, &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, ¤tTime, 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); diff --git a/desktop/gui.cpp b/desktop/gui.cpp index 2d911f1..3dc63e7 100644 --- a/desktop/gui.cpp +++ b/desktop/gui.cpp @@ -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(); diff --git a/desktop/os.header b/desktop/os.header index 58e0c3a..24a28c3 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -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); diff --git a/desktop/theme.cpp b/desktop/theme.cpp index 6040a3a..551eb59 100644 --- a/desktop/theme.cpp +++ b/desktop/theme.cpp @@ -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; diff --git a/res/Theme Source.dat b/res/Theme Source.dat index 7c8aa58a4e1bd65d85886d018ab36e6068832c00..0a47fb9a2c172e60b375aba313c6a238b147bd4a 100644 GIT binary patch delta 355 zcmWlT&nts*9LIe=&-Oe|O}o>#u4>(fbxM<*%<4EcIDtaZD^Qpw%XNYr_dtZ%fm2T+xH)Ps&i2_0 zqsf(}k!d?IzZ|z$rM(eGcNOcnsOA*yqW6Fr5lfK;XHAJ=_(s*;uQ2N`@>ua9KSeV* zJb3BX|gT?-M2!$omUE@xnR~$2D`_^G7c0#Qvr_4l|=#Y3D?BofGYK@DJ|1fSmvU delta 254 zcmexyNB+Vc`Gyw8ElmCb(|6xz=A3TP%e-W}!ZKzDMn;wG8|xYS87C(^3Yb2jkx^s1 z!40N}=??dRs_qIiMNfBNV$;~3Ai}hSW%>mNHjU{(X5{p_9W3gTIc5q>RFI#3Tau}D zI*TMz!}bSKOb!R9MKjNto)FE>IeldwqxPS1SD#JyeNE|bqPxLS9Rl7Q_zEzAlrlLfR?wx8L|T);Tl!AxQLhZ3j@ sCqKBO(Jt|X8Hic7OFUt{y^D#_c>2a}AYstKrqLcSpKW`G&*Y`aQyin4dCvo zuZ%g47I1&ptHO+H4$gMB8=dDN{NB%4SX>162X&>>OW;0Nbxc)tdd)#!_Z_3NAHqG! z!3}Wl>vfFjm`*bu2KQ$;(BTlA$m&xH;YQ~;l(c|X`HB?og9{5#;owz=r@_?;uge@q zhO<-$59}0UHGT>@$qnGPNFKt$Ii*NZGyo4fq5KKi>2YWoJHQ=V;gzv$aDSCb<0h^c zorj=2Rs%(HOBJ@_;uN^Oe(?fuoB{U_sa~B_3=bEe{7X_Uf!l(CkBHc4(emmA*A=jG zc>3rnJoH1Eld`)GE>N<*0q!eRUEy_<=HOur%CDq}HUaLLl-DG3KNGn9lARfx za|Oql72NlwF|mV7(JO02yyg9!GY1t18l4%CT-e6^_uWI_(j*tP;O_c`5*_x^)j%W7 z2CDmhAX#_9`Yk_e5%&VPHzm6snnMn~P%IFZ9Br3GPIfs*H^ zh*tN(os)_<2`*oKn*MA0PtwDj5!LK(e!f`$*#K;5YM;L4#Xql8t)^|g>nC3Ej!`6`pnpsr%UNTA<<6Fo|@&=o_mMnTeW`#syeUry=Dp32m-+sPzk#QpL=Hkt-ug=(w4CWqs*AE*j@kh_I%-ka zL~lQb^M~8dX~}uT6OFp#!)RiAD0!{GC&$0B5Mv`2F^LvuT})9vVOpr1sGByYu} z2%B$WuW6np<3t6z<1K>|am7O0Y7>TE+iGw#cqHMP`1xkn(p|M(r(3n0WY1puOVWXB zH}>lEcy=r@8b~tIM3TA|i7g$AIMxMxiykE9D31NqX4%9qQRIHN2yBMM!~Ki}qrST- z^*i_ZEOj~Dn(quJeHi>YEjVJ8UME%WvQxD)g3r)fPPf*zaJuJoDHoEdZQTainY>5i zhp9E$rWjJ_o#Z@?bI@F}4GSE(3E!_#ivK}F)B}YqolvaH4;vD zAdG@xXNXF-bA9900y2zF*)~vg-WDxYxXoK~o9FAb*-fA2V@l)& zDW~03UFsX$ekym@C@i0Dx^F7e`Lrg%L_f>lt<@&90PW%xZvlh|G8Nd-t^9%*Z0tzA{r_VS4;;HY!juf zH_-Fq9=DV;i%))LnD}BRV6;#1sW)+;bjzZcmxIh z{IE|zaZC3L+fp9|+tMZ5vJu5mj@&IYS7y};hJ{tW98Z}qAAH-hRlL6q92wycskOp4 zHbIq)sY|=v*`s!TgEm)oD26I}r_xu=GMcMgi1k?S;S==3dK*gmQGEw6?-Ya!J`j8#+X7OxtNMrVxKiwUXGDcc8m%d4)W_%cPw2AJx$TV-qDb;QiC< zQO3R4>Ne38uT`Je_$q-t%fUMvMQ~-JQL_?*+2|WN3}(~PU^cn`Urtf=&&u%1|r)bCZ?YS}j`1r(0j{+A&nrWKc5NpgZa0>NT2v zs!c0!QJY^v|D1Z6T-30wrGGFb<+XCVkM1O&Ml zO9U{#qG!1aTSEda3|R00@1#Mqe<^b&|YjD~=t6dW)P#Fl{r9OY;W zj2}UVD)5j460z!r0Yeo~jo>x#2bgN%8<^?9DI05O36zyz=WcpK0V zuwoUQ1#Sc8|Fbxzn;_U}`3OJgOG%yJ`nvoz7mDmCTuwz!$ P0z<$okkJMwz&!9@vWKsb delta 4314 zcmZu#ZA?_z89wLE9mEI<4y&*tI|!=?@}b43Fav`O4j%&o10o;FARq$_id{Bkx4K|7 zscCEryiIFcHw&vjOqLi7wlP9kwqX-YvB8E!cI$32THCa^g{+&}?I?ZD)H@6(z2>9aB}EUNh+K{ls9t0O6iw z&;#xxy^b**(`mt%!F>S(9WKF%tgcZgH<*W@WCbkeD^j=xZexH7gXIBFf~ym*uQ-kj zXQ&PikD=81DHtSQ0QZLEz}guzOFaeB4LF2B`4h6!MJ z_dOO&?G1^NUI7oof+DVM-)l=|xj7a?&tE&{Mbp=_4=8v?h+Z=;EfZ-I-J z9LA{*4iivf{1j2+DR9jz95|Z+_Z_LHS-KHmNPG-skDr6+Zyww|iF*ca9}NT;3ezQp zeHTa33XZctaNm>WCk$Ms6cW|GIFZ9;$_g}?uR$sBQ$(wq;Lb^P zzXh&PikqO`Ktsedl>1V~v)~TW*+4^Gmp(vPzRH9%50o2{PvBdO{aWI}z&Rw>NN{KM z-Xq@Ux0iOVHoRtmQXxg>4p*)Y*9EcFECl^u4Z@8cro~WyP>Dvy2IFM%lE&a8oY8y1 z4$g-E7~F)Pw&ApOALE0*4fz=N+o4cs?fQ?z_x1N7_ZbpI)L7U_@sYG)6IVr7w9~a| z*tPMg0`k!71veD!~-0i;d}v-3~fFc1gs%je3(d()6}4a>W%Q_BU}q5Lsr#J2aztTHL;k#^c`v{UlzbI+l1e7>xB69*KixxLrtQBnxJO6M zbd|@_jWk1FSkS5^THf$SN(wahPPh#F*7Bq$3RbUUL!i#JkmW-_;v zIdg=k(7!Vs{5%y}9Lj=)KD4wb)+{Qrl=2~}%WCB+MejHCZBprR)^4r+VQ{_-2mK#r z>CXNHwD|^iL}fepAibS!N6~(l9gq9dY#X=IZtFp1)JkK zdVMRU?Z6XSjN-4HLrQJq9&e=t7n^AOQvui0mv(d}at<=+?>PJRKmU1aH*TFmKq0K;@ zxsiMd&jz}dYf+4ObUk@PU!Jc-#bnM)=H1kWJ0>*GmpP-wygiCDpEA-nkR{)Qzbnt= z+Z0beoe14P5At_weHRy?Ks)F_!5doH;a1>vEAY9gvA z;ytvlrb}6 zfyNq^=SDF#3YuS}GmY8G^G15Nr6BCpsibGSn2D*Zp}u}8m7sS zdarT6Vr=oQrjQn2)i7}_>1h5=i~av)6G)%6)MGoCTR*^(`=Yg)U!{HS50JrU?rL#r zv?cIMRM+NP$CGW8(UQh-M7H@>f7uDK`o->dpGf7i{*sE9EUz>ic`{Y$>PTm-+l03= zAkNI#X&{%Y6m8OXFzT)W1YYhV9aBz80ZFOfS`QFoWM1} z0~8lP17-jfoBuFy3+O0hY!Y}5*o)u?OaUHX;UHei2aAyjcJVZDv6QhnAjE-60R3f* z)s$nDK*%991dJ8nfFU5{FgU= width || j - cy < 0 || j - cy >= height) { - *pixel = 0x738393; + *pixel = 0x77B9F9; } else { *pixel = image[i - cx + (j - cy) * width]; } diff --git a/util/build.c b/util/build.c index 1a6ff5a..0b260c9 100644 --- a/util/build.c +++ b/util/build.c @@ -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"); diff --git a/util/uefi.sh b/util/uefi.sh index 533eedd..203290f 100755 --- a/util/uefi.sh +++ b/util/uefi.sh @@ -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 diff --git a/util/uefi_compile.sh b/util/uefi_compile.sh new file mode 100755 index 0000000..fb5ad6b --- /dev/null +++ b/util/uefi_compile.sh @@ -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 diff --git a/util/uefi_to_device.sh b/util/uefi_to_device.sh index c9d71d2..e621526 100755 --- a/util/uefi_to_device.sh +++ b/util/uefi_to_device.sh @@ -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