gx_window_event_process in GUIX event handlers

Can someone please explain to me the usage of 'gx_window_event_process()' in GUIX event handlers.

In example projects, its use does not seem to follow a pattern.

Some handlers call the routine on entry to the handler, others only in certain events.

I can't find the source code for the routine (hidden for GUIX i assume), and as usual i struggle to find detailed documentation for GUIX.

Thanks

Alex

  • Hello Alex,

    The only documentation which I found is:
    X-Ware™ Component Documents for Renesas Synergy™ > GUIX
    which does not explain what this function does in details.

    The gx_window_event_process() function is used to handle essential GUIX events such as: GX_EVENT_SHOW, GX_EVENT_FOCUS_GAINED, GX_EVENT_PEN_UP, GX_EVENT_PEN_DOWN etc. Thanks to this function a window can be displayed, a pressed widget can gain a focus, a pressed button can be displayed as pressed down. If you would like to achieve a different bahaviour of the GUI in case of such basic events you could skip the gx_window_event_process() function call and implement event handling by yourself.

    Usually gx_window_event_process() function is called at the beginning of a window handler function. This guarantees that it will be called for every event.

    To view this function source code you would need the development and production license which you can generate on Synergy Gallery ("Create a Development/Production License" button). Set this license in e2 studio. Then add to your project the GUIX source:
    Synergy Configuration window > Components tab > Express Logic > all > gx_src (selected)
    Press Generate Project Content button and you will see the file:
    <project_dir>\synergy\ssp\src\framework\el\gx\gx_src\gx_window_event_process.c

    Best regards,
    anper

  • I think it's pretty clear that this function does the default processing for an event - I say this based on my experience with these types of event handling architectures. So normally you call it at the start and then have some logic that does additional stuff for specific events, like drawing extra stuff when the window is shown:

    gx_window_event_process() // do the usual stuff for everything
    switch (event)
    SHOW: do_more_stuff()

    Or less commonly you do some pre-processing before letting the event be handled:

    switch (event)
    SHOW: do_stuff_first()
    gx_window_event_process() // do the usual stuff for everything

    Or you could call it in a "default" clause. This would stop the default behavior for the events you handle. So maybe you don't want it to display a window when it gets a SHOW event; maybe you want to handle the SHOW event your own way. Thus you write something like this:

    switch (event)
    SHOW: do_only_my_stuff()
    default: gx_window_event_process() // do the usual stuff for everything but SHOW

    What you cannot do is both of these because it makes no sense at all. Why process the event and then process it again if your code doesn't handle it?

    gx_window_event_process() // do the usual stuff for everything
    switch (event)
    SHOW: do_more_stuff()
    default: gx_window_event_process() // do the usual stuff for everything but SHOW

    Unfortunately this is exactly what the Hello World example program does, with any comments to indicate why they would do something so incomprehensible. I don't know what processing an event twice does but it can't be good.
  • In reply to MCP:

    Hi,

    I can confirm that calling gx_window_event_process (or another xyz_event_process function for other widgets) does effectively let user retain default widget behavior while adding its own on the top.

    Each widget has its own event handler and draw functions - if user chooses to override either one or both, it is recommended that the new function calls the original handler so that necessary housekeeping is still performed. For example, defining your own draw function that is empty will result in widget being invisible (its children won't be drawn either).

    As for before/after/inside - it depends and what user is trying to achieve. Typically my projects call default draw function before everything else and default event function at the end. Standard drawing needs to performed first (for obvious reasons) but doing standard event processing last will allow to intercept certain events and prevent their default behavior from being implemented (by returning GX_SUCCESS immediately). Calling event processing at the start will take this opportunity away as default function has already completed by time user executes code.

    Calling event processing inside the event case is similar to doing it at the end but it optimizes certain cases that are known to do nothing inside the default event process function (all GX_SIGNAL cases fall-through). Typically compiler/linker would optimize these anyway, unless optimizations are disabled. I personally avoid this approach as multiple points of exit are considered a bad coding practice and violate MISRA C rule 14.7.

    Regards
  • In reply to Renesas Karol:

    I agree that handling it inside each event case is unwise; it's too easy to forget one.

    But what I was complaining about was the GUIApp project, which contains this code:


    UINT result = gx_window_event_process(widget, event_ptr);

    switch (event_ptr->gx_event_type)
    {
    ...
    default:
    gx_window_event_process(widget, event_ptr);
    break;
    }


    There's just no excuse for that. Unless they were trying to do the draw function and just mistyped the first function call? If you could fix the above code to do the draw function first and then just the event (but not draw) portion afterwards that would be instructive.
  • In reply to MCP:

    Hi MCP,

    I believe this is a copy & past mistake between two different functions. It should be addressed in the next version.

    Regards
  • In reply to Renesas Karol:

    That would be awesome. :)

    In a related matter, I've got a generic question about events and GUIX Studio: how do you handle dynamic menus? That is, the objects that appear in the menu change at run time. What would your general strategy be to handle this problem?
  • In reply to Renesas Karol:

    While you are updating the GUIApp project, could you take a look at this code from main_thread_entry.c:

    ORIGINAL CODE:
    // Create the widgets we have defined with the GUIX data structures and resources.
    GX_CONST GX_STUDIO_WIDGET ** pp_studio_widget = &guiapp_widget_table[0];
    GX_WIDGET * p_first_screen = NULL;

    while (GX_NULL != *pp_studio_widget)
    {
    // We must first create the widgets according the data generated in GUIX Studio.

    // Once we are working on the widget we want to see first, save the pointer for later.
    if (0 == strcmp("window1", (char*)(*pp_studio_widget)->widget_name))
    {
    gx_studio_named_widget_create((*pp_studio_widget)->widget_name, (GX_WIDGET *)p_window_root, GX_NULL);
    } else {
    gx_studio_named_widget_create((*pp_studio_widget)->widget_name, GX_NULL, GX_NULL);
    }
    // Move to next top-level widget
    pp_studio_widget++;
    }
    // Attach the first screen to the root so we can see it when the root is shown
    gx_widget_attach(p_window_root, p_first_screen);

    The thing is, the object guiapp_widget_table is defined as a GX_STUDIO_WIDGET_ENTRY, not as a GX_STUDIO_WIDGET. An _ENTRY is two pointers, one to widget information and one to a widget. The above code iterates over both, creating a "main_window" object from the information pointer and then another one from the widget pointer.

    The fact that this code runs at all is impressive, but it is a terrible example. I have replaced it with a direct reference to the actual table and an array index variable that increments, rather than trying to do fancy pointer math (sometimes simpler is better). Furthermore, the third comment is completely wrong; it is not saving a pointer but attaching the main window to the root window - which makes the final comment and statement completely unnecessary (and wrong, since p_first_screen has never been assigned a value).


    CORRECTED CODE:
    // Create the widgets we have defined with the GUIX data structures and resources.
    extern GX_CONST GX_STUDIO_WIDGET_ENTRY guiapp_widget_table[];
    int index = 0;
    while (guiapp_widget_table[index].widget_information != GX_NULL)
    {
    // We must create the widgets according the data generated in GUIX Studio.
    if (guiapp_widget_table[index].widget_information->widget_id == ID_WINDOW_MAIN)
    {
    // create and attach
    gx_studio_named_widget_create (guiapp_widget_table[index].widget_information->widget_name, (GX_WIDGET *) p_window_root, GX_NULL);
    }
    else
    {
    // create
    gx_studio_named_widget_create (guiapp_widget_table[index].widget_information->widget_name, (GX_NULL, GX_NULL);
    }
    // Move to next top-level widget
    index++;
    }

    Even this code can probably be cleaned up; is it necessary to create the widget by name since we have a pointer to the widget right there in the table? I haven't proven that works yet, though.
  • In reply to MCP:

    Note: the code is written correctly in the auto-generated gx_studio_named_widget_create(), where guiapp_widget_table is properly treated as a GX_STUDIO_WIDGET_ENTRY, so if you really want to use pointer math instead of indexes you can just copy that. But of course hard-casting all the objects to specific types so you can use pointer math is how this mistake slipped past the compiler in the first place. ;)