1 /* Logic to run the application in a standalone window */
2 
3 #include "studiox_includes.h"
4 #include "app_runner.h"
5 #include "gx_win32_studio_display_driver.h"
6 #include "gx_animation.h"
7 
8 #include "gx_api.h"
9 
10 #ifdef _DEBUG
11 #define new DEBUG_NEW
12 #endif
13 
14 typedef struct APP_ANIMATION_STRUCT{
15     GX_ANIMATION           *app_animation;
16     APP_ANIMATION_STRUCT   *app_animation_next;
17     INT                     app_animation_win_thread_id;
18 }APP_ANIMATION;
19 
20 APP_ANIMATION *app_animation_created_list;
21 UINT           app_animation_id;
22 extern CString SCREEN_STACK_POP_STRING;
23 
24 /**************************************************************************/
app_child_widget_find(GX_WIDGET * parent,CString widget_name)25 GX_WIDGET *app_child_widget_find(GX_WIDGET *parent, CString widget_name)
26 {
27     GX_WIDGET *child;
28     CString name;
29     GX_WIDGET *found = GX_NULL;
30 
31     /* Is there a widget?  */
32     if (parent)
33     {
34         child = parent->gx_widget_first_child;
35 
36         while (child)
37         {
38             name = (TCHAR *)child->gx_widget_name;
39             if (name == widget_name)
40             {
41                 found = child;
42             }
43             else if (child->gx_widget_first_child)
44             {
45                 found = app_child_widget_find(child, widget_name);
46             }
47 
48             if (found)
49             {
50                 break;
51             }
52 
53             child = child->gx_widget_next;
54         }
55     }
56 
57     if ((!found) && (parent->gx_widget_type == GX_TYPE_MENU))
58     {
59         GX_MENU *menu = (GX_MENU *)parent;
60         found = app_child_widget_find((GX_WIDGET *)&menu->gx_menu_list, widget_name);
61     }
62 
63     return found;
64 }
65 
66 /**************************************************************************/
app_widget_find(GX_WINDOW * root,CString widget_name)67 GX_WIDGET *app_widget_find(GX_WINDOW *root, CString widget_name)
68 {
69     int loop;
70     GX_WIDGET *screen;
71     GX_WIDGET *found = GX_NULL;
72     GX_WIN32_DISPLAY_DRIVER_DATA *driver_instance;
73     GX_DISPLAY *display;
74     CString name;
75 
76     display = ((GX_WINDOW_ROOT *)root)->gx_window_root_canvas->gx_canvas_display;
77     driver_instance = (GX_WIN32_DISPLAY_DRIVER_DATA *)display->gx_display_driver_data;
78 
79     if (widget_name.IsEmpty())
80     {
81         return GX_NULL;
82     }
83 
84     for (loop = 0; loop < driver_instance->win32_screen_count; loop++)
85     {
86         screen = driver_instance->win32_screens[loop];
87 
88         if (screen)
89         {
90             name = (TCHAR *)screen->gx_widget_name;
91             if (name == widget_name)
92             {
93                 found = screen;
94             }
95             else
96             {
97                 found = app_child_widget_find(screen, widget_name);
98             }
99 
100             if (found)
101             {
102                 break;
103             }
104         }
105     }
106 
107     return found;
108 }
109 
110 /**************************************************************************/
app_flow_item_get(studiox_project * project,int display_index,GX_WIDGET * screen)111 flow_item *app_flow_item_get(studiox_project *project, int display_index, GX_WIDGET *screen)
112 {
113     flow_item *flow_item = GX_NULL;
114     screen_flow *screen_flow = project->mDisplays[display_index].screenflow;
115 
116     if (screen_flow && screen)
117     {
118         CString widget_name = (TCHAR *)screen->gx_widget_name;
119         flow_item = screen_flow->GetFlowItem(widget_name);
120     }
121 
122     return flow_item;
123 }
124 
125 /**************************************************************************/
app_animation_clean_up(GX_WIN32_DISPLAY_DRIVER_DATA * data)126 void app_animation_clean_up(GX_WIN32_DISPLAY_DRIVER_DATA *data)
127 {
128     APP_ANIMATION *entry = app_animation_created_list;
129     APP_ANIMATION *pre = GX_NULL;
130     APP_ANIMATION *next;
131 
132     while (entry)
133     {
134         next = entry->app_animation_next;
135         if (entry->app_animation_win_thread_id == data->win32_window_ThreadId)
136         {
137             if (pre)
138             {
139                 pre->app_animation_next = entry->app_animation_next;
140             }
141             else
142             {
143                 app_animation_created_list = entry->app_animation_next;
144             }
145 
146             if (entry->app_animation->gx_animation_status != GX_ANIMATION_IDLE)
147             {
148                 gx_animation_stop(entry->app_animation);
149             }
150 
151             delete entry->app_animation;
152             delete entry;
153         }
154         else
155         {
156             pre = entry;
157         }
158         entry = next;
159     }
160 }
161 
162 /**************************************************************************/
app_animation_create(GX_WINDOW * root,GX_WIDGET * target)163 GX_ANIMATION *app_animation_create(GX_WINDOW *root, GX_WIDGET *target)
164 {
165     //Create a animation
166     APP_ANIMATION *animation;
167     GX_WIN32_DISPLAY_DRIVER_DATA *driver_instance;
168     GX_DISPLAY *display;
169 
170     display = ((GX_WINDOW_ROOT *)root)->gx_window_root_canvas->gx_canvas_display;
171     driver_instance = (GX_WIN32_DISPLAY_DRIVER_DATA *)display->gx_display_driver_data;
172 
173     animation = new APP_ANIMATION;
174     animation->app_animation = new GX_ANIMATION;
175     gx_animation_create(animation->app_animation);
176     animation->app_animation_win_thread_id = driver_instance->win32_window_ThreadId;
177 
178     GX_ENTER_CRITICAL
179     animation->app_animation_next = app_animation_created_list;
180     app_animation_created_list = animation;
181     GX_EXIT_CRITICAL
182 
183     return animation->app_animation;
184 }
185 
186 /**************************************************************************/
app_animation_delete(UINT animation_id)187 void app_animation_delete(UINT animation_id)
188 {
189     if (!animation_id)
190     {
191         return;
192     }
193 
194     GX_ENTER_CRITICAL
195     // Delete a animation
196     APP_ANIMATION *entry = app_animation_created_list;
197     APP_ANIMATION *pre = GX_NULL;
198 
199     while (entry)
200     {
201         if (entry->app_animation->gx_animation_info.gx_animation_id == animation_id)
202         {
203             if (pre)
204             {
205                 pre->app_animation_next = entry->app_animation_next;
206             }
207             else
208             {
209                 app_animation_created_list = entry->app_animation_next;
210             }
211 
212             delete entry->app_animation;
213             delete entry;
214             break;
215         }
216         pre = entry;
217         entry = entry->app_animation_next;
218     }
219     GX_EXIT_CRITICAL
220 }
221 
222 /**************************************************************************/
app_animation_process(GX_ANIMATION_INFO * animation,GX_WINDOW * root,GX_WIDGET * parent,GX_WIDGET * target)223 void app_animation_process(GX_ANIMATION_INFO *animation, GX_WINDOW *root, GX_WIDGET *parent, GX_WIDGET *target)
224 {
225     GX_ANIMATION *app_animation = app_animation_create(root, target);
226 
227     if (app_animation)
228     {
229         GX_ANIMATION_INFO info;
230         info = *animation;
231         info.gx_animation_parent = parent;
232         info.gx_animation_target = target;
233 
234         if (!info.gx_animation_id)
235         {
236             GX_ENTER_CRITICAL
237             info.gx_animation_id = app_animation_id;
238             app_animation_id++;
239             GX_EXIT_CRITICAL
240         }
241 
242         gx_animation_start(app_animation, &info);
243     }
244 }
245 
246 /**************************************************************************/
app_trigger_action_process(studiox_project * project,int display_index,GX_WINDOW * root,CArray<action_info * > * action_list,GX_WIDGET * screen,GX_EVENT * event_ptr)247 UINT app_trigger_action_process(studiox_project *project, int display_index, GX_WINDOW *root, CArray<action_info *> *action_list, GX_WIDGET *screen, GX_EVENT *event_ptr)
248 {
249     action_info *action;
250     GX_WIDGET *target;
251     GX_WIDGET *parent;
252     screen_flow *flow = project->mDisplays[display_index].screenflow;
253 
254     //handle child signals
255     for (int index = 0; index < action_list->GetCount(); index++)
256     {
257         action = action_list->GetAt(index);
258 
259         switch (action->action_type)
260         {
261         case GX_ACTION_TYPE_ATTACH:
262             if ((action->target_widget_name == SCREEN_STACK_POP_STRING) ||
263                 (action->parent_widget_name == SCREEN_STACK_POP_STRING))
264             {
265                 gx_system_screen_stack_get(&parent, &target);
266             }
267 
268             if (action->parent_widget_name != SCREEN_STACK_POP_STRING)
269             {
270                 parent = app_widget_find(root, action->parent_widget_name);
271             }
272 
273             if (action->target_widget_name != SCREEN_STACK_POP_STRING)
274             {
275                 target = app_widget_find(root, action->target_widget_name);
276             }
277 
278             if (!parent)
279             {
280                 parent = (GX_WIDGET *)root;
281             }
282 
283             if (parent && target)
284             {
285                 gx_widget_attach(parent, target);
286             }
287             break;
288 
289         case GX_ACTION_TYPE_WINDOW_EXECUTE:
290             if ((action->target_widget_name == SCREEN_STACK_POP_STRING) ||
291                 (action->parent_widget_name == SCREEN_STACK_POP_STRING))
292             {
293                 gx_system_screen_stack_get(&parent, &target);
294             }
295 
296             if (action->parent_widget_name != SCREEN_STACK_POP_STRING)
297             {
298                 parent = app_widget_find(root, action->parent_widget_name);
299             }
300 
301             if (action->target_widget_name != SCREEN_STACK_POP_STRING)
302             {
303                 target = app_widget_find(root, action->target_widget_name);
304             }
305 
306             if (!parent)
307             {
308                 parent = (GX_WIDGET *)root;
309             }
310 
311             if (parent && target && target->gx_widget_type == GX_TYPE_WINDOW)
312             {
313                 gx_widget_attach(parent, target);
314                 gx_window_execute((GX_WINDOW *)target, GX_NULL);
315             }
316             break;
317 
318         case GX_ACTION_TYPE_WINDOW_EXECUTE_STOP:
319             return event_ptr->gx_event_sender;
320             break;
321 
322         case GX_ACTION_TYPE_DETACH:
323             if (!action->target_widget_name.IsEmpty())
324             {
325                 target = app_widget_find(root, action->target_widget_name);
326             }
327             else
328             {
329                 target = screen;
330             }
331 
332             if (target)
333             {
334                 gx_widget_hide(target);
335             }
336             break;
337 
338         case GX_ACTION_TYPE_TOGGLE:
339             if (action->target_widget_name == SCREEN_STACK_POP_STRING)
340             {
341                 gx_system_screen_stack_get(&parent, &target);
342             }
343             else
344             {
345                 target = app_widget_find(root, action->target_widget_name);
346             }
347 
348             if (target)
349             {
350                 gx_widget_attach(screen->gx_widget_parent, target);
351                 gx_widget_hide(screen);
352             }
353             break;
354 
355         case GX_ACTION_TYPE_SHOW:
356             target = app_widget_find(root, action->target_widget_name);
357             if (target)
358             {
359                 gx_widget_show(target);
360             }
361             break;
362 
363         case GX_ACTION_TYPE_HIDE:
364             target = app_widget_find(root, action->target_widget_name);
365             if (target)
366             {
367                 gx_widget_hide(target);
368             }
369             break;
370 
371         case GX_ACTION_TYPE_ANIMATION:
372             if ((action->target_widget_name == SCREEN_STACK_POP_STRING) ||
373                 (action->parent_widget_name == SCREEN_STACK_POP_STRING))
374             {
375                 gx_system_screen_stack_get(&parent, &target);
376             }
377 
378             if (action->target_widget_name != SCREEN_STACK_POP_STRING)
379             {
380                 target = app_widget_find(root, action->target_widget_name);
381             }
382 
383             if (target && action->animation)
384             {
385                 action->animation->gx_animation_id = project->GetIdIndex(display_index, ID_TYPE_ANIMATION, action->animation_id_name);
386                 if (action->parent_widget_name != SCREEN_STACK_POP_STRING)
387                 {
388                     parent = app_widget_find(root, action->parent_widget_name);
389                 }
390 
391                 if (!parent)
392                 {
393                     //animation parent is not set
394                     if (target->gx_widget_parent)
395                     {
396                         //set animation parent to widget's parent
397                         parent = target->gx_widget_parent;
398                     }
399                     else
400                     {
401                         //set animation parent to root window
402                         parent = (GX_WIDGET *)root;
403                     }
404                 }
405 
406                 app_animation_process(action->animation, (GX_WINDOW *)root, parent, target);
407             }
408             break;
409 
410         case GX_ACTION_TYPE_SCREEN_STACK_PUSH:
411             target = app_widget_find(root, action->target_widget_name);
412             if (target)
413             {
414                 gx_system_screen_stack_push(target);
415             }
416             break;
417 
418         case GX_ACTION_TYPE_SCREEN_STACK_POP:
419             gx_system_screen_stack_pop();
420             break;
421 
422         case GX_ACTION_TYPE_SCREEN_STACK_RESET:
423             gx_system_screen_stack_reset();
424             break;
425         }
426     }
427 
428     return 0;
429 }
430 
431 /**************************************************************************/
app_root_event_process(GX_WINDOW * root,GX_EVENT * event_ptr)432 UINT app_root_event_process(GX_WINDOW *root, GX_EVENT *event_ptr)
433 {
434     studiox_project *project = GetOpenProject();
435     UINT status;
436 
437     switch (event_ptr->gx_event_type)
438     {
439     case GX_EVENT_ANIMATION_COMPLETE:
440         app_animation_delete(event_ptr->gx_event_sender);
441         break;
442     }
443 
444     status = gx_window_event_process(root, event_ptr);
445 
446     if (project && root->gx_widget_first_child)
447     {
448         BOOL process = GX_FALSE;
449         BOOL child_detect;
450         int display_index;
451         GX_WIDGET *screen = GX_NULL;
452         flow_item *flow_item = NULL;
453         trigger_info *trigger = GX_NULL;
454         GX_WIN32_DISPLAY_DRIVER_DATA *driver_instance;
455         GX_DISPLAY *display;
456 
457         display = ((GX_WINDOW_ROOT *)root)->gx_window_root_canvas->gx_canvas_display;
458         driver_instance = (GX_WIN32_DISPLAY_DRIVER_DATA *)display->gx_display_driver_data;
459         display_index = driver_instance->win32_display_index;
460 
461         // Loop through top level screens
462         for (int loop = 0; loop < driver_instance->win32_screen_count; loop++)
463         {
464             screen = driver_instance->win32_screens[loop];
465 
466             if (event_ptr->gx_event_target)
467             {
468                 if (screen == event_ptr->gx_event_target)
469                 {
470                     //the target is current screen
471                     child_detect = GX_TRUE;
472                 }
473                 else
474                 {
475                     //is event target a child of current screen?
476                     gx_widget_child_detect(screen, event_ptr->gx_event_target, &child_detect);
477                 }
478             }
479             else
480             {
481                 //no target specified
482                 child_detect = GX_TRUE;
483             }
484 
485             if ((!(screen->gx_widget_status | GX_STATUS_VISIBLE)) ||
486                 (!child_detect))
487             {
488                 screen = screen->gx_widget_next;
489                 continue;
490             }
491 
492             //app_widget_animation_process(project, display_index, root, screen, event_ptr);
493 
494             // Find top level screen
495             flow_item = app_flow_item_get(project, display_index, screen);
496 
497             if (flow_item)
498             {
499                 trigger = flow_item->trigger_list;
500             }
501 
502             while (trigger)
503             {
504                 CArray<action_info *> *action_list;
505                 ULONG signal = 0;
506                 INT id;
507 
508                 action_list = &trigger->action_list;
509 
510                 switch (trigger->trigger_type)
511                 {
512                 case TRIGGER_TYPE_SYSTEM_EVENT:
513                     if (trigger->event_type == event_ptr->gx_event_type)
514                     {
515                         if (event_ptr->gx_event_type == GX_EVENT_ANIMATION_COMPLETE)
516                         {
517                             id = project->GetIdIndex(display_index, ID_TYPE_ANIMATION, trigger->system_event_animat_id_name);
518                             if (event_ptr->gx_event_sender == id)
519                             {
520                                 process = TRUE;
521                             }
522                         }
523                         else
524                         {
525                             process = TRUE;
526                         }
527                     }
528                     break;
529 
530                 case TRIGGER_TYPE_CHILD_SIGNAL:
531                     id = project->GetIdIndex(display_index, ID_TYPE_WIDGET, trigger->signal_id_name);
532                     signal = GX_SIGNAL(id, trigger->event_type);
533 
534                     if (signal == event_ptr->gx_event_type)
535                     {
536                         process = TRUE;
537                     }
538                     break;
539 
540                 case TRIGGER_TYPE_USER_EVENT:
541                     break;
542                 }
543 
544                 if (process)
545                 {
546                     return app_trigger_action_process(project, display_index, root, action_list, screen, event_ptr);
547                 }
548                 trigger = trigger->next;
549             }
550 
551             screen = screen->gx_widget_next;
552         }
553     }
554 
555     return status;
556 }
557 
558 extern "C" {
559 
560 /**************************************************************************/
561 // This function is called by the application execution thread when the
562 // Windows window into which the application is rendering is closed. Cleanup
563 // the canvas, display, and root window
564 /**************************************************************************/
565 
guix_cleanup_win32_canvas(GX_WIN32_DISPLAY_DRIVER_DATA * driver)566 VOID guix_cleanup_win32_canvas(GX_WIN32_DISPLAY_DRIVER_DATA *driver)
567 {
568     GX_WIDGET *screen;
569     int loop;
570 
571     if (driver->win32_canvas)
572     {
573         gx_widget_hide((GX_WIDGET *)driver->win32_root_win);
574         if (driver->win32_canvas->gx_canvas_memory)
575         {
576             delete (driver->win32_canvas->gx_canvas_memory);
577         }
578 
579         resource_view::CleanupDisplayResources(driver->win32_display);
580 
581         guix_studio_delete_display(driver->win32_display);
582         delete(driver->win32_display);
583 
584         while(driver->win32_root_win->gx_widget_first_child)
585         {
586             screen = driver->win32_root_win->gx_widget_first_child;
587             gx_widget_detach(screen);
588         }
589         gx_window_root_delete(driver->win32_root_win);
590         delete(driver->win32_root_win);
591 
592         // make sure none of the top level screen are attached to each other:
593         for (loop = 0; loop < driver->win32_screen_count; loop++)
594         {
595             screen = driver->win32_screens[loop];
596 
597             if (screen)
598             {
599                 if (screen->gx_widget_parent)
600                 {
601                     gx_widget_detach(screen);
602                 }
603             }
604         }
605 
606         // now delete each of the top level screens:
607         for (loop = 0; loop < driver->win32_screen_count; loop++)
608         {
609             screen = driver->win32_screens[loop];
610 
611             if (screen)
612             {
613                 widget_factory::DeleteWidgets(screen);
614             }
615         }
616         if (driver->win32_screens)
617         {
618             delete [] driver->win32_screens;
619         }
620 
621         gx_canvas_delete(driver->win32_canvas);
622         delete driver->win32_canvas;
623 
624         memset(driver, 0, sizeof(GX_WIN32_DISPLAY_DRIVER_DATA));
625     }
626 }
627 
628 /**************************************************************************/
guix_execute_thread(ULONG thread_input)629 void guix_execute_thread(ULONG thread_input)
630 {
631     GX_WIN32_DISPLAY_DRIVER_DATA *data;
632 
633     studiox_project *project = GetOpenProject();
634 
635     if (!project)
636     {
637         return;
638     }
639 
640     data = (GX_WIN32_DISPLAY_DRIVER_DATA *)thread_input;
641 
642     screen_flow *flow = project->mDisplays[data->win32_display_index].screenflow;
643     int size = flow->GetFlowListCount() * 2;
644     GX_WIDGET **memory = new GX_WIDGET*[size];
645     _gx_system_screen_stack_create(memory, sizeof(GX_WIDGET *)* size);
646 
647     _gx_system_thread_entry(0);
648 
649     app_animation_clean_up(data);
650 
651     //save current win32 window position
652     project->mHeader.app_execute_xpos = data->win32_window_xpos;
653     project->mHeader.app_execute_ypos = data->win32_window_ypos;
654 
655     //delete system screen stack memory
656     delete _gx_system_screen_stack.gx_screen_stack_control_memory;
657 
658     guix_cleanup_win32_canvas(data);
659 
660     ExitThread(0);
661 }
662 }
663 
664 /**************************************************************************/
app_runner()665 app_runner::app_runner()
666 {
667 
668 }
669 
670 /**************************************************************************/
~app_runner()671 app_runner::~app_runner()
672 {
673 
674 }
675 
676 
677 /**************************************************************************/
HaveStartupScreens(const CArray<widget_info * > * screen_list) const678 BOOL app_runner::HaveStartupScreens(const CArray<widget_info *> *screen_list) const
679 {
680     widget_info *screen;
681 
682     for (int index = 0; index < screen_list->GetCount(); index++)
683     {
684         screen = screen_list->GetAt(index);
685 
686         if (screen->visible_at_startup)
687         {
688             return TRUE;
689         }
690     }
691     return FALSE;
692 }
693 
694 
695 /**************************************************************************/
RunApplication(int display_index,CWnd * parent)696 void app_runner::RunApplication(int display_index, CWnd *parent)
697 {
698 GX_WIN32_DISPLAY_DRIVER_DATA *data;
699 
700 int          memsize;
701 UCHAR        *canvas_memory;
702 GX_DISPLAY   *app_display;
703 GX_CANVAS    *app_canvas;
704 GX_WINDOW_ROOT *app_root;
705 GX_BOOL      status = GX_FALSE;
706 GX_RECTANGLE size;
707 CArray<widget_info *> screen_list;
708 widget_info *screen;
709 display_info *info;
710 
711     studiox_project *project = GetOpenProject();
712 
713     if (project)
714     {
715         info = &project->mDisplays[display_index];
716 
717         if (!info)
718         {
719             ErrorMsg("Internal Error: Invalid display", parent);
720             return;
721         }
722 
723         GetProjectView()->GetTopLevelWidgetList(display_index, &screen_list);
724 
725         if (!HaveStartupScreens(&screen_list))
726         {
727             ErrorMsg("No startup screen(s) have been defined, cannot run application", parent);
728             return;
729         }
730 
731         int canvas_xres = info->xres;
732         int canvas_yres = info->yres;
733 
734         if (info->rotation_angle == GX_SCREEN_ROTATION_CCW ||
735             info->rotation_angle == GX_SCREEN_ROTATION_CW)
736         {
737             GX_SWAP_VALS(canvas_xres, canvas_yres);
738         }
739 
740         app_display = new GX_DISPLAY;
741         int active_theme = project->mDisplays[display_index].active_theme;
742 
743         memsize = guix_create_app_display(app_display, "GUIX App Display",
744                                          canvas_xres, canvas_yres,
745                                          info->colorformat,
746                                          project->mHeader.target_cpu,
747                                          IsRenesasDave2D(project),
748                                          IsDave2dFontFormat(project, display_index),
749                                          info->themes[active_theme].palette,
750                                          info->themes[active_theme].palette_total_size,
751                                          project->mHeader.palette_mode_aa_text_colors);
752 
753         if (memsize)
754         {
755             data = (GX_WIN32_DISPLAY_DRIVER_DATA *) app_display->gx_display_driver_data;
756 
757             if (!data)
758             {
759                 ErrorMsg("Internal Error: Invalid display driver data", parent);
760                 delete app_display;
761                 return;
762             }
763 
764             GetResourceView()->BuildResourceTables(display_index, app_display, FALSE);
765 
766             canvas_memory = new UCHAR[memsize];
767             app_canvas = new GX_CANVAS;
768             app_root   = new GX_WINDOW_ROOT;
769 
770             app_animation_created_list = GX_NULL;
771             app_animation_id = 1024;
772 
773             // save the dynamically allocated control block pointers, so that we can clean up
774             // when the Win32 window is closed:
775 
776             data->win32_canvas = app_canvas;
777             data->win32_root_win = app_root;
778             data->win32_display = app_display;
779 
780             data->win32_window_xpos = project->mHeader.app_execute_xpos;
781             data->win32_window_ypos = project->mHeader.app_execute_ypos;
782 
783             gx_canvas_create(app_canvas, "GUIX App Canvas",
784                           app_display, GX_CANVAS_MANAGED | GX_CANVAS_VISIBLE,
785                           canvas_xres, canvas_yres, (GX_COLOR *) canvas_memory, memsize);
786 
787             /* Create a background root window and attach to the background canvas.  */
788 
789             gx_utility_rectangle_define(&size, 0, 0, canvas_xres - 1, canvas_yres - 1);
790             gx_window_root_create(app_root, "GUIX App Root Window", app_canvas,
791                                    GX_STYLE_BORDER_NONE, GX_ID_NONE, &size);
792 
793             gx_widget_event_process_set(app_root, app_root_event_process);
794 
795             int screen_count = 0;
796             for (int index = 0; index < screen_list.GetCount(); index++)
797             {
798                 screen = screen_list.GetAt(index);
799                 if (screen->is_template)
800                 {
801                     continue;
802                 }
803                 screen_count++;
804             }
805 
806             data->win32_screen_count = screen_count;
807             data->win32_screens = new GX_WIDGET *[screen_count];
808             data->win32_display_index = display_index;
809 
810             screen_count = 0;
811 
812             for (int index = 0; index < screen_list.GetCount(); index++)
813             {
814                 screen = screen_list.GetAt(index);
815 
816                 if (screen->is_template)
817                 {
818                     continue;
819                 }
820 
821                 data->win32_screens[screen_count] = widget_factory::GenerateAppScreen(NULL, screen);
822                 if (screen->visible_at_startup)
823                 {
824                     gx_widget_attach(app_root, data->win32_screens[screen_count]);
825                 }
826 
827                 screen_count++;
828             }
829 
830             /* create a Windows thread, hand off the configured canvas/display/root window */
831             CreateThread(NULL, GX_WIN32_STACK_SIZE, (LPTHREAD_START_ROUTINE) gx_win32_studio_driver_thread_entry, data, 0, (LPDWORD)&data->win32_window_ThreadId);
832 
833             /* create a Windows thread to execute the GUIX event loop */
834             CreateThread(NULL, GX_WIN32_STACK_SIZE, (LPTHREAD_START_ROUTINE) guix_execute_thread, data, 0, (LPDWORD)&data->win32_guix_ThreadId);
835 
836             gx_widget_show((GX_WIDGET *)app_root);
837         }
838         else
839         {
840             delete app_display;
841         }
842     }
843 }
844 
845 
846