posted by Jean-Louis Villecroze on Wed 8th Dec 2004 21:40 UTC

"Zinzala, Page 10/11"
5. Adding scriptability

A key feature of the Zinzala SDK is the ease with which we can add support for application scripting. We will now see how we can use this feature to add support for an on the fly skin change. This will be done while the application is running.

For testing, we will be using the tool yo which is part of the Zinzala library distribution. However, any application can send scripting messages to another application. For example, in the case of the Carrozza layer we discussed earlier, if requested a configuration panel could be sending a message to all the UI applications running in order to change the overall look of the UI. Because this will be done on the fly, there will be no interruption of services. For example, music or movie playback will remain active.

Without any modification to the application, we can already send some messages to it. For example:

#> yo hexaZen/Custom ping
got answer in 0.000000 ms
cCan::0x8047850 items=0
What    = 'zAPo'
Context = 0x0
#> yo hexaZen/Custom info
got answer in 0.999928 ms
cCan::0x8047850 items=6
What    = 'zARy'
Context = 0x0
Item 'zSDK' have 1 value(s)
        0       string  (4)     '0.8'
Item 'Username' have 1 value(s)
        0       string  (4)     'jlv'
Item 'MaxInstances' have 1 value(s)
        0       tUint8  (1)     125
Item 'Scripting' have 1 value(s)
        0       tUint8  (1)     0
Item 'MaxMSGLength' have 1 value(s)
        0       tUint16 (2)     100
Item 'GUIEngine' have 1 value(s)
        0       string  (7)     'Photon'
#> yo hexaZen/Custom list
window

However, if we ask the application to use a different skin, it will obviously not work:

#> yo hexaZen/Custom tell window do reskin Orange.so
Not allowed

There are 2 raisons for this. By default, scripting is not enabled, and the keyword reskin is unknown to the cWindow class. This can be easily changed. Let's have a look at what needs to be done in order to support the change of a skin on the fly.

cDApplication

Before adding support in the window class, we need to allow scripting at the application level. This is done by modifying the method Ready() as follow:

void cDApplication::Ready()
{
   // Allow scripting
   AllowScripting(eLocal);
   // Increase the buffer size for messaging
   SetBufferLength(250);

   ...
   ...
   ...
}

Because the path to the skin to be loaded is going to be included in the scripting message, we need to set the size of the receiving buffer to 250 bytes. The default size is 100 bytes. If we didn't do that, the path could have been truncated. 250 bytes should be enough for most cases. However, a better solution would have been to use the constant PATH_MAX defined in limits.h, and then add more bytes to it for the overhead generated by the transmission.

cDWindow

Next, we are going to add handling for the reskin command. The window should handle this scripting message, then ask each widget to use the new skin. This is what we are going to do.

First, we modify the definition of the cDWindow class:

class cDWindow : public cWindow
{
   public:
      static cDWindow *NewL(cSettings *aSettings,cDSkin &aSkin);
      virtual ~cDWindow();
		
   protected:
      void Ready();
      bool CloseRequested();
      void ScriptingReceived(cMessage *aMessage,cMessage *aReply);
		
   protected:
      cDWindow(cSettings *aSettings);
      void ConstructL(cDSkin &aSkin);

   private:
      void ReSkinL(const tChar *aSkin);

   private:
      cSettings*        iSettings;
      cMyConsoleView*   iConsole;
};

We have added the methods ScriptingReceived() and ReSkinL(). The first method is inherited from the framework and will be called when the window receives a scripting message. We will be using the second method to perform the change of skin.

Just like in the application class, we need to allow scripting for the window. We modify the method Ready() as follows:

void cDWindow::Ready()
{
   AllowScripting(eLocal);
   SetBeatRate(kBeatRate);
   cWindow::Ready();
}

In ScriptingReceived(), we need to detect if the scripting command is do reskin. If it is not, we can pass the scripting message to the base class method and let it deal with it. Here's how the method looks like:

void cDWindow::ScriptingReceived(cMessage *aMessage,cMessage *aReply)
{	
   tUint32 lCmd;

   aReply->SetBool(kScriptItemDone,true);

   if(!aMessage->GetUint32(kScriptItemCommand,&lCmd))
   {

The string do is converted by the tool yo into a tUint32 command, which we retrieve in the scripting message by using the label kScriptItemCommand. We will expect any other application sending scripting messages to send them in the format outlined in the protocol defined in the framework. If we can't find the command ID, the reply message will indicate that the script message was malformed.

      switch(lCmd)
      {
         case kScriptCmdDo:
         {
            const tChar *lFunction;

Now that we know that this scripting message is asking the window to do something, we will retrieve the first argument which is the label of the action that must be performed:

            if(!aMessage->GetString(kScriptItemArgs,&lFunction,0))
            {
               if(!strcmp(lFunction,"reskin"))
               {
                  const tChar *lSkin;

If the message asks the window to change the skin it is using, we will try to retrieve the next argument, which should be the path to the new skin:

                  if(!aMessage->GetString(kScriptItemArgs,&lSkin,1))
                  {
                     tErr lErr;

                     TRAP(lErr,ReSkinL(lSkin));

Because the method can leave (ea. if the skin cannot be loaded), we use the macro TRAP() to catch any possible exceptions. The variable lErr will be different from kErrNone if we catch an exception. In that case, in the reply message we will indicates that we failed to perform the command:

                     if(lErr)
                     {
                        aReply->SetBool(kScriptItemDone,false);
                        aReply->SetUint8(kScriptItemReason,kScriptErrFailed);
                     }
                  }
                  else
                  {
                     aReply->SetBool(kScriptItemDone,false);
                     aReply->SetUint8(kScriptItemReason,kScriptErrMissingArg);
                  }
               }
               else
               {
                  aReply->SetBool(kScriptItemDone,false);
                  aReply->SetUint8(kScriptItemReason,kScriptErrIncorrect);
               }
            }
            else
            {
               aReply->SetBool(kScriptItemDone,false);
               aReply->SetUint8(kScriptItemReason,kScriptErrMalformed);
            }
				
            break;
         }

For any other scripting command, we will pass the message to the base class method for handling:

         default:
            cWindow::ScriptingReceived(aMessage,aReply);	
      }
   }
   else
   {
      aReply->SetBool(kScriptItemDone,false);
      aReply->SetUint8(kScriptItemReason,kScriptErrMalformed);
   }
}

The application sending the scripting message expects to receive notice of whether or not it was successful. And if not, what the reason was for the failure. As we have seen in the above code, the reply's item kScriptItemDone will have true or false for its value. It will indicate if the command was performed or not. If an error occurs, the reply message will also contain the item kScriptItemReason which will contain an error code.

As we are going to see, the method ReSkinL() is far from complicate:

void cDWindow::ReSkinL(const tChar *aSkin)
{
   cDSkin lSkin(aSkin);
							
   sEnv::LeaveIfError(lSkin.GetFault());

   iConsole->ReSkinL(lSkin);
}

It first creates a cDSkin object from the path of the skin we would like to use. If the object is invalid, we will leave right away. If valid, we will be calling the method ReskinL() for all the widgets of the window that needs their skin to change. For this test application,we only have the console widget to update.

Table of contents
  1. "Zinzala, Page 1/11"
  2. "Zinzala, Page 2/11"
  3. "Zinzala, Page 3/11"
  4. "Zinzala, Page 4/11"
  5. "Zinzala, Page 5/11"
  6. "Zinzala, Page 6/11"
  7. "Zinzala, Page 7/11"
  8. "Zinzala, Page 8/11"
  9. "Zinzala, Page 9/11"
  10. "Zinzala, Page 10/11"
  11. "Zinzala, Page 11/11"
e p (0)    12 Comment(s)

Technology White Papers

See More