#include #include /// /// Welcome to Sample 6! /// /// In this sample we'll demonstrate how to set up a simple JavaScript app using only the C API. /// /// We will bind a JavaScript function to a C callback and use it to display a welcome message /// in our HTML view. /// /// __About the C API__ /// /// The C API is useful for porting the library to other languages or using it in scenarios that /// are unsuitable for C++. /// /// Most of the C++ API functionality is currently available via the CAPI headers with the /// exception of some of the Platform API. /// /// JavaScriptCore's native API is already in C so we can use it directly. /// /// Both Ultralight and JavaScriptCore follow the same paradigm when it comes to /// ownership/destruction: You should explicitly Destroy/Release anything you Create. /// /// Various globals ULApp app = 0; ULWindow window = 0; ULOverlay overlay = 0; ULView view = 0; /// Forward declaration of our OnUpdate callback. void OnUpdate(void* user_data); /// Forward declaration of our OnClose callback. void OnClose(void* user_data, ULWindow window); /// Forward declaration of our OnResize callback. void OnResize(void* user_data, ULWindow window, unsigned int width, unsigned int height); /// Forward declaration of our OnDOMReady callback. void OnDOMReady(void* user_data, ULView caller, unsigned long long frame_id, bool is_main_frame, ULString url); /// /// We set up our application here. /// void Init() { /// /// Create default settings/config /// ULSettings settings = ulCreateSettings(); ULConfig config = ulCreateConfig(); /// /// Create our App /// app = ulCreateApp(settings, config); /// /// Register a callback to handle app update logic. /// ulAppSetUpdateCallback(app, OnUpdate, 0); /// /// Done using settings/config, make sure to destroy anything we create /// ulDestroySettings(settings); ulDestroyConfig(config); /// /// Create our window, make it 500x500 with a titlebar and resize handles. /// window = ulCreateWindow(ulAppGetMainMonitor(app), 500, 500, false, kWindowFlags_Titled | kWindowFlags_Resizable); /// /// Set our window title. /// ulWindowSetTitle(window, "Ultralight Sample 6 - Intro to C API"); /// /// Register a callback to handle window close. /// ulWindowSetCloseCallback(window, OnClose, 0); /// /// Register a callback to handle window resize. /// ulWindowSetResizeCallback(window, OnResize, 0); /// /// Create an overlay same size as our window at 0,0 (top-left) origin. Overlays also create an /// HTML view for us to display content in. /// /// **Note**: /// Ownership of the view remains with the overlay since we don't explicitly create it. /// overlay = ulCreateOverlay(window, ulWindowGetWidth(window), ulWindowGetHeight(window), 0, 0); /// /// Get the overlay's view. /// view = ulOverlayGetView(overlay); /// /// Register a callback to handle our view's DOMReady event. We will use this event to setup any /// JavaScript <-> C bindings and initialize our page. /// ulViewSetDOMReadyCallback(view, OnDOMReady, 0); /// /// Load a file from the FileSystem. /// /// **IMPORTANT**: Make sure `file:///` has three (3) forward slashes. /// /// **Note**: You can configure the base path for the FileSystem in the Settings we passed to /// ulCreateApp earlier. /// ULString url = ulCreateString("file:///app.html"); ulViewLoadURL(view, url); ulDestroyString(url); } /// /// This is called continuously from the app's main run loop. You should update any app logic /// inside this callback. /// void OnUpdate(void* user_data) { /// We don't use this in this tutorial, just here for example. } /// /// This is called when the window is closed. /// void OnClose(void* user_data, ULWindow window) { ulAppQuit(app); } /// /// This is called whenever the window resizes. Width and height are in DPI-independent logical /// coordinates (not pixels). /// void OnResize(void* user_data, ULWindow window, unsigned int width, unsigned int height) { ulOverlayResize(overlay, width, height); } /// /// This callback is bound to a JavaScript function on the page. /// JSValueRef GetMessage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { /// /// Create a JavaScript String from a C-string, initialize it with our /// welcome message. /// JSStringRef str = JSStringCreateWithUTF8CString("Hello from C!"); /// /// Create a garbage-collected JSValue using the String we just created. /// /// **Note**: /// Both JSValueRef and JSObjectRef types are garbage-collected types. (And actually, /// JSObjectRef is just a typedef of JSValueRef, they share definitions). /// /// The garbage collector in JavaScriptCore periodically scans the entire stack to check if /// there are any active JSValueRefs, and marks those with no references for destruction. /// /// If you happen to store a JSValueRef/JSObjectRef in heap memory or in memory unreachable /// by the stack-based garbage-collector, you should explicitly call JSValueProtect() and /// JSValueUnprotect() on the reference to ensure it is kept alive. /// JSValueRef value = JSValueMakeString(ctx, str); /// /// Release the string we created earlier (we only Release what we Create). /// JSStringRelease(str); return value; } /// /// This is called when the page has finished parsing the document and is ready to execute scripts. /// /// We will use this event to set up our JavaScript <-> C callback. /// void OnDOMReady(void* user_data, ULView caller, unsigned long long frame_id, bool is_main_frame, ULString url) { /// /// Acquire the page's JavaScript execution context. /// /// This locks the JavaScript context so we can modify it safely on this thread, we need to /// unlock it when we're done via ulViewUnlockJSContext(). /// JSContextRef ctx = ulViewLockJSContext(view); /// /// Create a JavaScript String containing the name of our callback. /// JSStringRef name = JSStringCreateWithUTF8CString("GetMessage"); /// /// Create a garbage-collected JavaScript function that is bound to our native C callback /// 'GetMessage()'. /// JSObjectRef func = JSObjectMakeFunctionWithCallback(ctx, name, GetMessage); /// /// Store our function in the page's global JavaScript object so that it is accessible from the /// page as 'GetMessage()'. /// /// The global JavaScript object is also known as 'window' in JS. /// JSObjectSetProperty(ctx, JSContextGetGlobalObject(ctx), name, func, 0, 0); /// /// Release the JavaScript String we created earlier. /// JSStringRelease(name); /// /// Unlock the JS context so other threads can modify JavaScript state. /// ulViewUnlockJSContext(view); } /// /// We tear down our application here. /// void Shutdown() { /// /// Explicitly destroy everything we created in Init(). /// ulDestroyOverlay(overlay); ulDestroyWindow(window); ulDestroyApp(app); } int main() { /// /// Initialize the app. /// Init(); /// /// Run the app until the window is closed. (This is a modal operation) /// ulAppRun(app); /// /// Shutdown the app. /// Shutdown(); return 0; }