Edje Messages vs Signals

We saw in the previous Edje post how to send Signals down the Edje elements. We’re now going to see another way of communicating between the application and the Edje theme : Messages.

1. Difference between Messages and Signals

That was my first question when I discovered Messages : “what is this stuff for, since we have signals?”

The answer is :
Signals allow you to send some discrete (punctual) information. It fits really well in an “action” type communication “do this”, “hey this event happened”, …

Now what if you want, for example, to send data (which could be anything, like a bunch of strings, …), to the theme, or the other way? This doesn’t really fit in the signal+source mold. This is where messages come in handy.

For a concrete example, you could see the existing E “alarm” widget. (I will try to find the URL when I have time)

2. Structure of a message

Three things define a message :
– its Type
– its ID
– its data

The first one is obvious and tells the type of data contained. In C the existing types are defined by EDJE_MESSAGE_* (see Edje.h), and in Embryo as Edje_Type:MSG_*
The second one is an integer that allows you to know what is the function of the message. Use whatever you want, put the defined values in some header shared between your code and your edc files.
The last one is the data.

Now, about the data, you have a few defined types :
Edje_Message_String is just one string
Edje_Message_Int is just one int (ok, that was easy)
Edje_Message_Float oh well you guessed it…
Edje_Message_String_Set more interesting, a variable number of strings (in an array), the number of strings is a count field in the struct.
Edje_Message_Float_Set and Edje_Message_Int_Set, same as the previous one but with floats and strings
Edje_Message_String_Int, Edje_Message_String_Float, a string with an integer (or a float), could be used as a key => value pair for example
Edje_Message_String_Int_Set, Edje_Message_String_Int_Set, a string and an array of integers/floats (with the additional count field).

Note that the set is defined in the struct as an int[1], float[1], or char *[1]. This means you have to allocate your structure to a size bigger depending on the number of elements.


/* allocate a struct for 4 integers */
Edje_Message_String_Int_Set *msg = malloc(sizeof(Edje_Message_String_Int_Set + (4 - 1) * sizeof(int));
/* allocate a struct for 10 string pointers */
Edje_Message_String_Set *msg2 = malloc(sizeof(Edje_Message_String_Set + (10 - 1) * sizeof(char *));

3. Sending a message from Edje to the application

3.1 Binding a message callback

#define MSG_ID_GET_TIME 0
#define MSG_ID_GET_FLOAT AND STR 1

/* your callback */
void message_cb(void *data, Evas_Object *obj, Edje_Message_Type type, int id, void *msg)
{
    if (id == MSG_ID_GET_TIME && type == EDJE_MESSAGE_INT_SET) {
        /* check the right number of integers */
        if (msg->count != 3)
            return;
        int seconds, minutes, hours;
        hours = msg->val[0];
        minutes = msg->val[1];
        seconds = msg->val[2];
        /* do whatever processing you want with your values */
        ...
    } else if (id == MSG_ID_GET_FLOAT_AND_STR && type == EDJE_MESSAGE_STRING_FLOAT) {
        float f;
        char *str;
        f = msg->val;
        str = msg->str;
        /* processing again */
        ...
    }
}

int main()
{
    /* initialization and all */
    ...
    edje_object_message_handler_set(my_edje_object, &message_cb, NULL);
    ...
    /* more stuff after that, you could set the handler at anytime you want anyway */
}

3.2 Sending the message using Embryo

This probably has to be defined in the “top” group loaded as an Evas, I don’t know what would happen otherwise.

group {
    programs {
        program {
            name: "my_program";
            signal: "whatever";
            source: "same";
            script {
                send_message(MSG_INT_SET, MSG_ID_GET_TIME, 5, 10, 3);
                send_message(MSG_STRING_FLOAT, MSG_ID_GET_FLOAT_AND_STR, 5.2, "hello world");
            }
        }
    }
}

4. Sending a message from the application to Edje

Now, if you would want to do it the other way

4.1 Create an embryo callback in the skin

group {
    name: "mygroup";
    script {
        /* this function is automatically bound
          * you may have noticed we don't pass a structure but a variable
          * number of arguments */
        public message(Message_Type:type, int id, ...) {
            if (type == MSG_INT_SET && id == MSG_ID_GET_TIME) {
                /* look in the embryo doc if you need to count the arguments
                  * the "count" variable is not provided in the arguments */
                int sec = getarg(2);
                int min = getarg(3);
                int hour = getarg(4);
                /* do whatever you want in embryo with it */
            } else if (type == MSG_STRING_FLOAT && id == MSG_ID_GET_FLOAT_AND_STR) {
                float f = getfarg(2); /* get a float */
                new str[128];
                getsarg(3, str, 128);
                /* do whatever you want in embryo with it */
            }
        }
    }
}

4.2 Sending the message in the code

/* allocate a struct for 3 integers */
Edje_Message_Int_Set *msg = malloc(sizeof(Edje_Message_Int_Set + (3 - 1) * sizeof(int));
msg->val[0] = 10;
msg->val[1] = 42;
msg->val[2] = 31;
edje_object_send_message(my_edje, EDJE_MESSAGE_INT_SET, MSG_ID_GET_TIME, msg);
/* allocate a struct for string & float */
Edje_Message_String_Float *msg2 = malloc(sizeof(Edje_Message_String_Float);
msg2->str = "I can haz cheezburger";
msg2->val = 0.7777;
edje_object_message_send(my_edje, EDJE_MESSAGE_STRING_FLOAT, MSG_ID_GET_FLOAT_AND_STR, msg2);

Leave a comment

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: