Adding inline C functions to Sciter :)

As a response to WebAssembly initiative I am thinking about adding native inline C functions to Sciter.

// that is inline C function declared directly in script:

function getAverageColor( image ) C {
   typedef struct {
     byte r;
     byte g;
     byte b;
     byte a;
   } rgba;

   rgba*    pix   = image_pixels(image);
   unsigned total = image_pixels_count(image);  
   rgba*    pix_end  = pix + total;

   unsigned int r = 0, g = 0, b = 0, a = 0;
   
   for(; pix < pix_end; ++pix )  {     
     r += pix->r;   
     g += pix->g;
     b += pix->b;
     a += pix->a;
   }

   rgba out;
   out.r = r / total;
   out.g = g / total;
   out.b = b / total;
   out.a = a / total;
   return out;   
}

And so we can call that function in script when we will need to get maximum performance:

var img = new Image(w,h,element);
var averageColor = getAverageColor(img);

Such functions will be translated on the fly into native code and so executed as fast as possible.

Huh?

Making API thread safe

I have refactored public API to be thread safe.

It means that all API functions can be called from worker threads directly.

When the engine detects access from non-GUI thread it marshals the call to be executed in GUI thread
and blocks the worker thread until UI will execute it. Therefore if you have more or less massive UI updates from worker threads it is still desirable to use approach outlined here.

Using native child windows in Sciter.

Sometimes there is a need of using child windows in Sciter.
For example you would like to use Scintilla editor that is implemented on Windows as a child window component.

You can do that but with the following limitations:

  1. Elements with child window attached cannot appear inside scrollable containers as windows are drawn on top of everything. Only popup element can appear on top of child windows.
  2. Such elements cannot be under CSS transformations. Windows does not support affine transformations on child windows.

For such components to be useful in Sciter we will need to solve three tasks:

  1. Let Sciter know that we want custom functionality on that particular DOM element.
  2. Create such a window and attach it to the DOM element.
  3. Provide some component specific methods for the script to manipulate the component by script code.

To accomplish all three tasks we will need to define our own native behavior.

class editor: public sciter::event_handler 
{
   // ...
public:
   virtual void attached  (HELEMENT he ) //...
   virtual void detached  (HELEMENT he ) //...
}

struct editor_factory: public behavior_factory {

  editor_factory(): behavior_factory("editor") {}

  // the only behavior_factory method:
  virtual event_handler* create(HELEMENT he) { return new editor(); }

};

// instantiating and attaching it to the global list of supported behaviors
editor_factory editor_factory_instance;

We also need to instruct Sciter on which element it shall create an instance of our class editor.

Usually that is done by declaring special element type in CSS:

editor  /* element with tag 'editor' */
{ 
   behavior: editor;  /* will have that behavior */
   display: block;    /* displayed as rectangular block */
   width: *;          /* its width and height will take */
   height: *;         /* all available space inside the container */   
}

Having the above declaration we can define the editor in our markup as:

<body>
  <editor/>
</body>

Creating window and attaching it to the DOM element

When the engine will parse <editor/> element in markup it will find style for it. That style has behavior property defined for the element
so the engine will send SC_ATTACH_BEHAVIOR notification and default SC_ATTACH_BEHAVIOR handler ( see: sciter-x-host-callback.h ) will
request chain of registered behavior factories to create instance of the event_handler for the element. As a result our editor_factory::create() method will be invoked
At the very end the engine will call our editor::attached() method to indicate that the element has the editor attached to it.

Therefore the best place to call ::CreateWindow() Windows function is the attached() method of our behavior.

class editor : 
  public sciter::event_handler
{
public:

  HWND     hwnd;
  HELEMENT self; // note: weak ref (not addrefed)

  editor(): event_handler()
            , hwnd(0)
            , self(0) 
  {}

  virtual void attached  (HELEMENT he ) 
  {
    self = he;
    dom::element el = he;
    hwnd = ::CreateWindow(
                  TEXT("Scintilla"),
                  TEXT(""),
                  WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_CLIPCHILDREN | WS_VISIBLE,
                  0, 0,
                  0, 0,
                  el.get_element_hwnd(true), // get element's host window
                  0,
                  ghInstance,
                  0);
    el.attach_hwnd(hwnd); // attach the window handler to the DOM element.
                          // after that the engine will manage window position and dimension
                          // by CSS rules 
  } 

  virtual void detached  (HELEMENT he ) 
  { 
    if(hwnd && ::IsWindow(hwnd))
      ::DestroyWindow(hwnd);
    hwnd = 0;
    self = 0;
    dom::element el = he;
    el.attach_hwnd(0);
    delete this;   // we delete the handler here as no one is using it anymore.  
  }
  ...
} 

The behavior will manage life cycle of our window: it will create the window when DOM will be created and destroy it when the element will be removed from the DOM.

Defining scripting methods

The last task left is to define methods so our script can do something meaningful with the window.

In order to do that we need to define handle_scripting_call() in our behavior but instead of doing it that literally we will use BEGIN_FUNCTION_MAP/END_FUNCTION_MAP that provide
handle_scripting_call implementation for us:

class editor : 
  public sciter::event_handler
{
public:

  HWND     hwnd;
  HELEMENT self; // note: weak ref (not addrefed)

  editor(): event_handler()
            , hwnd(0)
            , self(0) 
  {}

  virtual void attached  (HELEMENT he ) { ... } 
  virtual void detached  (HELEMENT he ) { ... }

// scripting methods bindings
  BEGIN_FUNCTION_MAP
    FUNCTION_0("getText",get_text) // getText()
    FUNCTION_1("setText",set_text) // setText(text:string) 
  END_FUNCTION_MAP

  sciter::value get_text() {
    std::wstring text;
    // GetWindowText(hwnd) & friends here
    return sciter::value(text);
  }  

  sciter::value set_text(const sciter::value& text_val) {
    std::wstring text = text_val.get(L"");
    // SetWindowText(hwnd) & friends here
    return sciter::value(); // returns undefined value, a.k.a. void
  }  
}

This way we have defined our behavior that exposes two methods that we can use in script:

<script type="text/tiscript">
function self.ready() {
  var elEditor = $(editor);
  elEditor.setText("Hello world!"); // calling our native method
}
</script>
<body>
  <editor/>
</body>

In reality you probably will have more native methods defined. Just don’t forget to add their bindings to the FUNCTION_MAP.

And see this discussion about wrapping Scintilla editor.

Sciter UI, basic principles. Calling code behind UI from worker threads.

I’ve updated the SDK with new sample: /sdk/demos/ui-framework .
This sample demonstrates principles outlined in “Sciter UI, application architecture” article.

Sciter demo screenshot

In particular it demonstrates definition of native function (view.execTask() -> window::exec_task()) and call of UI methods (callbacks in this sample) from worker threads.

I’ve explained idea of calling UI code from worker threads in this article but in this demo I am using slightly different mechanism.

The gui_exec function looks like this:

// this function is called from worker threads to 
// execute the gui_block in GUI thread
inline void gui_exec( std::function<void()> gui_block )
{
  sciter::sync::event evt;
  PostThreadMessage(gGUIThreadId, WM_EXEC, WPARAM(&evt),LPARAM(&gui_block));
  evt.wait(); // suspend worker thread until GUI will execute the block.
}

It posts the message into GUI thread input queue. Receiver of WM_EXEC message is Windows WH_GETMESSAGE hook function:

// message hook to handle WM_EXEC in GUI thread
static LRESULT CALLBACK gui_exec_hook_GetMsgProc(int code, WPARAM wParam, LPARAM lParam )
{
  MSG* pmsg = reinterpret_cast<MSG*>(lParam);
  if(pmsg->message == WM_EXEC)
  {
    sciter::sync::event* pe = reinterpret_cast<sciter::sync::event*>(pmsg->wParam);
    gui_block* pf = reinterpret_cast<gui_block*>(pmsg->lParam);
    (*pf)();      // execute the block in this GUI thread
    pe->signal(); // signal that we've done with it
                  // this will resume execution of worker thread.
  }
  return CallNextHookEx(0,code, wParam,lParam);
}

Using hooks allows this mechanism to work reliably even when application is running modal dialog loops.

Sciter UI, application architecture

Architecture of applications that use Sciter based UI can be visualized as this:

Typically such applications contain two distinct layers:

  • UI layer that uses Sciter window with loaded HTML/CSS and scripts (code behind UI);
  • Application logic layer, most of the time that is native code implementing logic of the application.

Ideally these two layers shall be split appart – isolated from each other as they use conceptually different code models and probably code styles.

UI layer uses event driven model: "on click here expand section there and send request to logic layer for some data".

Application logic layer (ALL) is more linear usually. It is is a collection of functions that accepts some parameters and return some data. Even if ALL uses threads code inside such threads is still linear.

UI and app-logic interaction principles:

Most of the time code execution in UI applications is initiated by the UI itself but sometimes application code may generate its own events. For the UI such events are not anyhow different from pure UI events like mouse/keyboard clicks and the like. Informational flow between UI and ALL conceptually fall into these three groups:

  1. "get-request" – synchronous calls from UI to logic layer to get some data:
  2. "post-request" – asynchronous calls with callback "when-ready" functions:
  3. "application events" – application detects some change and needs to notify UI to reflect it somehow:

To support all these scenarios application can use only two "entry points" :

  • UI-to-logic calls: event_handler::on_script_call(name,args,retval)
  • logic-to-UI calls:  sciter::host:call_function(name, args ) – calls scripting function from C/C++ code. The name here could be a path: "namespace.func".  

get-requests

To handle UI-to-logic calls the application defines sciter::event_handler and attaches its instance to the Sciter window (view). Its on_script_call method will be invoked each time when script executes code like this in scipt:

view.getSomeData(param1, param2);

that will end up in this C/C++ call:

event_handler::on_script_call(NULL,
         "getSomeData", 
         2 /*argc*/ , 
         argv[2], 
         SCITER_VALUE& retval /* return value */ );

Sciter SDK contains convenient macro wrapper/dispatcher for such on_script_call function:

  class window
    : public sciter::host<window>
    , public sciter::event_handler
  {
    HWND   _hwnd;
    ...
    
    json::value  debug(unsigned argc, const json::value* arg);      
    json::value  getSomeData(json::value param1, json::value param2);      

BEGIN_FUNCTION_MAP
  FUNCTION_V("debug", debug);  
  FUNCTION_2("getSomeData", getSomeData); 
END_FUNCTION_MAP
  }

Declaration FUNCTION_2("getSomeData", getSomeData); binds view.getSomeData() in script with native window::getSomeData call.  

Therefore functionality exposed to the UI layer by logic layer can be defined as a content of single BEGIN_FUNCTION_MAP/END_FUNCTION_MAP block.

If your application contains many modules that are connected dynamically then you can define single view.exec("path", params...) function that will do name/call dispatch using some other principles:

var newAccount = view.exec("accounts/new", initialBalance);
view.exec("accounts/delete", accountId);
view.exec("accounts/update", {customerName:"new name"} );

application events

Application can generate some events by itself. When some condition or state inside application changes it may want to notify the UI about it. To do that application code can simply call function in script namespace with needed parameters.

Let’s assume that script has following declaration:

namespace Accounts 
{
  function created( accountId, accountProps ) {
     $(#accountList).append(...);
  }
  function deleted( accountId, accountProps ) {
     $(#accountList li[accid={accountId}]).remove();
  }
}

Then the application code can fire such events by simply calling:

window* pw = ...
pw->call_function("Accounts.created", accId, accFields );
pw->call_function("Accounts.deleted", accId );

post-request

Need of post request arises when some of work need to be done inside worker threads. Some task either take too long to complete or data for them needs to be loaded from the Net or other remote sources. UI cannot be blocked for long time – it still shall be responsive. The same situation happens in Web applications when JavaScript needs to send AJAX request. In this case callback functions are used. Call to native code includes reference to script function that will be executed when the requested data is available.

Consider this UI script function that asks app-logic to create some account on a remote server:

function createAccount( accountProps ) 
  {
    function whenCreated( accountId ) // inner callback function
    { 
      $(#accountList).append(...);
    }
    view.exec("accounts/create", accountProps, whenCreated );
  }

It passes accountProps data and callback function reference to the "accounts/create" thread. This thread creates the account (presumably takes some time) and invokes whenCreated at the end.

class createAccount: worker_thread 
  {
    handle<window> ui;
    SCITER_VALUE props;
    SCITER_VALUE callback;

    void run()
    {  // the thread body
       // ... do some time consuming stuff ...

       SCITER_VALUE accountId = createAccount(props);

       // done, execute the callback in UI thread:
       ui->ui_exec([=]() {
         callback.call(accountId); 
       }); 
    }
}

Note about that ui_exec function above: the UI is single threaded by its nature – singly display device, single keyboard and mouse, etc. Worker threads shall not access the UI directly – the UI shall be updated from UI thread only. The ui_exec function does just that – executes block of code in UI thread. See C++0x: Running code in GUI thread from worker threads article about it.

Epilogue

Having just two "ports"  (out-bound UI-to-logic and in-bound logic-to-UI) is a good thing in principle. This allows to isolate effectively two different worlds – asynchronous UI and deterministic application logic world. Easily "debuggable" and manageable.

HTML, CSS and script (code behind UI) runs in most natural mode and application core is comfortable too – not tied with the UI and its event and threading model.