GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/webviews.c
Date: 2026-08-06 22:46:24
Exec Total Coverage
Lines: 0 6 0.0%
Functions: 0 3 0.0%
Branches: 0 0 -%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/ui/webviews.h"
30 #include "gate/results.h"
31
32 #if defined(GATE_SYS_WIN16)
33 # define GATE_UI_WEBVIEW_NO_IMPL 1
34 #elif defined(GATE_UI_WINAPI)
35 # define GATE_UI_WEBVIEW_WINAPI_IMPL 1
36 #elif defined(GATE_UI_GTK)
37 # if defined(GATE_UI_GTK_WEBKIT2)
38 # define GATE_UI_WEBVIEW_GTK_IMPL 1
39 # else
40 # define GATE_UI_WEBVIEW_NO_IMPL 1
41 # endif
42 #elif defined(GATE_UI_MOTIF)
43 # define GATE_UI_WEBVIEW_NO_IMPL 1
44 #else
45 # define GATE_UI_WEBVIEW_NO_IMPL 1
46 #endif
47
48 #if defined(GATE_UI_WEBVIEW_WINAPI_IMPL)
49
50 #include "gate/platform/windows/win32com.h"
51 #include "gate/ui/gateui_winapi.h"
52 #include "gate/platforms.h"
53
54 #define GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL 1
55
56 #if defined(GATE_WIN32_UNICODE) && !defined(GATE_SYS_WINCE)
57 /* edge webview2 support is only available on WinNT unicode-platforms */
58 # define GATE_UI_WEBVIEW_EDGEWV2_IMPL 1
59 #endif
60
61
62 #include "gate/libraries.h"
63
64 #ifdef GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL
65 # include "gate/ui/webviews_win32.h"
66 #endif
67
68 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
69 # include "gate/ui/webviews_msedgewv2.h"
70 #endif
71
72 typedef struct gate_ui_webview_impl_class
73 {
74 gate_ui_webview_t* webview;
75 HWND hwnd;
76
77 #ifdef GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL
78 /* atl/webbrowser stuff: */
79 IWebBrowser* webbrowser;
80 IWebBrowser2* webbrowser2;
81 IDispatch* webbrowser_events;
82 #endif
83
84 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
85 /* webview2 stuff: */
86 ICoreWebView2Controller* wv2_controller;
87 ICoreWebView2* wv2;
88 IUnknown* wv2_event_handlers;
89 #endif
90
91 } gate_ui_webview_impl_t;
92
93 static IID const gate_IID_IUnknown = { 0x00000000, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
94 static IID const gate_IID_IDispatch = { 0x00020400, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
95
96 static gate_bool_t webview_windowproc_events(void* hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult);
97
98 static gate_result_t webview_destroy_impl(gate_ui_ctrl_t* ctrl);
99
100 static gate_ui_winapi_dispatchers_t global_webview_dispatchers =
101 {
102 &webview_destroy_impl,
103 &gate_ui_winapi_is_enabled,
104 &gate_ui_winapi_is_visible,
105 &gate_ui_winapi_is_focused,
106 &gate_ui_winapi_get_position,
107 &gate_ui_winapi_get_size,
108 &gate_ui_winapi_get_children,
109 &gate_ui_winapi_get_text_length,
110 &gate_ui_winapi_get_text,
111 &gate_ui_winapi_get_state,
112 &gate_ui_winapi_set_enabled,
113 &gate_ui_winapi_set_visible,
114 &gate_ui_winapi_set_focus,
115 &gate_ui_winapi_set_position,
116 &gate_ui_winapi_set_text,
117 &gate_ui_winapi_set_state,
118 &gate_ui_winapi_refresh
119 };
120
121
122
123 #ifdef GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL
124 /****************************/
125 /* */
126 /* ATL / webbrowser code: */
127 /* */
128 /****************************/
129
130 typedef struct gate_ui_winapi_atl_code
131 {
132 BOOL(__stdcall* WinInit)();
133 HRESULT(STDMETHODCALLTYPE* GetControl)(HWND hwnd, IUnknown** ptr);
134 HRESULT(STDMETHODCALLTYPE* GetHost)(HWND hwnd, IUnknown** ptr);
135 } gate_ui_winapi_atl_code_t;
136
137
138 static gate_library_t atl_lib = NULL;
139 static gate_bool_t volatile atl_code_loaded = false;
140 static gate_ui_winapi_atl_code_t atl_code = GATE_INIT_EMPTY;
141
142 static gate_result_t load_atl_code()
143 {
144 #if defined(GATE_SYS_WINCE)
145 static gate_string_t const atl_lib_name = { "atlce300.dll", 12, NULL };
146 #else
147 static gate_string_t const atl_lib_name = { "atl.dll", 7, NULL };
148 #endif
149 gate_result_t ret = GATE_RESULT_FAILED;
150 if (!atl_code_loaded)
151 {
152 gate_win32_com_init();
153 do
154 {
155 if (atl_lib == NULL)
156 {
157 ret = gate_library_open(&atl_lib_name, &atl_lib, 0);
158 GATE_BREAK_IF_FAILED(ret);
159 }
160
161 ret = gate_library_get_function_name(atl_lib, "AtlAxWinInit", &atl_code.WinInit);
162 GATE_BREAK_IF_FAILED(ret);
163
164 ret = gate_library_get_function_name(atl_lib, "AtlAxGetControl", &atl_code.GetControl);
165 GATE_BREAK_IF_FAILED(ret);
166
167 ret = gate_library_get_function_name(atl_lib, "AtlAxGetHost", &atl_code.GetHost);
168 GATE_BREAK_IF_FAILED(ret);
169
170 if (atl_code.WinInit())
171 {
172 atl_code_loaded = true;
173 ret = GATE_RESULT_OK;
174 }
175 } while (0);
176 }
177 else
178 {
179 ret = GATE_RESULT_OK;
180 }
181 return ret;
182 }
183
184
185 static gate_result_t get_control_interface(HWND hwnd, GUID const* interface_id, void** pptr_interface)
186 {
187 gate_result_t ret = GATE_RESULT_FAILED;
188 IUnknown* punk = NULL;
189 IUnknown* ptr_interface = NULL;
190 HRESULT hr;
191 do
192 {
193 hr = atl_code.GetControl(hwnd, &punk);
194 if (FAILED(hr))
195 {
196 ret = GATE_RESULT_NOTAVAILABLE;
197 break;
198 }
199 if (!punk)
200 {
201 ret = GATE_RESULT_NOTAVAILABLE;
202 break;
203 }
204 if (!interface_id)
205 {
206 ptr_interface = punk;
207 punk->lpVtbl->AddRef(punk);
208 }
209 else
210 {
211 hr = punk->lpVtbl->QueryInterface(punk, interface_id, (void**)&ptr_interface);
212 if (FAILED(hr))
213 {
214 ret = GATE_RESULT_INCORRECTTYPE;
215 break;
216 }
217 }
218 if (pptr_interface)
219 {
220 *pptr_interface = (void*)ptr_interface;
221 }
222 else
223 {
224 ptr_interface->lpVtbl->Release(ptr_interface);
225 }
226 ret = GATE_RESULT_OK;
227 } while (0);
228
229 if (punk)
230 {
231 punk->lpVtbl->Release(punk);
232 }
233
234 return ret;
235 }
236
237 static void* get_control_interface_ptr(HWND hwnd, GUID const* interface_id)
238 {
239 void* ptr_interface = NULL;
240 gate_result_t result = get_control_interface(hwnd, interface_id, &ptr_interface);
241 if (GATE_FAILED(result))
242 {
243 ptr_interface = NULL;
244 }
245 return ptr_interface;
246 }
247
248
249
250 typedef struct webbrowser_events_class
251 {
252 IDispatch dispatch;
253
254 gate_atomic_int_t ref_counter;
255 gate_ui_webview_t* webview;
256 } webbrowser_events_t;
257
258
259
260 static HRESULT STDMETHODCALLTYPE webbrowser_events_QueryInterface(IDispatch* This, REFIID riid, void** ppvObject)
261 {
262 webbrowser_events_t* self = (webbrowser_events_t*)This;
263
264 if (!ppvObject || !riid || !self)
265 {
266 return E_POINTER;
267 }
268
269 if (IsEqualGUID(riid, &gate_IID_IDispatch) || IsEqualGUID(riid, &gate_IID_IUnknown)
270 || IsEqualGUID(riid, &IID_DWebBrowserEvents2) || IsEqualGUID(riid, &IID_DWebBrowserEvents))
271 {
272 *ppvObject = self;
273 gate_atomic_int_inc(&self->ref_counter);
274 return S_OK;
275 }
276 return E_NOINTERFACE;
277 }
278 static ULONG STDMETHODCALLTYPE webbrowser_events_AddRef(IDispatch* This)
279 {
280 webbrowser_events_t* self = (webbrowser_events_t*)This;
281 return (ULONG)gate_atomic_int_inc(&self->ref_counter);
282 }
283 static ULONG STDMETHODCALLTYPE webbrowser_events_Release(IDispatch* This)
284 {
285 webbrowser_events_t* self = (webbrowser_events_t*)This;
286 ULONG cnt = (ULONG)gate_atomic_int_dec(&self->ref_counter);
287 if (cnt == 0)
288 {
289 if (self->webview)
290 {
291 self->webview = NULL;
292 }
293 gate_mem_dealloc(self);
294 }
295 return cnt;
296 }
297
298 static HRESULT STDMETHODCALLTYPE webbrowser_events_GetTypeInfoCount(IDispatch* This, UINT* pctinfo)
299 {
300 if (pctinfo)
301 {
302 *pctinfo = 0;
303 }
304 return S_OK;
305 }
306
307 static HRESULT STDMETHODCALLTYPE webbrowser_events_GetTypeInfo(IDispatch* This, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
308 {
309 return DISP_E_BADINDEX;
310 }
311
312 static gate_bool_t wstr_equal(wchar_t const* a, wchar_t const* b)
313 {
314 if (!a || !b)
315 {
316 return false;
317 }
318 for (; *a == *b; ++a, ++b)
319 {
320 if (*a == 0)
321 {
322 return true;
323 }
324 }
325 return false;
326 }
327
328 struct dispid_map
329 {
330 DISPID id;
331 wchar_t const* name;
332 };
333
334 static struct dispid_map const dispid_webbrowser_map[] =
335 {
336 { DISPID_BEFORENAVIGATE, L"" },
337 { DISPID_NAVIGATECOMPLETE, L"" },
338 { DISPID_STATUSTEXTCHANGE, L"" },
339 { DISPID_QUIT, L"" },
340 { DISPID_DOWNLOADCOMPLETE, L"" },
341 { DISPID_COMMANDSTATECHANGE, L"" },
342 { DISPID_DOWNLOADBEGIN, L"" },
343 { DISPID_NEWWINDOW, L"" },
344 { DISPID_PROGRESSCHANGE, L"" },
345 { DISPID_WINDOWMOVE, L"" },
346 { DISPID_WINDOWRESIZE, L"" },
347 { DISPID_WINDOWACTIVATE, L"" },
348 { DISPID_PROPERTYCHANGE, L"" },
349 { DISPID_TITLECHANGE, L"" },
350 { DISPID_TITLEICONCHANGE, L"" }
351 };
352 static gate_size_t const dispid_webbrowser_map_count = sizeof(dispid_webbrowser_map) / sizeof(dispid_webbrowser_map[0]);
353
354
355 static void webbrowser_disable_script_errors(gate_ui_webview_impl_t* impl)
356 {
357 if (impl->webbrowser2)
358 {
359 VARIANT vin;
360 VARIANT vout;
361 HRESULT hr;
362 VARIANT_BOOL vb = FALSE;
363 vin.vt = VT_BOOL;
364 vin.boolVal = vb;
365 vout.vt = VT_EMPTY;
366 hr = impl->webbrowser2->lpVtbl->ExecWB(impl->webbrowser2, OLECMDID_SHOWSCRIPTERROR, OLECMDEXECOPT_DONTPROMPTUSER, &vin, &vout);
367 impl->webbrowser2->lpVtbl->put_Silent(impl->webbrowser2, TRUE);
368 Sleep(0);
369 }
370 }
371
372
373 static HRESULT STDMETHODCALLTYPE webbrowser_events_GetIDsOfNames(IDispatch* This, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)
374 {
375 UINT ndx;
376 gate_size_t ndx_map;
377
378 for (ndx = 0; ndx != cNames; ++ndx)
379 {
380 rgDispId[ndx] = 0;
381 for (ndx_map = 0; ndx_map != dispid_webbrowser_map_count; ++ndx_map)
382 {
383 if (wstr_equal(rgszNames[ndx], dispid_webbrowser_map[ndx_map].name))
384 {
385 rgDispId[ndx] = dispid_webbrowser_map[ndx_map].id;
386 break;
387 }
388 }
389 }
390 return S_OK;
391 }
392
393 static HRESULT STDMETHODCALLTYPE webbrowser_events_Invoke(IDispatch* This, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
394 DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
395 {
396 webbrowser_events_t* self = (webbrowser_events_t*)This;
397 gate_string_t text = GATE_STRING_INIT_EMPTY;
398 gate_bool_t b = false;
399 gate_int32_t n1 = 0, n2 = 0;
400 gate_ui_webview_impl_t* impl = NULL;
401
402 do
403 {
404 if (!self || !self->webview)
405 {
406 break;
407 }
408 impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(&self->webview->ctrl);
409
410 switch (dispIdMember)
411 {
412 case DISPID_BEFORENAVIGATE:
413 {
414 webbrowser_disable_script_errors(impl);
415 if (self->webview->on_navigate_start)
416 {
417 VARIANTARG* a0 = &pDispParams->rgvarg[0];
418 VARIANTARG* a1 = &pDispParams->rgvarg[1];
419 VARIANTARG* a2 = &pDispParams->rgvarg[2];
420 VARIANTARG* a3 = &pDispParams->rgvarg[3];
421 VARIANTARG* a4 = &pDispParams->rgvarg[4];
422 VARIANTARG* a5 = &pDispParams->rgvarg[5];
423 self->webview->on_navigate_start(&self->webview->ctrl, &text, &b);
424 }
425 break;
426 }
427 case DISPID_PROGRESSCHANGE:
428 {
429 if (self->webview->on_navigate_progress)
430 {
431 self->webview->on_navigate_progress(&self->webview->ctrl, n1, n2);
432 }
433 break;
434 }
435 case DISPID_NAVIGATECOMPLETE:
436 case DISPID_NAVIGATECOMPLETE2:
437 {
438 webbrowser_disable_script_errors(impl);
439 if (self->webview->on_navigate_complete)
440 {
441 if (pDispParams->cArgs >= 1)
442 {
443 if (pDispParams->rgvarg[0].vt == VT_BSTR)
444 {
445 gate_win32_bstr_to_string(pDispParams->rgvarg[0].bstrVal, &text);
446 }
447 else if ((pDispParams->rgvarg[0].vt == (VT_VARIANT | VT_BYREF)) && (pDispParams->rgvarg[0].pvarVal))
448 {
449 if (pDispParams->rgvarg[0].pvarVal->vt == VT_BSTR)
450 {
451 gate_win32_bstr_to_string(pDispParams->rgvarg[0].pvarVal->bstrVal, &text);
452 }
453 }
454 }
455 self->webview->on_navigate_complete(&self->webview->ctrl, &text);
456 }
457 break;
458 }
459 case DISPID_COMMANDSTATECHANGE:
460 {
461 if (self->webview->on_internal_state_changed)
462 {
463 self->webview->on_internal_state_changed(&self->webview->ctrl, 0);
464 }
465 break;
466 }
467 case DISPID_TITLECHANGE:
468 {
469 if (self->webview->on_title_text_changed)
470 {
471 if ((pDispParams->cArgs >= 1) && (pDispParams->rgvarg[0].vt == VT_BSTR))
472 {
473 gate_win32_bstr_to_string(pDispParams->rgvarg[0].bstrVal, &text);
474 }
475 self->webview->on_title_text_changed(&self->webview->ctrl, &text);
476 }
477 break;
478 }
479 case DISPID_STATUSTEXTCHANGE:
480 {
481 if (self->webview->on_status_text_changed)
482 {
483 if ((pDispParams->cArgs >= 1) && (pDispParams->rgvarg[0].vt == VT_BSTR))
484 {
485 gate_win32_bstr_to_string(pDispParams->rgvarg[0].bstrVal, &text);
486 }
487 self->webview->on_status_text_changed(&self->webview->ctrl, &text);
488 }
489 break;
490 }
491 case DISPID_NAVIGATEERROR:
492 {
493 Sleep(0);
494 break;
495 }
496 case DISPID_NEWWINDOW2:
497 case DISPID_NEWWINDOW:
498 {
499 if (self->webview->on_new_window)
500 {
501 gate_ui_webview_t* ptr_newview = NULL;
502 self->webview->on_new_window(&self->webview->ctrl, &ptr_newview);
503 if (ptr_newview && (pDispParams->cArgs >= 2))
504 {
505 gate_ui_webview_impl_t* other_impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(&ptr_newview->ctrl);
506 VARIANTARG* a0 = &pDispParams->rgvarg[0];
507 //*a0->pboolVal = TRUE;
508 VARIANTARG* a1 = &pDispParams->rgvarg[1];
509 if (other_impl && other_impl->webbrowser2 && (a1->vt == (VT_DISPATCH | VT_BYREF)))
510 {
511 IDispatch* pdisp = NULL;
512 other_impl->webbrowser2->lpVtbl->put_RegisterAsBrowser(other_impl->webbrowser2, TRUE);
513 other_impl->webbrowser2->lpVtbl->QueryInterface(other_impl->webbrowser2, &gate_IID_IDispatch, (void**)&pdisp);
514 *a1->ppdispVal = pdisp;
515 }
516 Sleep(0);
517 }
518 }
519 break;
520 }
521 case DISPID_QUIT:
522 case DISPID_DOWNLOADCOMPLETE:
523 case DISPID_DOWNLOADBEGIN:
524 case DISPID_WINDOWMOVE:
525 case DISPID_WINDOWRESIZE:
526 case DISPID_WINDOWACTIVATE:
527 case DISPID_PROPERTYCHANGE:
528 case DISPID_TITLEICONCHANGE:
529 break;
530 }
531
532 } while (0);
533
534 gate_string_release(&text);
535
536
537 return S_OK;
538 }
539
540
541 static IDispatchVtbl webview_disp_vtbl =
542 {
543 &webbrowser_events_QueryInterface,
544 &webbrowser_events_AddRef,
545 &webbrowser_events_Release,
546
547 &webbrowser_events_GetTypeInfoCount,
548 &webbrowser_events_GetTypeInfo,
549 &webbrowser_events_GetIDsOfNames,
550 &webbrowser_events_Invoke
551 };
552
553
554
555
556 static DWORD register_webbrowser_event_dispatcher(IUnknown* target, IID const* event_iid, IDispatch* event_handler)
557 {
558 DWORD ret = 0;
559 HRESULT hr;
560 IConnectionPointContainer* ptr_container = NULL;
561 IConnectionPoint* ptr_point = NULL;
562 DWORD cookie = 0;
563
564 do
565 {
566 hr = target->lpVtbl->QueryInterface(target, &IID_IConnectionPointContainer, (void**)&ptr_container);
567 if (FAILED(hr))
568 {
569 break;
570 }
571 hr = ptr_container->lpVtbl->FindConnectionPoint(ptr_container, event_iid, &ptr_point);
572 if (FAILED(hr))
573 {
574 break;
575 }
576 hr = ptr_point->lpVtbl->Advise(ptr_point, (IUnknown*)event_handler, &cookie);
577 if (FAILED(hr))
578 {
579 break;
580 }
581 ret = cookie;
582 } while (0);
583
584 if (ptr_point)
585 {
586 ptr_point->lpVtbl->Release(ptr_point);
587 }
588 if (ptr_container)
589 {
590 ptr_container->lpVtbl->Release(ptr_container);
591 }
592 return ret;
593 }
594
595
596 static gate_ui_webview_impl_t* create_webbrowser_impl(gate_ui_webview_t* webview)
597 {
598 HWND hwnd_ctrl = NULL;
599 gate_ui_webview_impl_t* impl = NULL;
600 gate_ui_host_t* host = NULL;
601 RECT rect;
602 DWORD event_cookie = 0;
603 #if defined(GATE_SYS_WINCE)
604 static LPCTSTR browser_id = TEXT("Microsoft.PIEDocView");
605 #else
606 static LPCTSTR browser_id = TEXT("SHDocVwCtl.WebBrowser");
607 #endif
608 webbrowser_events_t* webbrowser_events;
609
610 do
611 {
612 hwnd_ctrl = GATE_UI_WINAPI_GET_HWND(&webview->ctrl);
613 host = GATE_UI_WINAPI_GET_HOST(&webview->ctrl);
614 impl = (gate_ui_webview_impl_t*)gate_mem_alloc(sizeof(gate_ui_webview_impl_t));
615 if (!impl)
616 {
617 break;
618 }
619
620 gate_mem_clear(impl, sizeof(gate_ui_webview_impl_t));
621 impl->webview = webview;
622 GetClientRect(hwnd_ctrl, &rect);
623 impl->hwnd = CreateWindow(TEXT("AtlAxWin"), browser_id,
624 WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_HSCROLL | WS_VSCROLL,
625 0, 0, rect.right, rect.bottom,
626 hwnd_ctrl, NULL,
627 (HINSTANCE)GATE_UI_WINAPI_GET_HOST_APPHANDLE(host), NULL);
628 if (impl->hwnd == NULL)
629 {
630 gate_mem_dealloc(impl);
631 impl = NULL;
632 break;
633 }
634
635 impl->webbrowser = (IWebBrowser*)get_control_interface_ptr(impl->hwnd, &IID_IWebBrowser);
636 impl->webbrowser2 = (IWebBrowser2*)get_control_interface_ptr(impl->hwnd, &IID_IWebBrowser2);
637
638 webbrowser_events = (webbrowser_events_t*)gate_mem_alloc(sizeof(webbrowser_events_t));
639 if (NULL != webbrowser_events)
640 {
641 gate_mem_clear(webbrowser_events, sizeof(webbrowser_events_t));
642 webbrowser_events->dispatch.lpVtbl = &webview_disp_vtbl;
643 gate_atomic_int_init(&webbrowser_events->ref_counter, 1);
644 webbrowser_events->webview = webview;
645
646 event_cookie = register_webbrowser_event_dispatcher((IUnknown*)impl->webbrowser, &IID_DWebBrowserEvents2, (IDispatch*)webbrowser_events);
647 if (0 == event_cookie)
648 {
649 event_cookie = register_webbrowser_event_dispatcher((IUnknown*)impl->webbrowser, &IID_DWebBrowserEvents, (IDispatch*)webbrowser_events);
650 }
651 impl->webbrowser_events = (IDispatch*)webbrowser_events;
652 }
653 } while (0);
654
655 return impl;
656 }
657
658 static gate_result_t gate_ui_webview_create_activex(gate_ui_webview_t* webview, gate_ui_ctrl_t* parent,
659 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
660 {
661 gate_result_t ret;
662
663 do
664 {
665 gate_uint32_t styles, exstyles;
666 gate_ui_host_t* host;
667 HWND hwnd_ctrl = NULL;
668 HWND hwnd_parent = NULL;
669 gate_ui_webview_impl_t* impl = NULL;
670
671 ret = load_atl_code();
672 GATE_BREAK_IF_FAILED(ret);
673
674 if (parent == NULL)
675 {
676 ret = GATE_RESULT_NULLPOINTER;
677 break;
678 }
679 host = GATE_UI_WINAPI_GET_HOST(parent);
680 hwnd_parent = GATE_UI_WINAPI_GET_HWND(parent);
681
682 gate_mem_clear(webview, sizeof(gate_ui_webview_t));
683
684 exstyles = 0;
685 #if !defined(GATE_SYS_WINCE)
686 exstyles |= WS_EX_CONTROLPARENT;
687 #endif
688 styles = WS_GROUP | WS_CHILD | WS_TABSTOP | WS_CLIPCHILDREN;
689 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
690 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
691
692 ret = gate_ui_winapi_create(&webview->ctrl, host, hwnd_parent, NULL, position, styles, exstyles, NULL, userparam, false);
693 if (GATE_SUCCEEDED(ret))
694 {
695 GATE_UI_WINAPI_SET_DISPATCHER(&webview->ctrl, &global_webview_dispatchers);
696 hwnd_ctrl = GATE_UI_WINAPI_GET_HWND(&webview->ctrl);
697 impl = create_webbrowser_impl(webview);
698 if (impl == NULL)
699 {
700 gate_ui_winapi_destroy(&webview->ctrl);
701 ret = GATE_RESULT_OUTOFMEMORY;
702 break;
703 }
704 GATE_UI_WINAPI_SET_CTRL_PARAM(&webview->ctrl, impl);
705
706 gate_ui_winapi_register_event(host, (void*)hwnd_ctrl, WM_SIZE, &webview_windowproc_events, &webview->ctrl);
707 }
708 } while (0);
709 return ret;
710 }
711
712 static gate_result_t webbrowser_navigate_to(gate_ui_webview_impl_t* impl, gate_string_t const* address)
713 {
714 gate_result_t ret = GATE_RESULT_FAILED;
715 BSTR bstr_address = NULL;
716 VARIANT var_addr;
717 VARIANT var_empty = GATE_INIT_EMPTY;
718 HRESULT hr;
719
720 do
721 {
722 if (!impl->webbrowser && !impl->webbrowser2)
723 {
724 ret = GATE_RESULT_NOTAVAILABLE;
725 break;
726 }
727 gate_win32_variant_init(&var_empty);
728 bstr_address = gate_win32_bstr_create(address);
729
730 if (impl->webbrowser2)
731 {
732 webbrowser_disable_script_errors(impl);
733
734 var_addr.vt = VT_BSTR;
735 var_addr.bstrVal = bstr_address;
736 hr = impl->webbrowser2->lpVtbl->Navigate2(impl->webbrowser2, &var_addr, NULL, NULL, NULL, NULL);
737 }
738 else
739 {
740 hr = impl->webbrowser->lpVtbl->Navigate(impl->webbrowser, bstr_address, NULL, NULL, NULL, NULL);
741 }
742
743 if (FAILED(hr))
744 {
745 ret = GATE_RESULT_FAILED;
746 break;
747 }
748 ret = GATE_RESULT_OK;
749 } while (0);
750
751 gate_win32_bstr_release(bstr_address);
752 return ret;
753 }
754
755 static gate_result_t webbrowser_execute(gate_ui_webview_impl_t* impl, gate_enumint_t command)
756 {
757 HRESULT hr;
758
759 switch (command)
760 {
761 case GATE_UI_WEBVIEW_COMMAND_STOP:
762 {
763 if (impl->webbrowser2)
764 {
765 hr = impl->webbrowser2->lpVtbl->Stop(impl->webbrowser2);
766 }
767 else
768 {
769 hr = impl->webbrowser->lpVtbl->Stop(impl->webbrowser);
770 }
771 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
772 }
773 case GATE_UI_WEBVIEW_COMMAND_REFRESH:
774 {
775 if (impl->webbrowser2)
776 {
777 hr = impl->webbrowser2->lpVtbl->Refresh(impl->webbrowser2);
778 }
779 else
780 {
781 hr = impl->webbrowser->lpVtbl->Refresh(impl->webbrowser);
782 }
783 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
784 }
785 case GATE_UI_WEBVIEW_COMMAND_GOBACK:
786 {
787 if (impl->webbrowser2)
788 {
789 hr = impl->webbrowser2->lpVtbl->GoBack(impl->webbrowser2);
790 }
791 else
792 {
793 hr = impl->webbrowser->lpVtbl->GoBack(impl->webbrowser);
794 }
795 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
796 }
797 case GATE_UI_WEBVIEW_COMMAND_GONEXT:
798 {
799 if (impl->webbrowser2)
800 {
801 hr = impl->webbrowser2->lpVtbl->GoForward(impl->webbrowser2);
802 }
803 else
804 {
805 hr = impl->webbrowser->lpVtbl->GoForward(impl->webbrowser);
806 }
807 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
808 }
809 case GATE_UI_WEBVIEW_COMMAND_GOHOME:
810 {
811 if (impl->webbrowser2)
812 {
813 hr = impl->webbrowser2->lpVtbl->GoHome(impl->webbrowser2);
814 }
815 else
816 {
817 hr = impl->webbrowser->lpVtbl->GoHome(impl->webbrowser);
818 }
819 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
820 }
821 }
822
823 return GATE_RESULT_NOTSUPPORTED;
824 }
825 #endif /* GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL */
826
827
828
829
830
831 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
832
833 /**********************************/
834 /* */
835 /* EDGE WebView2 implementation */
836 /* */
837 /**********************************/
838
839 #ifndef PM_QS_SENDMESSAGE
840 #define PM_QS_SENDMESSAGE (QS_SENDMESSAGE << 16)
841 #endif
842
843 #ifndef PM_QS_POSTMESSAGE
844 #define PM_QS_POSTMESSAGE ((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16)
845 #endif
846
847 static gate_result_t await_event_and_process_messages(HANDLE waitable, DWORD timeout_ms)
848 {
849 gate_win32_userapi_t const* const userapi = gate_win32_userapi();
850 MSG msg;
851 BOOL b;
852 DWORD result;
853
854 result = WaitForSingleObject(waitable, 0);
855 if (result == WAIT_OBJECT_0)
856 {
857 return GATE_RESULT_OK;
858 }
859
860 for (;;)
861 {
862 gate_mem_clear(&msg, sizeof(msg));
863 b = userapi->UserPeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
864 if (b == TRUE)
865 {
866 /* handle user message */
867 userapi->UserDispatchMessage(&msg);
868 continue;
869 }
870
871 /* wait for user message or even completion */
872 result = userapi->UserMsgWaitForMultipleObjects(1, &waitable, FALSE, timeout_ms, QS_ALLINPUT);
873 if (result == WAIT_TIMEOUT)
874 {
875 return GATE_RESULT_TIMEOUT;
876 }
877 if (result == WAIT_OBJECT_0)
878 {
879 return GATE_RESULT_OK;
880 }
881 if (result != (WAIT_OBJECT_0 + 1))
882 {
883 /* unknown error/state -> cancel loop */
884 break;
885 }
886 }
887 return GATE_RESULT_FAILED;
888 }
889
890
891
892 static gate_result_t wv2_event_init(HANDLE* ptr_waitable)
893 {
894 if (*ptr_waitable == NULL)
895 {
896 *ptr_waitable = CreateSemaphore(NULL, 0, 1, NULL);
897 if (*ptr_waitable == NULL)
898 {
899 return GATE_RESULT_OUTOFRESOURCES;
900 }
901 return GATE_RESULT_OK;
902 }
903 else
904 {
905 //return await_event_and_process_messages(*ptr_waitable, INFINITE);
906 return GATE_RESULT_OK;
907 }
908 }
909 static void wv2_event_notify(HANDLE waitable)
910 {
911 ReleaseSemaphore(waitable, 1, NULL);
912 }
913 static gate_result_t wv2_event_await(HANDLE waitable)
914 {
915 return await_event_and_process_messages(waitable, INFINITE);
916 }
917
918
919 typedef struct wv2_env_completed_class
920 {
921 ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl* lpVtbl;
922
923 ICoreWebView2Environment* env;
924 HANDLE semaphore;
925 } wv2_env_completed_t;
926
927 static HRESULT STDMETHODCALLTYPE wv2_env_completed_QueryInterface(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* This, REFIID riid, void** ppvObject)
928 {
929 wv2_env_completed_t* self = (wv2_env_completed_t*)This;
930 if (ppvObject)
931 {
932 *ppvObject = self;
933 }
934 return S_OK;
935 }
936 static ULONG STDMETHODCALLTYPE wv2_env_completed_AddRef(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* This)
937 {
938 wv2_env_completed_t* self = (wv2_env_completed_t*)This;
939 return 2;
940 }
941 static ULONG STDMETHODCALLTYPE wv2_env_completed_Release(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* This)
942 {
943 wv2_env_completed_t* self = (wv2_env_completed_t*)This;
944 return 1;
945 }
946
947 static HRESULT STDMETHODCALLTYPE wv2_env_completed_Invoke(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* This, HRESULT errorCode, ICoreWebView2Environment* createdEnvironment)
948 {
949 wv2_env_completed_t* self = (wv2_env_completed_t*)This;
950 if (createdEnvironment)
951 {
952 self->env = createdEnvironment;
953 createdEnvironment->lpVtbl->AddRef(createdEnvironment);
954 }
955 wv2_event_notify(self->semaphore);
956 return S_OK;
957 }
958
959 static ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl wv2_env_completed_vtbl = {
960 &wv2_env_completed_QueryInterface,
961 &wv2_env_completed_AddRef,
962 &wv2_env_completed_Release,
963 &wv2_env_completed_Invoke
964 };
965
966 static wv2_env_completed_t wv2_env_completed = {
967 &wv2_env_completed_vtbl,
968 NULL,
969 NULL
970 };
971
972
973
974
975 typedef struct wv2_ctrl_completed_class
976 {
977 ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl* lpVtbl;
978
979 ICoreWebView2Controller* ctrl;
980 HANDLE semaphore;
981 } wv2_ctrl_completed_t;
982
983 static HRESULT STDMETHODCALLTYPE wv2_ctrl_completed_QueryInterface(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler* This, REFIID riid, void** ppvObject)
984 {
985 wv2_ctrl_completed_t* self = (wv2_ctrl_completed_t*)This;
986 if (ppvObject)
987 {
988 *ppvObject = self;
989 }
990 return S_OK;
991 }
992 static ULONG STDMETHODCALLTYPE wv2_ctrl_completed_AddRef(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler* This)
993 {
994 wv2_ctrl_completed_t* self = (wv2_ctrl_completed_t*)This;
995 return 2;
996 }
997 static ULONG STDMETHODCALLTYPE wv2_ctrl_completed_Release(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler* This)
998 {
999 wv2_ctrl_completed_t* self = (wv2_ctrl_completed_t*)This;
1000 return 1;
1001 }
1002
1003 static HRESULT STDMETHODCALLTYPE wv2_ctrl_completed_Invoke(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler* This, HRESULT errorCode, ICoreWebView2Controller* createdController)
1004 {
1005 wv2_ctrl_completed_t* self = (wv2_ctrl_completed_t*)This;
1006 if (createdController)
1007 {
1008 self->ctrl = createdController;
1009 createdController->lpVtbl->AddRef(createdController);
1010 }
1011 wv2_event_notify(self->semaphore);
1012 return S_OK;
1013 }
1014
1015 static ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl wv2_ctrl_completed_vtbl = {
1016 &wv2_ctrl_completed_QueryInterface,
1017 &wv2_ctrl_completed_AddRef,
1018 &wv2_ctrl_completed_Release,
1019 &wv2_ctrl_completed_Invoke
1020 };
1021
1022 static wv2_ctrl_completed_t wv2_ctrl_completed = {
1023 &wv2_ctrl_completed_vtbl,
1024 NULL
1025 };
1026
1027
1028 typedef struct wv2_event_handlers_class
1029 {
1030 IUnknownVtbl* vtblUnkown;
1031
1032 ICoreWebView2NewWindowRequestedEventHandler NewWindowRequested;
1033 EventRegistrationToken tokenNewWindowRequested;
1034
1035 ICoreWebView2NavigationStartingEventHandler NavigationStarting;
1036 EventRegistrationToken tokenNavigationStarting;
1037
1038 ICoreWebView2NavigationCompletedEventHandler NavigationCompleted;
1039 EventRegistrationToken tokenNavigationCompleted;
1040
1041 gate_atomic_int_t ref_counter;
1042 gate_ui_webview_impl_t* impl;
1043
1044 } wv2_event_handlers_t;
1045
1046
1047 static void wv2_event_handlers_attach_events(wv2_event_handlers_t* handlers)
1048 {
1049 HRESULT hr;
1050 ICoreWebView2* wv2 = handlers->impl->wv2;
1051
1052 hr = wv2->lpVtbl->add_NewWindowRequested(wv2, &handlers->NewWindowRequested, &handlers->tokenNewWindowRequested);
1053 hr = wv2->lpVtbl->add_NavigationStarting(wv2, &handlers->NavigationStarting, &handlers->tokenNavigationStarting);
1054 hr = wv2->lpVtbl->add_NavigationCompleted(wv2, &handlers->NavigationCompleted, &handlers->tokenNavigationCompleted);
1055 }
1056
1057
1058 static void wv2_event_handlers_detach_events(wv2_event_handlers_t* handlers)
1059 {
1060 ICoreWebView2* wv2 = NULL;
1061
1062 if (!handlers || !handlers->impl || !handlers->impl->wv2) return;
1063 wv2 = handlers->impl->wv2;
1064
1065 if (handlers->tokenNewWindowRequested.value)
1066 {
1067 wv2->lpVtbl->remove_NewWindowRequested(wv2, handlers->tokenNewWindowRequested);
1068 handlers->tokenNewWindowRequested.value = 0;
1069 }
1070
1071 if (handlers->tokenNavigationStarting.value)
1072 {
1073 wv2->lpVtbl->remove_NavigationStarting(wv2, handlers->tokenNavigationStarting);
1074 handlers->tokenNavigationStarting.value = 0;
1075 }
1076
1077 if (handlers->tokenNavigationCompleted.value)
1078 {
1079 wv2->lpVtbl->remove_NavigationCompleted(wv2, handlers->tokenNavigationCompleted);
1080 handlers->tokenNavigationCompleted.value = 0;
1081 }
1082 }
1083
1084
1085
1086 static ULONG STDMETHODCALLTYPE wv2_event_handlers_AddRef(IUnknown* This)
1087 {
1088 wv2_event_handlers_t* handlers = (wv2_event_handlers_t*)This;
1089 return (ULONG)gate_atomic_int_inc(&handlers->ref_counter);
1090 }
1091
1092 static ULONG STDMETHODCALLTYPE wv2_event_handlers_Release(IUnknown* This)
1093 {
1094 wv2_event_handlers_t* handlers = (wv2_event_handlers_t*)This;
1095 ULONG cnt = (ULONG)gate_atomic_int_dec(&handlers->ref_counter);
1096 if (cnt == 0)
1097 {
1098 wv2_event_handlers_detach_events(handlers);
1099 gate_mem_dealloc(handlers);
1100 }
1101 return cnt;
1102 }
1103 static HRESULT STDMETHODCALLTYPE wv2_event_handlers_QueryInterface(IUnknown* This, REFIID riid, void** ppvObject)
1104 {
1105 wv2_event_handlers_t* handlers = (wv2_event_handlers_t*)This;
1106 if (!ppvObject || !riid || !This)
1107 {
1108 return E_INVALIDARG;
1109 }
1110
1111 if (IsEqualGUID(riid, &gate_IID_IUnknown))
1112 {
1113 *ppvObject = This;
1114 wv2_event_handlers_AddRef(This);
1115 return S_OK;
1116 }
1117 if (IsEqualGUID(riid, &IID_ICoreWebView2NewWindowRequestedEventHandler))
1118 {
1119 *ppvObject = &handlers->NewWindowRequested;
1120 wv2_event_handlers_AddRef(This);
1121 return S_OK;
1122 }
1123 if (IsEqualGUID(riid, &IID_ICoreWebView2NavigationStartingEventHandler))
1124 {
1125 *ppvObject = &handlers->NavigationStarting;
1126 wv2_event_handlers_AddRef(This);
1127 return S_OK;
1128 }
1129 if (IsEqualGUID(riid, &IID_ICoreWebView2NavigationCompletedEventHandler))
1130 {
1131 *ppvObject = &handlers->NavigationCompleted;
1132 wv2_event_handlers_AddRef(This);
1133 return S_OK;
1134 }
1135
1136 return E_NOTIMPL;
1137 }
1138
1139 static IUnknownVtbl IUnknown_wv2_event_handlers_vtbl = {
1140 &wv2_event_handlers_QueryInterface,
1141 &wv2_event_handlers_AddRef,
1142 &wv2_event_handlers_Release
1143 };
1144
1145 #define CREATE_WV2_EVENT_HANDLER_VTBL(event_name, iface_type, sender_type, args_type) \
1146 static HRESULT STDMETHODCALLTYPE event_name ## _QueryInterface ( iface_type * This, REFIID riid, void** ppvObject) \
1147 { \
1148 char* const this_ptr = (char*)This; \
1149 static size_t const obj_pos = offsetof(wv2_event_handlers_t, event_name); \
1150 IUnknown* unk_ptr = (IUnknown*)(this_ptr - obj_pos); \
1151 return wv2_event_handlers_QueryInterface(unk_ptr, riid, ppvObject); \
1152 } \
1153 static ULONG STDMETHODCALLTYPE event_name ## _AddRef ( iface_type * This) \
1154 { \
1155 char* const this_ptr = (char*)This; \
1156 static size_t const obj_pos = offsetof(wv2_event_handlers_t, event_name); \
1157 IUnknown* unk_ptr = (IUnknown*)(this_ptr - obj_pos); \
1158 return wv2_event_handlers_AddRef(unk_ptr); \
1159 } \
1160 static ULONG STDMETHODCALLTYPE event_name ## _Release( iface_type * This) \
1161 { \
1162 char* const this_ptr = (char*)This; \
1163 static size_t const obj_pos = offsetof(wv2_event_handlers_t, event_name); \
1164 IUnknown* unk_ptr = (IUnknown*)(this_ptr - obj_pos); \
1165 return wv2_event_handlers_Release(unk_ptr); \
1166 } \
1167 static HRESULT STDMETHODCALLTYPE event_name ## _Invoke( iface_type * This, sender_type sender, args_type args) \
1168 { \
1169 char* const this_ptr = (char*)This; \
1170 static size_t const obj_pos = offsetof(wv2_event_handlers_t, event_name); \
1171 wv2_event_handlers_t* evt_handlers_ptr = (wv2_event_handlers_t*)(this_ptr - obj_pos); \
1172 return event_name ## _wv2_callback (evt_handlers_ptr, sender, args); \
1173 } \
1174 static iface_type ## Vtbl event_name ## _wv2_event_handlers_vtbl = { \
1175 & event_name ## _QueryInterface, \
1176 & event_name ## _AddRef, \
1177 & event_name ## _Release, \
1178 & event_name ## _Invoke \
1179 }
1180
1181
1182
1183 typedef struct NewWindowRequested_task_class
1184 {
1185 GATE_INTERFACE_VTBL(gate_runnable) const* vtbl;
1186
1187 gate_atomic_int_t ref_counter;
1188 ICoreWebView2NewWindowRequestedEventArgs* args;
1189 ICoreWebView2Deferral* deferral;
1190 gate_ui_webview_t* webview;
1191 } NewWindowRequested_task_t;
1192
1193 static char const* NewWindowRequested_task_get_interface_name(void* ptr)
1194 {
1195 return GATE_INTERFACE_NAME_RUNNABLE;
1196 }
1197 static void NewWindowRequested_task_release(void* ptr)
1198 {
1199 NewWindowRequested_task_t* self = (NewWindowRequested_task_t*)ptr;
1200 if (0 == gate_atomic_int_dec(&self->ref_counter))
1201 {
1202 self->deferral->lpVtbl->Release(self->deferral);
1203 self->args->lpVtbl->Release(self->args);
1204 }
1205 }
1206 static int NewWindowRequested_task_retain(void* ptr)
1207 {
1208 NewWindowRequested_task_t* self = (NewWindowRequested_task_t*)ptr;
1209 return (int)gate_atomic_int_inc(&self->ref_counter);
1210 }
1211 static gate_result_t NewWindowRequested_task_run(void* ptr)
1212 {
1213 NewWindowRequested_task_t* self = (NewWindowRequested_task_t*)ptr;
1214 gate_ui_webview_t* ptr_new_webview = NULL;
1215
1216 self->webview->on_new_window(&self->webview->ctrl, &ptr_new_webview);
1217 if (ptr_new_webview)
1218 {
1219 gate_ui_webview_impl_t* impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(&ptr_new_webview->ctrl);
1220 self->args->lpVtbl->put_Handled(self->args, TRUE);
1221 self->args->lpVtbl->put_NewWindow(self->args, impl->wv2);
1222 }
1223 self->deferral->lpVtbl->Complete(self->deferral);
1224 return GATE_RESULT_OK;
1225 }
1226 GATE_INTERFACE_VTBL(gate_runnable) const NewWindowRequested_task_vtbl = {
1227 &NewWindowRequested_task_get_interface_name,
1228 &NewWindowRequested_task_release,
1229 &NewWindowRequested_task_retain,
1230 &NewWindowRequested_task_run
1231 };
1232
1233 static HRESULT NewWindowRequested_wv2_callback(wv2_event_handlers_t* handlers, ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args)
1234 {
1235 gate_ui_webview_t* ptr_new_webview = NULL;
1236 ICoreWebView2Deferral* deferral = NULL;
1237 gate_ui_host_t* host = NULL;
1238 NewWindowRequested_task_t* task = NULL;
1239 HRESULT hr;
1240
1241 if (handlers && handlers->impl && handlers->impl->webview && handlers->impl->webview->on_new_window)
1242 {
1243 host = GATE_UI_WINAPI_GET_HOST(&handlers->impl->webview->ctrl);
1244 // gate_ui_host_execute(host, gate_runnable_create)
1245 hr = args->lpVtbl->GetDeferral(args, &deferral);
1246 if (SUCCEEDED(hr))
1247 {
1248 NewWindowRequested_task_t* task = gate_mem_alloc(sizeof(NewWindowRequested_task_t));
1249 if (!task)
1250 {
1251 deferral->lpVtbl->Release(deferral);
1252 }
1253 else
1254 {
1255 gate_mem_clear(task, sizeof(NewWindowRequested_task_t));
1256 task->vtbl = &NewWindowRequested_task_vtbl;
1257 gate_atomic_int_init(&task->ref_counter, 1);
1258 task->args = args;
1259 task->deferral = deferral;
1260 task->args->lpVtbl->AddRef(task->args);
1261 task->deferral->lpVtbl->AddRef(task->deferral);
1262 task->webview = handlers->impl->webview;
1263 gate_ui_winapi_host_post_runner(host, (gate_runnable_t*)task, true, false);
1264 task = NULL;
1265 }
1266 }
1267 }
1268 if (task)
1269 {
1270 gate_object_release(task);
1271 }
1272 return S_OK;
1273 }
1274 CREATE_WV2_EVENT_HANDLER_VTBL(NewWindowRequested, ICoreWebView2NewWindowRequestedEventHandler, ICoreWebView2*, ICoreWebView2NewWindowRequestedEventArgs*);
1275
1276
1277 static HRESULT NavigationStarting_wv2_callback(wv2_event_handlers_t* handlers, ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args)
1278 {
1279 return S_OK;
1280 }
1281 CREATE_WV2_EVENT_HANDLER_VTBL(NavigationStarting, ICoreWebView2NavigationStartingEventHandler, ICoreWebView2*, ICoreWebView2NavigationStartingEventArgs*);
1282
1283
1284 static HRESULT NavigationCompleted_wv2_callback(wv2_event_handlers_t* handlers, ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args)
1285 {
1286 LPWSTR wstrUrl = NULL;
1287 HRESULT hr;
1288 gate_string_t url = GATE_STRING_INIT_EMPTY;
1289
1290 if (handlers && handlers->impl && handlers->impl->webview && handlers->impl->webview->on_navigate_complete)
1291 {
1292 hr = sender->lpVtbl->get_Source(sender, &wstrUrl);
1293 if (SUCCEEDED(hr))
1294 {
1295 gate_string_create_utf16(&url, wstrUrl, gate_str16_length(wstrUrl));
1296 }
1297 handlers->impl->webview->on_navigate_complete(&handlers->impl->webview->ctrl, &url);
1298 }
1299 gate_string_release(&url);
1300 if (wstrUrl)
1301 {
1302 // CoTaskMemFree needs to free the URL
1303 gate_win32_com_dealloc(wstrUrl);
1304 }
1305 return S_OK;
1306 }
1307 CREATE_WV2_EVENT_HANDLER_VTBL(NavigationCompleted, ICoreWebView2NavigationCompletedEventHandler, ICoreWebView2*, ICoreWebView2NavigationCompletedEventArgs*);
1308
1309
1310
1311
1312 static wv2_event_handlers_t* create_webview2_event_handlers(gate_ui_webview_impl_t* impl)
1313 {
1314 wv2_event_handlers_t* handlers = NULL;
1315 do
1316 {
1317 handlers = (wv2_event_handlers_t*)gate_mem_alloc(sizeof(wv2_event_handlers_t));
1318 if (NULL == handlers)
1319 {
1320 break;
1321 }
1322 gate_mem_clear(handlers, sizeof(wv2_event_handlers_t));
1323 gate_atomic_int_init(&handlers->ref_counter, 1);
1324
1325 handlers->impl = impl;
1326 handlers->vtblUnkown = &IUnknown_wv2_event_handlers_vtbl;
1327 handlers->NewWindowRequested.lpVtbl = &NewWindowRequested_wv2_event_handlers_vtbl;
1328 handlers->NavigationStarting.lpVtbl = &NavigationStarting_wv2_event_handlers_vtbl;
1329 handlers->NavigationCompleted.lpVtbl = &NavigationCompleted_wv2_event_handlers_vtbl;
1330
1331 wv2_event_handlers_attach_events(handlers);
1332 } while (0);
1333 return handlers;
1334
1335 }
1336
1337 static gate_ui_webview_impl_t* create_webview2_impl(gate_ui_webview_t* webview, ICoreWebView2Controller* controller)
1338 {
1339 gate_ui_webview_impl_t* impl = NULL;
1340 wv2_event_handlers_t* handlers = NULL;
1341 HRESULT hr;
1342
1343 do
1344 {
1345 impl = (gate_ui_webview_impl_t*)gate_mem_alloc(sizeof(gate_ui_webview_impl_t));
1346 if (!impl)
1347 {
1348 break;
1349 }
1350
1351 gate_mem_clear(impl, sizeof(gate_ui_webview_impl_t));
1352 impl->webview = webview;
1353 impl->wv2_controller = controller;
1354 hr = impl->wv2_controller->lpVtbl->get_CoreWebView2(impl->wv2_controller, &impl->wv2);
1355 if (FAILED(hr))
1356 {
1357 gate_mem_dealloc(impl);
1358 impl = NULL;
1359 break;
1360 }
1361 handlers = create_webview2_event_handlers(impl);
1362 if (!handlers)
1363 {
1364 gate_mem_dealloc(impl);
1365 impl = NULL;
1366 break;
1367 }
1368 impl->wv2_event_handlers = (IUnknown*)handlers;
1369
1370 hr = impl->wv2_controller->lpVtbl->put_IsVisible(impl->wv2_controller, TRUE);
1371
1372 } while (0);
1373
1374 return impl;
1375 }
1376
1377
1378 static gate_result_t gate_ui_webview_create_wv2(gate_ui_webview_t* webview, gate_ui_ctrl_t* parent,
1379 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
1380 {
1381 gate_result_t ret;
1382 HRESULT hr;
1383 HWND hwnd_parent = NULL;
1384 HWND hwnd_ctrl = NULL;
1385 gate_ui_host_t* host = NULL;
1386 gate_uint32_t exstyles = 0;
1387 gate_uint32_t styles = 0;
1388 gate_ui_webview_impl_t* impl = NULL;
1389 ICoreWebView2Controller* controller = NULL;
1390 static ICoreWebView2Environment* global_wv2_environment = NULL;
1391
1392 host = GATE_UI_WINAPI_GET_HOST(parent);
1393 hwnd_parent = GATE_UI_WINAPI_GET_HWND(parent);
1394
1395 do
1396 {
1397 ret = gate_win32_com_init();
1398
1399 ret = load_webview2();
1400 GATE_BREAK_IF_FAILED(ret);
1401
1402 if (global_wv2_environment == NULL)
1403 {
1404 ret = wv2_event_init(&wv2_env_completed.semaphore);
1405 GATE_BREAK_IF_FAILED(ret);
1406
1407 wv2_env_completed.env = NULL;
1408 hr = webview2_loader.CreateCoreWebView2EnvironmentWithOptions(NULL, NULL, NULL, (ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler*)&wv2_env_completed);
1409
1410 wv2_event_await(wv2_env_completed.semaphore);
1411 if (!wv2_env_completed.env)
1412 {
1413 break;
1414 }
1415 global_wv2_environment = wv2_env_completed.env;
1416 }
1417
1418 exstyles = 0;
1419 #if !defined(GATE_SYS_WINCE)
1420 exstyles |= WS_EX_CONTROLPARENT;
1421 #endif
1422 styles = WS_GROUP | WS_CHILD | WS_TABSTOP | WS_CLIPCHILDREN;
1423 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
1424 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
1425
1426 ret = gate_ui_winapi_create(&webview->ctrl, host, hwnd_parent, NULL, position, styles, exstyles, NULL, userparam, false);
1427 GATE_BREAK_IF_FAILED(ret);
1428
1429 GATE_UI_WINAPI_SET_DISPATCHER(&webview->ctrl, &global_webview_dispatchers);
1430 hwnd_ctrl = GATE_UI_WINAPI_GET_HWND(&webview->ctrl);
1431
1432 ret = wv2_event_init(&wv2_ctrl_completed.semaphore);
1433 GATE_BREAK_IF_FAILED(ret);
1434
1435 wv2_ctrl_completed.ctrl = NULL;
1436 hr = global_wv2_environment->lpVtbl->CreateCoreWebView2Controller(global_wv2_environment, hwnd_ctrl, (ICoreWebView2CreateCoreWebView2ControllerCompletedHandler*)&wv2_ctrl_completed);
1437
1438 ret = wv2_event_await(wv2_ctrl_completed.semaphore);
1439 if (!wv2_ctrl_completed.ctrl)
1440 {
1441 ret = GATE_RESULT_NOTAVAILABLE;
1442 break;
1443 }
1444 controller = wv2_ctrl_completed.ctrl;
1445 wv2_ctrl_completed.ctrl = NULL;
1446
1447 impl = create_webview2_impl(webview, controller);
1448 if (impl == NULL)
1449 {
1450 ret = GATE_RESULT_OUTOFMEMORY;
1451 break;
1452 }
1453 GATE_UI_WINAPI_SET_CTRL_PARAM(&webview->ctrl, impl);
1454
1455 gate_ui_winapi_register_event(host, (void*)hwnd_ctrl, WM_SIZE, &webview_windowproc_events, &webview->ctrl);
1456
1457 ret = GATE_RESULT_OK;
1458 } while (0);
1459
1460 if (GATE_FAILED(ret))
1461 {
1462 if (controller)
1463 {
1464 controller->lpVtbl->Release(controller);
1465 }
1466 if (hwnd_ctrl)
1467 {
1468 gate_ui_winapi_destroy(&webview->ctrl);
1469 }
1470 if (impl != NULL)
1471 {
1472 }
1473 }
1474
1475 return ret;
1476 }
1477
1478 static gate_result_t wv2_navigate_to(gate_ui_webview_impl_t* impl, gate_string_t const* address)
1479 {
1480 gate_result_t ret = GATE_RESULT_FAILED;
1481 gate_cstrbuffer16_t buffer = GATE_INIT_EMPTY;
1482 HRESULT hr;
1483
1484 do
1485 {
1486 if (NULL == gate_cstrbuffer16_create_string(&buffer, address))
1487 {
1488 ret = GATE_RESULT_OUTOFMEMORY;
1489 break;
1490 }
1491 hr = impl->wv2->lpVtbl->Navigate(impl->wv2, gate_cstrbuffer16_get(&buffer));
1492 if (FAILED(hr))
1493 {
1494 ret = GATE_RESULT_FAILED;
1495 break;
1496 }
1497
1498 ret = GATE_RESULT_OK;
1499 } while (0);
1500
1501 gate_cstrbuffer16_destroy(&buffer);
1502 return ret;
1503 }
1504
1505 static gate_result_t wv2_execute(gate_ui_webview_impl_t* impl, gate_enumint_t command)
1506 {
1507 HRESULT hr;
1508
1509 switch (command)
1510 {
1511 case GATE_UI_WEBVIEW_COMMAND_STOP:
1512 {
1513 hr = impl->wv2->lpVtbl->Stop(impl->wv2);
1514 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
1515 }
1516 case GATE_UI_WEBVIEW_COMMAND_REFRESH:
1517 {
1518 hr = impl->wv2->lpVtbl->Reload(impl->wv2);
1519 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
1520 }
1521 case GATE_UI_WEBVIEW_COMMAND_GOHOME:
1522 {
1523 break;
1524 }
1525 case GATE_UI_WEBVIEW_COMMAND_GOBACK:
1526 {
1527 hr = impl->wv2->lpVtbl->GoBack(impl->wv2);
1528 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
1529 }
1530 case GATE_UI_WEBVIEW_COMMAND_GONEXT:
1531 {
1532 hr = impl->wv2->lpVtbl->GoForward(impl->wv2);
1533 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
1534 }
1535 }
1536 return GATE_RESULT_NOTSUPPORTED;
1537 }
1538 #endif /* GATE_UI_WEBVIEW_EDGEWV2_IMPL */
1539
1540
1541
1542
1543
1544 /*******************************/
1545 /* */
1546 /* GATE webview control code: */
1547 /* */
1548 /*******************************/
1549
1550
1551 static gate_result_t webview_destroy_impl(gate_ui_ctrl_t* ctrl)
1552 {
1553 gate_ui_webview_impl_t* impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(ctrl);
1554
1555 GATE_UI_WINAPI_SET_CTRL_PARAM(ctrl, NULL);
1556
1557 if (impl != NULL)
1558 {
1559 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
1560
1561 if (impl->wv2_event_handlers)
1562 {
1563 wv2_event_handlers_t* wv2_handlers = (wv2_event_handlers_t*)impl->wv2_event_handlers;
1564 wv2_event_handlers_detach_events(wv2_handlers);
1565 impl->wv2_event_handlers->lpVtbl->Release(impl->wv2_event_handlers);
1566 impl->wv2_event_handlers = NULL;
1567 }
1568 if (impl->wv2)
1569 {
1570 impl->wv2->lpVtbl->Release(impl->wv2);
1571 impl->wv2 = NULL;
1572 }
1573 if (impl->wv2_controller)
1574 {
1575 impl->wv2_controller->lpVtbl->Close(impl->wv2_controller);
1576 impl->wv2_controller->lpVtbl->Release(impl->wv2_controller);
1577 impl->wv2_controller = NULL;
1578 }
1579 #endif
1580
1581 #ifdef GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL
1582 if (impl->webbrowser2)
1583 {
1584 impl->webbrowser2->lpVtbl->Release(impl->webbrowser2);
1585 impl->webbrowser2 = NULL;
1586 }
1587
1588 if (impl->webbrowser)
1589 {
1590 impl->webbrowser->lpVtbl->Release(impl->webbrowser);
1591 impl->webbrowser = NULL;
1592 }
1593 if (impl->webbrowser_events)
1594 {
1595 impl->webbrowser_events->lpVtbl->Release(impl->webbrowser_events);
1596 impl->webbrowser_events = NULL;
1597 }
1598 #endif
1599
1600 impl->webview = NULL;
1601 if (impl->hwnd)
1602 {
1603 DestroyWindow(impl->hwnd);
1604 impl->hwnd = NULL;
1605 }
1606 gate_mem_dealloc(impl);
1607 }
1608 return gate_ui_winapi_destroy(ctrl);
1609 }
1610
1611
1612 static gate_bool_t webview_windowproc_events(void* hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult)
1613 {
1614 HWND hwndctrl;
1615 gate_ui_webview_impl_t* impl = NULL;
1616 RECT rect;
1617
1618 if (!ctrl)
1619 {
1620 return false;
1621 }
1622
1623 hwndctrl = GATE_UI_WINAPI_GET_HWND(ctrl);
1624 impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(ctrl);
1625 if (!hwndctrl || !impl || (hwndctrl != hwnd))
1626 {
1627 return false;
1628 }
1629
1630 switch (msg)
1631 {
1632 case WM_SIZE:
1633 {
1634 GetClientRect(hwndctrl, &rect);
1635
1636 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
1637 if (impl->wv2_controller)
1638 {
1639 impl->wv2_controller->lpVtbl->put_Bounds(impl->wv2_controller, rect);
1640 }
1641 #endif
1642
1643 if (impl->hwnd)
1644 {
1645 SetWindowPos(impl->hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1646 SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1647 *lresult = 0;
1648 return true;
1649 }
1650 break;
1651 }
1652 }
1653 return false;
1654 }
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666 gate_result_t gate_ui_webview_create(gate_ui_webview_t* webview, gate_ui_ctrl_t* parent,
1667 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
1668 {
1669 gate_result_t ret = GATE_RESULT_FAILED;
1670 do
1671 {
1672
1673 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
1674 ret = gate_ui_webview_create_wv2(webview, parent, position, flags, userparam);
1675 if (GATE_SUCCEEDED(ret))
1676 {
1677 break;
1678 }
1679 #endif
1680
1681 #ifdef GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL
1682 ret = gate_ui_webview_create_activex(webview, parent, position, flags, userparam);
1683 if (GATE_SUCCEEDED(ret))
1684 {
1685 break;
1686 }
1687 #endif
1688
1689 } while (0);
1690 return ret;
1691 }
1692
1693
1694
1695
1696 gate_result_t gate_ui_webview_navigate_to(gate_ui_webview_t* webview, gate_string_t const* address)
1697 {
1698 gate_result_t ret = GATE_RESULT_FAILED;
1699 gate_ui_webview_impl_t* impl = NULL;
1700
1701 if (webview)
1702 {
1703 impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(&webview->ctrl);
1704 }
1705
1706 do
1707 {
1708 if (!impl)
1709 {
1710 ret = GATE_RESULT_NOTAVAILABLE;
1711 break;
1712 }
1713
1714 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
1715 if (impl->wv2)
1716 {
1717 ret = wv2_navigate_to(impl, address);
1718 break;
1719 }
1720 #endif
1721
1722 #ifdef GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL
1723 if (impl->webbrowser || impl->webbrowser2)
1724 {
1725 ret = webbrowser_navigate_to(impl, address);
1726 break;
1727 }
1728 #endif
1729
1730 } while (0);
1731
1732 return ret;
1733 }
1734
1735
1736
1737
1738 gate_result_t gate_ui_webview_execute(gate_ui_webview_t* webview, gate_enumint_t command)
1739 {
1740 gate_result_t ret = GATE_RESULT_FAILED;
1741 gate_ui_webview_impl_t* impl = NULL;
1742
1743 do
1744 {
1745 if (webview)
1746 {
1747 impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(&webview->ctrl);
1748 }
1749 if (!impl)
1750 {
1751 ret = GATE_RESULT_NOTAVAILABLE;
1752 break;
1753 }
1754
1755 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
1756 if (impl->wv2)
1757 {
1758 ret = wv2_execute(impl, command);
1759 break;
1760 }
1761 #endif
1762
1763 #ifdef GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL
1764 if (impl->webbrowser || impl->webbrowser2)
1765 {
1766 ret = webbrowser_execute(impl, command);
1767 break;
1768 }
1769 #endif
1770
1771 } while (0);
1772
1773 return ret;
1774 }
1775
1776 #endif /* GATE_UI_WEBVIEW_WINAPI_IMPL */
1777
1778
1779
1780
1781 #if defined(GATE_UI_WEBVIEW_GTK_IMPL)
1782
1783 #include <webkit2/webkit2.h>
1784 #include "gate/ui/gateui_gtk.h"
1785
1786
1787 static void callback_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event, gpointer user_data)
1788 {
1789 GtkWidget* const widget = (GtkWidget*)web_view;
1790 gate_ui_webview_t* const ctrl = (gate_ui_webview_t*)user_data;
1791 gchar const* uri = webkit_web_view_get_uri (web_view);
1792
1793
1794 if (ctrl && uri)
1795 {
1796 gate_string_t url = GATE_STRING_INIT_EMPTY;
1797
1798 if (NULL == gate_string_create(&url, uri, gate_str_length(uri)))
1799 {
1800 return;
1801 }
1802 switch (load_event)
1803 {
1804 case WEBKIT_LOAD_STARTED:
1805 {
1806 gate_bool_t cancel = false;
1807 if (ctrl->on_navigate_start)
1808 {
1809 ctrl->on_navigate_start(&ctrl->ctrl, &url, &cancel);
1810 }
1811 break;
1812 }
1813 case WEBKIT_LOAD_REDIRECTED:
1814 {
1815 break;
1816 }
1817 case WEBKIT_LOAD_COMMITTED:
1818 {
1819 break;
1820 }
1821 case WEBKIT_LOAD_FINISHED:
1822 {
1823 if (ctrl->on_navigate_complete)
1824 {
1825 ctrl->on_navigate_complete(&ctrl->ctrl, &url);
1826 }
1827 break;
1828 }
1829 }
1830 gate_string_release(&url);
1831 }
1832 }
1833
1834 static GtkWidget* callback_create(WebKitWebView* web_view, WebKitNavigationAction* navigation_action, gpointer user_data)
1835 {
1836 GtkWidget* ret_new_widget = NULL;
1837 /* GtkWidget* const widget = (GtkWidget*)web_view; */
1838 gate_ui_webview_t* new_webview = NULL;
1839 gate_ui_webview_t* const ctrl = (gate_ui_webview_t*)user_data;
1840
1841 if (ctrl->on_new_window)
1842 {
1843 ctrl->on_new_window(&ctrl->ctrl, &new_webview);
1844 if (new_webview)
1845 {
1846 ret_new_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&new_webview->ctrl);
1847 }
1848 }
1849 return ret_new_widget;
1850 }
1851
1852 static void callback_ready_to_show(WebKitWebView* web_view, gpointer user_data)
1853 {
1854 /* GtkWidget* const widget = (GtkWidget*)web_view; */
1855 gate_ui_webview_t* const ctrl = (gate_ui_webview_t*)user_data;
1856 gchar const* title_chars = webkit_web_view_get_title(web_view);
1857 gate_string_t title = GATE_STRING_INIT_EMPTY;
1858 if (NULL == gate_string_create(&title, title_chars, gate_str_length(title_chars)))
1859 {
1860 return;
1861 }
1862 if (ctrl->on_title_text_changed)
1863 {
1864 ctrl->on_title_text_changed(&ctrl->ctrl, &title);
1865 }
1866 gate_string_release(&title);
1867 }
1868
1869 static gate_ui_gtk_dispatcher_t gate_ui_gtk_webview_dispatcher =
1870 {
1871 NULL,
1872 NULL,
1873 NULL,
1874 NULL,
1875 NULL,
1876 NULL
1877 };
1878
1879
1880
1881 gate_result_t gate_ui_webview_create(gate_ui_webview_t* webview, gate_ui_ctrl_t* parent,
1882 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
1883 {
1884 gate_result_t ret = GATE_RESULT_OK;
1885 GtkWidget* widget;
1886 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
1887
1888 gate_mem_clear(webview, sizeof(gate_ui_webview_t));
1889 widget = webkit_web_view_new();
1890 if (widget == NULL)
1891 {
1892 return GATE_RESULT_FAILED;
1893 }
1894
1895 ret = gate_ui_gtk_ctrl_init(&webview->ctrl, widget, host, userparam, parent,
1896 &gate_ui_gtk_webview_dispatcher, false, false, position, &flags);
1897
1898 if (GATE_SUCCEEDED(ret))
1899 {
1900 g_signal_connect(G_OBJECT(widget), "load-changed", G_CALLBACK(callback_load_changed), (gpointer)webview);
1901 g_signal_connect(G_OBJECT(widget), "create", G_CALLBACK(callback_create), (gpointer)webview);
1902 g_signal_connect(G_OBJECT(widget), "ready-to-show", G_CALLBACK(callback_ready_to_show), (gpointer)webview);
1903 }
1904
1905 return ret;
1906 }
1907
1908 gate_result_t gate_ui_webview_navigate_to(gate_ui_webview_t* webview, gate_string_t const* address)
1909 {
1910 gate_result_t ret = GATE_RESULT_FAILED;
1911 gate_cstrbuffer_t uri_buffer = GATE_INIT_EMPTY;
1912 do
1913 {
1914 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&webview->ctrl);
1915 WebKitWebView* wv = WEBKIT_WEB_VIEW(widget);
1916
1917 if (!wv)
1918 {
1919 ret = GATE_RESULT_INVALIDCONTENT;
1920 break;
1921 }
1922
1923 if (NULL == gate_cstrbuffer_create_string(&uri_buffer, address, false))
1924 {
1925 ret = GATE_RESULT_OUTOFMEMORY;
1926 break;
1927 }
1928 webkit_web_view_load_uri(wv, gate_cstrbuffer_get(&uri_buffer));
1929 ret = GATE_RESULT_OK;
1930 } while (0);
1931
1932 gate_cstrbuffer_destroy(&uri_buffer);
1933 return ret;
1934 }
1935
1936 gate_result_t gate_ui_webview_execute(gate_ui_webview_t* webview, gate_enumint_t command)
1937 {
1938 return GATE_RESULT_NOTIMPLEMENTED;
1939 }
1940
1941 #endif /* GATE_UI_WEBVIEW_GTK_IMPL */
1942
1943
1944
1945 #if defined(GATE_UI_WEBVIEW_NO_IMPL)
1946
1947 gate_result_t gate_ui_webview_create(gate_ui_webview_t* webview, gate_ui_ctrl_t* parent,
1948 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
1949 {
1950 return GATE_RESULT_NOTIMPLEMENTED;
1951 }
1952
1953 gate_result_t gate_ui_webview_navigate_to(gate_ui_webview_t* webview, gate_string_t const* address)
1954 {
1955 return GATE_RESULT_NOTIMPLEMENTED;
1956 }
1957
1958 gate_result_t gate_ui_webview_execute(gate_ui_webview_t* webview, gate_enumint_t command)
1959 {
1960 return GATE_RESULT_NOTIMPLEMENTED;
1961 }
1962
1963
1964 #endif /* GATE_UI_WEBVIEW_NO_IMPL */
1965
1966