GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_widget_event_process.c Lines: 120 120 100.0 %
Date: 2024-12-05 08:52:37 Branches: 71 71 100.0 %

Line Branch Exec Source
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
/**************************************************************************/
72
32736
static VOID  _gx_widget_children_show_event_process(GX_WIDGET *widget, GX_EVENT *event_ptr)
73
{
74
75
GX_WIDGET *child;
76
32736
GX_WIDGET *start = GX_NULL;
77
32736
GX_WIDGET *end = GX_NULL;
78
79
    /* Pickup the first child of the widget.  */
80
32736
    child = widget -> gx_widget_first_child;
81
82
    /* Loop to send event to all client children of widget.  */
83
61759
    while (child)
84
    {
85
29023
        if (child -> gx_widget_status & GX_STATUS_NONCLIENT)
86
        {
87
428
            if (start == GX_NULL)
88
            {
89
                /* Record first non-client widget. */
90
268
                start = child;
91
            }
92
93
            /* Record last non-client widget. */
94
428
            end = child;
95
        }
96
        else
97
        {
98
            /* Call widget's event processing.  */
99
28595
            child -> gx_widget_event_process_function(child, event_ptr);
100
        }
101
102
        /* Move to next child widget.  */
103
29023
        child = child -> gx_widget_next;
104
    }
105
106
32736
    if (start)
107
    {
108
        /* Loop to send event to all non-client children of widget.  */
109
449
        while (start != end)
110
        {
111
181
            if (start -> gx_widget_status & GX_STATUS_NONCLIENT)
112
            {
113
                /* Call widget's event processing.  */
114
160
                start -> gx_widget_event_process_function(start, event_ptr);
115
            }
116
117
181
            start = start -> gx_widget_next;
118
        }
119
120
268
        start -> gx_widget_event_process_function(start, event_ptr);
121
    }
122
32736
}
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
/**************************************************************************/
182
104139
UINT  _gx_widget_event_process(GX_WIDGET *widget, GX_EVENT *event_ptr)
183
{
184
GX_WIDGET *child;
185
GX_EVENT   new_event;
186
104139
UINT       status = GX_SUCCESS;
187
GX_EVENT   input_release_event;
188
189
    /* Process relative to the type of event. */
190



104139
    switch (event_ptr -> gx_event_type)
191
    {
192
32974
    case GX_EVENT_SHOW:
193
32974
        if (!(widget -> gx_widget_status & (GX_STATUS_VISIBLE | GX_STATUS_HIDDEN)))
194
        {
195
32736
            widget -> gx_widget_status |= GX_STATUS_VISIBLE;
196
32736
            _gx_widget_children_show_event_process(widget, event_ptr);
197
        }
198
32974
        break;
199
200
16863
    case GX_EVENT_HIDE:
201
16863
        if (widget -> gx_widget_status & GX_STATUS_VISIBLE)
202
        {
203
16788
            widget -> gx_widget_status &= ~GX_STATUS_VISIBLE;
204
205
            /* Check if the widget still owns system input. */
206
16788
            if (widget -> gx_widget_status & GX_STATUS_OWNS_INPUT)
207
            {
208
36
                memset(&input_release_event, 0, sizeof(GX_EVENT));
209
36
                input_release_event.gx_event_target = widget;
210
36
                input_release_event.gx_event_type = GX_EVENT_INPUT_RELEASE;
211
36
                widget -> gx_widget_event_process_function(widget, &input_release_event);
212
            }
213
16788
            _gx_widget_children_event_process(widget, event_ptr);
214
        }
215
16863
        break;
216
217
7375
    case GX_EVENT_FOCUS_GAINED:
218
        /* if I don't already have focus */
219
7375
        if (!(widget -> gx_widget_status & GX_STATUS_HAS_FOCUS) &&
220
7362
            widget -> gx_widget_status & GX_STATUS_ACCEPTS_FOCUS)
221
        {
222
            /* then status flag indicating I have focus */
223
224
7356
            widget -> gx_widget_status |= GX_STATUS_HAS_FOCUS;
225
226
            /* and make sure my parent has focus as well */
227
7356
            if (widget -> gx_widget_parent)
228
            {
229
6366
                if (!(widget -> gx_widget_parent -> gx_widget_status & GX_STATUS_HAS_FOCUS))
230
                {
231
1271
                    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

6366
                if (widget -> gx_widget_id && widget -> gx_widget_status & GX_STATUS_NOTIFY_ON_GAIN_FOCUS)
236
                {
237
1
                    _gx_widget_event_generate(widget, GX_EVENT_FOCUS_GAIN_NOTIFY, 0);
238
                }
239
            }
240
7356
            if (widget -> gx_widget_style & GX_STYLE_ENABLED)
241
            {
242
2296
                widget -> gx_widget_style |= GX_STYLE_DRAW_SELECTED;
243
2296
                _gx_system_dirty_mark(widget);
244
            }
245
        }
246
7375
        break;
247
248
5170
    case GX_EVENT_FOCUS_LOST:
249
        /* if I previously had focus */
250
5170
        if (widget -> gx_widget_status & GX_STATUS_HAS_FOCUS)
251
        {
252
            /* clear focus status flag */
253
5147
            widget -> gx_widget_status &= ~GX_STATUS_HAS_FOCUS;
254
255
5147
            if (widget -> gx_widget_style & GX_STYLE_ENABLED)
256
            {
257
1713
                widget -> gx_widget_style &= ~GX_STYLE_DRAW_SELECTED;
258
1713
                _gx_system_dirty_mark(widget);
259
            }
260
        }
261
262
        /* and make sure my children don't think they have focus */
263
264
5170
        child = widget -> gx_widget_first_child;
265
266
24134
        while (child)
267
        {
268
21282
            if (child -> gx_widget_status & GX_STATUS_HAS_FOCUS)
269
            {
270
2318
                child -> gx_widget_event_process_function(child, event_ptr);
271
2318
                break;
272
            }
273
18964
            child = child -> gx_widget_next;
274
        }
275
5170
        break;
276
277
10169
    case GX_EVENT_PEN_DOWN:
278
10169
        if (widget -> gx_widget_status & GX_STATUS_SELECTABLE)
279
        {
280
3581
            if (widget -> gx_widget_id > 0)
281
            {
282
1301
                _gx_widget_event_generate(widget, GX_EVENT_CLICKED, 0);
283
            }
284
        }
285
10169
        status = _gx_widget_event_to_parent(widget, event_ptr);
286
10169
        break;
287
288
289
3534
    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
3534
        child = widget -> gx_widget_first_child;
297
6946
        while (child)
298
        {
299
3412
            child -> gx_widget_event_process_function(child, event_ptr);
300
3412
            child = child -> gx_widget_next;
301
        }
302
3534
        break;
303
304
910
    case GX_EVENT_KEY_DOWN:
305
910
        memset(&new_event, 0, sizeof(GX_EVENT));
306
307

910
        switch (event_ptr -> gx_event_payload.gx_event_ushortdata[0])
308
        {
309
2
        case GX_KEY_SELECT:
310
2
            if (widget -> gx_widget_style & GX_STYLE_ENABLED)
311
            {
312
                /* generate pen-down event */
313
1
                new_event.gx_event_type = GX_EVENT_SELECT;
314
1
                widget -> gx_widget_event_process_function(widget, &new_event);
315
            }
316
2
            break;
317
318
1
        case GX_KEY_NEXT:
319
1
            new_event.gx_event_type = GX_EVENT_FOCUS_NEXT;
320
1
            new_event.gx_event_sender = widget -> gx_widget_id;
321
1
            widget -> gx_widget_event_process_function(widget, &new_event);
322
1
            break;
323
324
1
        case GX_KEY_PREVIOUS:
325
1
            new_event.gx_event_type = GX_EVENT_FOCUS_PREVIOUS;
326
1
            new_event.gx_event_sender = widget -> gx_widget_id;
327
1
            widget -> gx_widget_event_process_function(widget, &new_event);
328
1
            break;
329
330
906
        default:
331
906
            _gx_widget_event_to_parent(widget, event_ptr);
332
906
            break;
333
        }
334
910
        break;
335
336
377
    case GX_EVENT_KEY_UP:
337
377
        if (widget -> gx_widget_style & GX_STYLE_ENABLED)
338
        {
339
189
            if (event_ptr -> gx_event_payload.gx_event_ushortdata[0] == GX_KEY_SELECT)
340
            {
341
                /* generate de-select event */
342
1
                memset(&new_event, 0, sizeof(GX_EVENT));
343
1
                new_event.gx_event_type = GX_EVENT_DESELECT;
344
1
                widget -> gx_widget_event_process_function(widget, &new_event);
345
            }
346
            else
347
            {
348
188
                _gx_widget_event_to_parent(widget, event_ptr);
349
            }
350
        }
351
377
        break;
352
353
1
    case GX_EVENT_FOCUS_NEXT:
354
1
        _gx_widget_focus_next(widget);
355
1
        break;
356
357
1
    case GX_EVENT_FOCUS_PREVIOUS:
358
1
        _gx_widget_focus_previous(widget);
359
1
        break;
360
361
8
    case GX_EVENT_INPUT_RELEASE:
362
8
        if (widget -> gx_widget_status & GX_STATUS_OWNS_INPUT)
363
        {
364
7
            _gx_system_input_release(widget);
365
        }
366
8
        break;
367
368
5977
    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
5977
        break;
374
375
20780
    case GX_EVENT_PEN_UP:
376
    case GX_EVENT_PEN_DRAG:
377
    default:
378
20780
        status = _gx_widget_event_to_parent(widget, event_ptr);
379
20780
        break;
380
    }
381
382
104139
    return(status);
383
}
384