1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** GUIX Component                                                        */
16 /**                                                                       */
17 /**   Widget Management (Widget)                                          */
18 /**                                                                       */
19 /**************************************************************************/
20 
21 #define GX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "gx_api.h"
27 #include "gx_system.h"
28 #include "gx_widget.h"
29 
30 /**************************************************************************/
31 /*                                                                        */
32 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    _gx_widget_children_show_event_process              PORTABLE C      */
35 /*                                                           6.1          */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Kenneth Maxwell, Microsoft Corporation                              */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    Internal helper function to propagate widget show events to the     */
43 /*    client children of the specified widget first, and then pass the    */
44 /*    event to the non-client children.                                   */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    widget                                Widget control block          */
49 /*    event_ptr                             Incoming event to process     */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    None                                                                */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*    [gx_widget_event_process_function]    Child widget event processing */
58 /*                                                                        */
59 /*  CALLED BY                                                             */
60 /*                                                                        */
61 /*    _gx_widget_event_process                                            */
62 /*                                                                        */
63 /*  RELEASE HISTORY                                                       */
64 /*                                                                        */
65 /*    DATE              NAME                      DESCRIPTION             */
66 /*                                                                        */
67 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
68 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
69 /*                                            resulting in version 6.1    */
70 /*                                                                        */
71 /**************************************************************************/
_gx_widget_children_show_event_process(GX_WIDGET * widget,GX_EVENT * event_ptr)72 static VOID  _gx_widget_children_show_event_process(GX_WIDGET *widget, GX_EVENT *event_ptr)
73 {
74 
75 GX_WIDGET *child;
76 GX_WIDGET *start = GX_NULL;
77 GX_WIDGET *end = GX_NULL;
78 
79     /* Pickup the first child of the widget.  */
80     child = widget -> gx_widget_first_child;
81 
82     /* Loop to send event to all client children of widget.  */
83     while (child)
84     {
85         if (child -> gx_widget_status & GX_STATUS_NONCLIENT)
86         {
87             if (start == GX_NULL)
88             {
89                 /* Record first non-client widget. */
90                 start = child;
91             }
92 
93             /* Record last non-client widget. */
94             end = child;
95         }
96         else
97         {
98             /* Call widget's event processing.  */
99             child -> gx_widget_event_process_function(child, event_ptr);
100         }
101 
102         /* Move to next child widget.  */
103         child = child -> gx_widget_next;
104     }
105 
106     if (start)
107     {
108         /* Loop to send event to all non-client children of widget.  */
109         while (start != end)
110         {
111             if (start -> gx_widget_status & GX_STATUS_NONCLIENT)
112             {
113                 /* Call widget's event processing.  */
114                 start -> gx_widget_event_process_function(start, event_ptr);
115             }
116 
117             start = start -> gx_widget_next;
118         }
119 
120         start -> gx_widget_event_process_function(start, event_ptr);
121     }
122 }
123 
124 /**************************************************************************/
125 /*                                                                        */
126 /*  FUNCTION                                               RELEASE        */
127 /*                                                                        */
128 /*    _gx_widget_event_process                            PORTABLE C      */
129 /*                                                           6.4.0        */
130 /*  AUTHOR                                                                */
131 /*                                                                        */
132 /*    Kenneth Maxwell, Microsoft Corporation                              */
133 /*                                                                        */
134 /*  DESCRIPTION                                                           */
135 /*                                                                        */
136 /*    This function processes events for the specified widget.            */
137 /*                                                                        */
138 /*  INPUT                                                                 */
139 /*                                                                        */
140 /*    widget                                Widget control block          */
141 /*    event_ptr                             Incoming event to process     */
142 /*                                                                        */
143 /*  OUTPUT                                                                */
144 /*                                                                        */
145 /*    status                                Completion status             */
146 /*                                                                        */
147 /*  CALLS                                                                 */
148 /*                                                                        */
149 /*    _gx_widget_children_event_process     Forward event to children     */
150 /*    [gx_widget_event_process_function]    Widget-specific event process */
151 /*                                            routine                     */
152 /*    _gx_system_dirty_mark                 Mark the widget as dirty      */
153 /*    _gx_widget_event_to_parent            Signal the parent             */
154 /*    _gx_widget_event_generate             Generate an event             */
155 /*                                                                        */
156 /*  CALLED BY                                                             */
157 /*                                                                        */
158 /*    Application Code                                                    */
159 /*    GUIX Internal Code                                                  */
160 /*                                                                        */
161 /*  RELEASE HISTORY                                                       */
162 /*                                                                        */
163 /*    DATE              NAME                      DESCRIPTION             */
164 /*                                                                        */
165 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
166 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
167 /*                                            added new event entries,    */
168 /*                                            resulting in version 6.1    */
169 /*  12-31-2020     Kenneth Maxwell          Modified comment(s),          */
170 /*                                            avoid pass widget delete    */
171 /*                                            event to parent,            */
172 /*                                            resulting in version 6.1.3  */
173 /*  04-25-2022     Ting Zhu                 Modified comment(s), modified */
174 /*                                            system input release logic  */
175 /*                                            on widget hide event,       */
176 /*                                            resulting in version 6.1.11 */
177 /*  12-31-2023     Ting Zhu                 Modified comment(s),          */
178 /*                                            improved focus lose logic,  */
179 /*                                            resulting in version 6.4.0  */
180 /*                                                                        */
181 /**************************************************************************/
_gx_widget_event_process(GX_WIDGET * widget,GX_EVENT * event_ptr)182 UINT  _gx_widget_event_process(GX_WIDGET *widget, GX_EVENT *event_ptr)
183 {
184 GX_WIDGET *child;
185 GX_EVENT   new_event;
186 UINT       status = GX_SUCCESS;
187 GX_EVENT   input_release_event;
188 
189     /* Process relative to the type of event. */
190     switch (event_ptr -> gx_event_type)
191     {
192     case GX_EVENT_SHOW:
193         if (!(widget -> gx_widget_status & (GX_STATUS_VISIBLE | GX_STATUS_HIDDEN)))
194         {
195             widget -> gx_widget_status |= GX_STATUS_VISIBLE;
196             _gx_widget_children_show_event_process(widget, event_ptr);
197         }
198         break;
199 
200     case GX_EVENT_HIDE:
201         if (widget -> gx_widget_status & GX_STATUS_VISIBLE)
202         {
203             widget -> gx_widget_status &= ~GX_STATUS_VISIBLE;
204 
205             /* Check if the widget still owns system input. */
206             if (widget -> gx_widget_status & GX_STATUS_OWNS_INPUT)
207             {
208                 memset(&input_release_event, 0, sizeof(GX_EVENT));
209                 input_release_event.gx_event_target = widget;
210                 input_release_event.gx_event_type = GX_EVENT_INPUT_RELEASE;
211                 widget -> gx_widget_event_process_function(widget, &input_release_event);
212             }
213             _gx_widget_children_event_process(widget, event_ptr);
214         }
215         break;
216 
217     case GX_EVENT_FOCUS_GAINED:
218         /* if I don't already have focus */
219         if (!(widget -> gx_widget_status & GX_STATUS_HAS_FOCUS) &&
220             widget -> gx_widget_status & GX_STATUS_ACCEPTS_FOCUS)
221         {
222             /* then status flag indicating I have focus */
223 
224             widget -> gx_widget_status |= GX_STATUS_HAS_FOCUS;
225 
226             /* and make sure my parent has focus as well */
227             if (widget -> gx_widget_parent)
228             {
229                 if (!(widget -> gx_widget_parent -> gx_widget_status & GX_STATUS_HAS_FOCUS))
230                 {
231                     widget -> gx_widget_parent -> gx_widget_event_process_function(widget -> gx_widget_parent, event_ptr);
232                 }
233 
234                 /* test to see if this widget should notify it's parent when it gains focus */
235                 if (widget -> gx_widget_id && widget -> gx_widget_status & GX_STATUS_NOTIFY_ON_GAIN_FOCUS)
236                 {
237                     _gx_widget_event_generate(widget, GX_EVENT_FOCUS_GAIN_NOTIFY, 0);
238                 }
239             }
240             if (widget -> gx_widget_style & GX_STYLE_ENABLED)
241             {
242                 widget -> gx_widget_style |= GX_STYLE_DRAW_SELECTED;
243                 _gx_system_dirty_mark(widget);
244             }
245         }
246         break;
247 
248     case GX_EVENT_FOCUS_LOST:
249         /* if I previously had focus */
250         if (widget -> gx_widget_status & GX_STATUS_HAS_FOCUS)
251         {
252             /* clear focus status flag */
253             widget -> gx_widget_status &= ~GX_STATUS_HAS_FOCUS;
254 
255             if (widget -> gx_widget_style & GX_STYLE_ENABLED)
256             {
257                 widget -> gx_widget_style &= ~GX_STYLE_DRAW_SELECTED;
258                 _gx_system_dirty_mark(widget);
259             }
260         }
261 
262         /* and make sure my children don't think they have focus */
263 
264         child = widget -> gx_widget_first_child;
265 
266         while (child)
267         {
268             if (child -> gx_widget_status & GX_STATUS_HAS_FOCUS)
269             {
270                 child -> gx_widget_event_process_function(child, event_ptr);
271                 break;
272             }
273             child = child -> gx_widget_next;
274         }
275         break;
276 
277     case GX_EVENT_PEN_DOWN:
278         if (widget -> gx_widget_status & GX_STATUS_SELECTABLE)
279         {
280             if (widget -> gx_widget_id > 0)
281             {
282                 _gx_widget_event_generate(widget, GX_EVENT_CLICKED, 0);
283             }
284         }
285         status = _gx_widget_event_to_parent(widget, event_ptr);
286         break;
287 
288 
289     case GX_EVENT_LANGUAGE_CHANGE:
290     case GX_EVENT_RESOURCE_CHANGE:
291 #if defined(GX_DYNAMIC_BIDI_TEXT_SUPPORT)
292     case GX_EVENT_DYNAMIC_BIDI_TEXT_DISABLE:
293     case GX_EVENT_DYNAMIC_BIDI_TEXT_ENABLE:
294 #endif
295         /* pass this event down to all my children */
296         child = widget -> gx_widget_first_child;
297         while (child)
298         {
299             child -> gx_widget_event_process_function(child, event_ptr);
300             child = child -> gx_widget_next;
301         }
302         break;
303 
304     case GX_EVENT_KEY_DOWN:
305         memset(&new_event, 0, sizeof(GX_EVENT));
306 
307         switch (event_ptr -> gx_event_payload.gx_event_ushortdata[0])
308         {
309         case GX_KEY_SELECT:
310             if (widget -> gx_widget_style & GX_STYLE_ENABLED)
311             {
312                 /* generate pen-down event */
313                 new_event.gx_event_type = GX_EVENT_SELECT;
314                 widget -> gx_widget_event_process_function(widget, &new_event);
315             }
316             break;
317 
318         case GX_KEY_NEXT:
319             new_event.gx_event_type = GX_EVENT_FOCUS_NEXT;
320             new_event.gx_event_sender = widget -> gx_widget_id;
321             widget -> gx_widget_event_process_function(widget, &new_event);
322             break;
323 
324         case GX_KEY_PREVIOUS:
325             new_event.gx_event_type = GX_EVENT_FOCUS_PREVIOUS;
326             new_event.gx_event_sender = widget -> gx_widget_id;
327             widget -> gx_widget_event_process_function(widget, &new_event);
328             break;
329 
330         default:
331             _gx_widget_event_to_parent(widget, event_ptr);
332             break;
333         }
334         break;
335 
336     case GX_EVENT_KEY_UP:
337         if (widget -> gx_widget_style & GX_STYLE_ENABLED)
338         {
339             if (event_ptr -> gx_event_payload.gx_event_ushortdata[0] == GX_KEY_SELECT)
340             {
341                 /* generate de-select event */
342                 memset(&new_event, 0, sizeof(GX_EVENT));
343                 new_event.gx_event_type = GX_EVENT_DESELECT;
344                 widget -> gx_widget_event_process_function(widget, &new_event);
345             }
346             else
347             {
348                 _gx_widget_event_to_parent(widget, event_ptr);
349             }
350         }
351         break;
352 
353     case GX_EVENT_FOCUS_NEXT:
354         _gx_widget_focus_next(widget);
355         break;
356 
357     case GX_EVENT_FOCUS_PREVIOUS:
358         _gx_widget_focus_previous(widget);
359         break;
360 
361     case GX_EVENT_INPUT_RELEASE:
362         if (widget -> gx_widget_status & GX_STATUS_OWNS_INPUT)
363         {
364             _gx_system_input_release(widget);
365         }
366         break;
367 
368     case GX_EVENT_STYLE_CHANGED:
369     case GX_EVENT_CLIENT_UPDATED:
370     case GX_EVENT_PARENT_SIZED:
371     case GX_EVENT_RESIZED:
372     case GX_EVENT_DELETE:
373         break;
374 
375     case GX_EVENT_PEN_UP:
376     case GX_EVENT_PEN_DRAG:
377     default:
378         status = _gx_widget_event_to_parent(widget, event_ptr);
379         break;
380     }
381 
382     return(status);
383 }
384 
385