Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LunaUI

LunaUI is a generic Win32 + WebView2 application shell: one top-level window, one WebView2 controller, optional local virtual-host content mapping, and a typed JSON message bridge between page JS and native code. WebView2 initialization is asynchronous but ready/error/closed lifecycle callbacks are explicit, and incoming messages are accepted only from an exact configured origin allowlist.

Features

  • Standard resizable, DPI-aware window with an optional dark title bar and always-on-top.
  • Frameless mode (borderless): the page draws its own title bar. The shell keeps an 8-direction native resize strip (resize_border px) around the WebView via WM_NCHITTEST (edges + corners), clamps maximize to the work area, and optionally rounds the client corners on Windows 11.
  • Optional window protocol manager (luna_ui_window_manager.hpp): page → native host: messages start native gestures (host:drag-move, host:resize-<left|right|top|bottom|top-left|…>) and run window commands (host:minimize-window, host:maximize-window, host:restore-window, host:toggle-maximize, host:close-window). Structured JSON commands use {"kind":"webui-command","command":"set-always-on-top","payload":{"value":true}} (also set-window-background-color, query-window-state, set-window-transparent — live DWM glass toggle — and set-backdrop-mode).
  • Backdrop modes (native transparency): host:cycle-backdrop-mode or the set-backdrop-mode command cycles through none → glass → layered-97 → layered-85 → mica → acrylic → blur → acrylic-blur. Modes map to DwmExtendFrameIntoClientArea, WS_EX_LAYERED + SetLayeredWindowAttributes, DWMWA_SYSTEMBACKDROP_TYPE (Mica/Acrylic), and the composition accent API (blur / acrylic-blur); the current mode is announced to the page as host:backdrop-mode:<label>. The WebView background is transparent (transparent_background), so the chosen backdrop shows through transparent page pixels.
  • Optional multi-window (LunaUIWindowManager::OpenWindow, page command open-window): child windows share the shell's WebView2 environment, are owned by the main window (they close with it), and can be transparent real glass frames (transparent): DwmExtendFrameIntoClientArea({-1,-1,-1,-1}) plus a fully transparent WebView background so the page draws floating rounded cards over the desktop. Child pages control their window through {"type":"window","action":…} JSON (drag, minimize, maximize, close, alwaysOnTop{enabled}, resize{edge}, state); the shell replies with {"type":"windowState",…} and {"type":"windowLifecycle", "state":"closing"|"minimizing"|"restoring"|"maximizing"}. Page-side commands: open-window, close-window, hide-window, destroy-window, window-list; native pushes {"kind":"host:window-event","event":"opened"|"ready"|"hidden"|"closed"|"error"|"list",…} back to the main page. BroadcastJson fans one JSON out to every window.
  • Window manager (window lifecycle kinds): every child window has a kind in open-window's payload —
    • transient (default): created on open, destroyed on close.
    • persistent (palette-like, e.g. a command-search popup): created once and kept alive — open-window shows/focuses it (optionally show:false prefetches it hidden at startup, so it is loaded on launch), close-window just hides it (host:window-event "hidden"), and its page state (query, scroll) survives across shows; hide-window hides, destroy-window tears it down, and the child page itself can post {"type":"window", "action":"close"|"hide"|"destroy"}. open-window also accepts auto_hide_on_focus_lost:true for palette-like windows: when the window loses focus (the user clicked elsewhere) it dismisses itself — persistent windows hide (page stays alive), transient windows close. A short deactivation guard prevents an instant hide during the show/activate hand-off. window-list / window-event entries now carry "kind" and "visible" so the page can render a full window-manager panel.
  • Window state push (native → page): the optional manager sends host:window-shown, child windowLifecycle events, and {"kind":"host:window-state",…} JSON.
  • WebView2 lifecycle: environment with a per-app user data folder (optionally isolated per process via isolate_user_data_folder_per_process so concurrent instances of the same app never share one WebView2 profile — two processes on one folder fight over the browser process and blank each other's windows), controller sizing on resize/DPI change, settings (DevTools, context menu, zoom).
  • Navigate(url) / NavigateToString(html) to load content.
  • Optional local content: map a folder to a https://<virtual-host>/ origin.
  • JSON message bridge: page window.chrome.webview.postMessage(json) reaches the typed native callback; PostJson(json) sends JSON into the page. Object fields may be reordered and string values are decoded with standard JSON escaping.
  • Handler subscriptions can be added before or after Start() and removed by id without replacing another consumer's callback. on_ready means the WebView2 controller is initialized; on_navigation_completed reports the later page navigation result.

Demo

luna_ui_example opens a borderless window hosting the LunaUI control gallery at example/ui/gallery.html — a control and interaction pattern collection demonstrating the framework's bridge and window APIs:

  • custom title bar (drag to move, double-click to maximize, minimize / maximize-restore / close chips, pin-to-top), 8-way native resize edges and card-style page corner grips (sticky to the content card's corners, styled as small rounded card tabs with an accent arc, starting native resize gestures); maximized state removes the content's max-width so the card stack fills the whole window width
  • transparent window mode: with transparent_background the frameless window is a real DWM glass frame from creation — the page background is fully transparent (.app-shell has no tint) and solid cards/masthead float directly over the desktop; the gallery's transparent switch (set-window-transparent) turns the glass off/on live, and set-backdrop-mode / host:cycle-backdrop-mode cycle the full backdrop family (glass / layered alpha / Mica / Acrylic / blur)
  • window lifecycle animations (close / minimize / restore sequences with the native handshake; the close chip closes directly with animation), live window-state badges, native event log
  • buttons (gradient CTA, chips, hover label swap, progress sweep), inputs, custom select with a "jelly" hover block, toggles with scope tags, segmented controls with sliding indicator, tabs, vertical/horizontal sliders, activity list with scroll-fade masks, modal dialog, command palette (staggered open, keyboard navigation, filtering), toasts
  • Timeline preview (片段条 segment strip + transport): a 20-segment timeline strip with wheel-scroll momentum + snap, and a two-mode drag-to-scroll — inside the window the strip follows the cursor 1:1, and once the cursor crosses a window edge the control switches to distance-based: the farther past the edge it is pushed, the faster the strip scrolls (pulling back toward the window slows it, crossing back inside resumes 1:1). A velocity-matched auto-scroll covers the case where the cursor is clamped at the edge (window fills the screen / remote-desktop sessions).
  • full motion language: reveal entrances, masthead piece animations, elastic easing, clip-path icon morphs, prefers-reduced-motion support; light/dark themes via data-theme CSS variables.
  • Multi-window demo + window manager: the gallery opens floating transparent child windows — an analytics panel (example/ui/dashboard.html, transient: created on open, destroyed on close) and the command palette (example/ui/command-palette.html, persistent: prefetched hidden at startup, loaded once, close only hides it and its query/scroll state survives). The window-management card lists every window with its kind and visibility and drives them with open-window / hide-window / close-window / destroy-window (显示 / 隐藏 / 关闭 / 销毁). The command palette forwards the picked command back to the main page through {"type":"command",…}; the main window can also be turned into a real DWM glass frame with set-window-transparent / set-backdrop-mode. Child pages speak the {"type":"window",…} protocol (drag / minimize / maximize / close / always-on-top / corner-resize) and animate on windowLifecycle events.

Build

Requirements: Visual Studio 2022 C++ tools, CMake, a WebView2 SDK, and the WebView2 Runtime. WEBVIEW2_ROOT is required and is intentionally not hardcoded to a machine-specific path.

cmake -S . -B build -A x64 -DWEBVIEW2_ROOT="<path-to-webview2-sdk>" -DLUNA_UI_BUILD_TESTS=ON
cmake --build build --config Release
ctest --test-dir build -C Release --output-on-failure

The demo is opt-in: add -DLUNA_UI_BUILD_EXAMPLE=ON when building the gallery.

Produces luna_ui.lib, the optional luna_ui_window_manager.lib, and the luna_ui_example demo in build/Release/.

To install the reusable targets and headers:

cmake --install build --config Release --prefix <install-prefix>

Consuming the library

add_subdirectory this project (or use the installed package) and link the core target:

add_subdirectory("<path-to-LunaUI>" LunaUI)
target_link_libraries(my_app PRIVATE luna_ui)

Then open a window:

#include "luna_ui.hpp"
#include <utility>

luna_ui::LunaUIConfig config;
config.title = L"My App";
config.initial_url = L"https://example.com";
luna_ui::LunaUIEvents events;
events.on_error = [](HRESULT, const std::wstring& detail) {
  // report initialization failure
};
luna_ui::LunaUI shell;
config.allowed_origins = {luna_ui::UrlOrigin(config.initial_url)};
if (!shell.Start(instance, config, std::move(events))) return 1;
return shell.RunMessageLoop();

The core target does not interpret application commands. Add luna_ui_window_manager when the optional host: / child-window protocol is needed. The manager is a protocol adapter over the core's private child-window primitives; applications that only need one top-level window can omit it:

target_link_libraries(my_app PRIVATE luna_ui_window_manager)
#include "luna_ui_window_manager.hpp"
luna_ui::LunaUIWindowManager windows(shell);
windows.Attach();

For an installed package, set LunaUI_WEBVIEW2_ROOT and use find_package(LunaUI CONFIG REQUIRED) with LunaUI::luna_ui or LunaUI::luna_ui_window_manager.

See include/luna_ui.hpp for the full config surface and the example in example/main.cpp.

Consumers

The first external consumer is the desktop shell in the companion dsh-desktop repository.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages