487 lines
15 KiB
C
487 lines
15 KiB
C
// shellExport.c — DXE export table and wrapper functions for DVX Shell
|
|
//
|
|
// Exports all dvx*/wgt*/ts* symbols that DXE apps need. A few functions
|
|
// are wrapped for resource tracking (window ownership via appId).
|
|
//
|
|
// DXE3 is DJGPP's dynamic linking mechanism. Unlike ELF shared libraries,
|
|
// DXE modules have no implicit access to the host's symbol table. Every
|
|
// function or variable the DXE needs must be explicitly listed in an
|
|
// export table registered via dlregsym() BEFORE any dlopen() call. If a
|
|
// symbol is missing, dlopen() returns NULL with a "symbol not found" error.
|
|
//
|
|
// This file is essentially the ABI contract between the shell and apps.
|
|
// Three categories of exports:
|
|
//
|
|
// 1. Wrapped functions: dvxCreateWindow, dvxCreateWindowCentered,
|
|
// dvxDestroyWindow. These are intercepted to stamp win->appId for
|
|
// resource ownership tracking. The DXE sees them under their original
|
|
// names — the app code calls dvxCreateWindow() normally and gets our
|
|
// wrapper transparently.
|
|
//
|
|
// 2. Direct exports: all other dvx/wgt/wm/ts functions. These are safe
|
|
// to call without shell-side interception.
|
|
//
|
|
// 3. libc functions: DXE modules are statically linked against DJGPP's
|
|
// libc, but DJGPP's DXE3 loader requires explicit re-export of any
|
|
// libc symbols the module references. Without these entries, the DXE
|
|
// would fail to load with unresolved symbol errors. This is a DXE3
|
|
// design limitation — there's no automatic fallback to the host's libc.
|
|
|
|
#include "shellApp.h"
|
|
#include "dvxApp.h"
|
|
#include "dvxDialog.h"
|
|
#include "dvxWidget.h"
|
|
#include "dvxDraw.h"
|
|
#include "dvxVideo.h"
|
|
#include "dvxWm.h"
|
|
#include "taskswitch.h"
|
|
|
|
#include <sys/dxe.h>
|
|
#include <sys/stat.h>
|
|
#include <dirent.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
|
|
// ============================================================
|
|
// Prototypes
|
|
// ============================================================
|
|
|
|
static void shellRegisterExports(void);
|
|
static WindowT *shellWrapCreateWindow(AppContextT *ctx, const char *title, int32_t x, int32_t y, int32_t w, int32_t h, bool resizable);
|
|
static WindowT *shellWrapCreateWindowCentered(AppContextT *ctx, const char *title, int32_t w, int32_t h, bool resizable);
|
|
static void shellWrapDestroyWindow(AppContextT *ctx, WindowT *win);
|
|
|
|
// ============================================================
|
|
// Wrapper: dvxCreateWindow — stamps win->appId
|
|
// ============================================================
|
|
|
|
// The wrapper calls the real dvxCreateWindow, then tags the result with
|
|
// sCurrentAppId. This is how the shell knows which app owns which window,
|
|
// enabling per-app window cleanup on crash/termination. The app never
|
|
// sees the difference — the wrapper has the same signature and is
|
|
// exported under the same name as the original function.
|
|
static WindowT *shellWrapCreateWindow(AppContextT *ctx, const char *title, int32_t x, int32_t y, int32_t w, int32_t h, bool resizable) {
|
|
WindowT *win = dvxCreateWindow(ctx, title, x, y, w, h, resizable);
|
|
|
|
if (win) {
|
|
win->appId = sCurrentAppId;
|
|
}
|
|
|
|
return win;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// Wrapper: dvxCreateWindowCentered — stamps win->appId
|
|
// ============================================================
|
|
|
|
static WindowT *shellWrapCreateWindowCentered(AppContextT *ctx, const char *title, int32_t w, int32_t h, bool resizable) {
|
|
WindowT *win = dvxCreateWindowCentered(ctx, title, w, h, resizable);
|
|
|
|
if (win) {
|
|
win->appId = sCurrentAppId;
|
|
}
|
|
|
|
return win;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// Wrapper: dvxDestroyWindow — checks for last-window reap
|
|
// ============================================================
|
|
|
|
// Beyond just destroying the window, this wrapper implements the lifecycle
|
|
// rule for callback-only apps: when their last window closes, they're done.
|
|
// Main-loop apps manage their own lifetime (their task returns from
|
|
// appMain), so this check only applies to callback-only apps.
|
|
// The appId is captured before destruction because the window struct is
|
|
// freed by dvxDestroyWindow.
|
|
static void shellWrapDestroyWindow(AppContextT *ctx, WindowT *win) {
|
|
int32_t appId = win->appId;
|
|
|
|
dvxDestroyWindow(ctx, win);
|
|
|
|
// If this was a callback-only app's last window, mark for reaping
|
|
if (appId > 0) {
|
|
ShellAppT *app = shellGetApp(appId);
|
|
|
|
if (app && !app->hasMainLoop && app->state == AppStateRunningE) {
|
|
// Check if app still has any windows
|
|
bool hasWindows = false;
|
|
|
|
for (int32_t i = 0; i < ctx->stack.count; i++) {
|
|
if (ctx->stack.windows[i]->appId == appId) {
|
|
hasWindows = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!hasWindows) {
|
|
app->state = AppStateTerminatingE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// Export table
|
|
// ============================================================
|
|
|
|
// DXE_EXPORT_TABLE generates a DXE symbol table array. DXE_EXPORT(fn)
|
|
// expands to { "_fn", (void *)fn } — the underscore prefix matches COFF
|
|
// symbol naming. For wrapped functions we use raw entries with explicit
|
|
// names so the DXE sees "_dvxCreateWindow" but gets our wrapper's address.
|
|
|
|
DXE_EXPORT_TABLE(shellExportTable)
|
|
// Wrapped functions (exported under original names, but pointing to
|
|
// our wrappers that add resource tracking)
|
|
{ "_dvxCreateWindow", (void *)shellWrapCreateWindow },
|
|
{ "_dvxDestroyWindow", (void *)shellWrapDestroyWindow },
|
|
|
|
// dvxApp.h — direct exports
|
|
DXE_EXPORT(dvxInit)
|
|
DXE_EXPORT(dvxShutdown)
|
|
DXE_EXPORT(dvxUpdate)
|
|
{ "_dvxCreateWindowCentered", (void *)shellWrapCreateWindowCentered },
|
|
DXE_EXPORT(dvxFitWindow)
|
|
DXE_EXPORT(dvxInvalidateRect)
|
|
DXE_EXPORT(dvxInvalidateWindow)
|
|
DXE_EXPORT(dvxMinimizeWindow)
|
|
DXE_EXPORT(dvxMaximizeWindow)
|
|
DXE_EXPORT(dvxQuit)
|
|
DXE_EXPORT(dvxSetTitle)
|
|
DXE_EXPORT(dvxGetFont)
|
|
DXE_EXPORT(dvxGetColors)
|
|
DXE_EXPORT(dvxGetDisplay)
|
|
DXE_EXPORT(dvxGetBlitOps)
|
|
DXE_EXPORT(dvxSetWindowIcon)
|
|
DXE_EXPORT(dvxLoadImage)
|
|
DXE_EXPORT(dvxFreeImage)
|
|
DXE_EXPORT(dvxSaveImage)
|
|
DXE_EXPORT(dvxScreenshot)
|
|
DXE_EXPORT(dvxWindowScreenshot)
|
|
DXE_EXPORT(dvxCreateAccelTable)
|
|
DXE_EXPORT(dvxFreeAccelTable)
|
|
DXE_EXPORT(dvxAddAccel)
|
|
DXE_EXPORT(dvxCascadeWindows)
|
|
DXE_EXPORT(dvxTileWindows)
|
|
DXE_EXPORT(dvxTileWindowsH)
|
|
DXE_EXPORT(dvxTileWindowsV)
|
|
DXE_EXPORT(dvxClipboardCopy)
|
|
DXE_EXPORT(dvxClipboardGet)
|
|
|
|
// dvxDialog.h
|
|
DXE_EXPORT(dvxMessageBox)
|
|
DXE_EXPORT(dvxFileDialog)
|
|
|
|
// dvxDraw.h
|
|
DXE_EXPORT(rectFill)
|
|
DXE_EXPORT(rectCopy)
|
|
DXE_EXPORT(drawBevel)
|
|
DXE_EXPORT(drawChar)
|
|
DXE_EXPORT(drawText)
|
|
DXE_EXPORT(drawTextN)
|
|
DXE_EXPORT(textWidth)
|
|
DXE_EXPORT(drawTextAccel)
|
|
DXE_EXPORT(textWidthAccel)
|
|
DXE_EXPORT(drawFocusRect)
|
|
DXE_EXPORT(drawHLine)
|
|
DXE_EXPORT(drawVLine)
|
|
|
|
// dvxVideo.h
|
|
DXE_EXPORT(packColor)
|
|
|
|
// dvxWm.h
|
|
DXE_EXPORT(wmAddMenuBar)
|
|
DXE_EXPORT(wmAddMenu)
|
|
DXE_EXPORT(wmAddMenuItem)
|
|
DXE_EXPORT(wmAddMenuCheckItem)
|
|
DXE_EXPORT(wmAddMenuRadioItem)
|
|
DXE_EXPORT(wmAddMenuSeparator)
|
|
DXE_EXPORT(wmAddSubMenu)
|
|
DXE_EXPORT(wmAddVScrollbar)
|
|
DXE_EXPORT(wmAddHScrollbar)
|
|
DXE_EXPORT(wmSetTitle)
|
|
DXE_EXPORT(wmSetIcon)
|
|
DXE_EXPORT(wmCreateMenu)
|
|
DXE_EXPORT(wmFreeMenu)
|
|
DXE_EXPORT(wmUpdateContentRect)
|
|
DXE_EXPORT(wmReallocContentBuf)
|
|
|
|
// dvxWidget.h — window integration
|
|
DXE_EXPORT(wgtInitWindow)
|
|
|
|
// dvxWidget.h — containers
|
|
DXE_EXPORT(wgtVBox)
|
|
DXE_EXPORT(wgtHBox)
|
|
DXE_EXPORT(wgtFrame)
|
|
|
|
// dvxWidget.h — basic widgets
|
|
DXE_EXPORT(wgtLabel)
|
|
DXE_EXPORT(wgtButton)
|
|
DXE_EXPORT(wgtCheckbox)
|
|
DXE_EXPORT(wgtTextInput)
|
|
DXE_EXPORT(wgtPasswordInput)
|
|
DXE_EXPORT(wgtMaskedInput)
|
|
|
|
// dvxWidget.h — radio buttons
|
|
DXE_EXPORT(wgtRadioGroup)
|
|
DXE_EXPORT(wgtRadio)
|
|
|
|
// dvxWidget.h — spacing
|
|
DXE_EXPORT(wgtSpacer)
|
|
DXE_EXPORT(wgtHSeparator)
|
|
DXE_EXPORT(wgtVSeparator)
|
|
|
|
// dvxWidget.h — complex widgets
|
|
DXE_EXPORT(wgtListBox)
|
|
DXE_EXPORT(wgtTextArea)
|
|
|
|
// dvxWidget.h — dropdown/combo
|
|
DXE_EXPORT(wgtDropdown)
|
|
DXE_EXPORT(wgtDropdownSetItems)
|
|
DXE_EXPORT(wgtDropdownGetSelected)
|
|
DXE_EXPORT(wgtDropdownSetSelected)
|
|
DXE_EXPORT(wgtComboBox)
|
|
DXE_EXPORT(wgtComboBoxSetItems)
|
|
DXE_EXPORT(wgtComboBoxGetSelected)
|
|
DXE_EXPORT(wgtComboBoxSetSelected)
|
|
|
|
// dvxWidget.h — progress bar
|
|
DXE_EXPORT(wgtProgressBar)
|
|
DXE_EXPORT(wgtProgressBarV)
|
|
DXE_EXPORT(wgtProgressBarSetValue)
|
|
DXE_EXPORT(wgtProgressBarGetValue)
|
|
|
|
// dvxWidget.h — slider
|
|
DXE_EXPORT(wgtSlider)
|
|
DXE_EXPORT(wgtSliderSetValue)
|
|
DXE_EXPORT(wgtSliderGetValue)
|
|
|
|
// dvxWidget.h — spinner
|
|
DXE_EXPORT(wgtSpinner)
|
|
DXE_EXPORT(wgtSpinnerSetValue)
|
|
DXE_EXPORT(wgtSpinnerGetValue)
|
|
DXE_EXPORT(wgtSpinnerSetRange)
|
|
DXE_EXPORT(wgtSpinnerSetStep)
|
|
|
|
// dvxWidget.h — tab control
|
|
DXE_EXPORT(wgtTabControl)
|
|
DXE_EXPORT(wgtTabPage)
|
|
DXE_EXPORT(wgtTabControlSetActive)
|
|
DXE_EXPORT(wgtTabControlGetActive)
|
|
|
|
// dvxWidget.h — status bar / toolbar
|
|
DXE_EXPORT(wgtStatusBar)
|
|
DXE_EXPORT(wgtToolbar)
|
|
|
|
// dvxWidget.h — tree view
|
|
DXE_EXPORT(wgtTreeView)
|
|
DXE_EXPORT(wgtTreeViewGetSelected)
|
|
DXE_EXPORT(wgtTreeViewSetSelected)
|
|
DXE_EXPORT(wgtTreeViewSetMultiSelect)
|
|
DXE_EXPORT(wgtTreeViewSetReorderable)
|
|
DXE_EXPORT(wgtTreeItem)
|
|
DXE_EXPORT(wgtTreeItemSetExpanded)
|
|
DXE_EXPORT(wgtTreeItemIsExpanded)
|
|
DXE_EXPORT(wgtTreeItemIsSelected)
|
|
DXE_EXPORT(wgtTreeItemSetSelected)
|
|
|
|
// dvxWidget.h — list view
|
|
DXE_EXPORT(wgtListView)
|
|
DXE_EXPORT(wgtListViewSetColumns)
|
|
DXE_EXPORT(wgtListViewSetData)
|
|
DXE_EXPORT(wgtListViewGetSelected)
|
|
DXE_EXPORT(wgtListViewSetSelected)
|
|
DXE_EXPORT(wgtListViewSetSort)
|
|
DXE_EXPORT(wgtListViewSetHeaderClickCallback)
|
|
DXE_EXPORT(wgtListViewSetMultiSelect)
|
|
DXE_EXPORT(wgtListViewIsItemSelected)
|
|
DXE_EXPORT(wgtListViewSetItemSelected)
|
|
DXE_EXPORT(wgtListViewSelectAll)
|
|
DXE_EXPORT(wgtListViewClearSelection)
|
|
DXE_EXPORT(wgtListViewSetReorderable)
|
|
|
|
// dvxWidget.h — scroll pane / splitter
|
|
DXE_EXPORT(wgtScrollPane)
|
|
DXE_EXPORT(wgtSplitter)
|
|
DXE_EXPORT(wgtSplitterSetPos)
|
|
DXE_EXPORT(wgtSplitterGetPos)
|
|
|
|
// dvxWidget.h — image / image button
|
|
DXE_EXPORT(wgtImageButton)
|
|
DXE_EXPORT(wgtImageButtonFromFile)
|
|
DXE_EXPORT(wgtImageButtonSetData)
|
|
DXE_EXPORT(wgtImage)
|
|
DXE_EXPORT(wgtImageFromFile)
|
|
DXE_EXPORT(wgtImageSetData)
|
|
|
|
// dvxWidget.h — canvas
|
|
DXE_EXPORT(wgtCanvas)
|
|
DXE_EXPORT(wgtCanvasClear)
|
|
DXE_EXPORT(wgtCanvasSetMouseCallback)
|
|
DXE_EXPORT(wgtCanvasSetPenColor)
|
|
DXE_EXPORT(wgtCanvasSetPenSize)
|
|
DXE_EXPORT(wgtCanvasSave)
|
|
DXE_EXPORT(wgtCanvasLoad)
|
|
DXE_EXPORT(wgtCanvasDrawLine)
|
|
DXE_EXPORT(wgtCanvasDrawRect)
|
|
DXE_EXPORT(wgtCanvasFillRect)
|
|
DXE_EXPORT(wgtCanvasFillCircle)
|
|
DXE_EXPORT(wgtCanvasSetPixel)
|
|
DXE_EXPORT(wgtCanvasGetPixel)
|
|
|
|
// dvxWidget.h — ANSI terminal
|
|
DXE_EXPORT(wgtAnsiTerm)
|
|
DXE_EXPORT(wgtAnsiTermWrite)
|
|
DXE_EXPORT(wgtAnsiTermClear)
|
|
DXE_EXPORT(wgtAnsiTermSetComm)
|
|
DXE_EXPORT(wgtAnsiTermSetScrollback)
|
|
DXE_EXPORT(wgtAnsiTermPoll)
|
|
DXE_EXPORT(wgtAnsiTermRepaint)
|
|
|
|
// dvxWidget.h — operations
|
|
DXE_EXPORT(wgtInvalidate)
|
|
DXE_EXPORT(wgtInvalidatePaint)
|
|
DXE_EXPORT(wgtSetDebugLayout)
|
|
DXE_EXPORT(wgtSetText)
|
|
DXE_EXPORT(wgtGetText)
|
|
DXE_EXPORT(wgtSetEnabled)
|
|
DXE_EXPORT(wgtSetVisible)
|
|
DXE_EXPORT(wgtGetContext)
|
|
DXE_EXPORT(wgtSetName)
|
|
DXE_EXPORT(wgtFind)
|
|
DXE_EXPORT(wgtDestroy)
|
|
|
|
// dvxWidget.h — list box ops
|
|
DXE_EXPORT(wgtListBoxSetItems)
|
|
DXE_EXPORT(wgtListBoxGetSelected)
|
|
DXE_EXPORT(wgtListBoxSetSelected)
|
|
DXE_EXPORT(wgtListBoxSetMultiSelect)
|
|
DXE_EXPORT(wgtListBoxIsItemSelected)
|
|
DXE_EXPORT(wgtListBoxSetItemSelected)
|
|
DXE_EXPORT(wgtListBoxSelectAll)
|
|
DXE_EXPORT(wgtListBoxClearSelection)
|
|
DXE_EXPORT(wgtListBoxSetReorderable)
|
|
|
|
// dvxWidget.h — layout
|
|
DXE_EXPORT(wgtResolveSize)
|
|
DXE_EXPORT(wgtLayout)
|
|
DXE_EXPORT(wgtPaint)
|
|
|
|
// taskswitch.h — only yield and query functions are exported.
|
|
// tsCreate/tsKill/etc. are NOT exported because apps should not
|
|
// manipulate the task system directly — the shell manages task
|
|
// lifecycle through shellLoadApp/shellForceKillApp.
|
|
DXE_EXPORT(tsYield)
|
|
DXE_EXPORT(tsCurrentId)
|
|
DXE_EXPORT(tsActiveCount)
|
|
|
|
// dvxWm.h — direct window management
|
|
DXE_EXPORT(wmRaiseWindow)
|
|
DXE_EXPORT(wmSetFocus)
|
|
DXE_EXPORT(wmRestoreMinimized)
|
|
|
|
// Shell API
|
|
DXE_EXPORT(shellLog)
|
|
DXE_EXPORT(shellLoadApp)
|
|
DXE_EXPORT(shellGetApp)
|
|
DXE_EXPORT(shellForceKillApp)
|
|
DXE_EXPORT(shellRunningAppCount)
|
|
DXE_EXPORT(shellRegisterDesktopUpdate)
|
|
|
|
// libc exports below. DXE3 modules are compiled as relocatable objects,
|
|
// not fully linked executables. Any libc function the DXE calls must be
|
|
// re-exported here so the DXE3 loader can resolve the reference at
|
|
// dlopen time. Forgetting an entry produces a cryptic "unresolved
|
|
// symbol" error at load time — no lazy binding fallback exists.
|
|
|
|
// libc — memory
|
|
DXE_EXPORT(malloc)
|
|
DXE_EXPORT(free)
|
|
DXE_EXPORT(calloc)
|
|
DXE_EXPORT(realloc)
|
|
|
|
// libc — string
|
|
DXE_EXPORT(memcpy)
|
|
DXE_EXPORT(memset)
|
|
DXE_EXPORT(memmove)
|
|
DXE_EXPORT(memcmp)
|
|
DXE_EXPORT(strlen)
|
|
DXE_EXPORT(strcmp)
|
|
DXE_EXPORT(strncmp)
|
|
DXE_EXPORT(strcpy)
|
|
DXE_EXPORT(strncpy)
|
|
DXE_EXPORT(strcat)
|
|
DXE_EXPORT(strncat)
|
|
DXE_EXPORT(strchr)
|
|
DXE_EXPORT(strrchr)
|
|
DXE_EXPORT(strstr)
|
|
DXE_EXPORT(strtol)
|
|
|
|
// libc — I/O
|
|
DXE_EXPORT(printf)
|
|
DXE_EXPORT(fprintf)
|
|
DXE_EXPORT(sprintf)
|
|
DXE_EXPORT(snprintf)
|
|
DXE_EXPORT(puts)
|
|
DXE_EXPORT(fopen)
|
|
DXE_EXPORT(fclose)
|
|
DXE_EXPORT(fread)
|
|
DXE_EXPORT(fwrite)
|
|
DXE_EXPORT(fgets)
|
|
DXE_EXPORT(fseek)
|
|
DXE_EXPORT(ftell)
|
|
DXE_EXPORT(feof)
|
|
DXE_EXPORT(ferror)
|
|
|
|
// libc — math
|
|
DXE_EXPORT(sin)
|
|
DXE_EXPORT(cos)
|
|
DXE_EXPORT(sqrt)
|
|
|
|
// libc — time
|
|
DXE_EXPORT(clock)
|
|
DXE_EXPORT(time)
|
|
DXE_EXPORT(localtime)
|
|
|
|
// libc — directory
|
|
DXE_EXPORT(opendir)
|
|
DXE_EXPORT(readdir)
|
|
DXE_EXPORT(closedir)
|
|
|
|
// libc — filesystem
|
|
DXE_EXPORT(stat)
|
|
|
|
// libc — misc
|
|
DXE_EXPORT(qsort)
|
|
DXE_EXPORT(rand)
|
|
DXE_EXPORT(srand)
|
|
DXE_EXPORT(abs)
|
|
DXE_EXPORT(atoi)
|
|
DXE_EXPORT_END
|
|
|
|
|
|
// ============================================================
|
|
// shellRegisterExports
|
|
// ============================================================
|
|
|
|
// dlregsym registers our export table with DJGPP's DXE3 runtime.
|
|
// Must be called once before any dlopen — subsequent dlopen calls
|
|
// will search this table to resolve DXE symbol references.
|
|
static void shellRegisterExports(void) {
|
|
dlregsym(shellExportTable);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// Public init function
|
|
// ============================================================
|
|
|
|
void shellExportInit(void) {
|
|
shellRegisterExports();
|
|
}
|