126 lines
4.7 KiB
C
126 lines
4.7 KiB
C
// shellExport.c -- DXE wrapper overrides for resource tracking
|
|
//
|
|
// Registers three wrapper functions via dlregsym that override the
|
|
// real dvxCreateWindow, dvxCreateWindowCentered, and dvxDestroyWindow
|
|
// for all subsequently loaded app DXEs.
|
|
//
|
|
// The key mechanic: dlregsym takes precedence over RTLD_GLOBAL exports.
|
|
// Since libdvx.dxe (which has the real functions) was loaded before
|
|
// shellExportInit() registers these wrappers, libdvx.dxe keeps the
|
|
// real implementations. But any app DXE loaded afterward gets the
|
|
// wrappers, which add resource tracking (appId stamping, last-window
|
|
// reaping) transparently.
|
|
//
|
|
// All other symbol exports (dvx*, wgt*, platform*, libc) are handled
|
|
// by the DXE modules and the loader's dlregsym table -- they no longer
|
|
// need to be listed here.
|
|
|
|
#include "shellApp.h"
|
|
#include "dvxApp.h"
|
|
#include "dvxWm.h"
|
|
|
|
#include <sys/dxe.h>
|
|
|
|
// ============================================================
|
|
// Prototypes
|
|
// ============================================================
|
|
|
|
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 (resolved from libdvx.dxe
|
|
// at shellcore load time), 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.
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// Wrapper export table
|
|
// ============================================================
|
|
|
|
// Only three entries: the resource-tracking wrappers exported under
|
|
// the original function names. All other symbols come from the
|
|
// loaded DXE modules (via RTLD_GLOBAL) and the loader's dlregsym.
|
|
DXE_EXPORT_TABLE(sWrapperTable)
|
|
{ "_dvxCreateWindow", (void *)shellWrapCreateWindow },
|
|
{ "_dvxCreateWindowCentered", (void *)shellWrapCreateWindowCentered },
|
|
{ "_dvxDestroyWindow", (void *)shellWrapDestroyWindow },
|
|
DXE_EXPORT_END
|
|
|
|
|
|
// ============================================================
|
|
// shellExportInit
|
|
// ============================================================
|
|
|
|
// Register the wrapper overrides. Must be called before any
|
|
// shellLoadApp() -- wrappers only affect subsequently loaded DXEs.
|
|
void shellExportInit(void) {
|
|
dlregsym(sWrapperTable);
|
|
}
|