1197 lines
67 KiB
Text
1197 lines
67 KiB
Text
# The MIT License (MIT)
|
|
#
|
|
# Copyright (C) 2026 Scott Duensing
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to
|
|
# deal in the Software without restriction, including without limitation the
|
|
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
# sell copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
# IN THE SOFTWARE.
|
|
|
|
.section Technical Reference (for Developers)|Libraries
|
|
.topic shell.overview
|
|
.title DVX Shell Library
|
|
.toc 0 DVX Shell Library
|
|
.default
|
|
.index DVX Shell
|
|
.index shellApp.h
|
|
.index DXE Application Loading
|
|
|
|
.h1 DVX Shell Library
|
|
|
|
The DVX shell library manages the lifecycle of DXE applications: loading, launching, tracking, and reaping. It provides the bridge between the DVX GUI compositor and dynamically loaded DXE3 application modules.
|
|
|
|
Header: dvxshell/shellApp.h
|
|
|
|
Loaded as: bin/libs/dvxshell.lib
|
|
|
|
.h2 App Model
|
|
|
|
The shell supports two kinds of DXE apps:
|
|
|
|
.list
|
|
.item Callback-only (hasMainLoop = false) -- appMain() runs in the shell's task 0, creates windows, registers event callbacks, and returns immediately. The app lives through GUI callbacks. Lifecycle ends when the last window is closed. Simpler and cheaper (no extra stack/task).
|
|
.item Main-loop (hasMainLoop = true) -- A dedicated cooperative task is created. appMain() runs in that task and can do its own polling loop, calling tsYield() to share CPU. Lifecycle ends when appMain() returns or the task is killed. Needed for terminal emulators, games, or long computations.
|
|
.endlist
|
|
|
|
Both types use the same DXE interface: an exported appDescriptor and appMain function.
|
|
|
|
.h2 DXE Interface
|
|
|
|
Every .app DXE module must export these symbols (COFF convention uses leading underscore):
|
|
|
|
.table
|
|
Symbol Type Required
|
|
------ ---- --------
|
|
_appDescriptor AppDescriptorT Yes
|
|
_appMain int32_t (*)(DxeAppContextT *) Yes
|
|
_appShutdown void (*)(void) No
|
|
.endtable
|
|
|
|
The shell resolves appDescriptor at dlopen time; if missing, the load fails with an error dialog. If its abiVersion is not the shell's DVX_ABI_VERSION the app was built against other headers: the load fails with "This program was built for a different version of DVX and cannot run." and both numbers go to DVX.LOG. appMain is called immediately for callback-only apps or from the new task for main-loop apps. appShutdown, if present, is called during graceful reap (but not during force kill from crashed apps).
|
|
|
|
.h2 Callback-Only vs Main-Loop Apps
|
|
|
|
The app descriptor's hasMainLoop flag selects between two very different lifecycles:
|
|
|
|
.list
|
|
.item hasMainLoop = false (callback-only). The shell calls appMain directly on task 0 at dlopen time. The function creates windows, registers event callbacks, and returns. After that the app has no executing thread of its own -- it exists purely through GUI callbacks dispatched by dvxUpdate. The shell reaps the app automatically when its last window closes. Best for modal tools, dialogs, and event-driven utilities.
|
|
.item hasMainLoop = true (main-loop). The shell creates a dedicated cooperative task (via tsCreate) with the descriptor's stackSize (or TS_DEFAULT_STACK_SIZE) and priority. appMain runs in that task and can do its own work loop, calling tsYield or any GUI function that yields. The app terminates when appMain returns (the wrapper sets AppStateTerminatingE) or when forced via shellForceKillApp. Best for terminal emulators, games, and any app with continuous background work.
|
|
.endlist
|
|
|
|
Both app types use the same export interface; only the descriptor's flags differ. Apps cannot switch modes at runtime.
|
|
|
|
.h2 Icon Conventions
|
|
|
|
Shell-level UI (Program Manager, Task Manager) displays app icons at 16x16 and 32x32. Icons are not handled by the shell itself; each app embeds its own icons via the DVX resource system (DVX_RES_ICON):
|
|
|
|
.list
|
|
.item 16x16 BMP for toolbar entries and list rows
|
|
.item 32x32 BMP for desktop shortcuts and Program Manager tiles
|
|
.endlist
|
|
|
|
The Program Manager reads the app's 32x32 icon resource when building shortcut tiles. Apps without an icon resource fall back to a default shell-provided bitmap.
|
|
|
|
.h2 State Machine
|
|
|
|
App slots progress through four states:
|
|
|
|
.code
|
|
Free -> Loaded -> Running -> Terminating -> Free
|
|
.endcode
|
|
|
|
LoadedE is transient (only during shellLoadApp before the entry point is called). TerminatingE means the app's task has exited, or a force kill was deferred (killPending) because the app's code was still running, but cleanup has not yet occurred. The shell's main loop reaps terminating apps each frame via shellReapApps().
|
|
|
|
.h2 Contents
|
|
|
|
.link shell.types Types and Constants
|
|
.link shell.lifecycle Lifecycle API
|
|
.link shell.query Query API
|
|
.link shell.startup Starting Up
|
|
.link shell.config Program Folders API
|
|
.link shell.desktop Desktop Callbacks
|
|
.link shell.info System Information
|
|
.link shell.programs Installed Programs
|
|
.link shell.run Running Programs and Documents
|
|
.link shell.assoc File Associations
|
|
.link shell.basic BASIC Entry Points
|
|
.link shell.sysbasic BASIC System Settings
|
|
|
|
.topic shell.types
|
|
.title Shell Types and Constants
|
|
.toc 1 Types and Constants
|
|
.index AppDescriptorT
|
|
.index DxeAppContextT
|
|
.index ShellAppT
|
|
.index AppStateE
|
|
.index SHELL_APP_NAME_MAX
|
|
.index SHELL_STACK_DEFAULT
|
|
.index SHELL_DESKTOP_APP
|
|
.index SHELL_APP_DESCRIPTOR
|
|
|
|
.h1 Types and Constants
|
|
|
|
.h2 Constants
|
|
|
|
.table
|
|
Constant Value Description
|
|
-------- ----- -----------
|
|
SHELL_APP_NAME_MAX 64 Maximum length of an app name string.
|
|
SHELL_STACK_DEFAULT 0 Use in AppDescriptorT.stackSize to get the default task stack size.
|
|
SHELL_DESKTOP_APP "apps/kpunch/progman/progman.app" Default desktop application path.
|
|
SHELL_INI_SECTION "shell" DVX.INI section of the shell's own keys.
|
|
SHELL_INI_DESKTOP "desktop" [shell] key: the desktop app (SHELL_DESKTOP_APP when missing).
|
|
SHELL_INI_WELCOME "welcome" [shell] key: a program started after the desktop while the key exists (see Starting Up).
|
|
SHELL_HELP_TOPIC_MAX 128 Capacity of DxeAppContextT.helpTopic.
|
|
DVX_HELP_VIEWER_APP_LITERAL "APPS\KPUNCH\DVXHELP\DVXHELP.APP" Path of the help viewer app.
|
|
DVX_SYSTEM_HELP_FILE_LITERAL "APPS\KPUNCH\PROGMAN\DVXHELP.HLP" Path of the system help file (F1 fallback, Program Manager's Help menu).
|
|
.endtable
|
|
|
|
.h3 SHELL_APP_CALL
|
|
|
|
.code
|
|
SHELL_APP_CALL(app, call);
|
|
.endcode
|
|
|
|
Brackets a direct shell call into an app's code (appMain of a callback-only app, appShutdown, onHelpQuery, onNewArgs). It counts the call on the calling task (shellAppCallEnter / shellAppCallLeave), so a force kill issued from inside that call is deferred until the call has returned.
|
|
|
|
.h2 AppDescriptorT
|
|
|
|
Exported by every DXE app as a global named appDescriptor. The shell reads it at load time to determine how to launch the app. Declare it with SHELL_APP_DESCRIPTOR, which names the global and fills abiVersion:
|
|
|
|
.code
|
|
SHELL_APP_DESCRIPTOR(
|
|
.name = "Clock",
|
|
.hasMainLoop = true,
|
|
.multiInstance = true,
|
|
.stackSize = SHELL_STACK_DEFAULT,
|
|
.priority = TS_PRIORITY_LOW
|
|
);
|
|
.endcode
|
|
|
|
.table
|
|
Field Type Description
|
|
----- ---- -----------
|
|
abiVersion uint32_t DVX_ABI_VERSION the app was built with (always the first field). The shell refuses the app when it differs from its own.
|
|
name[SHELL_APP_NAME_MAX] char[] Display name of the application.
|
|
hasMainLoop bool false = callback-only, true = dedicated task.
|
|
multiInstance bool true = allow multiple simultaneous instances via temp copy.
|
|
stackSize int32_t SHELL_STACK_DEFAULT or explicit byte count for the task stack.
|
|
priority int32_t Task priority, TS_PRIORITY_LOW..TS_PRIORITY_HIGH (0..10). Any other value makes the launch fail.
|
|
.endtable
|
|
|
|
.h2 DxeAppContextT
|
|
|
|
Passed as the sole argument to appMain(). Gives the app access to the shell's GUI context and its own identity. Heap-allocated by shellLoadApp so its address is stable across reallocations of the internal app slot table (apps may safely cache the pointer in their static globals).
|
|
|
|
.table
|
|
Field Type Description
|
|
----- ---- -----------
|
|
shellCtx AppContextT * The shell's GUI context (for creating windows, drawing, etc.).
|
|
appId int32_t This app's unique ID (slot index, 1-based).
|
|
appPath[DVX_MAX_PATH] char[] Full path to the .app DXE file.
|
|
appDir[DVX_MAX_PATH] char[] Directory containing the .app file (for loading resources).
|
|
userDir[DVX_MAX_PATH] char[] The program's folder in the user folder, for its settings and the files it saves (e.g. USER\APPS\KPUNCH\DVXBASIC). Made on first use (shellEnsureUserDir).
|
|
args[1024] char[] Launch arguments (empty string if none): blank-separated, one with blanks in double quotes. Walk them with dvxNextArg. A document opened through its file type arrives here (see File Associations); BASIC programs read these arguments with COMMAND$.
|
|
helpFile[DVX_MAX_PATH] char[] Help file path (for F1 context help). Before appMain the shell sets it to <app>.hlp in the .app's directory when that file exists (else empty); appMain may change it.
|
|
helpTopic[128] char[] Current help topic ID (updated by the app at runtime). Size is SHELL_HELP_TOPIC_MAX.
|
|
onHelpQuery void (*)(void *ctx) Optional callback the shell fires on F1 so the app can refresh helpTopic from context.
|
|
helpQueryCtx void * Opaque context pointer passed to onHelpQuery.
|
|
onNewArgs void (*)(void *ctx, const char *args) Optional. Set by an app that can take new launch arguments while running. Loading a single-instance app that is already running and sets this hands it the new arguments and raises it (the load returns its app id) instead of saying it is already running; F1 hands its "helpfile [topic]" arguments to a running help viewer that sets this, and raises it, instead of loading another copy.
|
|
newArgsCtx void * Opaque context pointer passed to onNewArgs.
|
|
.endtable
|
|
|
|
The appDir field is derived from the .app file path at load time so apps can find their own resources via relative paths. This is necessary because the working directory is shared by all apps in DOS. The user directory is mirrored from the app path in the user folder (platformAppUserDir): an app at APPS\KPUNCH\DVXBASIC\dvxbasic.app gets USER\APPS\KPUNCH\DVXBASIC. A full path inside the DVX directory (for example one picked with the Task Manager's Run... dialog) is mirrored the same way. An app outside the DVX directory, or loaded by a bare file name, gets USER\APPS\<file name without extension>. The user folder is USER in the DVX directory unless the DVXUSER environment variable names another (see DVX Folders in the architecture guide).
|
|
|
|
.h2 AppStateE
|
|
|
|
.table
|
|
Value Description
|
|
----- -----------
|
|
AppStateFreeE Slot is available for reuse.
|
|
AppStateLoadedE DXE loaded, entry point not yet called (transient).
|
|
AppStateRunningE Entry point called, app is active.
|
|
AppStateTerminatingE Shutdown in progress, awaiting reap.
|
|
.endtable
|
|
|
|
.h2 ShellAppT
|
|
|
|
Per-app slot in the shell's app table. Slot 0 is reserved for the shell itself; apps use slots 1 and above.
|
|
|
|
.table
|
|
Field Type Description
|
|
----- ---- -----------
|
|
appId int32_t Unique ID (slot index, 1-based; 0 = shell).
|
|
name[SHELL_APP_NAME_MAX] char[] Display name from AppDescriptorT.
|
|
path[DVX_MAX_PATH] char[] Original DXE file path.
|
|
tempPath[DVX_MAX_PATH] char[] Temp copy path for multi-instance (empty if not a copy).
|
|
dxeHandle void * dlopen() handle for the DXE module.
|
|
state AppStateE Current lifecycle state.
|
|
hasMainLoop bool Whether this app has a dedicated task.
|
|
mainTaskId uint32_t Task ID if hasMainLoop, else 0.
|
|
entryFn int32_t (*)(DxeAppContextT *) Pointer to appMain.
|
|
shutdownFn void (*)(void) Pointer to appShutdown (may be NULL).
|
|
dxeCtx DxeAppContextT * Heap-allocated context (address stable across realloc).
|
|
taskCodeDepth int32_t * Per task id: SHELL_APP_CALL calls into this app still open on that task's stack.
|
|
killPending bool A force kill was deferred; shellReapApps finishes it.
|
|
.endtable
|
|
|
|
.topic shell.lifecycle
|
|
.title App Lifecycle API
|
|
.toc 1 Lifecycle API
|
|
.index shellAppInit
|
|
.index shellLoadApp
|
|
.index shellLoadAppWithArgs
|
|
.index shellReapApps
|
|
.index shellReapApp
|
|
.index shellForceKillApp
|
|
.index shellTerminateAllApps
|
|
.index shellCloseAllApps
|
|
.index shellRequestExit
|
|
.index shellRunExitRequest
|
|
.index Exit DVX
|
|
.index shellCloseApp
|
|
.index shellRequestAppClose
|
|
.index shellRunCloseRequests
|
|
.index shellOpenHelp
|
|
.index shellAppCodeForgetTask
|
|
.index shellTaskDepthForget
|
|
.index shellTaskDepthShare
|
|
|
|
.h1 App Lifecycle API
|
|
|
|
.h2 shellAppInit
|
|
|
|
.code
|
|
void shellAppInit(void);
|
|
.endcode
|
|
|
|
Initialize the app slot table. Seeds slot 0 (reserved for the shell). Must be called once at startup before any other shell API function.
|
|
|
|
.h2 shellLoadApp
|
|
|
|
.code
|
|
int32_t shellLoadApp(AppContextT *ctx, const char *path);
|
|
.endcode
|
|
|
|
Load and start an app from a DXE file. Returns the app ID (>= 1) on success, or -1 on error.
|
|
|
|
For callback-only apps, appMain() runs synchronously and returns before shellLoadApp returns. For main-loop apps, a cooperative task is created and the app begins running on the next tsYield().
|
|
|
|
If multiInstance is false in the app's descriptor and the same DXE is already loaded, the running app is handed args through its onNewArgs and raised, and its app id is returned, when it sets onNewArgs; otherwise the call fails with an error dialog. If multiInstance is true, the DXE is copied to a temp file so dlopen gets an independent code and data image.
|
|
|
|
.h2 shellLoadAppWithArgs
|
|
|
|
.code
|
|
int32_t shellLoadAppWithArgs(AppContextT *ctx, const char *path, const char *args);
|
|
.endcode
|
|
|
|
Load and run an app with arguments. The args string is copied into DxeAppContextT.args before appMain() is called. Otherwise identical to shellLoadApp().
|
|
|
|
.h2 shellReapApps
|
|
|
|
.code
|
|
bool shellReapApps(AppContextT *ctx);
|
|
.endcode
|
|
|
|
Scan for and reap finished apps. Call once per frame from the main loop.
|
|
|
|
Returns true if any apps were reaped, so the caller can trigger a desktop refresh. For main-loop apps, termination is detected by the AppStateTerminatingE state (set when appMain returns). For callback-only apps, termination is detected when no windows remain for that app.
|
|
|
|
.h2 shellReapApp
|
|
|
|
.code
|
|
void shellReapApp(AppContextT *ctx, ShellAppT *app);
|
|
.endcode
|
|
|
|
Gracefully shut down a single app. Calls the app's shutdownFn (if present), destroys all windows belonging to the app, kills its task (if any), releases any widget classes and system-wide hotkeys the app registered and did not unregister (wgtUnregisterAppClasses, dvxUnregisterAppHotkeys), closes the DXE handle, and frees the context. The slot returns to AppStateFreeE.
|
|
|
|
.h2 shellForceKillApp
|
|
|
|
.code
|
|
void shellForceKillApp(AppContextT *ctx, ShellAppT *app);
|
|
.endcode
|
|
|
|
Forcibly kill an app. Used by the Task Manager "End Task" or as part of crash recovery. The app's shutdownFn is NOT called: a force kill targets a hung or faulting app whose own code cannot be trusted to run. Instead the shell drops every idle and desktop-update callback the app registered, destroys all of the app's windows, kills its task (for main-loop apps), and finally closes the DXE handle.
|
|
|
|
Cleanup order: callbacks and windows first (removes them from the compositor), then the task (frees its stack; any dispatch frames still open on it are dropped from the context's dispatch depth), then the widget classes and system-wide hotkeys the app registered (its shutdownFn never got the chance to unregister them), then the DXE handle (unmaps the code). Closing the DXE before destroying windows would cause callbacks into unmapped code.
|
|
|
|
If the app's code may still be running underneath the call -- End Task clicked in a dialog the app has open, a kill issued from the app's own task, or from inside a shell call into the app -- the unload is deferred: the app's windows are hidden and queued for destruction, the slot is marked Terminating, and the shell finishes the kill (still without shutdownFn) at the next safe point of its main loop, once that code has returned. Event-handler frames on the app's own task do not hold the kill back, since they end with the task: an app stuck in an endless event handler is killed at once (or at the next main-loop pass).
|
|
|
|
.h2 shellOpenHelp
|
|
|
|
.code
|
|
void shellOpenHelp(AppContextT *ctx, const char *args);
|
|
.endcode
|
|
|
|
Show help. args is "helpfile [topicId]"; empty or NULL args open the system help. A running help viewer that accepts new arguments (onNewArgs) is given them and raised; otherwise a new viewer is loaded. F1 and application Help menus both use it, so a Help > Contents command can pass ctx->helpFile as is.
|
|
|
|
.h2 shellTaskDepthForget / shellTaskDepthShare / shellAppCodeForgetTask
|
|
|
|
.code
|
|
void shellTaskDepthForget(uint32_t taskId);
|
|
int32_t shellTaskDepthShare(uint32_t taskId);
|
|
void shellAppCodeForgetTask(uint32_t taskId);
|
|
.endcode
|
|
|
|
The context's dispatch depth counts event-dispatch frames on every task's stack. shellTaskDepthShare returns one task's share. When a task is killed its frames can never unwind: shellTaskDepthForget removes its share, and (through shellAppCodeForgetTask) the SHELL_APP_CALL calls it held. Crash recovery does the same for the crashed task and the shell's own task.
|
|
|
|
.h2 shellTerminateAllApps
|
|
|
|
.code
|
|
void shellTerminateAllApps(AppContextT *ctx);
|
|
.endcode
|
|
|
|
Force-kill all running apps. Called during shell shutdown, after the main loop has exited, so every active app is released immediately (never deferred) and no shutdownFn runs. By then Exit DVX (below) has already given every app except the desktop the chance to close itself; what is left is the desktop app and apps that had no visible window to close.
|
|
|
|
.h2 Exit DVX: shellRequestExit / shellRunExitRequest / shellCloseAllApps
|
|
|
|
.code
|
|
void shellRequestExit(void);
|
|
void shellRunExitRequest(AppContextT *ctx, int32_t keepAppId);
|
|
bool shellCloseAllApps(AppContextT *ctx, int32_t keepAppId);
|
|
.endcode
|
|
|
|
Exiting DVX never closes an app without first asking it to close, the way the user would. The desktop app's Exit command (Program Manager's File > Exit DVX and its window's close box, after its own "Are you sure?" confirmation) calls shellRequestExit, which only records the request. The shell's main loop calls shellRunExitRequest after every frame; when a request is pending it clears it, runs shellCloseAllApps for every app except the desktop, and calls dvxQuit only if that returns true. Otherwise DVX keeps running.
|
|
|
|
shellCloseAllApps asks the running apps to close one at a time, in app-slot order, exactly as if the user had closed their windows: for each app, its oldest visible window is raised and dvxRequestWindowClose is called on it inside a dispatch frame, so the window's onClose runs just as it does for the close box or Alt+F4. A C app's onClose shows its own save prompt; a BASIC app's form runs QueryUnload and Unload. This repeats with the app's next visible window until it has none left or the app has ended. Windows that hide on close (tool palettes) count as closed, and hidden windows are left alone. Apps that close are reaped normally (their shutdownFn runs). Between requests the shell keeps pumping frames (dvxUpdate, a task yield, shellReapApps), so main-loop apps can react.
|
|
|
|
A window that is still open after a request is judged as follows:
|
|
|
|
.list
|
|
.item If the app created a window while handling the request (ctx->windowsCreated changed -- its save prompt) and no dialog box is still open, the user chose to keep it (Cancel). shellCloseAllApps returns false at once: that app and every app not yet asked keep running untouched. Apps already closed stay closed.
|
|
.item If the app showed nothing and still has the window after 5 seconds, it is not responding. The shell asks "'name' is not responding to the request to close. End it and continue exiting DVX?". Yes ends it with shellForceKillApp (no shutdownFn) and the exit continues; No returns false.
|
|
.endlist
|
|
|
|
shellCloseAllApps also returns false, without asking any app, when a dialog box is already open (ctx->modalWindow): the dialog is raised so it can be answered first. It pumps the event loop, so call it only from the shell's top level, never from inside a callback. An app ended from the Task Manager while the sequence runs simply counts as closed.
|
|
|
|
.h2 Closing one app: shellRequestAppClose / shellRunCloseRequests / shellCloseApp
|
|
|
|
.code
|
|
void shellRequestAppClose(int32_t appId);
|
|
void shellRunCloseRequests(AppContextT *ctx);
|
|
bool shellCloseApp(AppContextT *ctx, int32_t appId);
|
|
.endcode
|
|
|
|
shellCloseApp asks one app to close exactly as shellCloseAllApps asks each (the same routine): its visible windows are closed the way the user would close them, so its save prompt or QueryUnload runs, and one that does not respond is offered to be ended ("'name' is not responding to the request to close. End it?", titled Close Program). True when the app is gone or was not running; false when it kept a window or a dialog box is open. It pumps the event loop, so it belongs to the shell's top level. shellRequestAppClose only records the request (a second request for the same app is not added; an app that ends, or is ended, before it runs has its requests dropped by shellPurgeAppCallbacks, since its slot may be reused); the main loop calls shellRunCloseRequests right after each frame, before shellRunExitRequest, and it asks the waiting apps oldest first. BASIC's ShellRunningClose is shellRequestAppClose.
|
|
|
|
.h3 The desktop ending
|
|
|
|
The shell itself exits DVX when the desktop app ends in any other way -- its last window closed, ended from the Task Manager, or crashed: an app-cleanup hook (shellRegisterAppCleanup) notices the desktop's id going away, logs "Shell: the desktop ended; exiting DVX" and calls shellRequestExit, so every other app is asked to close as above. If one of them refuses, DVX keeps running and ends as soon as the last app has ended. A desktop app (C or BASIC) therefore never calls dvxQuit itself.
|
|
|
|
.topic shell.query
|
|
.title Query API
|
|
.toc 1 Query API
|
|
.index shellGetApp
|
|
.index shellAppSlotCount
|
|
.index shellRunningAppCount
|
|
.index shellRunningAppId
|
|
.index shellActivateApp
|
|
.index shellAppFindByPath
|
|
|
|
.h1 Query API
|
|
|
|
.h2 shellGetApp
|
|
|
|
.code
|
|
ShellAppT *shellGetApp(int32_t appId);
|
|
.endcode
|
|
|
|
Look up an app slot by ID. Returns a pointer to the ShellAppT, or NULL if the ID is out of range or the slot is free. Valid app IDs are 1 through shellAppSlotCount() - 1.
|
|
|
|
.h2 shellAppSlotCount
|
|
|
|
.code
|
|
int32_t shellAppSlotCount(void);
|
|
.endcode
|
|
|
|
Return the total number of app slots (including slot 0). Use as the iteration bound when scanning all slots. Slot 0 is the shell itself; app slots start at 1.
|
|
|
|
.h2 shellRunningAppCount
|
|
|
|
.code
|
|
int32_t shellRunningAppCount(void);
|
|
.endcode
|
|
|
|
Count running apps, not counting the shell itself. Includes apps in both AppStateLoadedE and AppStateRunningE states.
|
|
|
|
.h2 shellRunningAppId
|
|
|
|
.code
|
|
int32_t shellRunningAppId(int32_t index);
|
|
.endcode
|
|
|
|
The id of running app index, 0 .. shellRunningAppCount() - 1 in slot order (the same apps shellRunningAppCount counts); 0 out of range. BASIC: ShellRunningId.
|
|
|
|
.h2 shellActivateApp
|
|
|
|
.code
|
|
bool shellActivateApp(AppContextT *ctx, int32_t appId);
|
|
.endcode
|
|
|
|
Bring an app to the front, as the Task Manager's Switch To does (it calls this): its topmost visible window that is not being destroyed is restored when minimized (dvxRestoreWindow; a maximized window stays maximized), else raised (dvxRaiseWindow), and gets the focus. False when the app has no visible window. BASIC: ShellRunningActivate.
|
|
|
|
.h2 shellAppFindByPath
|
|
|
|
.code
|
|
ShellAppT *shellAppFindByPath(const char *path);
|
|
.endcode
|
|
|
|
Return an active app slot loaded from path, or NULL. Paths are compared with platformPathSame (/ and \ the same separator, a trailing one ignored, case ignored on DOS).
|
|
|
|
.topic shell.startup
|
|
.title Starting Up
|
|
.toc 1 Starting Up
|
|
.index Safe Video Mode
|
|
.index /SAFE
|
|
.index /RUN=
|
|
.index SHELL_INI_WELCOME
|
|
.index Welcome Program
|
|
|
|
.h1 Starting Up
|
|
|
|
shellMain brings DVX up in this order: preferences (DVX.INI), the task system, the GUI in the saved display mode, the desktop app, then the start-up programs.
|
|
|
|
.h2 Safe Video Mode
|
|
|
|
The GUI starts in the [video] mode of DVX.INI (prefsGetVideoMode). If that mode cannot be set (dvxInit fails), or a Shift key is held down while DVX starts (read with platformKeyboardGetModifiers just before the mode is set), or DVX was started with /SAFE, the shell starts in the built-in default mode instead (DVX_DEFAULT_VIDEO_W/H/BPP: 640x480, 16 bpp or the closest mode the card has). Before the desktop loads, a message box says so and asks whether to use that mode from now on: Yes writes it to DVX.INI (prefsSetVideoMode, prefsSave); No leaves DVX.INI alone, so the saved mode is tried again next time. If the default mode fails too, DVX does not start.
|
|
|
|
.h2 Start-up Programs
|
|
|
|
After the desktop app has loaded:
|
|
|
|
.list
|
|
.item When DVX's disk cannot be written to (as on a CD-ROM), a message says so once: either that the user folder is in the TEMP folder (platformUserInTemp; SHELL_USER_TEMP_MSG), or, without a TEMP folder, that nothing can be saved and changed settings last until DVX exits (platformIsReadOnly; SHELL_READ_ONLY_MSG). Both suggest setting DVXUSER to a folder on a hard disk.
|
|
.item The program named by DVX.INI [shell] welcome (SHELL_INI_WELCOME), if the key is there. The shipped DVX.INI names the Welcome window, which removes the key when the user ticks "Don't show this again", so the key itself is the "first start" flag.
|
|
.item The program given with /RUN=path on the DVX command line (for example DVX /RUN=APPS\KPUNCH\NOTEPAD\NOTEPAD.APP).
|
|
.endlist
|
|
|
|
Both are started with shellRunCommand, so a missing program is reported to the user.
|
|
|
|
.topic shell.config
|
|
.title Program Folders API
|
|
.toc 1 Program Folders API
|
|
.index shellEnsureUserDir
|
|
.index shellUserPath
|
|
.index shellDataPath
|
|
|
|
.h1 Program Folders API
|
|
|
|
Each program has two folders of its own. Its user folder (ctx->userDir) is in DVX's user folder, mirrored from its path: an app at APPS\KPUNCH\DVXBASIC\dvxbasic.app gets USER\APPS\KPUNCH\DVXBASIC. Settings and every file the program saves go there, apart from the program files, so an upgrade or a reinstall never overwrites them and backing up the user folder keeps them. Its DATA folder, beside its .app, holds the files it ships; DVX never writes there, and on a CD-ROM it cannot be written at all.
|
|
|
|
A program never writes or installs into SHARED (DVX's own fonts, sounds, themes, and wallpapers): its own files live in its DATA folder or as resources in its .app.
|
|
|
|
.h2 shellEnsureUserDir
|
|
|
|
.code
|
|
int32_t shellEnsureUserDir(const DxeAppContextT *ctx);
|
|
.endcode
|
|
|
|
Make the program's user folder, with all parent folders as needed. Returns 0 on success, -1 on failure. Call it before writing the first file there.
|
|
|
|
.h2 shellUserPath
|
|
|
|
.code
|
|
void shellUserPath(const DxeAppContextT *ctx, const char *filename, char *outPath, int32_t outSize);
|
|
.endcode
|
|
|
|
Build the full path of a file in the program's user folder by joining ctx->userDir with filename.
|
|
|
|
.code
|
|
// Example:
|
|
char path[DVX_MAX_PATH];
|
|
shellEnsureUserDir(ctx);
|
|
shellUserPath(ctx, "PROGMAN.INI", path, sizeof(path));
|
|
// -> "USER\APPS\KPUNCH\PROGMAN\PROGMAN.INI"
|
|
.endcode
|
|
|
|
.h2 shellDataPath
|
|
|
|
.code
|
|
void shellDataPath(const DxeAppContextT *ctx, const char *filename, char *outPath, int32_t outSize);
|
|
.endcode
|
|
|
|
Build the full path of a file the program ships in the DATA folder beside its .app ("" when it does not fit), e.g. "APPS\ACME\MYGAME\DATA\LEVEL1.DAT". Read-only.
|
|
|
|
.h2 Random Seed File
|
|
|
|
When the serial library is loaded, the shell feeds keyboard and mouse event timings to its random-number generator (dvxSetInputEntropyHook) and carries generator state across runs in SECLINK.RND in the user folder: the file is read and immediately rewritten at startup, and rewritten again at shutdown. The library is found at run time; without it no seed file is written.
|
|
|
|
.topic shell.desktop
|
|
.title Desktop Callbacks
|
|
.toc 1 Desktop Callbacks
|
|
.index shellRegisterDesktopUpdate
|
|
.index shellUnregisterDesktopUpdate
|
|
.index shellRegisterIdle
|
|
.index shellUnregisterIdle
|
|
.index shellRegisterAppCleanup
|
|
.index shellUnregisterAppCleanup
|
|
.index ShellAppCleanupFnT
|
|
.index shellDesktopUpdate
|
|
.index shellDesktopChangeCount
|
|
.index shellCtrlEscFn
|
|
.index shellOpenTaskManager
|
|
|
|
.h1 Desktop Callbacks
|
|
|
|
The shell wires several AppContextT event hooks (onCtrlEsc, onF1, onTitleChange, idleCallback) during startup and exposes them to other DXEs via function-pointer extern and registration API. Desktop managers register a callback to refresh their display when apps come and go. The Task Manager DXE registers its Ctrl+Esc handler via the shellCtrlEscFn extern pointer (see Task Manager documentation); shellOpenTaskManager is the one way to open it.
|
|
|
|
.h2 Shell Event Hooks
|
|
|
|
.table
|
|
AppContextT field Handler Purpose
|
|
----------------- ------- -------
|
|
idleCallback shellIdleDispatch Runs one frame of Run Minimized (shellMinimizeIdle) and every registered idle handler (see shellRegisterIdle), then yields to cooperative tasks, when dvxUpdate has no input events and no dirty rects.
|
|
onCtrlEsc ctrlEscHandler shellOpenTaskManager.
|
|
onF1 f1HelpHandler Opens the focused app's helpFile/helpTopic (or the system help) in the help viewer, reusing a running viewer that sets onNewArgs.
|
|
onTitleChange titleChangeHandler Runs shellDesktopUpdate so Program Manager window lists refresh.
|
|
.endtable
|
|
|
|
.h2 shellRegisterDesktopUpdate
|
|
|
|
.code
|
|
void shellRegisterDesktopUpdate(void (*updateFn)(void));
|
|
.endcode
|
|
|
|
Register a callback for app state change notifications. Multiple callbacks are supported; registering the same callback again has no effect. Apps typically call this during appMain() to receive notifications. A callback may register or unregister callbacks (including itself) while notifications are being delivered.
|
|
|
|
.h2 shellUnregisterDesktopUpdate
|
|
|
|
.code
|
|
void shellUnregisterDesktopUpdate(void (*updateFn)(void));
|
|
.endcode
|
|
|
|
Remove a previously registered callback. Call this before app shutdown to avoid dangling function pointers.
|
|
|
|
.h2 shellRegisterIdle
|
|
|
|
.code
|
|
void shellRegisterIdle(void (*fn)(void *ctx), void *ctx);
|
|
.endcode
|
|
|
|
Register an idle handler invoked every idle frame by the shell main loop, regardless of which app is foreground. Background pollers (serial and secLink) register here so their connections keep pumping while another app is in front. Registration is idempotent on the (fn, ctx) pair. The registering module MUST unregister before it is unloaded -- app DXEs do this from their _appShutdown hook on a graceful exit. On a force kill (which does not run _appShutdown) the shell drops the app's registrations itself.
|
|
|
|
.h2 shellUnregisterIdle
|
|
|
|
.code
|
|
void shellUnregisterIdle(void (*fn)(void *ctx), void *ctx);
|
|
.endcode
|
|
|
|
Remove a previously registered idle handler. No-op if the (fn, ctx) pair is absent, so a double-unregister is harmless.
|
|
|
|
.h2 shellRegisterAppCleanup
|
|
|
|
.code
|
|
typedef void (*ShellAppCleanupFnT)(int32_t appId);
|
|
|
|
void shellRegisterAppCleanup(ShellAppCleanupFnT fn);
|
|
void shellUnregisterAppCleanup(ShellAppCleanupFnT fn);
|
|
.endcode
|
|
|
|
Register a function the shell calls with an app's id whenever that app ends -- normally, force-killed, or after a crash -- once its windows are gone, next to the shell's own release of the app's widget classes and hotkeys. A library uses it to release what the app left open with it: the networking library closes the app's sockets this way. For library code that stays loaded; registering the same function again has no effect, and unregistering one that is not registered does nothing.
|
|
|
|
.h2 shellDesktopUpdate
|
|
|
|
.code
|
|
void shellDesktopUpdate(void);
|
|
.endcode
|
|
|
|
Notify all registered desktop callbacks that app state has changed. Called internally by the shell after loading or reaping an app. Can also be called by apps that need to trigger a desktop refresh. Each call also adds one to the change counter (shellDesktopChangeCount).
|
|
|
|
.h2 shellDesktopChangeCount
|
|
|
|
.code
|
|
int32_t shellDesktopChangeCount(void);
|
|
.endcode
|
|
|
|
How many times shellDesktopUpdate has run (it wraps around). For a desktop that cannot take a callback -- a BASIC program polls it from a Timer (ShellChangeCount) and refreshes its running-program count when the value differs from the one it saw last.
|
|
|
|
.h2 shellCtrlEscFn / shellOpenTaskManager
|
|
|
|
.code
|
|
extern void (*shellCtrlEscFn)(AppContextT *ctx);
|
|
void shellOpenTaskManager(AppContextT *ctx);
|
|
.endcode
|
|
|
|
shellCtrlEscFn is set by the taskmgr DXE's constructor; NULL if the task manager is not loaded. shellOpenTaskManager calls it when it is set and does nothing otherwise; Ctrl+Esc, Program Manager's Help > Task Manager, and BASIC's ShellTaskManager all open Task Manager through it.
|
|
|
|
.topic shell.info
|
|
.title System Information
|
|
.toc 1 System Information
|
|
.index shellInfoInit
|
|
.index shellGetSystemInfo
|
|
|
|
.h1 System Information
|
|
|
|
Header: dvxshell/shellInf.h
|
|
|
|
Thin wrapper around the platform layer's hardware detection. Gathers system information at startup, logs it, and caches the result for display in dialogs.
|
|
|
|
.h2 shellInfoInit
|
|
|
|
.code
|
|
void shellInfoInit(AppContextT *ctx);
|
|
.endcode
|
|
|
|
Gather all hardware information via the platform layer, log each line to DVX.LOG, and store the result for later retrieval. Call once after dvxInit().
|
|
|
|
.h2 shellGetSystemInfo
|
|
|
|
.code
|
|
const char *shellGetSystemInfo(void);
|
|
.endcode
|
|
|
|
Return the formatted system information text. The returned pointer is valid for the lifetime of the process (static buffer in the platform layer).
|
|
|
|
.topic shell.programs
|
|
.title Installed Programs
|
|
.toc 1 Installed Programs
|
|
.index shellProgramScan
|
|
.index shellProgramInfo
|
|
.index shellProgramIcon
|
|
.index shellItemIcon
|
|
.index shellItemIconFile
|
|
.index shellProgramListFree
|
|
.index shellIsProgram
|
|
.index ShellProgramT
|
|
|
|
.h1 Installed Programs
|
|
|
|
Header: dvxshell/shellProg.h
|
|
|
|
Finds the installed programs (every .app file under APPS, SHELL_PROG_DIR) and reads what they are called and what they look like, for launchers, file managers, and setup programs. A program's display name and description are its "name" and "description" text resources (the capitalized file name when it has no name resource); its picture is its "icon32" resource.
|
|
|
|
.table
|
|
Constant Value Meaning
|
|
-------- ----- -------
|
|
SHELL_PROG_DIR "apps" Folder, relative to the DVX root, holding every program.
|
|
SHELL_PROG_EXT ".app" A program's file extension.
|
|
SHELL_PROG_DESC_MAX 128 ShellProgramT.description capacity.
|
|
SHELL_PROG_ICON 32 Large icon edge in pixels.
|
|
SHELL_PROG_ICON_SMALL 16 Small icon edge in pixels.
|
|
.endtable
|
|
|
|
.code
|
|
typedef struct {
|
|
char path[DVX_MAX_PATH];
|
|
char name[SHELL_APP_NAME_MAX];
|
|
char description[SHELL_PROG_DESC_MAX];
|
|
} ShellProgramT;
|
|
.endcode
|
|
|
|
.h2 shellProgramScan
|
|
|
|
.code
|
|
int32_t shellProgramScan(const char *dir, const char *skipPath, bool readInfo, ShellProgressFnT progress, void *progressCtx, ShellProgramT **outList);
|
|
.endcode
|
|
|
|
Every program under dir (NULL for SHELL_PROG_DIR) and its subfolders, except skipPath (compared with platformPathSame; NULL for none), in the order found. With readInfo each entry is filled by shellProgramInfo; without it only path is set, which is fast (no program file is opened) and enough to notice programs being added or removed. progress, when not NULL, is called with progressCtx after each program (for example to keep the screen responsive). Returns the count; *outList is an array of that many entries, NULL when there are none. Free it with shellProgramListFree.
|
|
|
|
.h2 shellProgramInfo
|
|
|
|
.code
|
|
void shellProgramInfo(const char *path, ShellProgramT *out);
|
|
.endcode
|
|
|
|
Fill out with the program's path, display name, and description. Always succeeds: without resources (or for a file that is not a program) the name is the file name without its extension, first letter capitalized, and the description is empty.
|
|
|
|
.h2 shellProgramIcon
|
|
|
|
.code
|
|
uint8_t *shellProgramIcon(AppContextT *ctx, const char *path, int32_t edge, int32_t *outPitch);
|
|
.endcode
|
|
|
|
A picture edge x edge pixels in display format, for drawing with rectCopy: a program's icon32 resource, or any image file dvxLoadImage reads (BMP, PNG, JPEG, GIF). Other sizes are scaled (nearest pixel). Returns NULL when there is no picture. Free with dvxFreeImage.
|
|
|
|
.h2 shellItemIcon
|
|
|
|
.code
|
|
uint8_t *shellItemIcon(AppContextT *ctx, const char *iconPath, const char *path, int32_t edge, int32_t *outPitch);
|
|
.endcode
|
|
|
|
The icon a launcher shows for path (a program or a document), edge x edge pixels as shellProgramIcon gives them: the picture file iconPath when it is given (NULL or "" for none) and can be read; else path's own picture -- a program's icon32, or path itself when it is a picture file; else, for a document, the icon of the program its file type opens in (shellAssocCommand). NULL when there is none; free with dvxFreeImage. Program Manager's items (both sizes) and its Properties preview use it, so an item and its preview always show the same icon. (A BASIC program's LOADPICTURE of a .app reads the program's icon itself, with dvxResLoadIconData.)
|
|
|
|
.h2 shellItemIconFile
|
|
|
|
.code
|
|
bool shellItemIconFile(AppContextT *ctx, const char *iconPath, const char *path, char *out, int32_t outSize);
|
|
.endcode
|
|
|
|
The same rule as shellItemIcon (one implementation), naming the file the icon comes from in out: iconPath, path, or the program path's file type opens in; false with "" when none gives a picture. dvxLoadImage of that file (BASIC LOADPICTURE) gives the icon. BASIC: ShellItemIcon$ in shell.bas.
|
|
|
|
.h2 shellProgramListFree / shellIsProgram
|
|
|
|
.code
|
|
void shellProgramListFree(ShellProgramT *list);
|
|
bool shellIsProgram(const char *path);
|
|
.endcode
|
|
|
|
shellProgramListFree frees a list from shellProgramScan (NULL is fine). shellIsProgram is true when path has the .app extension (any case).
|
|
|
|
.topic shell.run
|
|
.title Running Programs and Documents
|
|
.toc 1 Running Programs and Documents
|
|
.index shellRunProgram
|
|
.index shellRunCommand
|
|
.index shellRunDialog
|
|
.index shellSplitCommand
|
|
.index shellResolveArgs
|
|
.index shellMinimizeApp
|
|
.index Run dialog
|
|
.index Run Minimized
|
|
|
|
.h1 Running Programs and Documents
|
|
|
|
Header: dvxshell/shellRun.h
|
|
|
|
One way for every program to start another (Program Manager's items and Run..., the Task Manager's Run..., File Manager, setup programs). A command line is a program, in quotes if it contains blanks, followed by its arguments; it is split with dvxNextArg, the same rule a program uses to read its own arguments. A document in place of a program opens in the program associated with its file type (see File Associations).
|
|
|
|
.h2 shellRunProgram
|
|
|
|
.code
|
|
int32_t shellRunProgram(AppContextT *ctx, const char *program, const char *args, const char *folder);
|
|
.endcode
|
|
|
|
Start program with args. A .app is loaded with shellLoadAppWithArgs, its arguments first passed through shellResolveArgs(folder, ...). Anything else is a document: it is looked for in folder first (when relative), must exist, and is opened with shellAssocCommand's program and arguments. Problems are shown to the user in an error box (a missing document, a document type with no association; load errors come from shellLoadApp as usual). Returns the new application id, or -1.
|
|
|
|
.h2 shellRunCommand
|
|
|
|
.code
|
|
int32_t shellRunCommand(AppContextT *ctx, const char *command);
|
|
.endcode
|
|
|
|
shellSplitCommand, then shellRunProgram with no working folder. Returns the application id or -1 (also for an empty command).
|
|
|
|
.h2 shellRunDialog
|
|
|
|
.code
|
|
bool shellRunDialog(AppContextT *ctx, const char *const *history, int32_t historyCount, char *outCommand, int32_t outSize);
|
|
.endcode
|
|
|
|
The standard Run dialog: an Open box listing history (newest first, the first one preselected) with a Browse... button. Returns true with the trimmed, non-empty command in outCommand when the user chose OK; OK with an empty box does nothing. The caller runs the command (shellRunCommand) and keeps its own history. SHELL_RUN_CMD_MAX (512) is a suitable outCommand size.
|
|
|
|
.h2 shellSplitCommand
|
|
|
|
.code
|
|
bool shellSplitCommand(const char *command, char *program, int32_t programSize, char *args, int32_t argsSize);
|
|
.endcode
|
|
|
|
Split a command line into the program (quotes removed) and the rest, trimmed. False, with both outputs empty, when there is no program.
|
|
|
|
.h2 shellResolveArgs
|
|
|
|
.code
|
|
void shellResolveArgs(const char *folder, const char *args, char *out, int32_t outSize);
|
|
.endcode
|
|
|
|
Copy args to out with blanks normalized, replacing every relative argument that names an existing file inside folder by folder\name, so a program finds the files an item's arguments name no matter where it runs. Quoted arguments keep their quotes. With an empty or NULL folder the arguments are only normalized. DVX programs share one current folder, so this is how a program item's working folder takes effect.
|
|
|
|
.h2 shellMinimizeApp
|
|
|
|
.code
|
|
void shellMinimizeApp(AppContextT *ctx, int32_t appId);
|
|
void shellMinimizeIdle(AppContextT *ctx);
|
|
.endcode
|
|
|
|
Run Minimized. shellMinimizeApp minimizes every visible window of appId (an id from shellRunProgram) at once and again on each of the next SHELL_MINIMIZE_FRAMES (60) idle frames, because a program with a main loop opens its windows from its own task after it has started. Asking again for the same program starts its frames over; nothing happens for an id that is not running, and a program that ends is forgotten (an app-cleanup hook). shellMinimizeIdle is the per-frame step, called by the shell's idle dispatch. Program Manager's Run Minimized items and BASIC's ShellMinimizeApp use it.
|
|
|
|
.topic shell.assoc
|
|
.title File Associations
|
|
.toc 1 File Associations
|
|
.index shellAssocLookup
|
|
.index shellAssocOpenDocument
|
|
.index shellAssocCommand
|
|
.index shellAssocSet
|
|
.index shellAssocRemove
|
|
.index shellAssocCount
|
|
.index shellAssocGet
|
|
.index shellAssocNormalize
|
|
.index ASSOC.INI
|
|
.index File Associations
|
|
|
|
.h1 File Associations
|
|
|
|
Header: dvxshell/shellAssoc.h
|
|
|
|
Which program opens each kind of document. One store serves every program, in two layers: the shipped list, SYSTEM\ASSOC.INI (SHELL_ASSOC_SHIPPED_PATH), and the user's changes, ASSOC.INI in the user folder, both with the section [associations]. A type in the user's file replaces the shipped one; an empty value there removes a shipped type. Each key is an extension without the dot, upper case; each value is a program path relative to the DVX root, optionally followed by ,arguments where %1 stands for the document:
|
|
|
|
.code
|
|
[associations]
|
|
TXT = apps/kpunch/notepad/notepad.app
|
|
FRM = apps/kpunch/dvxbasic/dvxbasic.app,%1
|
|
.endcode
|
|
|
|
Users change the types on the Control Panel's File Types page, and a setup program registers its own types with shellAssocSet. Every change goes to the user's file, so an upgrade's new shipped types appear while the user's choices stay. Both files are read once through dvxPrefs and kept; every change is saved at once with the crash-safe rewrite, and a failed save drops the cached copies so the next call rereads the files. Extension arguments may have a leading dot and any case.
|
|
|
|
.h2 Looking Up
|
|
|
|
.code
|
|
bool shellAssocLookup(const char *extension, char *programPath, int32_t programPathSize);
|
|
int32_t shellAssocCount(void);
|
|
bool shellAssocGet(int32_t index, char *extension, int32_t extensionSize, char *programPath, int32_t programPathSize);
|
|
.endcode
|
|
|
|
shellAssocLookup gives the stored value (program plus any ,arguments) for an extension; false when there is none (or its value is empty). shellAssocCount and shellAssocGet walk every association in file order (index 0 to count-1); the extension comes back as written in the file.
|
|
|
|
.h2 Opening a Document
|
|
|
|
.code
|
|
bool shellAssocCommand(const char *documentPath, char *program, int32_t programSize, char *args, int32_t argsSize);
|
|
bool shellAssocOpenDocument(AppContextT *ctx, const char *documentPath);
|
|
.endcode
|
|
|
|
shellAssocCommand builds the program and argument string that open a document: the value is split at the first comma, every %1 in the arguments becomes documentPath, and without arguments documentPath alone is passed. The path goes in double quotes when it contains a blank (dvxArgAppend), so dvxNextArg and COMMAND$(1) still return a long name such as C:\My Documents\Letter.txt whole; a template that already quotes the token ("%1") gets the path as it is. A program that opens documents takes the first argument of its DxeAppContextT.args (dvxNextArg) as the file to open when it starts; a BASIC program uses COMMAND$(1). shellAssocOpenDocument does that and starts the program; false when there is no association or the program does not start. It shows nothing to the user (shellRunProgram does, for a document it cannot open).
|
|
|
|
.h2 Changing
|
|
|
|
.code
|
|
bool shellAssocSet(const char *extension, const char *programPath);
|
|
bool shellAssocRemove(const char *extension);
|
|
bool shellAssocNormalize(const char *extension, char *out);
|
|
.endcode
|
|
|
|
shellAssocSet adds or replaces an association (programPath may carry ,arguments) and saves; false for a bad extension, an empty program, or a failed save. shellAssocRemove removes one and saves; false when it did not exist or the save failed. shellAssocNormalize writes the extension as the store keys it (SHELL_ASSOC_EXT_MAX bytes: no dot, upper case) and is false for an empty extension, one longer than eight characters, or anything but letters and digits.
|
|
|
|
|
|
.topic shell.basic
|
|
.title BASIC Entry Points
|
|
.toc 1 BASIC Entry Points
|
|
.index ShellRun
|
|
.index ShellRunProgram
|
|
.index ShellRunCommand
|
|
.index ShellRunDialog
|
|
.index ShellMinimizeApp
|
|
.index ShellOpenDocument
|
|
.index ShellProgramScan
|
|
.index ShellProgramCount
|
|
.index ShellProgramPath
|
|
.index ShellProgramFree
|
|
.index ShellProgramName
|
|
.index ShellProgramDescription
|
|
.index ShellIsProgram
|
|
.index ShellAssocProgram
|
|
.index ShellAssocCommand
|
|
.index ShellAssocCount
|
|
.index ShellAssocExt
|
|
.index ShellAssocValue
|
|
.index ShellAssocSet
|
|
.index ShellAssocRemove
|
|
.index ShellAssocNormalize
|
|
.index ShellRunningCount
|
|
.index ShellRunningId
|
|
.index ShellRunningName
|
|
.index ShellRunningPath
|
|
.index ShellRunningFind
|
|
.index ShellRunningActivate
|
|
.index ShellRunningClose
|
|
.index ShellRunningKill
|
|
.index ShellAppIsHung
|
|
.index ShellAppMemory
|
|
.index ShellAppId
|
|
.index ShellPriority
|
|
.index ShellSetPriority
|
|
.index ShellCommandProgram
|
|
.index ShellCommandArgs
|
|
.index ShellArg
|
|
.index ShellArgCount
|
|
.index ShellArgQuote
|
|
.index ShellChangeCount
|
|
.index ShellTaskManager
|
|
.index ShellSystemInfo
|
|
.index ShellExitDvx
|
|
.index HotkeyAdd
|
|
.index HotkeyRemove
|
|
.index HotkeyNext
|
|
.index HotkeyText
|
|
.index ShellAppPath
|
|
.index ShellInstanceCount
|
|
.index ShellLog
|
|
.index ShellSetDesktop
|
|
.index ShellSetWelcome
|
|
.index shell.bas
|
|
|
|
.h1 BASIC Entry Points
|
|
|
|
Source: dvxshell/shellBas.c; BASIC declarations: src/include/basic/shell.bas (DECLARE LIBRARY "dvxshell").
|
|
|
|
The shell's services for DVX BASIC programs -- everything Program Manager does, so a desktop can be written in BASIC. Only BASIC-marshalable types: strings and LONG in, LONG or STRING out, True (-1) / False (0) for success. "This program" is the app whose code is running (ctx->currentAppId, which the shell keeps for every app's task and window callback). A returned string stays valid until the next call of the same function. Program lists (1, 2, ...; 0 means none) and hotkeys belong to the program that made them and are released by an app-cleanup hook (shellRegisterAppCleanup) when it ends.
|
|
|
|
.h2 Starting programs and documents
|
|
|
|
.code
|
|
int32_t ShellRun(const char *program, const char *args);
|
|
int32_t ShellRunProgram(const char *program, const char *args, const char *folder);
|
|
int32_t ShellRunCommand(const char *command);
|
|
const char *ShellRunDialog(const char *history);
|
|
void ShellMinimizeApp(int32_t appId);
|
|
int32_t ShellOpenDocument(const char *path);
|
|
.endcode
|
|
|
|
ShellRunProgram is shellRunProgram (a document opens through its association; file names in args, and a relative document, are looked for in folder; "" for none), returning the new app id or 0. ShellRun is ShellRunProgram without a folder, True when it started; the two are one launch path. ShellRunCommand is shellRunCommand (id or 0). ShellRunDialog splits history at line ends (CHR$(10), a CR before it is dropped, empty lines skipped) into the list shellRunDialog shows, and returns the command chosen or "" when cancelled. ShellMinimizeApp is shellMinimizeApp. ShellOpenDocument is shellAssocOpenDocument (it shows nothing when there is no association; ShellRunProgram does).
|
|
|
|
.h2 Installed programs
|
|
|
|
.code
|
|
int32_t ShellProgramScan(const char *folder, const char *skipPath);
|
|
int32_t ShellProgramCount(int32_t list);
|
|
const char *ShellProgramPath(int32_t list, int32_t index);
|
|
void ShellProgramFree(int32_t list);
|
|
const char *ShellProgramName(const char *path);
|
|
const char *ShellProgramDescription(const char *path);
|
|
int32_t ShellIsProgram(const char *path);
|
|
.endcode
|
|
|
|
ShellProgramScan is shellProgramScan of folder ("" for SHELL_PROG_DIR) without skipPath ("" for none), paths only (readInfo false), so it never opens a program; it returns a list handle, 0 when nothing was found. ShellProgramCount and ShellProgramPath read it (0 / "" for a bad list or index); ShellProgramFree frees it. ShellProgramName and ShellProgramDescription are shellProgramInfo's name and description, read one program at a time so a long list can be filled with DoEvents in between (the C progress callback). ShellIsProgram is shellIsProgram.
|
|
|
|
.h2 File types
|
|
|
|
.code
|
|
const char *ShellAssocProgram(const char *extension);
|
|
const char *ShellAssocCommand(const char *document);
|
|
int32_t ShellAssocCount(void);
|
|
const char *ShellAssocExt(int32_t index);
|
|
const char *ShellAssocValue(int32_t index);
|
|
int32_t ShellAssocSet(const char *extension, const char *value);
|
|
int32_t ShellAssocRemove(const char *extension);
|
|
const char *ShellAssocNormalize(const char *extension);
|
|
.endcode
|
|
|
|
ShellAssocProgram is shellAssocLookup: the stored value, the program followed by ",args" when there is a template. ShellAssocCommand is the program part of shellAssocCommand for a document. ShellAssocCount, ShellAssocExt, and ShellAssocValue enumerate shellAssocGet (0-based; "" past the end). ShellAssocSet, ShellAssocRemove, and ShellAssocNormalize are shellAssocSet, shellAssocRemove, and shellAssocNormalize ("" when the extension cannot be one). Every change is saved at once.
|
|
|
|
.h2 Running programs and DVX
|
|
|
|
.code
|
|
int32_t ShellRunningCount(void);
|
|
int32_t ShellChangeCount(void);
|
|
void ShellTaskManager(void);
|
|
const char *ShellSystemInfo(void);
|
|
void ShellExitDvx(void);
|
|
.endcode
|
|
|
|
ShellRunningCount is shellRunningAppCount. ShellChangeCount is shellDesktopChangeCount: a BASIC desktop polls it from a Timer in place of shellRegisterDesktopUpdate's callback. ShellTaskManager is shellOpenTaskManager, ShellSystemInfo is shellGetSystemInfo ("" before shellInfoInit), and ShellExitDvx is shellRequestExit (every app is asked to close, then DVX quits; a desktop asks the user first).
|
|
|
|
.code
|
|
int32_t ShellRunningId(int32_t index);
|
|
const char *ShellRunningName(int32_t appId);
|
|
const char *ShellRunningPath(int32_t appId);
|
|
int32_t ShellRunningFind(const char *program);
|
|
int32_t ShellRunningActivate(int32_t appId);
|
|
int32_t ShellRunningClose(int32_t appId);
|
|
int32_t ShellRunningKill(int32_t appId);
|
|
int32_t ShellAppIsHung(int32_t appId);
|
|
int32_t ShellAppMemory(int32_t appId);
|
|
.endcode
|
|
|
|
The Task Manager's operations, one routine each with it. ShellRunningId is shellRunningAppId. ShellRunningName and ShellRunningPath are the ShellAppT name and path of an app in AppStateRunningE ("" otherwise; the same state every call below requires). ShellRunningFind is shellAppFindByPath (platformPathSame rules), 0 when that app is not running. ShellRunningActivate is shellActivateApp. ShellRunningClose is shellRequestAppClose: the app is asked at the main loop's top level, after the BASIC code has returned; True when the request was recorded. ShellRunningKill is shellForceKillApp followed by shellDesktopUpdate (End Task: no shutdownFn, callbacks purged, the unload deferred while the app's code is on a stack); the running program itself is refused (BASIC's END ends it). ShellAppIsHung is dvxAppIsHung and ShellAppMemory dvxMemGetAppUsage (clamped to INT32_MAX; 0 for an app that is not running).
|
|
|
|
.h2 Command lines and priority
|
|
|
|
.code
|
|
const char *ShellCommandProgram(const char *command);
|
|
const char *ShellCommandArgs(const char *command);
|
|
int32_t ShellArgCount(const char *command);
|
|
const char *ShellArg(const char *command, int32_t index);
|
|
const char *ShellArgQuote(const char *arg);
|
|
int32_t ShellAppId(void);
|
|
int32_t ShellPriority(void);
|
|
int32_t ShellSetPriority(int32_t priority);
|
|
.endcode
|
|
|
|
ShellCommandProgram and ShellCommandArgs are the two parts of shellSplitCommand (what shellRunCommand runs). ShellArgCount and ShellArg walk a command line with dvxNextArg -- the tokenizer shellSplitCommand and COMMAND$(n) use -- counting the program as argument 0; ShellArg drops the quotes and gives "" past the last. ShellArgQuote is the other direction (dvxArgAppend): arg as one word of a command line, in double quotes when it holds blanks, "" when it is too long for one (SHELL_ARGS_MAX). ShellAppId is ctx->currentAppId. ShellPriority and ShellSetPriority are tsGetPriority / tsSetPriority on the running program's mainTaskId (TS_PRIORITY_LOW .. TS_PRIORITY_HIGH, shell.bas SHELL_PRIORITY_*); -1 / False for a program without a task of its own (every BASIC program has one) or a priority out of range.
|
|
|
|
.h2 Hotkeys
|
|
|
|
.code
|
|
int32_t HotkeyAdd(const char *keyText);
|
|
int32_t HotkeyNext(void);
|
|
void HotkeyRemove(int32_t id);
|
|
const char *HotkeyText(const char *keyText);
|
|
.endcode
|
|
|
|
HotkeyAdd parses keyText with dvxAccelParse and registers it with dvxRegisterHotkey for the running program; it returns an id of its own (> 0), or 0 when keyText is not a key or dvxRegisterHotkey refuses it (it needs Ctrl or Alt unless it is a function or navigation key, and a key already registered is refused). A BASIC program cannot be called back, so the hotkey's callback queues the id for its program (up to 16 presses not yet collected); HotkeyNext returns and removes the oldest one, 0 when there is none. HotkeyRemove drops one of the running program's hotkeys (other ids are ignored). HotkeyText is dvxAccelParse followed by dvxAccelFormat ("" when keyText is not a key): the spelling menus show. dvxUnregisterAppHotkeys removes a program's hotkeys when it ends; the app-cleanup hook drops their records and queued presses.
|
|
|
|
.h2 This program and DVX settings
|
|
|
|
.code
|
|
const char *ShellAppPath(void);
|
|
int32_t ShellInstanceCount(void);
|
|
void ShellLog(const char *text);
|
|
int32_t ShellSetDesktop(const char *program);
|
|
int32_t ShellSetWelcome(const char *program);
|
|
.endcode
|
|
|
|
ShellAppPath is the running program's .app path as started ("" when unknown). A BASIC program's user folder is App.User (the folder a C program's userDir names; every copy of a program gets the same one). ShellInstanceCount counts the running apps with the same path, this one included (a second copy of a multiInstance program loads from a temporary copy but keeps the original path). ShellLog writes one line with dvxLog. ShellSetDesktop and ShellSetWelcome set, or with "" remove, DVX.INI [shell] desktop (the desktop app; SHELL_DESKTOP_APP when missing) and [shell] welcome (the program started after the desktop); both share one writer and return False (logged) when DVX.INI cannot be saved.
|
|
|
|
.h2 Programs folder, item icons, program groups
|
|
|
|
.code
|
|
const char *ShellProgramsFolder(void);
|
|
const char *ShellItemIcon(const char *iconPath, const char *path);
|
|
.endcode
|
|
|
|
ShellProgramsFolder is SHELL_PROG_DIR (where ShellProgramScan("") looks and a Browse for a program starts). ShellItemIcon is shellItemIconFile ("" for none). The program-group bindings (ShellGroups*, ShellGroup*, ShellItem*) are in pmModelBas.c; see Program Groups.
|
|
|
|
.h2 A desktop in BASIC
|
|
|
|
A BASIC program can be the desktop ([shell] desktop, ShellSetDesktop): the shell exits DVX when it ends, so it needs no code for that; its Exit command confirms and calls ShellExitDvx. Its groups use the shell's program-group model (Program Groups: the same PROGMAN.INI format, rules, and limits as Program Manager) through shell.bas, in its App.User folder. An icon grid is drawn on a PictureBox with PaintPicture and pictures from LOADPICTURE of ShellItemIcon$ (a .app gives its icon), with MouseDown/MouseUp for selecting and dragging and KeyDown for the keyboard. The test fixture src/test/dos/fixtures/parpm does all of this.
|
|
|
|
.topic shell.groups
|
|
.title Program Groups
|
|
.toc 1 Program Groups
|
|
.index pmModel.h
|
|
.index PmModelT
|
|
.index pmModelLoad
|
|
.index pmModelSave
|
|
.index pmInstalledScan
|
|
.index pmHotkeyParse
|
|
.index pmItemGetField
|
|
.index ShellGroupsLoad
|
|
.index PROGMAN.INI
|
|
|
|
.h1 Program Groups
|
|
|
|
Header: dvxshell/pmModel.h; source pmModel.c (model) and pmModelBas.c (BASIC entry points, shell.bas).
|
|
|
|
Program Manager's groups, items, and PROGMAN.INI, as plain data with no windows, part of the shell so the C Program Manager and a desktop written in BASIC share one model (the pm prefix names it). groups[PM_INSTALLED_IDX] is the automatic Installed Programs group (pmInstalledScan: every program under SHELL_PROG_DIR, sorted by name, never saved; pmInstalledChanged tells cheaply whether a program was added or removed); the others are the user's, saved by pmModelSave with a crash-safe rewrite in this layout:
|
|
|
|
.code
|
|
[options] minimizeOnRun, restoreAlone, autoArrange, view, group
|
|
[groups] count
|
|
[groupN] name, count, itemM.name, itemM.program, itemM.args,
|
|
itemM.folder, itemM.icon, itemM.key, itemM.minimized,
|
|
itemM.col, itemM.row (N and M count from 1)
|
|
[run] historyN (newest first)
|
|
.endcode
|
|
|
|
.table
|
|
Function Description
|
|
-------- -----------
|
|
pmModelInit / pmModelLoad / pmModelSave / pmModelFree An empty model; load a file (one never saved gives Main and Startup; damaged entries are skipped); save; free.
|
|
pmGroupAdd / pmGroupDelete / pmGroupFind / pmGroupRename / pmGroupNameValid Groups (names trimmed, unique in any case, PM_GROUP_MAX of them; the automatic group cannot change).
|
|
pmItemAdd / pmItemCopy / pmItemMove / pmItemDelete / pmItemReorder / pmItemPlace Items (a name and a program each, PM_ITEM_MAX per group).
|
|
pmItemGetField / pmItemSetField An item's field by its PROGMAN.INI name (PM_FIELD_*); a key must pass pmHotkeyParse, a name or program cannot be emptied.
|
|
pmOptionGet / pmOptionSet An [options] value by name (flags, view, group).
|
|
pmArrangeGroup / pmPlaceUnplaced / pmCellItem Grid cells for an icon view.
|
|
pmItemMatches / pmContainsNoCase Program Manager's search.
|
|
pmHistoryAdd The Run history (PM_HISTORY_MAX, newest first).
|
|
pmHotkeyParse An item shortcut: dvxAccelParse, and Ctrl plus Alt or Shift so it never takes a key a program uses itself; "" is no shortcut.
|
|
pmInstalledScan / pmInstalledChanged / pmInstalledReplace The automatic group.
|
|
.endtable
|
|
|
|
BASIC (shell.bas, DECLARE LIBRARY "dvxshell"): ShellGroupsLoad / Save / Free / Scan / Changed / Get / Set / History$ / HistoryAdd, ShellGroupCount / Name$ / Find / Add / Delete / Rename / NameValid / Arrange / PlaceUnplaced / CellItem, ShellItemCount / Add / Get$ / Set / Delete / Copy / Move / Reorder / Place / Matches / KeyValid. A groups file is a handle of the program that opened it, freed when it ends (shellRegisterAppCleanup).
|
|
|
|
.topic shell.sysbasic
|
|
.title BASIC System Settings
|
|
.toc 1 BASIC System Settings
|
|
.index system.bas
|
|
.index SysSetVideoMode
|
|
.index SysVideoModeCount
|
|
.index SysSetColor
|
|
.index SysGetColor
|
|
.index SysColorId
|
|
.index SysLoadTheme
|
|
.index SysSaveTheme
|
|
.index SysColorsStore
|
|
.index SysSetWallpaper
|
|
.index SysWallpaperStore
|
|
.index SysSetTextSmoothing
|
|
.index SysTextSmoothing
|
|
.index SysFontsStore
|
|
.index SysSetMouse
|
|
.index SysMouseStore
|
|
.index SysMouseX
|
|
.index SysMouseY
|
|
.index SysMouseButtons
|
|
.index SysSetMousePos
|
|
.index SysShiftState
|
|
.index SysSendKey
|
|
.index SysScreenshot
|
|
.index SysMemoryTotalKb
|
|
.index SysMemoryFreeKb
|
|
.index SYS_VIDEO_DEFAULT_WIDTH
|
|
|
|
.h1 BASIC System Settings
|
|
|
|
Source: dvxshell/shellSysBas.c; BASIC declarations: src/include/basic/system.bas (DECLARE LIBRARY "dvxshell"); prototypes in shellApp.h.
|
|
|
|
What Control Panel changes, for DVX BASIC programs: the video mode, the system colors and themes, the wallpaper, text smoothing, and the mouse, each applied at once to shellContext(). Only BASIC-marshalable types; True (-1) / False (0); colors are BASIC RGB() values (&HBBGGRR, converted with wgtBasicColor); lists are 0-based. Arguments named prefs are prefs.bas handles, resolved with prefsBasHandle (dvxPrefs.h); 0 or a closed handle makes a Store or Load do nothing (a Load returns False).
|
|
|
|
.code
|
|
int32_t SysVideoModeCount(void);
|
|
int32_t SysVideoModeWidth(int32_t index);
|
|
int32_t SysVideoModeHeight(int32_t index);
|
|
int32_t SysVideoModeBpp(int32_t index);
|
|
int32_t SysSetVideoMode(int32_t width, int32_t height, int32_t bpp);
|
|
int32_t SysColorCount(void);
|
|
const char *SysColorLabel(int32_t id);
|
|
const char *SysColorName(int32_t id);
|
|
int32_t SysColorId(const char *name);
|
|
int32_t SysGetColor(int32_t id);
|
|
void SysSetColor(int32_t id, int32_t rgb);
|
|
void SysResetColors(void);
|
|
int32_t SysLoadTheme(const char *path);
|
|
int32_t SysSaveTheme(const char *path);
|
|
void SysColorsStore(int32_t prefs);
|
|
int32_t SysColorsLoad(int32_t prefs);
|
|
int32_t SysSetWallpaper(const char *path);
|
|
const char *SysWallpaper(void);
|
|
void SysSetWallpaperMode(int32_t mode);
|
|
int32_t SysWallpaperMode(void);
|
|
void SysWallpaperStore(int32_t prefs);
|
|
int32_t SysWallpaperLoad(int32_t prefs);
|
|
void SysSetTextSmoothing(int32_t on);
|
|
int32_t SysTextSmoothing(void);
|
|
void SysFontsStore(int32_t prefs);
|
|
void SysFontsLoad(int32_t prefs);
|
|
void SysSetMouse(int32_t wheelDir, int32_t dblClickMs, int32_t accel, int32_t mickeys, int32_t wheelStep);
|
|
int32_t SysMouseWheelDir(void);
|
|
int32_t SysMouseDoubleClick(void);
|
|
int32_t SysMouseAccel(void);
|
|
int32_t SysMouseMickeys(void);
|
|
int32_t SysMouseWheelStep(void);
|
|
void SysMouseStore(int32_t prefs);
|
|
void SysMouseLoad(int32_t prefs);
|
|
int32_t SysFontWidth(void);
|
|
int32_t SysFontHeight(void);
|
|
int32_t SysFontFirstChar(void);
|
|
int32_t SysFontCharCount(void);
|
|
int32_t SysFontGlyphRow(int32_t code, int32_t row);
|
|
int32_t SysMouseX(void);
|
|
int32_t SysMouseY(void);
|
|
int32_t SysMouseButtons(void);
|
|
void SysSetMousePos(int32_t x, int32_t y);
|
|
int32_t SysShiftState(void);
|
|
int32_t SysSendKey(int32_t keyCode, int32_t shift);
|
|
int32_t SysScreenshot(const char *path);
|
|
int32_t SysMemoryTotalKb(void);
|
|
int32_t SysMemoryFreeKb(void);
|
|
.endcode
|
|
|
|
.table
|
|
Function Calls
|
|
-------- -----
|
|
SysVideoMode* dvxGetVideoModes (0 out of range)
|
|
SysSetVideoMode dvxChangeVideoMode; False on -1 (also while a program is in exclusive full-screen mode)
|
|
SysColorLabel / SysColorName dvxColorLabel / dvxColorName ("" for an id outside 0 .. ColorCountE - 1)
|
|
SysColorId the id whose dvxColorName matches, any case; -1 for none
|
|
SysGetColor / SysSetColor dvxGetColor / dvxSetColor (an unknown id: 0 / nothing)
|
|
SysResetColors dvxResetColorScheme
|
|
SysLoadTheme / SysSaveTheme dvxLoadTheme / dvxSaveTheme
|
|
SysColorsStore / Load dvxColorsToPrefs / dvxColorsFromPrefs (Load: True when the handle had a [colors] key)
|
|
SysSetWallpaper dvxSetWallpaper ("" clears)
|
|
SysSetWallpaperMode dvxSetWallpaperMode with the value of prefsWallpaperChoices[mode]; other modes are ignored
|
|
SysWallpaper / Mode ctx->wallpaperPath; the prefsWallpaperChoices index of ctx->wallpaperMode
|
|
SysWallpaperStore / Load dvxWallpaperToPrefs / dvxWallpaperFromPrefs (Load: False when the image could not be loaded)
|
|
SysSetTextSmoothing dvxSetFontSmoothing (nonzero is on)
|
|
SysTextSmoothing ctx->fontSmoothing (the setting; text is smoothed only above 8 bits per pixel)
|
|
SysFontsStore / Load dvxFontsToPrefs / dvxFontsFromPrefs
|
|
SysSetMouse dvxSetMouseConfig
|
|
SysMouse* ctx->wheelDirection, dblClickMs, mouseAccel, mouseMickeys, wheelStep
|
|
SysMouseStore / Load dvxMouseToPrefs / dvxMouseFromPrefs
|
|
SysFont* dvxGetFont: charWidth, charHeight, firstChar, numChars; SysFontGlyphRow is glyphData[(code - firstChar) * charHeight + row] (0 outside the font)
|
|
SysMouseX / Y / Buttons ctx->mouseX, mouseY, mouseButtons (MOUSE_LEFT / RIGHT / MIDDLE = vbLeftButton ...)
|
|
SysSetMousePos platformMouseWarp, clamped to the screen; the next poll reports the move like the user's
|
|
SysShiftState ctx->keyModifiers & KEY_MOD_ALL (KEY_MOD_SHIFT / CTRL / ALT = vbShiftMask / vbCtrlMask / vbAltMask)
|
|
SysSendKey queues (up to 64) keyCode + shift as the BIOS stores the keystroke (platformBiosScanCode for combinations with codes of their own, KEY_EXT_FLAG keys by scan code, Ctrl+letter as its control character); a shell idle handler (shellRegisterIdle) injects one per idle frame with platformInjectKey, so each is read with its own modifiers, and releases them (platformInjectModifiers(0)) after the last
|
|
SysScreenshot dvxScreenshot (BMP for .bmp, else PNG)
|
|
SysMemoryTotalKb / FreeKb platformGetMemoryInfo; -1 when unknown
|
|
.endtable
|
|
|
|
There is no binding for platformInjectMouse: on DOS it replaces the real mouse until the next call and has no way back to it, so a synthesized click would leave the pointer stuck. A program moves the pointer with SysSetMousePos and "clicks" a control by calling its event procedure or setting its value.
|
|
|
|
system.bas also holds MOUSE_WHEEL_STEP_MIN / MAX / DEFAULT, MOUSE_DBLCLICK_DEFAULT_MS, and MOUSE_SPEED_DEFAULT, and SYS_VIDEO_DEFAULT_WIDTH / HEIGHT / BPP (DVX_DEFAULT_VIDEO_W / H / BPP, the mode prefsGetVideoMode and safe mode fall back to), as CONSTs; the basdev test suite (caseIncludeConsts) checks each against dvxTypes.h.
|
|
|
|
The Store / Load routines are the ones the shell uses at start (dvxMouseFromPrefs, dvxColorsFromPrefs, dvxWallpaperFromPrefs on DVX.INI) and Control Panel uses for OK and for its Cancel snapshot (an in-memory prefsCreate handle), so the INI keys are written in one place (dvxApp.c).
|
|
|