GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/webviews.c
Date: 2026-03-20 22:56:14
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 static gate_string_t active_x_progid = { "SHDocVwCtl.WebBrowser", 21, NULL };
662 //static gate_string_t active_x_progid = { "Shell.Explorer.2", 16, NULL };
663 //static gate_string_t active_x_progid = { "MsRDP.MsRDP.2", 13, NULL };
664 gate_result_t ret = GATE_RESULT_FAILED;
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 do
672 {
673 ret = load_atl_code();
674 GATE_BREAK_IF_FAILED(ret);
675
676 if (parent == NULL)
677 {
678 ret = GATE_RESULT_NULLPOINTER;
679 break;
680 }
681 host = GATE_UI_WINAPI_GET_HOST(parent);
682 hwnd_parent = GATE_UI_WINAPI_GET_HWND(parent);
683
684 gate_mem_clear(webview, sizeof(gate_ui_webview_t));
685
686 exstyles = 0;
687 #if !defined(GATE_SYS_WINCE)
688 exstyles |= WS_EX_CONTROLPARENT;
689 #endif
690 styles = WS_GROUP | WS_CHILD | WS_TABSTOP | WS_CLIPCHILDREN;
691 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
692 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
693
694 ret = gate_ui_winapi_create(&webview->ctrl, host, hwnd_parent, NULL, position, styles, exstyles, NULL, userparam, false);
695 if (GATE_SUCCEEDED(ret))
696 {
697 GATE_UI_WINAPI_SET_DISPATCHER(&webview->ctrl, &global_webview_dispatchers);
698 hwnd_ctrl = GATE_UI_WINAPI_GET_HWND(&webview->ctrl);
699 impl = create_webbrowser_impl(webview);
700 if (impl == NULL)
701 {
702 gate_ui_winapi_destroy(&webview->ctrl);
703 ret = GATE_RESULT_OUTOFMEMORY;
704 break;
705 }
706 GATE_UI_WINAPI_SET_CTRL_PARAM(&webview->ctrl, impl);
707
708 gate_ui_winapi_register_event(host, (void*)hwnd_ctrl, WM_SIZE, &webview_windowproc_events, &webview->ctrl);
709 }
710 } while (0);
711 return ret;
712 }
713
714 static gate_result_t webbrowser_navigate_to(gate_ui_webview_impl_t* impl, gate_string_t const* address)
715 {
716 gate_result_t ret = GATE_RESULT_FAILED;
717 BSTR bstr_address = NULL;
718 VARIANT var_addr;
719 VARIANT var_empty = GATE_INIT_EMPTY;
720 HRESULT hr;
721
722 do
723 {
724 if (!impl->webbrowser && !impl->webbrowser2)
725 {
726 ret = GATE_RESULT_NOTAVAILABLE;
727 break;
728 }
729 gate_win32_variant_init(&var_empty);
730 bstr_address = gate_win32_bstr_create(address);
731
732 if (impl->webbrowser2)
733 {
734 webbrowser_disable_script_errors(impl);
735
736 var_addr.vt = VT_BSTR;
737 var_addr.bstrVal = bstr_address;
738 hr = impl->webbrowser2->lpVtbl->Navigate2(impl->webbrowser2, &var_addr, NULL, NULL, NULL, NULL);
739 }
740 else
741 {
742 hr = impl->webbrowser->lpVtbl->Navigate(impl->webbrowser, bstr_address, NULL, NULL, NULL, NULL);
743 }
744
745 if (FAILED(hr))
746 {
747 ret = GATE_RESULT_FAILED;
748 break;
749 }
750 ret = GATE_RESULT_OK;
751 } while (0);
752
753 gate_win32_bstr_release(bstr_address);
754 return ret;
755 }
756
757 static gate_result_t webbrowser_execute(gate_ui_webview_impl_t* impl, gate_enumint_t command)
758 {
759 HRESULT hr;
760
761 switch (command)
762 {
763 case GATE_UI_WEBVIEW_COMMAND_STOP:
764 {
765 if (impl->webbrowser2)
766 {
767 hr = impl->webbrowser2->lpVtbl->Stop(impl->webbrowser2);
768 }
769 else
770 {
771 hr = impl->webbrowser->lpVtbl->Stop(impl->webbrowser);
772 }
773 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
774 }
775 case GATE_UI_WEBVIEW_COMMAND_REFRESH:
776 {
777 if (impl->webbrowser2)
778 {
779 hr = impl->webbrowser2->lpVtbl->Refresh(impl->webbrowser2);
780 }
781 else
782 {
783 hr = impl->webbrowser->lpVtbl->Refresh(impl->webbrowser);
784 }
785 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
786 }
787 case GATE_UI_WEBVIEW_COMMAND_GOBACK:
788 {
789 if (impl->webbrowser2)
790 {
791 hr = impl->webbrowser2->lpVtbl->GoBack(impl->webbrowser2);
792 }
793 else
794 {
795 hr = impl->webbrowser->lpVtbl->GoBack(impl->webbrowser);
796 }
797 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
798 }
799 case GATE_UI_WEBVIEW_COMMAND_GONEXT:
800 {
801 if (impl->webbrowser2)
802 {
803 hr = impl->webbrowser2->lpVtbl->GoForward(impl->webbrowser2);
804 }
805 else
806 {
807 hr = impl->webbrowser->lpVtbl->GoForward(impl->webbrowser);
808 }
809 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
810 }
811 case GATE_UI_WEBVIEW_COMMAND_GOHOME:
812 {
813 if (impl->webbrowser2)
814 {
815 hr = impl->webbrowser2->lpVtbl->GoHome(impl->webbrowser2);
816 }
817 else
818 {
819 hr = impl->webbrowser->lpVtbl->GoHome(impl->webbrowser);
820 }
821 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
822 }
823 }
824
825 return GATE_RESULT_NOTSUPPORTED;
826 }
827 #endif /* GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL */
828
829
830
831
832
833 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
834
835 /**********************************/
836 /* */
837 /* EDGE WebView2 implementation */
838 /* */
839 /**********************************/
840
841 #ifndef PM_QS_SENDMESSAGE
842 #define PM_QS_SENDMESSAGE (QS_SENDMESSAGE << 16)
843 #endif
844
845 #ifndef PM_QS_POSTMESSAGE
846 #define PM_QS_POSTMESSAGE ((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16)
847 #endif
848
849 static gate_result_t await_event_and_process_messages(HANDLE waitable, DWORD timeout_ms)
850 {
851 gate_win32_userapi_t const* const userapi = gate_win32_userapi();
852 MSG msg;
853 BOOL b;
854 DWORD result;
855
856 result = WaitForSingleObject(waitable, 0);
857 if (result == WAIT_OBJECT_0)
858 {
859 return GATE_RESULT_OK;
860 }
861
862 for (;;)
863 {
864 gate_mem_clear(&msg, sizeof(msg));
865 b = userapi->UserPeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
866 if (b == TRUE)
867 {
868 /* handle user message */
869 userapi->UserDispatchMessage(&msg);
870 continue;
871 }
872
873 /* wait for user message or even completion */
874 result = userapi->UserMsgWaitForMultipleObjects(1, &waitable, FALSE, timeout_ms, QS_ALLINPUT);
875 if (result == WAIT_TIMEOUT)
876 {
877 return GATE_RESULT_TIMEOUT;
878 }
879 if (result == WAIT_OBJECT_0)
880 {
881 return GATE_RESULT_OK;
882 }
883 if (result != (WAIT_OBJECT_0 + 1))
884 {
885 /* unknown error/state -> cancel loop */
886 break;
887 }
888 }
889 return GATE_RESULT_FAILED;
890 }
891
892
893
894 static gate_result_t wv2_event_init(HANDLE* ptr_waitable)
895 {
896 if (*ptr_waitable == NULL)
897 {
898 *ptr_waitable = CreateSemaphore(NULL, 0, 1, NULL);
899 if (*ptr_waitable == NULL)
900 {
901 return GATE_RESULT_OUTOFRESOURCES;
902 }
903 return GATE_RESULT_OK;
904 }
905 else
906 {
907 //return await_event_and_process_messages(*ptr_waitable, INFINITE);
908 return GATE_RESULT_OK;
909 }
910 }
911 static void wv2_event_notify(HANDLE waitable)
912 {
913 ReleaseSemaphore(waitable, 1, NULL);
914 }
915 static gate_result_t wv2_event_await(HANDLE waitable)
916 {
917 return await_event_and_process_messages(waitable, INFINITE);
918 }
919
920
921 typedef struct wv2_env_completed_class
922 {
923 ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl* lpVtbl;
924
925 ICoreWebView2Environment* env;
926 HANDLE semaphore;
927 } wv2_env_completed_t;
928
929 static HRESULT STDMETHODCALLTYPE wv2_env_completed_QueryInterface(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* This, REFIID riid, void** ppvObject)
930 {
931 wv2_env_completed_t* self = (wv2_env_completed_t*)This;
932 if (ppvObject)
933 {
934 *ppvObject = self;
935 }
936 return S_OK;
937 }
938 static ULONG STDMETHODCALLTYPE wv2_env_completed_AddRef(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* This)
939 {
940 wv2_env_completed_t* self = (wv2_env_completed_t*)This;
941 return 2;
942 }
943 static ULONG STDMETHODCALLTYPE wv2_env_completed_Release(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* This)
944 {
945 wv2_env_completed_t* self = (wv2_env_completed_t*)This;
946 return 1;
947 }
948
949 static HRESULT STDMETHODCALLTYPE wv2_env_completed_Invoke(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* This, HRESULT errorCode, ICoreWebView2Environment* createdEnvironment)
950 {
951 wv2_env_completed_t* self = (wv2_env_completed_t*)This;
952 if (createdEnvironment)
953 {
954 self->env = createdEnvironment;
955 createdEnvironment->lpVtbl->AddRef(createdEnvironment);
956 }
957 wv2_event_notify(self->semaphore);
958 return S_OK;
959 }
960
961 static ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl wv2_env_completed_vtbl = {
962 &wv2_env_completed_QueryInterface,
963 &wv2_env_completed_AddRef,
964 &wv2_env_completed_Release,
965 &wv2_env_completed_Invoke
966 };
967
968 static wv2_env_completed_t wv2_env_completed = {
969 &wv2_env_completed_vtbl,
970 NULL,
971 NULL
972 };
973
974
975
976
977 typedef struct wv2_ctrl_completed_class
978 {
979 ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl* lpVtbl;
980
981 ICoreWebView2Controller* ctrl;
982 HANDLE semaphore;
983 } wv2_ctrl_completed_t;
984
985 static HRESULT STDMETHODCALLTYPE wv2_ctrl_completed_QueryInterface(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler* This, REFIID riid, void** ppvObject)
986 {
987 wv2_ctrl_completed_t* self = (wv2_ctrl_completed_t*)This;
988 if (ppvObject)
989 {
990 *ppvObject = self;
991 }
992 return S_OK;
993 }
994 static ULONG STDMETHODCALLTYPE wv2_ctrl_completed_AddRef(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler* This)
995 {
996 wv2_ctrl_completed_t* self = (wv2_ctrl_completed_t*)This;
997 return 2;
998 }
999 static ULONG STDMETHODCALLTYPE wv2_ctrl_completed_Release(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler* This)
1000 {
1001 wv2_ctrl_completed_t* self = (wv2_ctrl_completed_t*)This;
1002 return 1;
1003 }
1004
1005 static HRESULT STDMETHODCALLTYPE wv2_ctrl_completed_Invoke(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler* This, HRESULT errorCode, ICoreWebView2Controller* createdController)
1006 {
1007 wv2_ctrl_completed_t* self = (wv2_ctrl_completed_t*)This;
1008 if (createdController)
1009 {
1010 self->ctrl = createdController;
1011 createdController->lpVtbl->AddRef(createdController);
1012 }
1013 wv2_event_notify(self->semaphore);
1014 return S_OK;
1015 }
1016
1017 static ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl wv2_ctrl_completed_vtbl = {
1018 &wv2_ctrl_completed_QueryInterface,
1019 &wv2_ctrl_completed_AddRef,
1020 &wv2_ctrl_completed_Release,
1021 &wv2_ctrl_completed_Invoke
1022 };
1023
1024 static wv2_ctrl_completed_t wv2_ctrl_completed = {
1025 &wv2_ctrl_completed_vtbl,
1026 NULL
1027 };
1028
1029
1030 typedef struct wv2_event_handlers_class
1031 {
1032 IUnknownVtbl* vtblUnkown;
1033
1034 ICoreWebView2NewWindowRequestedEventHandler NewWindowRequested;
1035 EventRegistrationToken tokenNewWindowRequested;
1036
1037 ICoreWebView2NavigationStartingEventHandler NavigationStarting;
1038 EventRegistrationToken tokenNavigationStarting;
1039
1040 ICoreWebView2NavigationCompletedEventHandler NavigationCompleted;
1041 EventRegistrationToken tokenNavigationCompleted;
1042
1043 gate_atomic_int_t ref_counter;
1044 gate_ui_webview_impl_t* impl;
1045
1046 } wv2_event_handlers_t;
1047
1048
1049 static void wv2_event_handlers_attach_events(wv2_event_handlers_t* handlers)
1050 {
1051 HRESULT hr;
1052 ICoreWebView2* wv2 = handlers->impl->wv2;
1053
1054 hr = wv2->lpVtbl->add_NewWindowRequested(wv2, &handlers->NewWindowRequested, &handlers->tokenNewWindowRequested);
1055 hr = wv2->lpVtbl->add_NavigationStarting(wv2, &handlers->NavigationStarting, &handlers->tokenNavigationStarting);
1056 hr = wv2->lpVtbl->add_NavigationCompleted(wv2, &handlers->NavigationCompleted, &handlers->tokenNavigationCompleted);
1057 }
1058
1059
1060 static void wv2_event_handlers_detach_events(wv2_event_handlers_t* handlers)
1061 {
1062 ICoreWebView2* wv2 = NULL;
1063
1064 if (!handlers || !handlers->impl || !handlers->impl->wv2) return;
1065 wv2 = handlers->impl->wv2;
1066
1067 if (handlers->tokenNewWindowRequested.value)
1068 {
1069 wv2->lpVtbl->remove_NewWindowRequested(wv2, handlers->tokenNewWindowRequested);
1070 handlers->tokenNewWindowRequested.value = 0;
1071 }
1072
1073 if (handlers->tokenNavigationStarting.value)
1074 {
1075 wv2->lpVtbl->remove_NavigationStarting(wv2, handlers->tokenNavigationStarting);
1076 handlers->tokenNavigationStarting.value = 0;
1077 }
1078
1079 if (handlers->tokenNavigationCompleted.value)
1080 {
1081 wv2->lpVtbl->remove_NavigationCompleted(wv2, handlers->tokenNavigationCompleted);
1082 handlers->tokenNavigationCompleted.value = 0;
1083 }
1084 }
1085
1086
1087
1088 static ULONG STDMETHODCALLTYPE wv2_event_handlers_AddRef(IUnknown* This)
1089 {
1090 wv2_event_handlers_t* handlers = (wv2_event_handlers_t*)This;
1091 return (ULONG)gate_atomic_int_inc(&handlers->ref_counter);
1092 }
1093
1094 static ULONG STDMETHODCALLTYPE wv2_event_handlers_Release(IUnknown* This)
1095 {
1096 wv2_event_handlers_t* handlers = (wv2_event_handlers_t*)This;
1097 ULONG cnt = (ULONG)gate_atomic_int_dec(&handlers->ref_counter);
1098 if (cnt == 0)
1099 {
1100 wv2_event_handlers_detach_events(handlers);
1101 gate_mem_dealloc(handlers);
1102 }
1103 return cnt;
1104 }
1105 static HRESULT STDMETHODCALLTYPE wv2_event_handlers_QueryInterface(IUnknown* This, REFIID riid, void** ppvObject)
1106 {
1107 wv2_event_handlers_t* handlers = (wv2_event_handlers_t*)This;
1108 if (!ppvObject || !riid || !This)
1109 {
1110 return E_INVALIDARG;
1111 }
1112
1113 if (IsEqualGUID(riid, &gate_IID_IUnknown))
1114 {
1115 *ppvObject = This;
1116 wv2_event_handlers_AddRef(This);
1117 return S_OK;
1118 }
1119 if (IsEqualGUID(riid, &IID_ICoreWebView2NewWindowRequestedEventHandler))
1120 {
1121 *ppvObject = &handlers->NewWindowRequested;
1122 wv2_event_handlers_AddRef(This);
1123 return S_OK;
1124 }
1125 if (IsEqualGUID(riid, &IID_ICoreWebView2NavigationStartingEventHandler))
1126 {
1127 *ppvObject = &handlers->NavigationStarting;
1128 wv2_event_handlers_AddRef(This);
1129 return S_OK;
1130 }
1131 if (IsEqualGUID(riid, &IID_ICoreWebView2NavigationCompletedEventHandler))
1132 {
1133 *ppvObject = &handlers->NavigationCompleted;
1134 wv2_event_handlers_AddRef(This);
1135 return S_OK;
1136 }
1137
1138 return E_NOTIMPL;
1139 }
1140
1141 static IUnknownVtbl IUnknown_wv2_event_handlers_vtbl = {
1142 &wv2_event_handlers_QueryInterface,
1143 &wv2_event_handlers_AddRef,
1144 &wv2_event_handlers_Release
1145 };
1146
1147 #define CREATE_WV2_EVENT_HANDLER_VTBL(event_name, iface_type, sender_type, args_type) \
1148 static HRESULT STDMETHODCALLTYPE event_name ## _QueryInterface ( iface_type * This, REFIID riid, void** ppvObject) \
1149 { \
1150 char* const this_ptr = (char*)This; \
1151 static size_t const obj_pos = offsetof(wv2_event_handlers_t, event_name); \
1152 IUnknown* unk_ptr = (IUnknown*)(this_ptr - obj_pos); \
1153 return wv2_event_handlers_QueryInterface(unk_ptr, riid, ppvObject); \
1154 } \
1155 static ULONG STDMETHODCALLTYPE event_name ## _AddRef ( iface_type * This) \
1156 { \
1157 char* const this_ptr = (char*)This; \
1158 static size_t const obj_pos = offsetof(wv2_event_handlers_t, event_name); \
1159 IUnknown* unk_ptr = (IUnknown*)(this_ptr - obj_pos); \
1160 return wv2_event_handlers_AddRef(unk_ptr); \
1161 } \
1162 static ULONG STDMETHODCALLTYPE event_name ## _Release( iface_type * This) \
1163 { \
1164 char* const this_ptr = (char*)This; \
1165 static size_t const obj_pos = offsetof(wv2_event_handlers_t, event_name); \
1166 IUnknown* unk_ptr = (IUnknown*)(this_ptr - obj_pos); \
1167 return wv2_event_handlers_Release(unk_ptr); \
1168 } \
1169 static HRESULT STDMETHODCALLTYPE event_name ## _Invoke( iface_type * This, sender_type sender, args_type args) \
1170 { \
1171 char* const this_ptr = (char*)This; \
1172 static size_t const obj_pos = offsetof(wv2_event_handlers_t, event_name); \
1173 wv2_event_handlers_t* evt_handlers_ptr = (wv2_event_handlers_t*)(this_ptr - obj_pos); \
1174 return event_name ## _wv2_callback (evt_handlers_ptr, sender, args); \
1175 } \
1176 static iface_type ## Vtbl event_name ## _wv2_event_handlers_vtbl = { \
1177 & event_name ## _QueryInterface, \
1178 & event_name ## _AddRef, \
1179 & event_name ## _Release, \
1180 & event_name ## _Invoke \
1181 }
1182
1183
1184
1185 typedef struct NewWindowRequested_task_class
1186 {
1187 GATE_INTERFACE_VTBL(gate_runnable) const* vtbl;
1188
1189 gate_atomic_int_t ref_counter;
1190 ICoreWebView2NewWindowRequestedEventArgs* args;
1191 ICoreWebView2Deferral* deferral;
1192 gate_ui_webview_t* webview;
1193 } NewWindowRequested_task_t;
1194
1195 static char const* NewWindowRequested_task_get_interface_name(void* ptr)
1196 {
1197 return GATE_INTERFACE_NAME_RUNNABLE;
1198 }
1199 static void NewWindowRequested_task_release(void* ptr)
1200 {
1201 NewWindowRequested_task_t* self = (NewWindowRequested_task_t*)ptr;
1202 if (0 == gate_atomic_int_dec(&self->ref_counter))
1203 {
1204 self->deferral->lpVtbl->Release(self->deferral);
1205 self->args->lpVtbl->Release(self->args);
1206 }
1207 }
1208 static int NewWindowRequested_task_retain(void* ptr)
1209 {
1210 NewWindowRequested_task_t* self = (NewWindowRequested_task_t*)ptr;
1211 return (int)gate_atomic_int_inc(&self->ref_counter);
1212 }
1213 static gate_result_t NewWindowRequested_task_run(void* ptr)
1214 {
1215 NewWindowRequested_task_t* self = (NewWindowRequested_task_t*)ptr;
1216 gate_ui_webview_t* ptr_new_webview = NULL;
1217
1218 self->webview->on_new_window(&self->webview->ctrl, &ptr_new_webview);
1219 if (ptr_new_webview)
1220 {
1221 gate_ui_webview_impl_t* impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(&ptr_new_webview->ctrl);
1222 self->args->lpVtbl->put_Handled(self->args, TRUE);
1223 self->args->lpVtbl->put_NewWindow(self->args, impl->wv2);
1224 }
1225 self->deferral->lpVtbl->Complete(self->deferral);
1226 return GATE_RESULT_OK;
1227 }
1228 GATE_INTERFACE_VTBL(gate_runnable) const NewWindowRequested_task_vtbl = {
1229 &NewWindowRequested_task_get_interface_name,
1230 &NewWindowRequested_task_release,
1231 &NewWindowRequested_task_retain,
1232 &NewWindowRequested_task_run
1233 };
1234
1235 static HRESULT NewWindowRequested_wv2_callback(wv2_event_handlers_t* handlers, ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args)
1236 {
1237 gate_ui_webview_t* ptr_new_webview = NULL;
1238 ICoreWebView2Deferral* deferral = NULL;
1239 gate_ui_host_t* host = NULL;
1240 NewWindowRequested_task_t* task = NULL;
1241 HRESULT hr;
1242
1243 if (handlers && handlers->impl && handlers->impl->webview && handlers->impl->webview->on_new_window)
1244 {
1245 host = GATE_UI_WINAPI_GET_HOST(&handlers->impl->webview->ctrl);
1246 // gate_ui_host_execute(host, gate_runnable_create)
1247 hr = args->lpVtbl->GetDeferral(args, &deferral);
1248 if (SUCCEEDED(hr))
1249 {
1250 NewWindowRequested_task_t* task = gate_mem_alloc(sizeof(NewWindowRequested_task_t));
1251 if (!task)
1252 {
1253 deferral->lpVtbl->Release(deferral);
1254 }
1255 else
1256 {
1257 gate_mem_clear(task, sizeof(NewWindowRequested_task_t));
1258 task->vtbl = &NewWindowRequested_task_vtbl;
1259 gate_atomic_int_init(&task->ref_counter, 1);
1260 task->args = args;
1261 task->deferral = deferral;
1262 task->args->lpVtbl->AddRef(task->args);
1263 task->deferral->lpVtbl->AddRef(task->deferral);
1264 task->webview = handlers->impl->webview;
1265 gate_ui_winapi_host_post_runner(host, (gate_runnable_t*)task, true, false);
1266 task = NULL;
1267 }
1268 }
1269 }
1270 if (task)
1271 {
1272 gate_object_release(task);
1273 }
1274 return S_OK;
1275 }
1276 CREATE_WV2_EVENT_HANDLER_VTBL(NewWindowRequested, ICoreWebView2NewWindowRequestedEventHandler, ICoreWebView2*, ICoreWebView2NewWindowRequestedEventArgs*);
1277
1278
1279 static HRESULT NavigationStarting_wv2_callback(wv2_event_handlers_t* handlers, ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args)
1280 {
1281 return S_OK;
1282 }
1283 CREATE_WV2_EVENT_HANDLER_VTBL(NavigationStarting, ICoreWebView2NavigationStartingEventHandler, ICoreWebView2*, ICoreWebView2NavigationStartingEventArgs*);
1284
1285
1286 static HRESULT NavigationCompleted_wv2_callback(wv2_event_handlers_t* handlers, ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args)
1287 {
1288 LPWSTR wstrUrl = NULL;
1289 HRESULT hr;
1290 gate_string_t url = GATE_STRING_INIT_EMPTY;
1291
1292 if (handlers && handlers->impl && handlers->impl->webview && handlers->impl->webview->on_navigate_complete)
1293 {
1294 hr = sender->lpVtbl->get_Source(sender, &wstrUrl);
1295 if (SUCCEEDED(hr))
1296 {
1297 gate_string_create_utf16(&url, wstrUrl, gate_str16_length(wstrUrl));
1298 }
1299 handlers->impl->webview->on_navigate_complete(&handlers->impl->webview->ctrl, &url);
1300 }
1301 gate_string_release(&url);
1302 if (wstrUrl)
1303 {
1304 // CoTaskMemFree needs to free the URL
1305 gate_win32_com_dealloc(wstrUrl);
1306 }
1307 return S_OK;
1308 }
1309 CREATE_WV2_EVENT_HANDLER_VTBL(NavigationCompleted, ICoreWebView2NavigationCompletedEventHandler, ICoreWebView2*, ICoreWebView2NavigationCompletedEventArgs*);
1310
1311
1312
1313
1314 static wv2_event_handlers_t* create_webview2_event_handlers(gate_ui_webview_impl_t* impl)
1315 {
1316 wv2_event_handlers_t* handlers = NULL;
1317 do
1318 {
1319 handlers = (wv2_event_handlers_t*)gate_mem_alloc(sizeof(wv2_event_handlers_t));
1320 if (NULL == handlers)
1321 {
1322 break;
1323 }
1324 gate_mem_clear(handlers, sizeof(wv2_event_handlers_t));
1325 gate_atomic_int_init(&handlers->ref_counter, 1);
1326
1327 handlers->impl = impl;
1328 handlers->vtblUnkown = &IUnknown_wv2_event_handlers_vtbl;
1329 handlers->NewWindowRequested.lpVtbl = &NewWindowRequested_wv2_event_handlers_vtbl;
1330 handlers->NavigationStarting.lpVtbl = &NavigationStarting_wv2_event_handlers_vtbl;
1331 handlers->NavigationCompleted.lpVtbl = &NavigationCompleted_wv2_event_handlers_vtbl;
1332
1333 wv2_event_handlers_attach_events(handlers);
1334 } while (0);
1335 return handlers;
1336
1337 }
1338
1339 static gate_ui_webview_impl_t* create_webview2_impl(gate_ui_webview_t* webview, ICoreWebView2Controller* controller)
1340 {
1341 gate_ui_webview_impl_t* impl = NULL;
1342 wv2_event_handlers_t* handlers = NULL;
1343 HRESULT hr;
1344
1345 do
1346 {
1347 impl = (gate_ui_webview_impl_t*)gate_mem_alloc(sizeof(gate_ui_webview_impl_t));
1348 if (!impl)
1349 {
1350 break;
1351 }
1352
1353 gate_mem_clear(impl, sizeof(gate_ui_webview_impl_t));
1354 impl->webview = webview;
1355 impl->wv2_controller = controller;
1356 hr = impl->wv2_controller->lpVtbl->get_CoreWebView2(impl->wv2_controller, &impl->wv2);
1357 if (FAILED(hr))
1358 {
1359 gate_mem_dealloc(impl);
1360 impl = NULL;
1361 break;
1362 }
1363 handlers = create_webview2_event_handlers(impl);
1364 if (!handlers)
1365 {
1366 gate_mem_dealloc(impl);
1367 impl = NULL;
1368 break;
1369 }
1370 impl->wv2_event_handlers = (IUnknown*)handlers;
1371
1372 hr = impl->wv2_controller->lpVtbl->put_IsVisible(impl->wv2_controller, TRUE);
1373
1374 } while (0);
1375
1376 return impl;
1377 }
1378
1379
1380 static gate_result_t gate_ui_webview_create_wv2(gate_ui_webview_t* webview, gate_ui_ctrl_t* parent,
1381 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
1382 {
1383 gate_result_t ret;
1384 HRESULT hr;
1385 HWND hwnd_parent = NULL;
1386 HWND hwnd_ctrl = NULL;
1387 gate_ui_host_t* host = NULL;
1388 gate_uint32_t exstyles = 0;
1389 gate_uint32_t styles = 0;
1390 gate_ui_webview_impl_t* impl = NULL;
1391 ICoreWebView2Controller* controller = NULL;
1392 static ICoreWebView2Environment* global_wv2_environment = NULL;
1393
1394 host = GATE_UI_WINAPI_GET_HOST(parent);
1395 hwnd_parent = GATE_UI_WINAPI_GET_HWND(parent);
1396
1397 do
1398 {
1399 ret = gate_win32_com_init();
1400
1401 ret = load_webview2();
1402 GATE_BREAK_IF_FAILED(ret);
1403
1404 if (global_wv2_environment == NULL)
1405 {
1406 ret = wv2_event_init(&wv2_env_completed.semaphore);
1407 GATE_BREAK_IF_FAILED(ret);
1408
1409 wv2_env_completed.env = NULL;
1410 hr = webview2_loader.CreateCoreWebView2EnvironmentWithOptions(NULL, NULL, NULL, (ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler*)&wv2_env_completed);
1411
1412 wv2_event_await(wv2_env_completed.semaphore);
1413 if (!wv2_env_completed.env)
1414 {
1415 break;
1416 }
1417 global_wv2_environment = wv2_env_completed.env;
1418 }
1419
1420 exstyles = 0;
1421 #if !defined(GATE_SYS_WINCE)
1422 exstyles |= WS_EX_CONTROLPARENT;
1423 #endif
1424 styles = WS_GROUP | WS_CHILD | WS_TABSTOP | WS_CLIPCHILDREN;
1425 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
1426 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
1427
1428 ret = gate_ui_winapi_create(&webview->ctrl, host, hwnd_parent, NULL, position, styles, exstyles, NULL, userparam, false);
1429 GATE_BREAK_IF_FAILED(ret);
1430
1431 GATE_UI_WINAPI_SET_DISPATCHER(&webview->ctrl, &global_webview_dispatchers);
1432 hwnd_ctrl = GATE_UI_WINAPI_GET_HWND(&webview->ctrl);
1433
1434 ret = wv2_event_init(&wv2_ctrl_completed.semaphore);
1435 GATE_BREAK_IF_FAILED(ret);
1436
1437 wv2_ctrl_completed.ctrl = NULL;
1438 hr = global_wv2_environment->lpVtbl->CreateCoreWebView2Controller(global_wv2_environment, hwnd_ctrl, (ICoreWebView2CreateCoreWebView2ControllerCompletedHandler*)&wv2_ctrl_completed);
1439
1440 ret = wv2_event_await(wv2_ctrl_completed.semaphore);
1441 if (!wv2_ctrl_completed.ctrl)
1442 {
1443 ret = GATE_RESULT_NOTAVAILABLE;
1444 break;
1445 }
1446 controller = wv2_ctrl_completed.ctrl;
1447 wv2_ctrl_completed.ctrl = NULL;
1448
1449 impl = create_webview2_impl(webview, controller);
1450 if (impl == NULL)
1451 {
1452 ret = GATE_RESULT_OUTOFMEMORY;
1453 break;
1454 }
1455 GATE_UI_WINAPI_SET_CTRL_PARAM(&webview->ctrl, impl);
1456
1457 gate_ui_winapi_register_event(host, (void*)hwnd_ctrl, WM_SIZE, &webview_windowproc_events, &webview->ctrl);
1458
1459 ret = GATE_RESULT_OK;
1460 } while (0);
1461
1462 if (GATE_FAILED(ret))
1463 {
1464 if (controller)
1465 {
1466 controller->lpVtbl->Release(controller);
1467 }
1468 if (hwnd_ctrl)
1469 {
1470 gate_ui_winapi_destroy(&webview->ctrl);
1471 }
1472 if (impl != NULL)
1473 {
1474 }
1475 }
1476
1477 return ret;
1478 }
1479
1480 static gate_result_t wv2_navigate_to(gate_ui_webview_impl_t* impl, gate_string_t const* address)
1481 {
1482 gate_result_t ret = GATE_RESULT_FAILED;
1483 gate_cstrbuffer16_t buffer = GATE_INIT_EMPTY;
1484 HRESULT hr;
1485
1486 do
1487 {
1488 if (NULL == gate_cstrbuffer16_create_string(&buffer, address))
1489 {
1490 ret = GATE_RESULT_OUTOFMEMORY;
1491 break;
1492 }
1493 hr = impl->wv2->lpVtbl->Navigate(impl->wv2, gate_cstrbuffer16_get(&buffer));
1494 if (FAILED(hr))
1495 {
1496 ret = GATE_RESULT_FAILED;
1497 break;
1498 }
1499
1500 ret = GATE_RESULT_OK;
1501 } while (0);
1502
1503 gate_cstrbuffer16_destroy(&buffer);
1504 return ret;
1505 }
1506
1507 static gate_result_t wv2_execute(gate_ui_webview_impl_t* impl, gate_enumint_t command)
1508 {
1509 HRESULT hr;
1510
1511 switch (command)
1512 {
1513 case GATE_UI_WEBVIEW_COMMAND_STOP:
1514 {
1515 hr = impl->wv2->lpVtbl->Stop(impl->wv2);
1516 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
1517 }
1518 case GATE_UI_WEBVIEW_COMMAND_REFRESH:
1519 {
1520 hr = impl->wv2->lpVtbl->Reload(impl->wv2);
1521 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
1522 }
1523 case GATE_UI_WEBVIEW_COMMAND_GOHOME:
1524 {
1525 break;
1526 }
1527 case GATE_UI_WEBVIEW_COMMAND_GOBACK:
1528 {
1529 hr = impl->wv2->lpVtbl->GoBack(impl->wv2);
1530 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
1531 }
1532 case GATE_UI_WEBVIEW_COMMAND_GONEXT:
1533 {
1534 hr = impl->wv2->lpVtbl->GoForward(impl->wv2);
1535 return SUCCEEDED(hr) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
1536 }
1537 }
1538 return GATE_RESULT_NOTSUPPORTED;
1539 }
1540 #endif /* GATE_UI_WEBVIEW_EDGEWV2_IMPL */
1541
1542
1543
1544
1545
1546 /*******************************/
1547 /* */
1548 /* GATE webview control code: */
1549 /* */
1550 /*******************************/
1551
1552
1553 static gate_result_t webview_destroy_impl(gate_ui_ctrl_t* ctrl)
1554 {
1555 gate_ui_webview_impl_t* impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(ctrl);
1556
1557 GATE_UI_WINAPI_SET_CTRL_PARAM(ctrl, NULL);
1558
1559 if (impl != NULL)
1560 {
1561 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
1562
1563 if (impl->wv2_event_handlers)
1564 {
1565 wv2_event_handlers_t* wv2_handlers = (wv2_event_handlers_t*)impl->wv2_event_handlers;
1566 wv2_event_handlers_detach_events(wv2_handlers);
1567 impl->wv2_event_handlers->lpVtbl->Release(impl->wv2_event_handlers);
1568 impl->wv2_event_handlers = NULL;
1569 }
1570 if (impl->wv2)
1571 {
1572 impl->wv2->lpVtbl->Release(impl->wv2);
1573 impl->wv2 = NULL;
1574 }
1575 if (impl->wv2_controller)
1576 {
1577 impl->wv2_controller->lpVtbl->Close(impl->wv2_controller);
1578 impl->wv2_controller->lpVtbl->Release(impl->wv2_controller);
1579 impl->wv2_controller = NULL;
1580 }
1581 #endif
1582
1583 #ifdef GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL
1584 if (impl->webbrowser2)
1585 {
1586 impl->webbrowser2->lpVtbl->Release(impl->webbrowser2);
1587 impl->webbrowser2 = NULL;
1588 }
1589
1590 if (impl->webbrowser)
1591 {
1592 impl->webbrowser->lpVtbl->Release(impl->webbrowser);
1593 impl->webbrowser = NULL;
1594 }
1595 if (impl->webbrowser_events)
1596 {
1597 impl->webbrowser_events->lpVtbl->Release(impl->webbrowser_events);
1598 impl->webbrowser_events = NULL;
1599 }
1600 #endif
1601
1602 impl->webview = NULL;
1603 if (impl->hwnd)
1604 {
1605 DestroyWindow(impl->hwnd);
1606 impl->hwnd = NULL;
1607 }
1608 gate_mem_dealloc(impl);
1609 }
1610 return gate_ui_winapi_destroy(ctrl);
1611 }
1612
1613
1614 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)
1615 {
1616 HWND hwndctrl;
1617 gate_ui_webview_impl_t* impl = NULL;
1618 RECT rect;
1619
1620 if (!ctrl)
1621 {
1622 return false;
1623 }
1624
1625 hwndctrl = GATE_UI_WINAPI_GET_HWND(ctrl);
1626 impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(ctrl);
1627 if (!hwndctrl || !impl || (hwndctrl != hwnd))
1628 {
1629 return false;
1630 }
1631
1632 switch (msg)
1633 {
1634 case WM_SIZE:
1635 {
1636 GetClientRect(hwndctrl, &rect);
1637
1638 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
1639 if (impl->wv2_controller)
1640 {
1641 impl->wv2_controller->lpVtbl->put_Bounds(impl->wv2_controller, rect);
1642 }
1643 #endif
1644
1645 if (impl->hwnd)
1646 {
1647 SetWindowPos(impl->hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1648 SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1649 *lresult = 0;
1650 return true;
1651 }
1652 break;
1653 }
1654 }
1655 return false;
1656 }
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668 gate_result_t gate_ui_webview_create(gate_ui_webview_t* webview, gate_ui_ctrl_t* parent,
1669 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
1670 {
1671 gate_result_t ret = GATE_RESULT_FAILED;
1672 do
1673 {
1674
1675 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
1676 ret = gate_ui_webview_create_wv2(webview, parent, position, flags, userparam);
1677 if (GATE_SUCCEEDED(ret))
1678 {
1679 break;
1680 }
1681 #endif
1682
1683 #ifdef GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL
1684 ret = gate_ui_webview_create_activex(webview, parent, position, flags, userparam);
1685 if (GATE_SUCCEEDED(ret))
1686 {
1687 break;
1688 }
1689 #endif
1690
1691 } while (0);
1692 return ret;
1693 }
1694
1695
1696
1697
1698 gate_result_t gate_ui_webview_navigate_to(gate_ui_webview_t* webview, gate_string_t const* address)
1699 {
1700 gate_result_t ret = GATE_RESULT_FAILED;
1701 gate_ui_webview_impl_t* impl = NULL;
1702
1703 if (webview)
1704 {
1705 impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(&webview->ctrl);
1706 }
1707
1708 do
1709 {
1710 if (!impl)
1711 {
1712 ret = GATE_RESULT_NOTAVAILABLE;
1713 break;
1714 }
1715
1716 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
1717 if (impl->wv2)
1718 {
1719 ret = wv2_navigate_to(impl, address);
1720 break;
1721 }
1722 #endif
1723
1724 #ifdef GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL
1725 if (impl->webbrowser || impl->webbrowser2)
1726 {
1727 ret = webbrowser_navigate_to(impl, address);
1728 break;
1729 }
1730 #endif
1731
1732 } while (0);
1733
1734 return ret;
1735 }
1736
1737
1738
1739
1740 gate_result_t gate_ui_webview_execute(gate_ui_webview_t* webview, gate_enumint_t command)
1741 {
1742 gate_result_t ret = GATE_RESULT_FAILED;
1743 gate_ui_webview_impl_t* impl = NULL;
1744
1745 do
1746 {
1747 if (webview)
1748 {
1749 impl = (gate_ui_webview_impl_t*)GATE_UI_WINAPI_GET_CTRL_PARAM(&webview->ctrl);
1750 }
1751 if (!impl)
1752 {
1753 ret = GATE_RESULT_NOTAVAILABLE;
1754 break;
1755 }
1756
1757 #ifdef GATE_UI_WEBVIEW_EDGEWV2_IMPL
1758 if (impl->wv2)
1759 {
1760 ret = wv2_execute(impl, command);
1761 break;
1762 }
1763 #endif
1764
1765 #ifdef GATE_UI_WEBVIEW_ATLWEBBROWSER_IMPL
1766 if (impl->webbrowser || impl->webbrowser2)
1767 {
1768 ret = webbrowser_execute(impl, command);
1769 break;
1770 }
1771 #endif
1772
1773 } while (0);
1774
1775 return ret;
1776 }
1777
1778 #endif /* GATE_UI_WEBVIEW_WINAPI_IMPL */
1779
1780
1781
1782
1783 #if defined(GATE_UI_WEBVIEW_GTK_IMPL)
1784
1785 #include <webkit2/webkit2.h>
1786 #include "gate/ui/gateui_gtk.h"
1787
1788
1789 static void callback_load_changed(WebKitWebView* web_view, WebKitLoadEvent load_event, gpointer user_data)
1790 {
1791 GtkWidget* const widget = (GtkWidget*)web_view;
1792 gate_ui_webview_t* const ctrl = (gate_ui_webview_t*)user_data;
1793 gchar const* uri = webkit_web_view_get_uri (web_view);
1794
1795
1796 if (ctrl && uri)
1797 {
1798 gate_string_t url = GATE_STRING_INIT_EMPTY;
1799
1800 if (NULL == gate_string_create(&url, uri, gate_str_length(uri)))
1801 {
1802 return;
1803 }
1804 switch (load_event)
1805 {
1806 case WEBKIT_LOAD_STARTED:
1807 {
1808 gate_bool_t cancel = false;
1809 if (ctrl->on_navigate_start)
1810 {
1811 ctrl->on_navigate_start(&ctrl->ctrl, &url, &cancel);
1812 }
1813 break;
1814 }
1815 case WEBKIT_LOAD_REDIRECTED:
1816 {
1817 break;
1818 }
1819 case WEBKIT_LOAD_COMMITTED:
1820 {
1821 break;
1822 }
1823 case WEBKIT_LOAD_FINISHED:
1824 {
1825 if (ctrl->on_navigate_complete)
1826 {
1827 ctrl->on_navigate_complete(&ctrl->ctrl, &url);
1828 }
1829 break;
1830 }
1831 }
1832 gate_string_release(&url);
1833 }
1834 }
1835
1836 static GtkWidget* callback_create(WebKitWebView* web_view, WebKitNavigationAction* navigation_action, gpointer user_data)
1837 {
1838 GtkWidget* ret_new_widget = NULL;
1839 GtkWidget* const widget = (GtkWidget*)web_view;
1840 gate_ui_webview_t* new_webview = NULL;
1841 gate_ui_webview_t* const ctrl = (gate_ui_webview_t*)user_data;
1842
1843 if (ctrl->on_new_window)
1844 {
1845 ctrl->on_new_window(&ctrl->ctrl, &new_webview);
1846 if (new_webview)
1847 {
1848 ret_new_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&new_webview->ctrl);
1849 }
1850 }
1851 return ret_new_widget;
1852 }
1853
1854 static void callback_ready_to_show(WebKitWebView* web_view, gpointer user_data)
1855 {
1856 GtkWidget* const widget = (GtkWidget*)web_view;
1857 gate_ui_webview_t* const ctrl = (gate_ui_webview_t*)user_data;
1858 gchar const* title_chars = webkit_web_view_get_title(web_view);
1859 gate_string_t title = GATE_STRING_INIT_EMPTY;
1860 if (NULL == gate_string_create(&title, title_chars, gate_str_length(title_chars)))
1861 {
1862 return;
1863 }
1864 if (ctrl->on_title_text_changed)
1865 {
1866 ctrl->on_title_text_changed(&ctrl->ctrl, &title);
1867 }
1868 gate_string_release(&title);
1869 }
1870
1871 static gate_ui_gtk_dispatcher_t gate_ui_gtk_webview_dispatcher =
1872 {
1873 NULL,
1874 NULL,
1875 NULL,
1876 NULL,
1877 NULL,
1878 NULL
1879 };
1880
1881
1882
1883 gate_result_t gate_ui_webview_create(gate_ui_webview_t* webview, gate_ui_ctrl_t* parent,
1884 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
1885 {
1886 gate_result_t ret = GATE_RESULT_OK;
1887 GtkWidget* widget;
1888 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
1889
1890 gate_mem_clear(webview, sizeof(gate_ui_webview_t));
1891 widget = webkit_web_view_new();
1892 if (widget == NULL)
1893 {
1894 return GATE_RESULT_FAILED;
1895 }
1896
1897 ret = gate_ui_gtk_ctrl_init(&webview->ctrl, widget, host, userparam, parent,
1898 &gate_ui_gtk_webview_dispatcher, false, false, position, &flags);
1899
1900 if (GATE_SUCCEEDED(ret))
1901 {
1902 g_signal_connect(G_OBJECT(widget), "load-changed", G_CALLBACK(callback_load_changed), (gpointer)webview);
1903 g_signal_connect(G_OBJECT(widget), "create", G_CALLBACK(callback_create), (gpointer)webview);
1904 g_signal_connect(G_OBJECT(widget), "ready-to-show", G_CALLBACK(callback_ready_to_show), (gpointer)webview);
1905 }
1906
1907 return ret;
1908 }
1909
1910 gate_result_t gate_ui_webview_navigate_to(gate_ui_webview_t* webview, gate_string_t const* address)
1911 {
1912 gate_result_t ret = GATE_RESULT_FAILED;
1913 gate_cstrbuffer_t uri_buffer = GATE_INIT_EMPTY;
1914 do
1915 {
1916 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&webview->ctrl);
1917 WebKitWebView* wv = WEBKIT_WEB_VIEW(widget);
1918
1919 if (!wv)
1920 {
1921 ret = GATE_RESULT_INVALIDCONTENT;
1922 break;
1923 }
1924
1925 if (NULL == gate_cstrbuffer_create_string(&uri_buffer, address, false))
1926 {
1927 ret = GATE_RESULT_OUTOFMEMORY;
1928 break;
1929 }
1930 webkit_web_view_load_uri(wv, gate_cstrbuffer_get(&uri_buffer));
1931 ret = GATE_RESULT_OK;
1932 } while (0);
1933
1934 gate_cstrbuffer_destroy(&uri_buffer);
1935 return ret;
1936 }
1937
1938 gate_result_t gate_ui_webview_execute(gate_ui_webview_t* webview, gate_enumint_t command)
1939 {
1940 return GATE_RESULT_NOTIMPLEMENTED;
1941 }
1942
1943 #endif /* GATE_UI_WEBVIEW_GTK_IMPL */
1944
1945
1946
1947 #if defined(GATE_UI_WEBVIEW_NO_IMPL)
1948
1949 gate_result_t gate_ui_webview_create(gate_ui_webview_t* webview, gate_ui_ctrl_t* parent,
1950 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
1951 {
1952 return GATE_RESULT_NOTIMPLEMENTED;
1953 }
1954
1955 gate_result_t gate_ui_webview_navigate_to(gate_ui_webview_t* webview, gate_string_t const* address)
1956 {
1957 return GATE_RESULT_NOTIMPLEMENTED;
1958 }
1959
1960 gate_result_t gate_ui_webview_execute(gate_ui_webview_t* webview, gate_enumint_t command)
1961 {
1962 return GATE_RESULT_NOTIMPLEMENTED;
1963 }
1964
1965
1966 #endif /* GATE_UI_WEBVIEW_NO_IMPL */
1967
1968