From 47e3bb54a5e63a21544c00bddb23f8b021e92757 Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Mon, 18 May 2026 20:00:42 +0200 Subject: [PATCH] feat: added Files app USB medium detection --- kernel/src/Api/Filesystem.hpp | 9 +++++++++ kernel/src/Api/Syscall.cpp | 2 ++ kernel/src/Api/Syscall.hpp | 1 + kernel/src/Fs/FsProbe.cpp | 12 ++++++++++++ kernel/src/Fs/FsProbe.hpp | 4 ++++ programs/include/Api/Syscall.hpp | 1 + programs/include/gui/desktop.hpp | 2 ++ programs/include/montauk/syscall.h | 5 +++++ .../obj/src/libprintersapplet.o | Bin 17560 -> 17616 bytes .../obj/src/libtimezonesapplet.o | Bin 17704 -> 17760 bytes programs/src/desktop/apps/filemanager/app.cpp | 2 ++ .../apps/filemanager/filemanager_internal.hpp | 1 + .../desktop/apps/filemanager/filesystem.cpp | 4 ++++ .../src/desktop/apps/filemanager/render.cpp | 9 +++++++-- 14 files changed, 50 insertions(+), 2 deletions(-) diff --git a/kernel/src/Api/Filesystem.hpp b/kernel/src/Api/Filesystem.hpp index d6aef9c..9e1892c 100644 --- a/kernel/src/Api/Filesystem.hpp +++ b/kernel/src/Api/Filesystem.hpp @@ -7,6 +7,8 @@ #pragma once #include +#include +#include #include #include #include @@ -126,4 +128,11 @@ namespace Montauk { static int Sys_DriveLabel(int driveNumber, char* outLabel, int maxLen) { return Fs::Vfs::VfsDriveLabel(driveNumber, outLabel, maxLen); } + + static int Sys_DriveKind(int driveNumber) { + int blockDev = Fs::FsProbe::GetBlockDeviceForDrive(driveNumber); + if (blockDev < 0) return 0; + auto* dev = Drivers::Storage::GetBlockDevice(blockDev); + return dev ? (int)dev->Kind : 0; + } }; diff --git a/kernel/src/Api/Syscall.cpp b/kernel/src/Api/Syscall.cpp index a65d51e..30e9ca4 100644 --- a/kernel/src/Api/Syscall.cpp +++ b/kernel/src/Api/Syscall.cpp @@ -217,6 +217,8 @@ namespace Montauk { if ((int64_t)frame->arg3 <= 0) return -1; if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return -1; return (int64_t)Sys_DriveLabel((int)frame->arg1, (char*)frame->arg2, (int)frame->arg3); + case SYS_DRIVEKIND: + return (int64_t)Sys_DriveKind((int)frame->arg1); case SYS_TERMSCALE: return Sys_TermScale(frame->arg1, frame->arg2); case SYS_RESOLVE: diff --git a/kernel/src/Api/Syscall.hpp b/kernel/src/Api/Syscall.hpp index 9410e4d..4c576fa 100644 --- a/kernel/src/Api/Syscall.hpp +++ b/kernel/src/Api/Syscall.hpp @@ -225,6 +225,7 @@ namespace Montauk { /* Filesystem.hpp */ static constexpr uint64_t SYS_DRIVELABEL = 124; + static constexpr uint64_t SYS_DRIVEKIND = 127; /* Net.hpp */ static constexpr uint64_t SYS_NETSTATUS = 125; diff --git a/kernel/src/Fs/FsProbe.cpp b/kernel/src/Fs/FsProbe.cpp index b962eb1..96ca425 100644 --- a/kernel/src/Fs/FsProbe.cpp +++ b/kernel/src/Fs/FsProbe.cpp @@ -142,6 +142,18 @@ namespace Fs::FsProbe { return -1; } + int GetBlockDeviceForDrive(int driveNum) { + if (driveNum < 0) return -1; + int partCount = Drivers::Storage::Gpt::GetPartitionCount(); + for (int i = 0; i < partCount && i < Drivers::Storage::Gpt::MaxPartitions; i++) { + if (g_mounted[i] && g_driveForPart[i] == driveNum) { + auto* part = Drivers::Storage::Gpt::GetPartition(i); + if (part) return part->BlockDevIndex; + } + } + return -1; + } + int UnmountPartitionsForBlockDevice(int blockDevIndex) { int partCount = Drivers::Storage::Gpt::GetPartitionCount(); int unmounted = 0; diff --git a/kernel/src/Fs/FsProbe.hpp b/kernel/src/Fs/FsProbe.hpp index 72cc3d8..aa836b8 100644 --- a/kernel/src/Fs/FsProbe.hpp +++ b/kernel/src/Fs/FsProbe.hpp @@ -34,4 +34,8 @@ namespace Fs::FsProbe { // mount bookkeeping to match Gpt::RemovePartitionsForBlockDevice(). int UnmountPartitionsForBlockDevice(int blockDevIndex); + // Return the block-device index backing a mounted VFS drive, or -1 if the + // drive isn't backed by a partition (e.g. ramdisk). + int GetBlockDeviceForDrive(int driveNum); + }; diff --git a/programs/include/Api/Syscall.hpp b/programs/include/Api/Syscall.hpp index ca75747..fa255ef 100644 --- a/programs/include/Api/Syscall.hpp +++ b/programs/include/Api/Syscall.hpp @@ -160,6 +160,7 @@ namespace Montauk { static constexpr uint64_t SYS_INPUT_WAIT = 123; static constexpr uint64_t SYS_DRIVELABEL = 124; static constexpr uint64_t SYS_NETSTATUS = 125; + static constexpr uint64_t SYS_DRIVEKIND = 127; static constexpr uint32_t CLIPBOARD_MAX_TEXT_BYTES = 256 * 1024; diff --git a/programs/include/gui/desktop.hpp b/programs/include/gui/desktop.hpp index a5e1cf0..7852bd4 100644 --- a/programs/include/gui/desktop.hpp +++ b/programs/include/gui/desktop.hpp @@ -123,6 +123,8 @@ struct DesktopState { SvgIcon icon_exec_lg; SvgIcon icon_drive; SvgIcon icon_drive_lg; + SvgIcon icon_drive_usb; + SvgIcon icon_drive_usb_lg; SvgIcon icon_delete; SvgIcon icon_copy; SvgIcon icon_cut; diff --git a/programs/include/montauk/syscall.h b/programs/include/montauk/syscall.h index 51a60dd..449acc7 100644 --- a/programs/include/montauk/syscall.h +++ b/programs/include/montauk/syscall.h @@ -164,6 +164,11 @@ namespace montauk { inline int drivelabel(int drive, char* outLabel, int maxLen) { return (int)syscall3(Montauk::SYS_DRIVELABEL, (uint64_t)drive, (uint64_t)outLabel, (uint64_t)maxLen); } + // Returns the kernel BlockDeviceKind backing the drive: 0=unknown/ramdisk, + // 1=SATA, 2=SATAPI, 3=NVMe, 4=USB MSC. + inline int drivekind(int drive) { + return (int)syscall1(Montauk::SYS_DRIVEKIND, (uint64_t)drive); + } // Memory inline void* alloc(uint64_t size) { return (void*)syscall1(Montauk::SYS_ALLOC, size); } diff --git a/programs/libs/libprintersapplet/obj/src/libprintersapplet.o b/programs/libs/libprintersapplet/obj/src/libprintersapplet.o index a75e69bd6f509e269e1ccf21d6f784724cc22e0d..d577fdc95d1ad7b3c2c2c92a0705657cf3d11f23 100644 GIT binary patch delta 3348 zcmZ{m4Qy0J5XawM>2XJ?QmAZR5lZa`?e*aG(MsC@y*ntLr3rcx`AjSq1cb(zi%LLD z&WjN##z-?nJ~YGv25J-Sd3=Nrfl3q+Q7e96jAElv@C&aoU`3;|`{v-7#7(+y_Wzrm znccT;K|R-G>lwjy4H_(7i5X^~u<~yeT=cBS$QTu2N|}KU{?|j5*H3 z7=ce!n;-g-o*}xJ(LEr_q*wuFSy;@2DB4Z1zRWW3^*W9RnST@Xl}R%(%#qJB+5%~$ zLCWtze0*SxKv@8g;aU1K9x7JZw7mkG_TN0YGt$zqDX(BJz36Z z6LcaCQVkmz-35I}x6z&eqX|eO6_mG!QGk+4Y3`*RILT-`M38!@s;?Nm0*Oi~e6XX^ zGOy68^YkZiW7U2bzz9bvdnu!jK|z%?*HHH9jNS?%r1w+y`HVgZF{E$Pp0qPM5xS5* zMRT8K^fL4#-QjlL=}U}$4#FqR9$Ha~(Uo8$)rShFpJ8+@M17W+1f9OHd4OsgLy^=_ zeJ`6J?USMvywzbb9wOCJtbx^Ne+o&o8{l-cC1$`-wPl{83Xie~Q3&~^*-N{6j?or~ z`K9;`I{X%1W=H&%nL|4~j-HuH)`6HT?N(B28O_tTq+tY@UI;CdEwh$Zx17-;=$tIY z7toD9ZB#!npBEsFd6V>ZdKh)nNj}W&3#=9snC2Y1+f@nms#S83;+|s>F45V&0MV&3ewoqFh+bp*GZbw&tvgfC3i2Pr^z-xAU_^WQxr{kSP6+LJqkc-Wm+AYc+$7WU>BM!@SC`q>MYMm1NLQ<(&}bRPaYy%E-@nmR?)zC2D2ARe z0I@o0{*skOrPBW!;PZFrs*^24|1;M`|8A%m%7uo;Em^u^RrsgcXb^Wwa~z`~2O7m- zBdsK=7M5M74N;^s+1v=t4M8W;xr|1M&VxRr3mIKcbSb2fF3X~7E$Sa5)mB5vH2iS0 zs9Mppni<9hh#=iaRMkwUM)O^em?q=hS##Be@1i%-%k<1A{T|aV&=L8F=}*v+8Dx5l zuCjj|eaZEs@F4}7p{l^97NX1!RX4WTOfRGabGc6MB?7T}8Ct~X1=@i&rthR>uVnh} z)am+FZm}QirsLuSq_IB_$v{}N!%(2!JF(O$?jke>>+xqY77U1kkPHS~o(32UHlbvP z0^(bUVUOQlDB!AWguze~{^Z%S0^${j%?fz0jdr3mz>!(?q88Ff%D|o-z#rHc_76c4 T`z?^hJ_vSmKx~It^Q8X(R&0FW delta 3203 zcmZ9O4Qx|Y6vy8!TcNNi1@ZEjjFo+`bz`sXkPatw8)z*gl1WrR$Xuqvz^HXW6iAlF zpe#T_a}Y)h(IH=R;iIbz2oYF_Mli+^qJn5-YIFs^<`)J-^xXSSp*c6{d;fcW=bn4+ zdH3DE{&vyPF1D09F5Vya_KL?61DAy8NuF?A&u+^%unpfm>3MZGvJ8j1?bThO^**f~ zTJP67OY1JJM`-=7)}ysPFd?KuXnjy?JI*1k?Kp?E9)>=P3?rdCcF-QJv-RMl)=sUD zXl)1T)!H#i%`#5tnT75w61JD_EKY87wL8SOP>?g%xqXCTh~2O%C*1Z_j$wGzP+?9} zI^En~WORlptH_(+ypmybUd!mXuV-|!mAm7WiB2O|DZ4pcnVm7zDOGT?x)kPRaAk1) zh?gRz#JK#|p*hzxPUTdrERL5)t6MexdSOSd&$%7R^&I##cS3eA%F^U7xi>~6|GvA< zm8>qQVhT#-8PG@o%qQz1?0`0|N z(GBNOe+8-HMzfXtyP5x&&{SfH!w@f#<|!2f+coC13Hs3I2n>}-Q39?hmg%I-tMpbg zZdGX=G)$4^AnqO2<}q3VF{Br%Ce4icAb~VMIjm)L3k)D_r7+|<{w168C?%` zNVic1&M>+ZqDXI0&X*Y-gw9ea?t$Z_mN`hP9;G+??N#T4D3j&^icrYtGvG(Mgl4Z{ zR6rBbFx6xMqt8Jc>3dX@m5h#oKBOMQF|d(Ziz}T zD=hN^%J2k>umGAWq`8Z#dV$dzh*wB)1-dFMu?sF?oWIB;k1CzcWCeJpO8-o2 z@c5*82hEjao+)TR+L+!aj2?rS&k~6k#mA!ReL025x_&mU37j{xppmPU}wR zbB>m*!kXR}-BNbx0R7+D>!{M3Jt@ zpz5eSO@G&`pmVxx+stT;YTLo=f6@bgi`lbjLmXxH^RyvOGW)X>XTY}K-YCs<9{kwlMSsW!b}wZlZ1XD6?-(it1%fu>o3U zof2;yysSAny(1q7E zkg5wgeyav={Vee{wA6>ha_FiLxvq|}qj+JcJ}B;jve_Y#4J~*b4_$cmK?<)gK-rv- TD1eqZA=i^N_K24tT0iN3!S#7Y diff --git a/programs/libs/libtimezonesapplet/obj/src/libtimezonesapplet.o b/programs/libs/libtimezonesapplet/obj/src/libtimezonesapplet.o index a61cdbe988c11d0c19e71379f8fd8e34f8d7a7cc..1c12087bf16ecfa1cdf6ec72682a3865e525f7d8 100644 GIT binary patch delta 3350 zcmZ{m4Q!J|7{~8AR#wK4GUR+WVa#pptMIPdWLv;>-M~_oOec}g#BCvfun@DT2x3wi z6&=RN@)%JxBm)c^OLVn-NQgioiil_yL?9%6_DqvLVoN;&qL+N+39bk2_d)Xsvlk&83;W) zQixnVURsq}CyM)0QX@sXGCRvTlw>;pPHMQ*G7=+&NY&D@X1vp#WID5w8+p`tLU(;Y zS9zW!t_|0ZSmkRa@15{=(p;FlDe^tnR4K%0-EfT1`4$+t+Bnsyk3vsInX?B;S_YiY z$VxqmvL<>f6T4I70vOCw*6YJ{7$IiHA7TVPN8!%{ z?tEn(C%S;qZQ##WatSQR56C9yMqLa0@@?x;SG?nH*1r~HfwIEG;`RwfgWyG4M|1tk zXfd=QJ!JM-2q$iWE{QxZLsx;4tp4llyyP} z!SXZfvl#}l&k=AJDp?7|g|;=8GOsYF^3LoVprcS(*XSiRGFl1UNPnO`Sq=NP>Pu_7f);B1j?U87Z} zn@{4-sy&cftgQVsdmf|DKr_-6H2XA0?}0GV$7%LCjJ^O7q=#uw+8Lb)gGkrW*cTbS z0`3xJz2l6(({~yD7W_#2Xhl&*mqG_pbEt6maYk1`cZn?vVW1>n?V{W=DUxpL@8wnS zmMYl@!P0;n4_&BNKriZVU`_)f?dnNJgAnm3`5PR= zIQ?(~Q@-$q=J}s0# zus&~qcZ%{x=ZFsrm-$y=&6EJ%MX@OXtDPdJ(=)N6Ly&7L>rCRjFW@Q_106_< zi0XwU=jnxRqz|#N%{0~z14w5x+D5bq>7ib4sn7^5py_ES|qps@b zoD%vo9weU6DW z;Ha;aec-S6$tNLP?{kbA1BcPN2(rQF%Fc{OsfJ)fm7D|N2A>Q<4C_{qGkmfK{8)bs PVXW6d4C^x>XBPekdz^TJ delta 3205 zcmZ9O3v5(H6o&6C?ZQG^DGiR7N?}VM+Xub7Tcj-wY#+#4NF*y!DMCtv4+NuPW3WKd zGz3in6Pm-LXowVf+VI$}6gNhoK@DI`Xow=##I71Gq9N-e&>GY;bI-!&OtN#&{NI@~ zXU?5__YQ3pN4JU{9^vUMx+b2A2ytDA-pHWic4}LWfo<%;X|JfOkzzR1<**(KZ6DFL zL)%BSouchy+8(Fv541f|+sCH_R0wUK(6$}tq_*uir?fo=eHslTtOs_`UTvr9$q{Wk zwS8LKcA!3OJ0_@ACJVi?(1S){d+EWlNS~|2A%1|Gw1v(+;|xO_gk5RDwrA4}!>y(Y zbC$9bE%RE^V2n~l_7vw(lIXmdG|0T2G)PtMj@GG8BVAc`bGniTlW5>kFjsXmvXi(H zT)$wKrz|l!=PlTr?w+i2%2$fxjfv_~iN8LGrhA=xklap#Tj^6$`_S}6GBQTTMIMw5 zuE@&i`^ShyAo8TyHdf6tj7RN@F&?iO_{#ww(ocxuJdR z8TYER2|5dD72&26mE}{K7WR^-%3`M1u zD1*jQ%lwQo{Fp^p0^Oz3JU~^w%4jtVV4NYifpHFiIny%#CXZ~YbRv^A&^%N6=8{^@ z=v~S`z;q`Z!2`{uAsi3*x&d zRu(i@kk16VCU(>dwU#t5C(awAxv)mN1{QFn|%_w7a#8t_IO6 z5ca7|Vm>Lhz=$s>=0L4qieI78Z{g|c@LTR96!$8N;HL`w2ywq`xW(xDL{?0Hj%JOe zeJAp{Om`~_Lglhy8l(FtN(s|1(C#Xj{xhv!58-lYE@t#GiuMe|%4ORNjGm;JElh8q zaU0V+>Akj%={dAY7t{ArZij5W_}(l2KU%m;e>2>F2`;449D?py(mcUv3eAeb0MaXr zZlZDzf_Oxl-zQOJCO#X6)!c@75>+HY?RC=Kjv5kjLTq}c7{UL@_ zLO;^!NmQA+Y9h8$h$HnTQ5AWyW`(?PRTeiK;Xgk%mi|K#S4S$d6sdOODFnxdy#95}lL~&xae*d7XqWAG{ zY{Gd8R07=ko(c_G6r(^dd(|1N{E7v>4MTpKj z=NQU`4S|0hckoiPKrDm)nhICV3_I=>5VaMkRn-Q>r_hT1M2KR)3`S}Lj^Rp}Q#Vh% z1Fdxd{Njt&1sr!XVHBmKP*oprjnA^96hnJ`g_s4=`T+j*jbL8`Rr3SlRcOV&3!>Ps Sgpv6H*ZyjI#ugCu)BXqQFMSUH diff --git a/programs/src/desktop/apps/filemanager/app.cpp b/programs/src/desktop/apps/filemanager/app.cpp index 8baeebb..284b428 100644 --- a/programs/src/desktop/apps/filemanager/app.cpp +++ b/programs/src/desktop/apps/filemanager/app.cpp @@ -72,6 +72,8 @@ void ensure_filemanager_icons_loaded(DesktopState* ds) { Color defColor = colors::ICON_COLOR; ds->icon_drive = svg_load("0:/icons/drive-harddisk.svg", 16, 16, defColor); ds->icon_drive_lg = svg_load("0:/icons/drive-harddisk.svg", 48, 48, defColor); + ds->icon_drive_usb = svg_load("0:/icons/drive-harddisk-usb.svg", 16, 16, defColor); + ds->icon_drive_usb_lg = svg_load("0:/icons/drive-harddisk-usb.svg", 48, 48, defColor); ds->icon_home_folder = svg_load("0:/icons/folder-blue-home.svg", 16, 16, defColor); ds->icon_home_folder_lg = svg_load("0:/icons/folder-blue-home.svg", 48, 48, defColor); ds->icon_apps = svg_load("0:/icons/folder-blue-development.svg", 16, 16, defColor); diff --git a/programs/src/desktop/apps/filemanager/filemanager_internal.hpp b/programs/src/desktop/apps/filemanager/filemanager_internal.hpp index ed45516..2350166 100644 --- a/programs/src/desktop/apps/filemanager/filemanager_internal.hpp +++ b/programs/src/desktop/apps/filemanager/filemanager_internal.hpp @@ -68,6 +68,7 @@ struct FileManagerState { DesktopState* desktop; bool grid_view; int drive_indices[64]; // drive number or special-folder index for Computer view entries + int drive_kinds[64]; // kernel BlockDeviceKind for FM_ENTRY_DRIVE entries (4 = USB MSC) // Clipboard char clipboard_path[256]; diff --git a/programs/src/desktop/apps/filemanager/filesystem.cpp b/programs/src/desktop/apps/filemanager/filesystem.cpp index bcd9297..3510011 100644 --- a/programs/src/desktop/apps/filemanager/filesystem.cpp +++ b/programs/src/desktop/apps/filemanager/filesystem.cpp @@ -39,6 +39,10 @@ static void filemanager_add_root_entry(FileManagerState* fm, fm->entry_sizes[idx] = 0; fm->is_dir[idx] = true; fm->drive_indices[idx] = drive_index; + fm->drive_kinds[idx] = 0; + if (type == FM_ENTRY_DRIVE && drive_index >= 0) { + fm->drive_kinds[idx] = montauk::drivekind(drive_index); + } } static int filemanager_add_virtual_entry(FileManagerState* fm, diff --git a/programs/src/desktop/apps/filemanager/render.cpp b/programs/src/desktop/apps/filemanager/render.cpp index 8005a14..06d04fc 100644 --- a/programs/src/desktop/apps/filemanager/render.cpp +++ b/programs/src/desktop/apps/filemanager/render.cpp @@ -333,7 +333,10 @@ void filemanager_on_draw(Window* win, Framebuffer& fb) { } else if (ds && fm->entry_types[i] == FM_ENTRY_HOME && ds->icon_home_folder_lg.pixels) { c.icon(icon_x, icon_y, ds->icon_home_folder_lg); } else if (ds && fm->entry_types[i] == FM_ENTRY_DRIVE && ds->icon_drive_lg.pixels) { - c.icon(icon_x, icon_y, ds->icon_drive_lg); + // Kind 4 = USB MSC (kernel BlockDeviceKind enum) + const SvgIcon& di = (fm->drive_kinds[i] == 4 && ds->icon_drive_usb_lg.pixels) + ? ds->icon_drive_usb_lg : ds->icon_drive_lg; + c.icon(icon_x, icon_y, di); } else if (ds && fm->entry_types[i] == FM_ENTRY_DIR && ds->icon_folder_lg.pixels) { c.icon(icon_x, icon_y, ds->icon_folder_lg); } else if (ds && fm->entry_types[i] == FM_ENTRY_EXEC && ds->icon_exec_lg.pixels) { @@ -464,7 +467,9 @@ void filemanager_on_draw(Window* win, Framebuffer& fb) { } else if (ds && fm->entry_types[i] == FM_ENTRY_HOME && ds->icon_home_folder.pixels) { c.icon(ico_x, ico_y, ds->icon_home_folder); } else if (ds && fm->entry_types[i] == FM_ENTRY_DRIVE && ds->icon_drive.pixels) { - c.icon(ico_x, ico_y, ds->icon_drive); + const SvgIcon& di = (fm->drive_kinds[i] == 4 && ds->icon_drive_usb.pixels) + ? ds->icon_drive_usb : ds->icon_drive; + c.icon(ico_x, ico_y, di); } else if (ds && fm->entry_types[i] == FM_ENTRY_DIR && ds->icon_folder.pixels) { c.icon(ico_x, ico_y, ds->icon_folder); } else if (ds && fm->entry_types[i] == FM_ENTRY_EXEC && ds->icon_exec.pixels) {