tauri.h 84 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309
  1. /*
  2. * MIT License
  3. *
  4. * Copyright (c) 2017 Serge Zaitsev, (c) 2019 Quasar Framework
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. * SOFTWARE.
  23. */
  24. #ifndef WEBVIEW_H
  25. #define WEBVIEW_H
  26. #ifdef __cplusplus
  27. extern "C" {
  28. #endif
  29. #ifdef WEBVIEW_STATIC
  30. #define WEBVIEW_API static
  31. #else
  32. #define WEBVIEW_API extern
  33. #endif
  34. #include <stdint.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #if defined(WEBVIEW_GTK)
  38. #include <JavaScriptCore/JavaScript.h>
  39. #include <gtk/gtk.h>
  40. #include <webkit2/webkit2.h>
  41. struct webview_priv {
  42. GtkWidget *window;
  43. GtkWidget *scroller;
  44. GtkWidget *webview;
  45. GtkWidget *inspector_window;
  46. GAsyncQueue *queue;
  47. int ready;
  48. int js_busy;
  49. int should_exit;
  50. };
  51. #elif defined(WEBVIEW_WINAPI)
  52. #define CINTERFACE
  53. #include <windows.h>
  54. #include <commctrl.h>
  55. #include <exdisp.h>
  56. #include <mshtmhst.h>
  57. #include <mshtml.h>
  58. #include <shobjidl.h>
  59. #include <stdio.h>
  60. struct webview_priv {
  61. HWND hwnd;
  62. IOleObject **browser;
  63. BOOL is_fullscreen;
  64. DWORD saved_style;
  65. DWORD saved_ex_style;
  66. RECT saved_rect;
  67. };
  68. #elif defined(WEBVIEW_COCOA)
  69. #include <objc/objc-runtime.h>
  70. #include <CoreGraphics/CoreGraphics.h>
  71. #include <limits.h>
  72. struct webview_priv {
  73. id pool;
  74. id window;
  75. id webview;
  76. id windowDelegate;
  77. int should_exit;
  78. };
  79. #else
  80. #error "Define one of: WEBVIEW_GTK, WEBVIEW_COCOA or WEBVIEW_WINAPI"
  81. #endif
  82. struct webview;
  83. typedef void (*webview_external_invoke_cb_t)(struct webview *w,
  84. const char *arg);
  85. struct webview {
  86. const char *url;
  87. const char *title;
  88. int width;
  89. int height;
  90. int resizable;
  91. int debug;
  92. webview_external_invoke_cb_t external_invoke_cb;
  93. struct webview_priv priv;
  94. void *userdata;
  95. };
  96. enum webview_dialog_type {
  97. WEBVIEW_DIALOG_TYPE_OPEN = 0,
  98. WEBVIEW_DIALOG_TYPE_SAVE = 1,
  99. WEBVIEW_DIALOG_TYPE_ALERT = 2
  100. };
  101. #define WEBVIEW_DIALOG_FLAG_FILE (0 << 0)
  102. #define WEBVIEW_DIALOG_FLAG_DIRECTORY (1 << 0)
  103. #define WEBVIEW_DIALOG_FLAG_INFO (1 << 1)
  104. #define WEBVIEW_DIALOG_FLAG_WARNING (2 << 1)
  105. #define WEBVIEW_DIALOG_FLAG_ERROR (3 << 1)
  106. #define WEBVIEW_DIALOG_FLAG_ALERT_MASK (3 << 1)
  107. typedef void (*webview_dispatch_fn)(struct webview *w, void *arg);
  108. struct webview_dispatch_arg {
  109. webview_dispatch_fn fn;
  110. struct webview *w;
  111. void *arg;
  112. };
  113. #define DEFAULT_URL \
  114. "data:text/" \
  115. "html,%3C%21DOCTYPE%20html%3E%0A%3Chtml%20lang=%22en%22%3E%0A%3Chead%3E%" \
  116. "3Cmeta%20charset=%22utf-8%22%3E%3Cmeta%20http-equiv=%22X-UA-Compatible%22%" \
  117. "20content=%22IE=edge%22%3E%3C%2Fhead%3E%0A%3Cbody%3E%3Cdiv%20id=%22app%22%" \
  118. "3E%3C%2Fdiv%3E%3Cscript%20type=%22text%2Fjavascript%22%3E%3C%2Fscript%3E%" \
  119. "3C%2Fbody%3E%0A%3C%2Fhtml%3E"
  120. #define CSS_INJECT_FUNCTION \
  121. "(function(e){var " \
  122. "t=document.createElement('style'),d=document.head||document." \
  123. "getElementsByTagName('head')[0];t.setAttribute('type','text/" \
  124. "css'),t.styleSheet?t.styleSheet.cssText=e:t.appendChild(document." \
  125. "createTextNode(e)),d.appendChild(t)})"
  126. static const char *webview_check_url(const char *url) {
  127. if (url == NULL || strlen(url) == 0) {
  128. return DEFAULT_URL;
  129. }
  130. return url;
  131. }
  132. WEBVIEW_API int webview(const char *title, const char *url, int width,
  133. int height, int resizable);
  134. WEBVIEW_API int webview_init(struct webview *w);
  135. WEBVIEW_API int webview_loop(struct webview *w, int blocking);
  136. WEBVIEW_API int webview_eval(struct webview *w, const char *js);
  137. WEBVIEW_API int webview_inject_css(struct webview *w, const char *css);
  138. WEBVIEW_API void webview_set_title(struct webview *w, const char *title);
  139. WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen);
  140. WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
  141. uint8_t b, uint8_t a);
  142. WEBVIEW_API void webview_dialog(struct webview *w,
  143. enum webview_dialog_type dlgtype, int flags,
  144. const char *title, const char *arg,
  145. char *result, size_t resultsz);
  146. WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
  147. void *arg);
  148. WEBVIEW_API void webview_terminate(struct webview *w);
  149. WEBVIEW_API void webview_exit(struct webview *w);
  150. WEBVIEW_API void webview_debug(const char *format, ...);
  151. WEBVIEW_API void webview_print_log(const char *s);
  152. #ifdef WEBVIEW_IMPLEMENTATION
  153. #undef WEBVIEW_IMPLEMENTATION
  154. WEBVIEW_API int webview(const char *title, const char *url, int width,
  155. int height, int resizable) {
  156. struct webview webview;
  157. memset(&webview, 0, sizeof(webview));
  158. webview.title = title;
  159. webview.url = url;
  160. webview.width = width;
  161. webview.height = height;
  162. webview.resizable = resizable;
  163. int r = webview_init(&webview);
  164. if (r != 0) {
  165. return r;
  166. }
  167. while (webview_loop(&webview, 1) == 0) {
  168. }
  169. webview_exit(&webview);
  170. return 0;
  171. }
  172. WEBVIEW_API void webview_debug(const char *format, ...) {
  173. char buf[4096];
  174. va_list ap;
  175. va_start(ap, format);
  176. vsnprintf(buf, sizeof(buf), format, ap);
  177. webview_print_log(buf);
  178. va_end(ap);
  179. }
  180. static int webview_js_encode(const char *s, char *esc, size_t n) {
  181. int r = 1; /* At least one byte for trailing zero */
  182. for (; *s; s++) {
  183. const unsigned char c = *s;
  184. if (c >= 0x20 && c < 0x80 && strchr("<>\\'\"", c) == NULL) {
  185. if (n > 0) {
  186. *esc++ = c;
  187. n--;
  188. }
  189. r++;
  190. } else {
  191. if (n > 0) {
  192. snprintf(esc, n, "\\x%02x", (int)c);
  193. esc += 4;
  194. n -= 4;
  195. }
  196. r += 4;
  197. }
  198. }
  199. return r;
  200. }
  201. WEBVIEW_API int webview_inject_css(struct webview *w, const char *css) {
  202. int n = webview_js_encode(css, NULL, 0);
  203. char *esc = (char *)calloc(1, sizeof(CSS_INJECT_FUNCTION) + n + 4);
  204. if (esc == NULL) {
  205. return -1;
  206. }
  207. char *js = (char *)calloc(1, n);
  208. webview_js_encode(css, js, n);
  209. snprintf(esc, sizeof(CSS_INJECT_FUNCTION) + n + 4, "%s(\"%s\")",
  210. CSS_INJECT_FUNCTION, js);
  211. int r = webview_eval(w, esc);
  212. free(js);
  213. free(esc);
  214. return r;
  215. }
  216. #if defined(WEBVIEW_GTK)
  217. static void external_message_received_cb(WebKitUserContentManager *m,
  218. WebKitJavascriptResult *r,
  219. gpointer arg) {
  220. (void)m;
  221. struct webview *w = (struct webview *)arg;
  222. if (w->external_invoke_cb == NULL) {
  223. return;
  224. }
  225. JSGlobalContextRef context = webkit_javascript_result_get_global_context(r);
  226. JSValueRef value = webkit_javascript_result_get_value(r);
  227. JSStringRef js = JSValueToStringCopy(context, value, NULL);
  228. size_t n = JSStringGetMaximumUTF8CStringSize(js);
  229. char *s = g_new(char, n);
  230. JSStringGetUTF8CString(js, s, n);
  231. w->external_invoke_cb(w, s);
  232. JSStringRelease(js);
  233. g_free(s);
  234. }
  235. static void webview_load_changed_cb(WebKitWebView *webview,
  236. WebKitLoadEvent event, gpointer arg) {
  237. (void)webview;
  238. struct webview *w = (struct webview *)arg;
  239. if (event == WEBKIT_LOAD_FINISHED) {
  240. w->priv.ready = 1;
  241. }
  242. }
  243. static void webview_destroy_cb(GtkWidget *widget, gpointer arg) {
  244. (void)widget;
  245. struct webview *w = (struct webview *)arg;
  246. webview_terminate(w);
  247. }
  248. static gboolean webview_context_menu_cb(WebKitWebView *webview,
  249. GtkWidget *default_menu,
  250. WebKitHitTestResult *hit_test_result,
  251. gboolean triggered_with_keyboard,
  252. gpointer userdata) {
  253. (void)webview;
  254. (void)default_menu;
  255. (void)hit_test_result;
  256. (void)triggered_with_keyboard;
  257. (void)userdata;
  258. return TRUE;
  259. }
  260. WEBVIEW_API int webview_init(struct webview *w) {
  261. if (gtk_init_check(0, NULL) == FALSE) {
  262. return -1;
  263. }
  264. w->priv.ready = 0;
  265. w->priv.should_exit = 0;
  266. w->priv.queue = g_async_queue_new();
  267. w->priv.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  268. gtk_window_set_title(GTK_WINDOW(w->priv.window), w->title);
  269. if (w->resizable) {
  270. gtk_window_set_default_size(GTK_WINDOW(w->priv.window), w->width,
  271. w->height);
  272. } else {
  273. gtk_widget_set_size_request(w->priv.window, w->width, w->height);
  274. }
  275. gtk_window_set_resizable(GTK_WINDOW(w->priv.window), !!w->resizable);
  276. gtk_window_set_position(GTK_WINDOW(w->priv.window), GTK_WIN_POS_CENTER);
  277. w->priv.scroller = gtk_scrolled_window_new(NULL, NULL);
  278. gtk_container_add(GTK_CONTAINER(w->priv.window), w->priv.scroller);
  279. WebKitUserContentManager *m = webkit_user_content_manager_new();
  280. webkit_user_content_manager_register_script_message_handler(m, "external");
  281. g_signal_connect(m, "script-message-received::external",
  282. G_CALLBACK(external_message_received_cb), w);
  283. w->priv.webview = webkit_web_view_new_with_user_content_manager(m);
  284. webkit_web_view_load_uri(WEBKIT_WEB_VIEW(w->priv.webview),
  285. webview_check_url(w->url));
  286. g_signal_connect(G_OBJECT(w->priv.webview), "load-changed",
  287. G_CALLBACK(webview_load_changed_cb), w);
  288. gtk_container_add(GTK_CONTAINER(w->priv.scroller), w->priv.webview);
  289. if (w->debug) {
  290. WebKitSettings *settings =
  291. webkit_web_view_get_settings(WEBKIT_WEB_VIEW(w->priv.webview));
  292. webkit_settings_set_enable_write_console_messages_to_stdout(settings, true);
  293. webkit_settings_set_enable_developer_extras(settings, true);
  294. } else {
  295. g_signal_connect(G_OBJECT(w->priv.webview), "context-menu",
  296. G_CALLBACK(webview_context_menu_cb), w);
  297. }
  298. gtk_widget_show_all(w->priv.window);
  299. webkit_web_view_run_javascript(
  300. WEBKIT_WEB_VIEW(w->priv.webview),
  301. "window.external={invoke:function(x){"
  302. "window.webkit.messageHandlers.external.postMessage(x);}}",
  303. NULL, NULL, NULL);
  304. g_signal_connect(G_OBJECT(w->priv.window), "destroy",
  305. G_CALLBACK(webview_destroy_cb), w);
  306. return 0;
  307. }
  308. WEBVIEW_API int webview_loop(struct webview *w, int blocking) {
  309. gtk_main_iteration_do(blocking);
  310. return w->priv.should_exit;
  311. }
  312. WEBVIEW_API void webview_set_title(struct webview *w, const char *title) {
  313. gtk_window_set_title(GTK_WINDOW(w->priv.window), title);
  314. }
  315. WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) {
  316. if (fullscreen) {
  317. gtk_window_fullscreen(GTK_WINDOW(w->priv.window));
  318. } else {
  319. gtk_window_unfullscreen(GTK_WINDOW(w->priv.window));
  320. }
  321. }
  322. WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
  323. uint8_t b, uint8_t a) {
  324. GdkRGBA color = {r / 255.0, g / 255.0, b / 255.0, a / 255.0};
  325. webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(w->priv.webview),
  326. &color);
  327. }
  328. WEBVIEW_API void webview_dialog(struct webview *w,
  329. enum webview_dialog_type dlgtype, int flags,
  330. const char *title, const char *arg,
  331. char *result, size_t resultsz) {
  332. GtkWidget *dlg;
  333. if (result != NULL) {
  334. result[0] = '\0';
  335. }
  336. if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
  337. dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) {
  338. dlg = gtk_file_chooser_dialog_new(
  339. title, GTK_WINDOW(w->priv.window),
  340. (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN
  341. ? (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY
  342. ? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
  343. : GTK_FILE_CHOOSER_ACTION_OPEN)
  344. : GTK_FILE_CHOOSER_ACTION_SAVE),
  345. "_Cancel", GTK_RESPONSE_CANCEL,
  346. (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"),
  347. GTK_RESPONSE_ACCEPT, NULL);
  348. gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE);
  349. gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE);
  350. gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE);
  351. gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dlg), TRUE);
  352. gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dlg), TRUE);
  353. gint response = gtk_dialog_run(GTK_DIALOG(dlg));
  354. if (response == GTK_RESPONSE_ACCEPT) {
  355. gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg));
  356. g_strlcpy(result, filename, resultsz);
  357. g_free(filename);
  358. }
  359. gtk_widget_destroy(dlg);
  360. } else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) {
  361. GtkMessageType type = GTK_MESSAGE_OTHER;
  362. switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) {
  363. case WEBVIEW_DIALOG_FLAG_INFO:
  364. type = GTK_MESSAGE_INFO;
  365. break;
  366. case WEBVIEW_DIALOG_FLAG_WARNING:
  367. type = GTK_MESSAGE_WARNING;
  368. break;
  369. case WEBVIEW_DIALOG_FLAG_ERROR:
  370. type = GTK_MESSAGE_ERROR;
  371. break;
  372. }
  373. dlg = gtk_message_dialog_new(GTK_WINDOW(w->priv.window), GTK_DIALOG_MODAL,
  374. type, GTK_BUTTONS_OK, "%s", title);
  375. gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dlg), "%s",
  376. arg);
  377. gtk_dialog_run(GTK_DIALOG(dlg));
  378. gtk_widget_destroy(dlg);
  379. }
  380. }
  381. static void webview_eval_finished(GObject *object, GAsyncResult *result,
  382. gpointer userdata) {
  383. (void)object;
  384. (void)result;
  385. struct webview *w = (struct webview *)userdata;
  386. w->priv.js_busy = 0;
  387. }
  388. WEBVIEW_API int webview_eval(struct webview *w, const char *js) {
  389. while (w->priv.ready == 0) {
  390. g_main_context_iteration(NULL, TRUE);
  391. }
  392. w->priv.js_busy = 1;
  393. webkit_web_view_run_javascript(WEBKIT_WEB_VIEW(w->priv.webview), js, NULL,
  394. webview_eval_finished, w);
  395. while (w->priv.js_busy) {
  396. g_main_context_iteration(NULL, TRUE);
  397. }
  398. return 0;
  399. }
  400. static gboolean webview_dispatch_wrapper(gpointer userdata) {
  401. struct webview *w = (struct webview *)userdata;
  402. for (;;) {
  403. struct webview_dispatch_arg *arg =
  404. (struct webview_dispatch_arg *)g_async_queue_try_pop(w->priv.queue);
  405. if (arg == NULL) {
  406. break;
  407. }
  408. (arg->fn)(w, arg->arg);
  409. g_free(arg);
  410. }
  411. return FALSE;
  412. }
  413. WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
  414. void *arg) {
  415. struct webview_dispatch_arg *context =
  416. (struct webview_dispatch_arg *)g_new(struct webview_dispatch_arg, 1);
  417. context->w = w;
  418. context->arg = arg;
  419. context->fn = fn;
  420. g_async_queue_lock(w->priv.queue);
  421. g_async_queue_push_unlocked(w->priv.queue, context);
  422. if (g_async_queue_length_unlocked(w->priv.queue) == 1) {
  423. gdk_threads_add_idle(webview_dispatch_wrapper, w);
  424. }
  425. g_async_queue_unlock(w->priv.queue);
  426. }
  427. WEBVIEW_API void webview_terminate(struct webview *w) {
  428. w->priv.should_exit = 1;
  429. }
  430. WEBVIEW_API void webview_exit(struct webview *w) { (void)w; }
  431. WEBVIEW_API void webview_print_log(const char *s) {
  432. fprintf(stderr, "%s\n", s);
  433. }
  434. #endif /* WEBVIEW_GTK */
  435. #if defined(WEBVIEW_WINAPI)
  436. #pragma comment(lib, "user32.lib")
  437. #pragma comment(lib, "ole32.lib")
  438. #pragma comment(lib, "oleaut32.lib")
  439. #define WM_WEBVIEW_DISPATCH (WM_APP + 1)
  440. typedef struct {
  441. IOleInPlaceFrame frame;
  442. HWND window;
  443. } _IOleInPlaceFrameEx;
  444. typedef struct {
  445. IOleInPlaceSite inplace;
  446. _IOleInPlaceFrameEx frame;
  447. } _IOleInPlaceSiteEx;
  448. typedef struct {
  449. IDocHostUIHandler ui;
  450. } _IDocHostUIHandlerEx;
  451. typedef struct {
  452. IInternetSecurityManager mgr;
  453. } _IInternetSecurityManagerEx;
  454. typedef struct {
  455. IServiceProvider provider;
  456. _IInternetSecurityManagerEx mgr;
  457. } _IServiceProviderEx;
  458. typedef struct {
  459. IOleClientSite client;
  460. _IOleInPlaceSiteEx inplace;
  461. _IDocHostUIHandlerEx ui;
  462. IDispatch external;
  463. _IServiceProviderEx provider;
  464. } _IOleClientSiteEx;
  465. #ifdef __cplusplus
  466. #define iid_ref(x) &(x)
  467. #define iid_unref(x) *(x)
  468. #else
  469. #define iid_ref(x) (x)
  470. #define iid_unref(x) (x)
  471. #endif
  472. static inline WCHAR *webview_to_utf16(const char *s) {
  473. DWORD size = MultiByteToWideChar(CP_UTF8, 0, s, -1, 0, 0);
  474. WCHAR *ws = (WCHAR *)GlobalAlloc(GMEM_FIXED, sizeof(WCHAR) * size);
  475. if (ws == NULL) {
  476. return NULL;
  477. }
  478. MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, size);
  479. return ws;
  480. }
  481. static inline char *webview_from_utf16(WCHAR *ws) {
  482. int n = WideCharToMultiByte(CP_UTF8, 0, ws, -1, NULL, 0, NULL, NULL);
  483. char *s = (char *)GlobalAlloc(GMEM_FIXED, n);
  484. if (s == NULL) {
  485. return NULL;
  486. }
  487. WideCharToMultiByte(CP_UTF8, 0, ws, -1, s, n, NULL, NULL);
  488. return s;
  489. }
  490. static int iid_eq(REFIID a, const IID *b) {
  491. return memcmp((const void *)iid_ref(a), (const void *)b, sizeof(GUID)) == 0;
  492. }
  493. static HRESULT STDMETHODCALLTYPE JS_QueryInterface(IDispatch FAR *This,
  494. REFIID riid,
  495. LPVOID FAR *ppvObj) {
  496. if (iid_eq(riid, &IID_IDispatch)) {
  497. *ppvObj = This;
  498. return S_OK;
  499. }
  500. *ppvObj = 0;
  501. return E_NOINTERFACE;
  502. }
  503. static ULONG STDMETHODCALLTYPE JS_AddRef(IDispatch FAR *This) { return 1; }
  504. static ULONG STDMETHODCALLTYPE JS_Release(IDispatch FAR *This) { return 1; }
  505. static HRESULT STDMETHODCALLTYPE JS_GetTypeInfoCount(IDispatch FAR *This,
  506. UINT *pctinfo) {
  507. return S_OK;
  508. }
  509. static HRESULT STDMETHODCALLTYPE JS_GetTypeInfo(IDispatch FAR *This,
  510. UINT iTInfo, LCID lcid,
  511. ITypeInfo **ppTInfo) {
  512. return S_OK;
  513. }
  514. #define WEBVIEW_JS_INVOKE_ID 0x1000
  515. static HRESULT STDMETHODCALLTYPE JS_GetIDsOfNames(IDispatch FAR *This,
  516. REFIID riid,
  517. LPOLESTR *rgszNames,
  518. UINT cNames, LCID lcid,
  519. DISPID *rgDispId) {
  520. if (cNames != 1) {
  521. return S_FALSE;
  522. }
  523. if (wcscmp(rgszNames[0], L"invoke") == 0) {
  524. rgDispId[0] = WEBVIEW_JS_INVOKE_ID;
  525. return S_OK;
  526. }
  527. return S_FALSE;
  528. }
  529. static HRESULT STDMETHODCALLTYPE
  530. JS_Invoke(IDispatch FAR *This, DISPID dispIdMember, REFIID riid, LCID lcid,
  531. WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
  532. EXCEPINFO *pExcepInfo, UINT *puArgErr) {
  533. size_t offset = (size_t) & ((_IOleClientSiteEx *)NULL)->external;
  534. _IOleClientSiteEx *ex = (_IOleClientSiteEx *)((char *)(This)-offset);
  535. struct webview *w = (struct webview *)GetWindowLongPtr(
  536. ex->inplace.frame.window, GWLP_USERDATA);
  537. if (pDispParams->cArgs == 1 && pDispParams->rgvarg[0].vt == VT_BSTR) {
  538. BSTR bstr = pDispParams->rgvarg[0].bstrVal;
  539. char *s = webview_from_utf16(bstr);
  540. if (s != NULL) {
  541. if (dispIdMember == WEBVIEW_JS_INVOKE_ID) {
  542. if (w->external_invoke_cb != NULL) {
  543. w->external_invoke_cb(w, s);
  544. }
  545. } else {
  546. return S_FALSE;
  547. }
  548. GlobalFree(s);
  549. }
  550. }
  551. return S_OK;
  552. }
  553. static IDispatchVtbl ExternalDispatchTable = {
  554. JS_QueryInterface, JS_AddRef, JS_Release, JS_GetTypeInfoCount,
  555. JS_GetTypeInfo, JS_GetIDsOfNames, JS_Invoke};
  556. static ULONG STDMETHODCALLTYPE Site_AddRef(IOleClientSite FAR *This) {
  557. return 1;
  558. }
  559. static ULONG STDMETHODCALLTYPE Site_Release(IOleClientSite FAR *This) {
  560. return 1;
  561. }
  562. static HRESULT STDMETHODCALLTYPE Site_SaveObject(IOleClientSite FAR *This) {
  563. return E_NOTIMPL;
  564. }
  565. static HRESULT STDMETHODCALLTYPE Site_GetMoniker(IOleClientSite FAR *This,
  566. DWORD dwAssign,
  567. DWORD dwWhichMoniker,
  568. IMoniker **ppmk) {
  569. return E_NOTIMPL;
  570. }
  571. static HRESULT STDMETHODCALLTYPE
  572. Site_GetContainer(IOleClientSite FAR *This, LPOLECONTAINER FAR *ppContainer) {
  573. *ppContainer = 0;
  574. return E_NOINTERFACE;
  575. }
  576. static HRESULT STDMETHODCALLTYPE Site_ShowObject(IOleClientSite FAR *This) {
  577. return NOERROR;
  578. }
  579. static HRESULT STDMETHODCALLTYPE Site_OnShowWindow(IOleClientSite FAR *This,
  580. BOOL fShow) {
  581. return E_NOTIMPL;
  582. }
  583. static HRESULT STDMETHODCALLTYPE
  584. Site_RequestNewObjectLayout(IOleClientSite FAR *This) {
  585. return E_NOTIMPL;
  586. }
  587. static HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite FAR *This,
  588. REFIID riid,
  589. void **ppvObject) {
  590. if (iid_eq(riid, &IID_IUnknown) || iid_eq(riid, &IID_IOleClientSite)) {
  591. *ppvObject = &((_IOleClientSiteEx *)This)->client;
  592. } else if (iid_eq(riid, &IID_IOleInPlaceSite)) {
  593. *ppvObject = &((_IOleClientSiteEx *)This)->inplace;
  594. } else if (iid_eq(riid, &IID_IDocHostUIHandler)) {
  595. *ppvObject = &((_IOleClientSiteEx *)This)->ui;
  596. } else if (iid_eq(riid, &IID_IServiceProvider)) {
  597. *ppvObject = &((_IOleClientSiteEx *)This)->provider;
  598. } else {
  599. *ppvObject = 0;
  600. return (E_NOINTERFACE);
  601. }
  602. return S_OK;
  603. }
  604. static HRESULT STDMETHODCALLTYPE InPlace_QueryInterface(
  605. IOleInPlaceSite FAR *This, REFIID riid, LPVOID FAR *ppvObj) {
  606. return (Site_QueryInterface(
  607. (IOleClientSite *)((char *)This - sizeof(IOleClientSite)), riid, ppvObj));
  608. }
  609. static ULONG STDMETHODCALLTYPE InPlace_AddRef(IOleInPlaceSite FAR *This) {
  610. return 1;
  611. }
  612. static ULONG STDMETHODCALLTYPE InPlace_Release(IOleInPlaceSite FAR *This) {
  613. return 1;
  614. }
  615. static HRESULT STDMETHODCALLTYPE InPlace_GetWindow(IOleInPlaceSite FAR *This,
  616. HWND FAR *lphwnd) {
  617. *lphwnd = ((_IOleInPlaceSiteEx FAR *)This)->frame.window;
  618. return S_OK;
  619. }
  620. static HRESULT STDMETHODCALLTYPE
  621. InPlace_ContextSensitiveHelp(IOleInPlaceSite FAR *This, BOOL fEnterMode) {
  622. return E_NOTIMPL;
  623. }
  624. static HRESULT STDMETHODCALLTYPE
  625. InPlace_CanInPlaceActivate(IOleInPlaceSite FAR *This) {
  626. return S_OK;
  627. }
  628. static HRESULT STDMETHODCALLTYPE
  629. InPlace_OnInPlaceActivate(IOleInPlaceSite FAR *This) {
  630. return S_OK;
  631. }
  632. static HRESULT STDMETHODCALLTYPE
  633. InPlace_OnUIActivate(IOleInPlaceSite FAR *This) {
  634. return S_OK;
  635. }
  636. static HRESULT STDMETHODCALLTYPE InPlace_GetWindowContext(
  637. IOleInPlaceSite FAR *This, LPOLEINPLACEFRAME FAR *lplpFrame,
  638. LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPRECT lprcPosRect, LPRECT lprcClipRect,
  639. LPOLEINPLACEFRAMEINFO lpFrameInfo) {
  640. *lplpFrame = (LPOLEINPLACEFRAME) & ((_IOleInPlaceSiteEx *)This)->frame;
  641. *lplpDoc = 0;
  642. lpFrameInfo->fMDIApp = FALSE;
  643. lpFrameInfo->hwndFrame = ((_IOleInPlaceFrameEx *)*lplpFrame)->window;
  644. lpFrameInfo->haccel = 0;
  645. lpFrameInfo->cAccelEntries = 0;
  646. return S_OK;
  647. }
  648. static HRESULT STDMETHODCALLTYPE InPlace_Scroll(IOleInPlaceSite FAR *This,
  649. SIZE scrollExtent) {
  650. return E_NOTIMPL;
  651. }
  652. static HRESULT STDMETHODCALLTYPE
  653. InPlace_OnUIDeactivate(IOleInPlaceSite FAR *This, BOOL fUndoable) {
  654. return S_OK;
  655. }
  656. static HRESULT STDMETHODCALLTYPE
  657. InPlace_OnInPlaceDeactivate(IOleInPlaceSite FAR *This) {
  658. return S_OK;
  659. }
  660. static HRESULT STDMETHODCALLTYPE
  661. InPlace_DiscardUndoState(IOleInPlaceSite FAR *This) {
  662. return E_NOTIMPL;
  663. }
  664. static HRESULT STDMETHODCALLTYPE
  665. InPlace_DeactivateAndUndo(IOleInPlaceSite FAR *This) {
  666. return E_NOTIMPL;
  667. }
  668. static HRESULT STDMETHODCALLTYPE
  669. InPlace_OnPosRectChange(IOleInPlaceSite FAR *This, LPCRECT lprcPosRect) {
  670. IOleObject *browserObject;
  671. IOleInPlaceObject *inplace;
  672. browserObject = *((IOleObject **)((char *)This - sizeof(IOleObject *) -
  673. sizeof(IOleClientSite)));
  674. if (!browserObject->lpVtbl->QueryInterface(browserObject,
  675. iid_unref(&IID_IOleInPlaceObject),
  676. (void **)&inplace)) {
  677. inplace->lpVtbl->SetObjectRects(inplace, lprcPosRect, lprcPosRect);
  678. inplace->lpVtbl->Release(inplace);
  679. }
  680. return S_OK;
  681. }
  682. static HRESULT STDMETHODCALLTYPE Frame_QueryInterface(
  683. IOleInPlaceFrame FAR *This, REFIID riid, LPVOID FAR *ppvObj) {
  684. return E_NOTIMPL;
  685. }
  686. static ULONG STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame FAR *This) {
  687. return 1;
  688. }
  689. static ULONG STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame FAR *This) {
  690. return 1;
  691. }
  692. static HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame FAR *This,
  693. HWND FAR *lphwnd) {
  694. *lphwnd = ((_IOleInPlaceFrameEx *)This)->window;
  695. return S_OK;
  696. }
  697. static HRESULT STDMETHODCALLTYPE
  698. Frame_ContextSensitiveHelp(IOleInPlaceFrame FAR *This, BOOL fEnterMode) {
  699. return E_NOTIMPL;
  700. }
  701. static HRESULT STDMETHODCALLTYPE Frame_GetBorder(IOleInPlaceFrame FAR *This,
  702. LPRECT lprectBorder) {
  703. return E_NOTIMPL;
  704. }
  705. static HRESULT STDMETHODCALLTYPE Frame_RequestBorderSpace(
  706. IOleInPlaceFrame FAR *This, LPCBORDERWIDTHS pborderwidths) {
  707. return E_NOTIMPL;
  708. }
  709. static HRESULT STDMETHODCALLTYPE Frame_SetBorderSpace(
  710. IOleInPlaceFrame FAR *This, LPCBORDERWIDTHS pborderwidths) {
  711. return E_NOTIMPL;
  712. }
  713. static HRESULT STDMETHODCALLTYPE Frame_SetActiveObject(
  714. IOleInPlaceFrame FAR *This, IOleInPlaceActiveObject *pActiveObject,
  715. LPCOLESTR pszObjName) {
  716. return S_OK;
  717. }
  718. static HRESULT STDMETHODCALLTYPE
  719. Frame_InsertMenus(IOleInPlaceFrame FAR *This, HMENU hmenuShared,
  720. LPOLEMENUGROUPWIDTHS lpMenuWidths) {
  721. return E_NOTIMPL;
  722. }
  723. static HRESULT STDMETHODCALLTYPE Frame_SetMenu(IOleInPlaceFrame FAR *This,
  724. HMENU hmenuShared,
  725. HOLEMENU holemenu,
  726. HWND hwndActiveObject) {
  727. return S_OK;
  728. }
  729. static HRESULT STDMETHODCALLTYPE Frame_RemoveMenus(IOleInPlaceFrame FAR *This,
  730. HMENU hmenuShared) {
  731. return E_NOTIMPL;
  732. }
  733. static HRESULT STDMETHODCALLTYPE Frame_SetStatusText(IOleInPlaceFrame FAR *This,
  734. LPCOLESTR pszStatusText) {
  735. return S_OK;
  736. }
  737. static HRESULT STDMETHODCALLTYPE
  738. Frame_EnableModeless(IOleInPlaceFrame FAR *This, BOOL fEnable) {
  739. return S_OK;
  740. }
  741. static HRESULT STDMETHODCALLTYPE
  742. Frame_TranslateAccelerator(IOleInPlaceFrame FAR *This, LPMSG lpmsg, WORD wID) {
  743. return E_NOTIMPL;
  744. }
  745. static HRESULT STDMETHODCALLTYPE UI_QueryInterface(IDocHostUIHandler FAR *This,
  746. REFIID riid,
  747. LPVOID FAR *ppvObj) {
  748. return (Site_QueryInterface((IOleClientSite *)((char *)This -
  749. sizeof(IOleClientSite) -
  750. sizeof(_IOleInPlaceSiteEx)),
  751. riid, ppvObj));
  752. }
  753. static ULONG STDMETHODCALLTYPE UI_AddRef(IDocHostUIHandler FAR *This) {
  754. return 1;
  755. }
  756. static ULONG STDMETHODCALLTYPE UI_Release(IDocHostUIHandler FAR *This) {
  757. return 1;
  758. }
  759. static HRESULT STDMETHODCALLTYPE UI_ShowContextMenu(
  760. IDocHostUIHandler FAR *This, DWORD dwID, POINT __RPC_FAR *ppt,
  761. IUnknown __RPC_FAR *pcmdtReserved, IDispatch __RPC_FAR *pdispReserved) {
  762. return S_OK;
  763. }
  764. static HRESULT STDMETHODCALLTYPE
  765. UI_GetHostInfo(IDocHostUIHandler FAR *This, DOCHOSTUIINFO __RPC_FAR *pInfo) {
  766. pInfo->cbSize = sizeof(DOCHOSTUIINFO);
  767. pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER;
  768. pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
  769. return S_OK;
  770. }
  771. static HRESULT STDMETHODCALLTYPE UI_ShowUI(
  772. IDocHostUIHandler FAR *This, DWORD dwID,
  773. IOleInPlaceActiveObject __RPC_FAR *pActiveObject,
  774. IOleCommandTarget __RPC_FAR *pCommandTarget,
  775. IOleInPlaceFrame __RPC_FAR *pFrame, IOleInPlaceUIWindow __RPC_FAR *pDoc) {
  776. return S_OK;
  777. }
  778. static HRESULT STDMETHODCALLTYPE UI_HideUI(IDocHostUIHandler FAR *This) {
  779. return S_OK;
  780. }
  781. static HRESULT STDMETHODCALLTYPE UI_UpdateUI(IDocHostUIHandler FAR *This) {
  782. return S_OK;
  783. }
  784. static HRESULT STDMETHODCALLTYPE UI_EnableModeless(IDocHostUIHandler FAR *This,
  785. BOOL fEnable) {
  786. return S_OK;
  787. }
  788. static HRESULT STDMETHODCALLTYPE
  789. UI_OnDocWindowActivate(IDocHostUIHandler FAR *This, BOOL fActivate) {
  790. return S_OK;
  791. }
  792. static HRESULT STDMETHODCALLTYPE
  793. UI_OnFrameWindowActivate(IDocHostUIHandler FAR *This, BOOL fActivate) {
  794. return S_OK;
  795. }
  796. static HRESULT STDMETHODCALLTYPE
  797. UI_ResizeBorder(IDocHostUIHandler FAR *This, LPCRECT prcBorder,
  798. IOleInPlaceUIWindow __RPC_FAR *pUIWindow, BOOL fRameWindow) {
  799. return S_OK;
  800. }
  801. static HRESULT STDMETHODCALLTYPE
  802. UI_TranslateAccelerator(IDocHostUIHandler FAR *This, LPMSG lpMsg,
  803. const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID) {
  804. return S_FALSE;
  805. }
  806. static HRESULT STDMETHODCALLTYPE UI_GetOptionKeyPath(
  807. IDocHostUIHandler FAR *This, LPOLESTR __RPC_FAR *pchKey, DWORD dw) {
  808. return S_FALSE;
  809. }
  810. static HRESULT STDMETHODCALLTYPE UI_GetDropTarget(
  811. IDocHostUIHandler FAR *This, IDropTarget __RPC_FAR *pDropTarget,
  812. IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget) {
  813. return S_FALSE;
  814. }
  815. static HRESULT STDMETHODCALLTYPE UI_GetExternal(
  816. IDocHostUIHandler FAR *This, IDispatch __RPC_FAR *__RPC_FAR *ppDispatch) {
  817. *ppDispatch = (IDispatch *)(This + 1);
  818. return S_OK;
  819. }
  820. static HRESULT STDMETHODCALLTYPE UI_TranslateUrl(
  821. IDocHostUIHandler FAR *This, DWORD dwTranslate, OLECHAR __RPC_FAR *pchURLIn,
  822. OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut) {
  823. *ppchURLOut = 0;
  824. return S_FALSE;
  825. }
  826. static HRESULT STDMETHODCALLTYPE
  827. UI_FilterDataObject(IDocHostUIHandler FAR *This, IDataObject __RPC_FAR *pDO,
  828. IDataObject __RPC_FAR *__RPC_FAR *ppDORet) {
  829. *ppDORet = 0;
  830. return S_FALSE;
  831. }
  832. static const TCHAR *classname = "WebView";
  833. static const SAFEARRAYBOUND ArrayBound = {1, 0};
  834. static IOleClientSiteVtbl MyIOleClientSiteTable = {
  835. Site_QueryInterface, Site_AddRef, Site_Release,
  836. Site_SaveObject, Site_GetMoniker, Site_GetContainer,
  837. Site_ShowObject, Site_OnShowWindow, Site_RequestNewObjectLayout};
  838. static IOleInPlaceSiteVtbl MyIOleInPlaceSiteTable = {
  839. InPlace_QueryInterface,
  840. InPlace_AddRef,
  841. InPlace_Release,
  842. InPlace_GetWindow,
  843. InPlace_ContextSensitiveHelp,
  844. InPlace_CanInPlaceActivate,
  845. InPlace_OnInPlaceActivate,
  846. InPlace_OnUIActivate,
  847. InPlace_GetWindowContext,
  848. InPlace_Scroll,
  849. InPlace_OnUIDeactivate,
  850. InPlace_OnInPlaceDeactivate,
  851. InPlace_DiscardUndoState,
  852. InPlace_DeactivateAndUndo,
  853. InPlace_OnPosRectChange};
  854. static IOleInPlaceFrameVtbl MyIOleInPlaceFrameTable = {
  855. Frame_QueryInterface,
  856. Frame_AddRef,
  857. Frame_Release,
  858. Frame_GetWindow,
  859. Frame_ContextSensitiveHelp,
  860. Frame_GetBorder,
  861. Frame_RequestBorderSpace,
  862. Frame_SetBorderSpace,
  863. Frame_SetActiveObject,
  864. Frame_InsertMenus,
  865. Frame_SetMenu,
  866. Frame_RemoveMenus,
  867. Frame_SetStatusText,
  868. Frame_EnableModeless,
  869. Frame_TranslateAccelerator};
  870. static IDocHostUIHandlerVtbl MyIDocHostUIHandlerTable = {
  871. UI_QueryInterface,
  872. UI_AddRef,
  873. UI_Release,
  874. UI_ShowContextMenu,
  875. UI_GetHostInfo,
  876. UI_ShowUI,
  877. UI_HideUI,
  878. UI_UpdateUI,
  879. UI_EnableModeless,
  880. UI_OnDocWindowActivate,
  881. UI_OnFrameWindowActivate,
  882. UI_ResizeBorder,
  883. UI_TranslateAccelerator,
  884. UI_GetOptionKeyPath,
  885. UI_GetDropTarget,
  886. UI_GetExternal,
  887. UI_TranslateUrl,
  888. UI_FilterDataObject};
  889. static HRESULT STDMETHODCALLTYPE IS_QueryInterface(IInternetSecurityManager FAR *This, REFIID riid, void **ppvObject) {
  890. return E_NOTIMPL;
  891. }
  892. static ULONG STDMETHODCALLTYPE IS_AddRef(IInternetSecurityManager FAR *This) { return 1; }
  893. static ULONG STDMETHODCALLTYPE IS_Release(IInternetSecurityManager FAR *This) { return 1; }
  894. static HRESULT STDMETHODCALLTYPE IS_SetSecuritySite(IInternetSecurityManager FAR *This, IInternetSecurityMgrSite *pSited) {
  895. return INET_E_DEFAULT_ACTION;
  896. }
  897. static HRESULT STDMETHODCALLTYPE IS_GetSecuritySite(IInternetSecurityManager FAR *This, IInternetSecurityMgrSite **ppSite) {
  898. return INET_E_DEFAULT_ACTION;
  899. }
  900. static HRESULT STDMETHODCALLTYPE IS_MapUrlToZone(IInternetSecurityManager FAR *This, LPCWSTR pwszUrl, DWORD *pdwZone, DWORD dwFlags) {
  901. *pdwZone = URLZONE_LOCAL_MACHINE;
  902. return S_OK;
  903. }
  904. static HRESULT STDMETHODCALLTYPE IS_GetSecurityId(IInternetSecurityManager FAR *This, LPCWSTR pwszUrl, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved) {
  905. return INET_E_DEFAULT_ACTION;
  906. }
  907. static HRESULT STDMETHODCALLTYPE IS_ProcessUrlAction(IInternetSecurityManager FAR *This, LPCWSTR pwszUrl, DWORD dwAction, BYTE *pPolicy, DWORD cbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwFlags, DWORD dwReserved) {
  908. return INET_E_DEFAULT_ACTION;
  909. }
  910. static HRESULT STDMETHODCALLTYPE IS_QueryCustomPolicy(IInternetSecurityManager FAR *This, LPCWSTR pwszUrl, REFGUID guidKey, BYTE **ppPolicy, DWORD *pcbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwReserved) {
  911. return INET_E_DEFAULT_ACTION;
  912. }
  913. static HRESULT STDMETHODCALLTYPE IS_SetZoneMapping(IInternetSecurityManager FAR *This, DWORD dwZone, LPCWSTR lpszPattern, DWORD dwFlags) {
  914. return INET_E_DEFAULT_ACTION;
  915. }
  916. static HRESULT STDMETHODCALLTYPE IS_GetZoneMappings(IInternetSecurityManager FAR *This, DWORD dwZone, IEnumString **ppenumString, DWORD dwFlags) {
  917. return INET_E_DEFAULT_ACTION;
  918. }
  919. static IInternetSecurityManagerVtbl MyInternetSecurityManagerTable = {IS_QueryInterface, IS_AddRef, IS_Release, IS_SetSecuritySite, IS_GetSecuritySite, IS_MapUrlToZone, IS_GetSecurityId, IS_ProcessUrlAction, IS_QueryCustomPolicy, IS_SetZoneMapping, IS_GetZoneMappings};
  920. static HRESULT STDMETHODCALLTYPE SP_QueryInterface(IServiceProvider FAR *This, REFIID riid, void **ppvObject) {
  921. return (Site_QueryInterface(
  922. (IOleClientSite *)((char *)This - sizeof(IOleClientSite) - sizeof(_IOleInPlaceSiteEx) - sizeof(_IDocHostUIHandlerEx) - sizeof(IDispatch)), riid, ppvObject));
  923. }
  924. static ULONG STDMETHODCALLTYPE SP_AddRef(IServiceProvider FAR *This) { return 1; }
  925. static ULONG STDMETHODCALLTYPE SP_Release(IServiceProvider FAR *This) { return 1; }
  926. static HRESULT STDMETHODCALLTYPE SP_QueryService(IServiceProvider FAR *This, REFGUID siid, REFIID riid, void **ppvObject) {
  927. if (iid_eq(siid, &IID_IInternetSecurityManager) && iid_eq(riid, &IID_IInternetSecurityManager)) {
  928. *ppvObject = &((_IServiceProviderEx *)This)->mgr;
  929. } else {
  930. *ppvObject = 0;
  931. return (E_NOINTERFACE);
  932. }
  933. return S_OK;
  934. }
  935. static IServiceProviderVtbl MyServiceProviderTable = {SP_QueryInterface, SP_AddRef, SP_Release, SP_QueryService};
  936. static void UnEmbedBrowserObject(struct webview *w) {
  937. if (w->priv.browser != NULL) {
  938. (*w->priv.browser)->lpVtbl->Close(*w->priv.browser, OLECLOSE_NOSAVE);
  939. (*w->priv.browser)->lpVtbl->Release(*w->priv.browser);
  940. GlobalFree(w->priv.browser);
  941. w->priv.browser = NULL;
  942. }
  943. }
  944. static int EmbedBrowserObject(struct webview *w) {
  945. RECT rect;
  946. IWebBrowser2 *webBrowser2 = NULL;
  947. LPCLASSFACTORY pClassFactory = NULL;
  948. _IOleClientSiteEx *_iOleClientSiteEx = NULL;
  949. IOleObject **browser = (IOleObject **)GlobalAlloc(
  950. GMEM_FIXED, sizeof(IOleObject *) + sizeof(_IOleClientSiteEx));
  951. if (browser == NULL) {
  952. goto error;
  953. }
  954. w->priv.browser = browser;
  955. _iOleClientSiteEx = (_IOleClientSiteEx *)(browser + 1);
  956. _iOleClientSiteEx->client.lpVtbl = &MyIOleClientSiteTable;
  957. _iOleClientSiteEx->inplace.inplace.lpVtbl = &MyIOleInPlaceSiteTable;
  958. _iOleClientSiteEx->inplace.frame.frame.lpVtbl = &MyIOleInPlaceFrameTable;
  959. _iOleClientSiteEx->inplace.frame.window = w->priv.hwnd;
  960. _iOleClientSiteEx->ui.ui.lpVtbl = &MyIDocHostUIHandlerTable;
  961. _iOleClientSiteEx->external.lpVtbl = &ExternalDispatchTable;
  962. _iOleClientSiteEx->provider.provider.lpVtbl = &MyServiceProviderTable;
  963. _iOleClientSiteEx->provider.mgr.mgr.lpVtbl = &MyInternetSecurityManagerTable;
  964. if (CoGetClassObject(iid_unref(&CLSID_WebBrowser),
  965. CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, NULL,
  966. iid_unref(&IID_IClassFactory),
  967. (void **)&pClassFactory) != S_OK) {
  968. goto error;
  969. }
  970. if (pClassFactory == NULL) {
  971. goto error;
  972. }
  973. if (pClassFactory->lpVtbl->CreateInstance(pClassFactory, 0,
  974. iid_unref(&IID_IOleObject),
  975. (void **)browser) != S_OK) {
  976. goto error;
  977. }
  978. pClassFactory->lpVtbl->Release(pClassFactory);
  979. if ((*browser)->lpVtbl->SetClientSite(
  980. *browser, (IOleClientSite *)_iOleClientSiteEx) != S_OK) {
  981. goto error;
  982. }
  983. (*browser)->lpVtbl->SetHostNames(*browser, L"My Host Name", 0);
  984. if (OleSetContainedObject((struct IUnknown *)(*browser), TRUE) != S_OK) {
  985. goto error;
  986. }
  987. GetClientRect(w->priv.hwnd, &rect);
  988. if ((*browser)->lpVtbl->DoVerb((*browser), OLEIVERB_SHOW, NULL,
  989. (IOleClientSite *)_iOleClientSiteEx, -1,
  990. w->priv.hwnd, &rect) != S_OK) {
  991. goto error;
  992. }
  993. if ((*browser)->lpVtbl->QueryInterface((*browser),
  994. iid_unref(&IID_IWebBrowser2),
  995. (void **)&webBrowser2) != S_OK) {
  996. goto error;
  997. }
  998. webBrowser2->lpVtbl->put_Left(webBrowser2, 0);
  999. webBrowser2->lpVtbl->put_Top(webBrowser2, 0);
  1000. webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right);
  1001. webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom);
  1002. webBrowser2->lpVtbl->Release(webBrowser2);
  1003. return 0;
  1004. error:
  1005. UnEmbedBrowserObject(w);
  1006. if (pClassFactory != NULL) {
  1007. pClassFactory->lpVtbl->Release(pClassFactory);
  1008. }
  1009. if (browser != NULL) {
  1010. GlobalFree(browser);
  1011. }
  1012. return -1;
  1013. }
  1014. #define WEBVIEW_DATA_URL_PREFIX "data:text/html,"
  1015. static int DisplayHTMLPage(struct webview *w) {
  1016. IWebBrowser2 *webBrowser2;
  1017. VARIANT myURL;
  1018. LPDISPATCH lpDispatch;
  1019. IHTMLDocument2 *htmlDoc2;
  1020. BSTR bstr;
  1021. IOleObject *browserObject;
  1022. SAFEARRAY *sfArray;
  1023. VARIANT *pVar;
  1024. browserObject = *w->priv.browser;
  1025. int isDataURL = 0;
  1026. const char *webview_url = webview_check_url(w->url);
  1027. if (!browserObject->lpVtbl->QueryInterface(
  1028. browserObject, iid_unref(&IID_IWebBrowser2), (void **)&webBrowser2)) {
  1029. LPCSTR webPageName;
  1030. isDataURL = (strncmp(webview_url, WEBVIEW_DATA_URL_PREFIX,
  1031. strlen(WEBVIEW_DATA_URL_PREFIX)) == 0);
  1032. if (isDataURL) {
  1033. webPageName = "about:blank";
  1034. } else {
  1035. webPageName = (LPCSTR)webview_url;
  1036. }
  1037. VariantInit(&myURL);
  1038. myURL.vt = VT_BSTR;
  1039. #ifndef UNICODE
  1040. {
  1041. wchar_t *buffer = webview_to_utf16(webPageName);
  1042. if (buffer == NULL) {
  1043. goto badalloc;
  1044. }
  1045. myURL.bstrVal = SysAllocString(buffer);
  1046. GlobalFree(buffer);
  1047. }
  1048. #else
  1049. myURL.bstrVal = SysAllocString(webPageName);
  1050. #endif
  1051. if (!myURL.bstrVal) {
  1052. badalloc:
  1053. webBrowser2->lpVtbl->Release(webBrowser2);
  1054. return (-6);
  1055. }
  1056. webBrowser2->lpVtbl->Navigate2(webBrowser2, &myURL, 0, 0, 0, 0);
  1057. VariantClear(&myURL);
  1058. if (!isDataURL) {
  1059. return 0;
  1060. }
  1061. char *url = (char *)calloc(1, strlen(webview_url) + 1);
  1062. char *q = url;
  1063. for (const char *p = webview_url + strlen(WEBVIEW_DATA_URL_PREFIX); *q = *p;
  1064. p++, q++) {
  1065. if (*q == '%' && *(p + 1) && *(p + 2)) {
  1066. sscanf(p + 1, "%02x", q);
  1067. p = p + 2;
  1068. }
  1069. }
  1070. if (webBrowser2->lpVtbl->get_Document(webBrowser2, &lpDispatch) == S_OK) {
  1071. if (lpDispatch->lpVtbl->QueryInterface(lpDispatch,
  1072. iid_unref(&IID_IHTMLDocument2),
  1073. (void **)&htmlDoc2) == S_OK) {
  1074. if ((sfArray = SafeArrayCreate(VT_VARIANT, 1,
  1075. (SAFEARRAYBOUND *)&ArrayBound))) {
  1076. if (!SafeArrayAccessData(sfArray, (void **)&pVar)) {
  1077. pVar->vt = VT_BSTR;
  1078. #ifndef UNICODE
  1079. {
  1080. wchar_t *buffer = webview_to_utf16(url);
  1081. if (buffer == NULL) {
  1082. goto release;
  1083. }
  1084. bstr = SysAllocString(buffer);
  1085. GlobalFree(buffer);
  1086. }
  1087. #else
  1088. bstr = SysAllocString(string);
  1089. #endif
  1090. if ((pVar->bstrVal = bstr)) {
  1091. htmlDoc2->lpVtbl->write(htmlDoc2, sfArray);
  1092. htmlDoc2->lpVtbl->close(htmlDoc2);
  1093. }
  1094. }
  1095. SafeArrayDestroy(sfArray);
  1096. }
  1097. release:
  1098. free(url);
  1099. htmlDoc2->lpVtbl->Release(htmlDoc2);
  1100. }
  1101. lpDispatch->lpVtbl->Release(lpDispatch);
  1102. }
  1103. webBrowser2->lpVtbl->Release(webBrowser2);
  1104. return (0);
  1105. }
  1106. return (-5);
  1107. }
  1108. static LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam,
  1109. LPARAM lParam) {
  1110. struct webview *w = (struct webview *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1111. switch (uMsg) {
  1112. case WM_CREATE:
  1113. w = (struct webview *)((CREATESTRUCT *)lParam)->lpCreateParams;
  1114. w->priv.hwnd = hwnd;
  1115. return EmbedBrowserObject(w);
  1116. case WM_DESTROY:
  1117. UnEmbedBrowserObject(w);
  1118. PostQuitMessage(0);
  1119. return TRUE;
  1120. case WM_SIZE: {
  1121. IWebBrowser2 *webBrowser2;
  1122. IOleObject *browser = *w->priv.browser;
  1123. if (browser->lpVtbl->QueryInterface(browser, iid_unref(&IID_IWebBrowser2),
  1124. (void **)&webBrowser2) == S_OK) {
  1125. RECT rect;
  1126. GetClientRect(hwnd, &rect);
  1127. webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right);
  1128. webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom);
  1129. }
  1130. return TRUE;
  1131. }
  1132. case WM_WEBVIEW_DISPATCH: {
  1133. webview_dispatch_fn f = (webview_dispatch_fn)wParam;
  1134. void *arg = (void *)lParam;
  1135. (*f)(w, arg);
  1136. return TRUE;
  1137. }
  1138. }
  1139. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1140. }
  1141. #define WEBVIEW_KEY_FEATURE_BROWSER_EMULATION \
  1142. "Software\\Microsoft\\Internet " \
  1143. "Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION"
  1144. static int webview_fix_ie_compat_mode() {
  1145. HKEY hKey;
  1146. DWORD ie_version = 11000;
  1147. TCHAR appname[MAX_PATH + 1];
  1148. TCHAR *p;
  1149. if (GetModuleFileName(NULL, appname, MAX_PATH + 1) == 0) {
  1150. return -1;
  1151. }
  1152. for (p = &appname[strlen(appname) - 1]; p != appname && *p != '\\'; p--) {
  1153. }
  1154. p++;
  1155. if (RegCreateKey(HKEY_CURRENT_USER, WEBVIEW_KEY_FEATURE_BROWSER_EMULATION,
  1156. &hKey) != ERROR_SUCCESS) {
  1157. return -1;
  1158. }
  1159. if (RegSetValueEx(hKey, p, 0, REG_DWORD, (BYTE *)&ie_version,
  1160. sizeof(ie_version)) != ERROR_SUCCESS) {
  1161. RegCloseKey(hKey);
  1162. return -1;
  1163. }
  1164. RegCloseKey(hKey);
  1165. return 0;
  1166. }
  1167. WEBVIEW_API int webview_init(struct webview *w) {
  1168. WNDCLASSEX wc;
  1169. HINSTANCE hInstance;
  1170. DWORD style;
  1171. RECT clientRect;
  1172. RECT rect;
  1173. if (webview_fix_ie_compat_mode() < 0) {
  1174. return -1;
  1175. }
  1176. hInstance = GetModuleHandle(NULL);
  1177. if (hInstance == NULL) {
  1178. return -1;
  1179. }
  1180. if (OleInitialize(NULL) != S_OK) {
  1181. return -1;
  1182. }
  1183. ZeroMemory(&wc, sizeof(WNDCLASSEX));
  1184. wc.cbSize = sizeof(WNDCLASSEX);
  1185. wc.hInstance = hInstance;
  1186. wc.lpfnWndProc = wndproc;
  1187. wc.lpszClassName = classname;
  1188. RegisterClassEx(&wc);
  1189. style = WS_OVERLAPPEDWINDOW;
  1190. if (!w->resizable) {
  1191. style = WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
  1192. }
  1193. rect.left = 0;
  1194. rect.top = 0;
  1195. rect.right = w->width;
  1196. rect.bottom = w->height;
  1197. AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, 0);
  1198. GetClientRect(GetDesktopWindow(), &clientRect);
  1199. int left = (clientRect.right / 2) - ((rect.right - rect.left) / 2);
  1200. int top = (clientRect.bottom / 2) - ((rect.bottom - rect.top) / 2);
  1201. rect.right = rect.right - rect.left + left;
  1202. rect.left = left;
  1203. rect.bottom = rect.bottom - rect.top + top;
  1204. rect.top = top;
  1205. w->priv.hwnd =
  1206. CreateWindowEx(0, classname, w->title, style, rect.left, rect.top,
  1207. rect.right - rect.left, rect.bottom - rect.top,
  1208. HWND_DESKTOP, NULL, hInstance, (void *)w);
  1209. if (w->priv.hwnd == 0) {
  1210. OleUninitialize();
  1211. return -1;
  1212. }
  1213. SetWindowLongPtr(w->priv.hwnd, GWLP_USERDATA, (LONG_PTR)w);
  1214. DisplayHTMLPage(w);
  1215. SetWindowText(w->priv.hwnd, w->title);
  1216. ShowWindow(w->priv.hwnd, SW_SHOWDEFAULT);
  1217. UpdateWindow(w->priv.hwnd);
  1218. SetFocus(w->priv.hwnd);
  1219. return 0;
  1220. }
  1221. WEBVIEW_API int webview_loop(struct webview *w, int blocking) {
  1222. MSG msg;
  1223. if (blocking) {
  1224. GetMessage(&msg, 0, 0, 0);
  1225. } else {
  1226. PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
  1227. }
  1228. switch (msg.message) {
  1229. case WM_QUIT:
  1230. return -1;
  1231. case WM_COMMAND:
  1232. case WM_KEYDOWN:
  1233. case WM_KEYUP: {
  1234. HRESULT r = S_OK;
  1235. IWebBrowser2 *webBrowser2;
  1236. IOleObject *browser = *w->priv.browser;
  1237. if (browser->lpVtbl->QueryInterface(browser, iid_unref(&IID_IWebBrowser2),
  1238. (void **)&webBrowser2) == S_OK) {
  1239. IOleInPlaceActiveObject *pIOIPAO;
  1240. if (browser->lpVtbl->QueryInterface(
  1241. browser, iid_unref(&IID_IOleInPlaceActiveObject),
  1242. (void **)&pIOIPAO) == S_OK) {
  1243. r = pIOIPAO->lpVtbl->TranslateAccelerator(pIOIPAO, &msg);
  1244. pIOIPAO->lpVtbl->Release(pIOIPAO);
  1245. }
  1246. webBrowser2->lpVtbl->Release(webBrowser2);
  1247. }
  1248. if (r != S_FALSE) {
  1249. break;
  1250. }
  1251. }
  1252. default:
  1253. TranslateMessage(&msg);
  1254. DispatchMessage(&msg);
  1255. }
  1256. return 0;
  1257. }
  1258. WEBVIEW_API int webview_eval(struct webview *w, const char *js) {
  1259. IWebBrowser2 *webBrowser2;
  1260. IHTMLDocument2 *htmlDoc2;
  1261. IDispatch *docDispatch;
  1262. IDispatch *scriptDispatch;
  1263. if ((*w->priv.browser)
  1264. ->lpVtbl->QueryInterface((*w->priv.browser),
  1265. iid_unref(&IID_IWebBrowser2),
  1266. (void **)&webBrowser2) != S_OK) {
  1267. return -1;
  1268. }
  1269. if (webBrowser2->lpVtbl->get_Document(webBrowser2, &docDispatch) != S_OK) {
  1270. return -1;
  1271. }
  1272. if (docDispatch->lpVtbl->QueryInterface(docDispatch,
  1273. iid_unref(&IID_IHTMLDocument2),
  1274. (void **)&htmlDoc2) != S_OK) {
  1275. return -1;
  1276. }
  1277. if (htmlDoc2->lpVtbl->get_Script(htmlDoc2, &scriptDispatch) != S_OK) {
  1278. return -1;
  1279. }
  1280. DISPID dispid;
  1281. BSTR evalStr = SysAllocString(L"eval");
  1282. if (scriptDispatch->lpVtbl->GetIDsOfNames(
  1283. scriptDispatch, iid_unref(&IID_NULL), &evalStr, 1,
  1284. LOCALE_SYSTEM_DEFAULT, &dispid) != S_OK) {
  1285. SysFreeString(evalStr);
  1286. return -1;
  1287. }
  1288. SysFreeString(evalStr);
  1289. DISPPARAMS params;
  1290. VARIANT arg;
  1291. VARIANT result;
  1292. EXCEPINFO excepInfo;
  1293. UINT nArgErr = (UINT)-1;
  1294. params.cArgs = 1;
  1295. params.cNamedArgs = 0;
  1296. params.rgvarg = &arg;
  1297. arg.vt = VT_BSTR;
  1298. static const char *prologue = "(function(){";
  1299. static const char *epilogue = ";})();";
  1300. int n = strlen(prologue) + strlen(epilogue) + strlen(js) + 1;
  1301. char *eval = (char *)malloc(n);
  1302. snprintf(eval, n, "%s%s%s", prologue, js, epilogue);
  1303. wchar_t *buf = webview_to_utf16(eval);
  1304. if (buf == NULL) {
  1305. return -1;
  1306. }
  1307. arg.bstrVal = SysAllocString(buf);
  1308. if (scriptDispatch->lpVtbl->Invoke(
  1309. scriptDispatch, dispid, iid_unref(&IID_NULL), 0, DISPATCH_METHOD,
  1310. &params, &result, &excepInfo, &nArgErr) != S_OK) {
  1311. return -1;
  1312. }
  1313. SysFreeString(arg.bstrVal);
  1314. free(eval);
  1315. scriptDispatch->lpVtbl->Release(scriptDispatch);
  1316. htmlDoc2->lpVtbl->Release(htmlDoc2);
  1317. docDispatch->lpVtbl->Release(docDispatch);
  1318. return 0;
  1319. }
  1320. WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
  1321. void *arg) {
  1322. PostMessageW(w->priv.hwnd, WM_WEBVIEW_DISPATCH, (WPARAM)fn, (LPARAM)arg);
  1323. }
  1324. WEBVIEW_API void webview_set_title(struct webview *w, const char *title) {
  1325. SetWindowText(w->priv.hwnd, title);
  1326. }
  1327. WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) {
  1328. if (w->priv.is_fullscreen == !!fullscreen) {
  1329. return;
  1330. }
  1331. if (w->priv.is_fullscreen == 0) {
  1332. w->priv.saved_style = GetWindowLong(w->priv.hwnd, GWL_STYLE);
  1333. w->priv.saved_ex_style = GetWindowLong(w->priv.hwnd, GWL_EXSTYLE);
  1334. GetWindowRect(w->priv.hwnd, &w->priv.saved_rect);
  1335. }
  1336. w->priv.is_fullscreen = !!fullscreen;
  1337. if (fullscreen) {
  1338. MONITORINFO monitor_info;
  1339. SetWindowLong(w->priv.hwnd, GWL_STYLE,
  1340. w->priv.saved_style & ~(WS_CAPTION | WS_THICKFRAME));
  1341. SetWindowLong(w->priv.hwnd, GWL_EXSTYLE,
  1342. w->priv.saved_ex_style &
  1343. ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
  1344. WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
  1345. monitor_info.cbSize = sizeof(monitor_info);
  1346. GetMonitorInfo(MonitorFromWindow(w->priv.hwnd, MONITOR_DEFAULTTONEAREST),
  1347. &monitor_info);
  1348. RECT r;
  1349. r.left = monitor_info.rcMonitor.left;
  1350. r.top = monitor_info.rcMonitor.top;
  1351. r.right = monitor_info.rcMonitor.right;
  1352. r.bottom = monitor_info.rcMonitor.bottom;
  1353. SetWindowPos(w->priv.hwnd, NULL, r.left, r.top, r.right - r.left,
  1354. r.bottom - r.top,
  1355. SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  1356. } else {
  1357. SetWindowLong(w->priv.hwnd, GWL_STYLE, w->priv.saved_style);
  1358. SetWindowLong(w->priv.hwnd, GWL_EXSTYLE, w->priv.saved_ex_style);
  1359. SetWindowPos(w->priv.hwnd, NULL, w->priv.saved_rect.left,
  1360. w->priv.saved_rect.top,
  1361. w->priv.saved_rect.right - w->priv.saved_rect.left,
  1362. w->priv.saved_rect.bottom - w->priv.saved_rect.top,
  1363. SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  1364. }
  1365. }
  1366. WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
  1367. uint8_t b, uint8_t a) {
  1368. HBRUSH brush = CreateSolidBrush(RGB(r, g, b));
  1369. SetClassLongPtr(w->priv.hwnd, GCLP_HBRBACKGROUND, (LONG_PTR)brush);
  1370. }
  1371. /* These are missing parts from MinGW */
  1372. #ifndef __IFileDialog_INTERFACE_DEFINED__
  1373. #define __IFileDialog_INTERFACE_DEFINED__
  1374. enum _FILEOPENDIALOGOPTIONS {
  1375. FOS_OVERWRITEPROMPT = 0x2,
  1376. FOS_STRICTFILETYPES = 0x4,
  1377. FOS_NOCHANGEDIR = 0x8,
  1378. FOS_PICKFOLDERS = 0x20,
  1379. FOS_FORCEFILESYSTEM = 0x40,
  1380. FOS_ALLNONSTORAGEITEMS = 0x80,
  1381. FOS_NOVALIDATE = 0x100,
  1382. FOS_ALLOWMULTISELECT = 0x200,
  1383. FOS_PATHMUSTEXIST = 0x800,
  1384. FOS_FILEMUSTEXIST = 0x1000,
  1385. FOS_CREATEPROMPT = 0x2000,
  1386. FOS_SHAREAWARE = 0x4000,
  1387. FOS_NOREADONLYRETURN = 0x8000,
  1388. FOS_NOTESTFILECREATE = 0x10000,
  1389. FOS_HIDEMRUPLACES = 0x20000,
  1390. FOS_HIDEPINNEDPLACES = 0x40000,
  1391. FOS_NODEREFERENCELINKS = 0x100000,
  1392. FOS_DONTADDTORECENT = 0x2000000,
  1393. FOS_FORCESHOWHIDDEN = 0x10000000,
  1394. FOS_DEFAULTNOMINIMODE = 0x20000000,
  1395. FOS_FORCEPREVIEWPANEON = 0x40000000
  1396. };
  1397. typedef DWORD FILEOPENDIALOGOPTIONS;
  1398. typedef enum FDAP { FDAP_BOTTOM = 0, FDAP_TOP = 1 } FDAP;
  1399. DEFINE_GUID(IID_IFileDialog, 0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07,
  1400. 0x5d, 0x13, 0x5f, 0xc8);
  1401. typedef struct IFileDialogVtbl {
  1402. BEGIN_INTERFACE
  1403. HRESULT(STDMETHODCALLTYPE *QueryInterface)
  1404. (IFileDialog *This, REFIID riid, void **ppvObject);
  1405. ULONG(STDMETHODCALLTYPE *AddRef)(IFileDialog *This);
  1406. ULONG(STDMETHODCALLTYPE *Release)(IFileDialog *This);
  1407. HRESULT(STDMETHODCALLTYPE *Show)(IFileDialog *This, HWND hwndOwner);
  1408. HRESULT(STDMETHODCALLTYPE *SetFileTypes)
  1409. (IFileDialog *This, UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec);
  1410. HRESULT(STDMETHODCALLTYPE *SetFileTypeIndex)
  1411. (IFileDialog *This, UINT iFileType);
  1412. HRESULT(STDMETHODCALLTYPE *GetFileTypeIndex)
  1413. (IFileDialog *This, UINT *piFileType);
  1414. HRESULT(STDMETHODCALLTYPE *Advise)
  1415. (IFileDialog *This, IFileDialogEvents *pfde, DWORD *pdwCookie);
  1416. HRESULT(STDMETHODCALLTYPE *Unadvise)(IFileDialog *This, DWORD dwCookie);
  1417. HRESULT(STDMETHODCALLTYPE *SetOptions)
  1418. (IFileDialog *This, FILEOPENDIALOGOPTIONS fos);
  1419. HRESULT(STDMETHODCALLTYPE *GetOptions)
  1420. (IFileDialog *This, FILEOPENDIALOGOPTIONS *pfos);
  1421. HRESULT(STDMETHODCALLTYPE *SetDefaultFolder)
  1422. (IFileDialog *This, IShellItem *psi);
  1423. HRESULT(STDMETHODCALLTYPE *SetFolder)(IFileDialog *This, IShellItem *psi);
  1424. HRESULT(STDMETHODCALLTYPE *GetFolder)(IFileDialog *This, IShellItem **ppsi);
  1425. HRESULT(STDMETHODCALLTYPE *GetCurrentSelection)
  1426. (IFileDialog *This, IShellItem **ppsi);
  1427. HRESULT(STDMETHODCALLTYPE *SetFileName)(IFileDialog *This, LPCWSTR pszName);
  1428. HRESULT(STDMETHODCALLTYPE *GetFileName)(IFileDialog *This, LPWSTR *pszName);
  1429. HRESULT(STDMETHODCALLTYPE *SetTitle)(IFileDialog *This, LPCWSTR pszTitle);
  1430. HRESULT(STDMETHODCALLTYPE *SetOkButtonLabel)
  1431. (IFileDialog *This, LPCWSTR pszText);
  1432. HRESULT(STDMETHODCALLTYPE *SetFileNameLabel)
  1433. (IFileDialog *This, LPCWSTR pszLabel);
  1434. HRESULT(STDMETHODCALLTYPE *GetResult)(IFileDialog *This, IShellItem **ppsi);
  1435. HRESULT(STDMETHODCALLTYPE *AddPlace)
  1436. (IFileDialog *This, IShellItem *psi, FDAP fdap);
  1437. HRESULT(STDMETHODCALLTYPE *SetDefaultExtension)
  1438. (IFileDialog *This, LPCWSTR pszDefaultExtension);
  1439. HRESULT(STDMETHODCALLTYPE *Close)(IFileDialog *This, HRESULT hr);
  1440. HRESULT(STDMETHODCALLTYPE *SetClientGuid)(IFileDialog *This, REFGUID guid);
  1441. HRESULT(STDMETHODCALLTYPE *ClearClientData)(IFileDialog *This);
  1442. HRESULT(STDMETHODCALLTYPE *SetFilter)
  1443. (IFileDialog *This, IShellItemFilter *pFilter);
  1444. END_INTERFACE
  1445. } IFileDialogVtbl;
  1446. interface IFileDialog {
  1447. CONST_VTBL IFileDialogVtbl *lpVtbl;
  1448. };
  1449. DEFINE_GUID(IID_IFileOpenDialog, 0xd57c7288, 0xd4ad, 0x4768, 0xbe, 0x02, 0x9d,
  1450. 0x96, 0x95, 0x32, 0xd9, 0x60);
  1451. DEFINE_GUID(IID_IFileSaveDialog, 0x84bccd23, 0x5fde, 0x4cdb, 0xae, 0xa4, 0xaf,
  1452. 0x64, 0xb8, 0x3d, 0x78, 0xab);
  1453. #endif
  1454. WEBVIEW_API void webview_dialog(struct webview *w,
  1455. enum webview_dialog_type dlgtype, int flags,
  1456. const char *title, const char *arg,
  1457. char *result, size_t resultsz) {
  1458. if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
  1459. dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) {
  1460. IFileDialog *dlg = NULL;
  1461. IShellItem *res = NULL;
  1462. WCHAR *ws = NULL;
  1463. char *s = NULL;
  1464. FILEOPENDIALOGOPTIONS opts = 0, add_opts = 0;
  1465. if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) {
  1466. if (CoCreateInstance(
  1467. iid_unref(&CLSID_FileOpenDialog), NULL, CLSCTX_INPROC_SERVER,
  1468. iid_unref(&IID_IFileOpenDialog), (void **)&dlg) != S_OK) {
  1469. goto error_dlg;
  1470. }
  1471. if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) {
  1472. add_opts |= FOS_PICKFOLDERS;
  1473. }
  1474. add_opts |= FOS_NOCHANGEDIR | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE |
  1475. FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_SHAREAWARE |
  1476. FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS |
  1477. FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE;
  1478. } else {
  1479. if (CoCreateInstance(
  1480. iid_unref(&CLSID_FileSaveDialog), NULL, CLSCTX_INPROC_SERVER,
  1481. iid_unref(&IID_IFileSaveDialog), (void **)&dlg) != S_OK) {
  1482. goto error_dlg;
  1483. }
  1484. add_opts |= FOS_OVERWRITEPROMPT | FOS_NOCHANGEDIR |
  1485. FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_SHAREAWARE |
  1486. FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS |
  1487. FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE;
  1488. }
  1489. if (dlg->lpVtbl->GetOptions(dlg, &opts) != S_OK) {
  1490. goto error_dlg;
  1491. }
  1492. opts &= ~FOS_NOREADONLYRETURN;
  1493. opts |= add_opts;
  1494. if (dlg->lpVtbl->SetOptions(dlg, opts) != S_OK) {
  1495. goto error_dlg;
  1496. }
  1497. if (dlg->lpVtbl->Show(dlg, w->priv.hwnd) != S_OK) {
  1498. goto error_dlg;
  1499. }
  1500. if (dlg->lpVtbl->GetResult(dlg, &res) != S_OK) {
  1501. goto error_dlg;
  1502. }
  1503. if (res->lpVtbl->GetDisplayName(res, SIGDN_FILESYSPATH, &ws) != S_OK) {
  1504. goto error_result;
  1505. }
  1506. s = webview_from_utf16(ws);
  1507. strncpy(result, s, resultsz);
  1508. result[resultsz - 1] = '\0';
  1509. CoTaskMemFree(ws);
  1510. error_result:
  1511. res->lpVtbl->Release(res);
  1512. error_dlg:
  1513. dlg->lpVtbl->Release(dlg);
  1514. return;
  1515. } else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) {
  1516. #if 0
  1517. /* MinGW often doesn't contain TaskDialog, we'll use MessageBox for now */
  1518. WCHAR *wtitle = webview_to_utf16(title);
  1519. WCHAR *warg = webview_to_utf16(arg);
  1520. TaskDialog(w->priv.hwnd, NULL, NULL, wtitle, warg, 0, NULL, NULL);
  1521. GlobalFree(warg);
  1522. GlobalFree(wtitle);
  1523. #else
  1524. UINT type = MB_OK;
  1525. switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) {
  1526. case WEBVIEW_DIALOG_FLAG_INFO:
  1527. type |= MB_ICONINFORMATION;
  1528. break;
  1529. case WEBVIEW_DIALOG_FLAG_WARNING:
  1530. type |= MB_ICONWARNING;
  1531. break;
  1532. case WEBVIEW_DIALOG_FLAG_ERROR:
  1533. type |= MB_ICONERROR;
  1534. break;
  1535. }
  1536. MessageBox(w->priv.hwnd, arg, title, type);
  1537. #endif
  1538. }
  1539. }
  1540. WEBVIEW_API void webview_terminate(struct webview *w) { PostQuitMessage(0); }
  1541. WEBVIEW_API void webview_exit(struct webview *w) {
  1542. DestroyWindow(w->priv.hwnd);
  1543. OleUninitialize();
  1544. }
  1545. WEBVIEW_API void webview_print_log(const char *s) { OutputDebugString(s); }
  1546. #endif /* WEBVIEW_WINAPI */
  1547. #if defined(WEBVIEW_COCOA)
  1548. #define NSAlertStyleWarning 0
  1549. #define NSAlertStyleCritical 2
  1550. #define NSWindowStyleMaskResizable 8
  1551. #define NSWindowStyleMaskMiniaturizable 4
  1552. #define NSWindowStyleMaskTitled 1
  1553. #define NSWindowStyleMaskClosable 2
  1554. #define NSWindowStyleMaskFullScreen (1 << 14)
  1555. #define NSViewWidthSizable 2
  1556. #define NSViewHeightSizable 16
  1557. #define NSBackingStoreBuffered 2
  1558. #define NSEventMaskAny ULONG_MAX
  1559. #define NSEventModifierFlagCommand (1 << 20)
  1560. #define NSEventModifierFlagOption (1 << 19)
  1561. #define NSAlertStyleInformational 1
  1562. #define NSAlertFirstButtonReturn 1000
  1563. #define WKNavigationActionPolicyDownload 2
  1564. #define NSModalResponseOK 1
  1565. #define WKNavigationActionPolicyDownload 2
  1566. #define WKNavigationResponsePolicyAllow 1
  1567. #define WKUserScriptInjectionTimeAtDocumentStart 0
  1568. #define NSApplicationActivationPolicyRegular 0
  1569. static id get_nsstring(const char *c_str) {
  1570. return objc_msgSend((id)objc_getClass("NSString"),
  1571. sel_registerName("stringWithUTF8String:"), c_str);
  1572. }
  1573. static id create_menu_item(id title, const char *action, const char *key) {
  1574. id item =
  1575. objc_msgSend((id)objc_getClass("NSMenuItem"), sel_registerName("alloc"));
  1576. objc_msgSend(item, sel_registerName("initWithTitle:action:keyEquivalent:"),
  1577. title, sel_registerName(action), get_nsstring(key));
  1578. objc_msgSend(item, sel_registerName("autorelease"));
  1579. return item;
  1580. }
  1581. static void webview_window_will_close(id self, SEL cmd, id notification) {
  1582. struct webview *w =
  1583. (struct webview *)objc_getAssociatedObject(self, "webview");
  1584. webview_terminate(w);
  1585. }
  1586. static void webview_external_invoke(id self, SEL cmd, id contentController,
  1587. id message) {
  1588. struct webview *w =
  1589. (struct webview *)objc_getAssociatedObject(contentController, "webview");
  1590. if (w == NULL || w->external_invoke_cb == NULL) {
  1591. return;
  1592. }
  1593. w->external_invoke_cb(w, (const char *)objc_msgSend(
  1594. objc_msgSend(message, sel_registerName("body")),
  1595. sel_registerName("UTF8String")));
  1596. }
  1597. static void run_open_panel(id self, SEL cmd, id webView, id parameters,
  1598. id frame, void (^completionHandler)(id)) {
  1599. id openPanel = objc_msgSend((id)objc_getClass("NSOpenPanel"),
  1600. sel_registerName("openPanel"));
  1601. objc_msgSend(
  1602. openPanel, sel_registerName("setAllowsMultipleSelection:"),
  1603. objc_msgSend(parameters, sel_registerName("allowsMultipleSelection")));
  1604. objc_msgSend(openPanel, sel_registerName("setCanChooseFiles:"), 1);
  1605. objc_msgSend(
  1606. openPanel, sel_registerName("beginWithCompletionHandler:"), ^(id result) {
  1607. if (result == (id)NSModalResponseOK) {
  1608. completionHandler(objc_msgSend(openPanel, sel_registerName("URLs")));
  1609. } else {
  1610. completionHandler(nil);
  1611. }
  1612. });
  1613. }
  1614. static void run_save_panel(id self, SEL cmd, id download, id filename,
  1615. void (^completionHandler)(int allowOverwrite,
  1616. id destination)) {
  1617. id savePanel = objc_msgSend((id)objc_getClass("NSSavePanel"),
  1618. sel_registerName("savePanel"));
  1619. objc_msgSend(savePanel, sel_registerName("setCanCreateDirectories:"), 1);
  1620. objc_msgSend(savePanel, sel_registerName("setNameFieldStringValue:"),
  1621. filename);
  1622. objc_msgSend(savePanel, sel_registerName("beginWithCompletionHandler:"),
  1623. ^(id result) {
  1624. if (result == (id)NSModalResponseOK) {
  1625. id url = objc_msgSend(savePanel, sel_registerName("URL"));
  1626. id path = objc_msgSend(url, sel_registerName("path"));
  1627. completionHandler(1, path);
  1628. } else {
  1629. completionHandler(NO, nil);
  1630. }
  1631. });
  1632. }
  1633. static void run_confirmation_panel(id self, SEL cmd, id webView, id message,
  1634. id frame, void (^completionHandler)(bool)) {
  1635. id alert =
  1636. objc_msgSend((id)objc_getClass("NSAlert"), sel_registerName("new"));
  1637. objc_msgSend(alert, sel_registerName("setIcon:"),
  1638. objc_msgSend((id)objc_getClass("NSImage"),
  1639. sel_registerName("imageNamed:"),
  1640. get_nsstring("NSCaution")));
  1641. objc_msgSend(alert, sel_registerName("setShowsHelp:"), 0);
  1642. objc_msgSend(alert, sel_registerName("setInformativeText:"), message);
  1643. objc_msgSend(alert, sel_registerName("addButtonWithTitle:"),
  1644. get_nsstring("OK"));
  1645. objc_msgSend(alert, sel_registerName("addButtonWithTitle:"),
  1646. get_nsstring("Cancel"));
  1647. if (objc_msgSend(alert, sel_registerName("runModal")) ==
  1648. (id)NSAlertFirstButtonReturn) {
  1649. completionHandler(true);
  1650. } else {
  1651. completionHandler(false);
  1652. }
  1653. objc_msgSend(alert, sel_registerName("release"));
  1654. }
  1655. static void run_alert_panel(id self, SEL cmd, id webView, id message, id frame,
  1656. void (^completionHandler)(void)) {
  1657. id alert =
  1658. objc_msgSend((id)objc_getClass("NSAlert"), sel_registerName("new"));
  1659. objc_msgSend(alert, sel_registerName("setIcon:"),
  1660. objc_msgSend((id)objc_getClass("NSImage"),
  1661. sel_registerName("imageNamed:"),
  1662. get_nsstring("NSCaution")));
  1663. objc_msgSend(alert, sel_registerName("setShowsHelp:"), 0);
  1664. objc_msgSend(alert, sel_registerName("setInformativeText:"), message);
  1665. objc_msgSend(alert, sel_registerName("addButtonWithTitle:"),
  1666. get_nsstring("OK"));
  1667. objc_msgSend(alert, sel_registerName("runModal"));
  1668. objc_msgSend(alert, sel_registerName("release"));
  1669. completionHandler();
  1670. }
  1671. static void download_failed(id self, SEL cmd, id download, id error) {
  1672. printf("%s",
  1673. (const char *)objc_msgSend(
  1674. objc_msgSend(error, sel_registerName("localizedDescription")),
  1675. sel_registerName("UTF8String")));
  1676. }
  1677. static void make_nav_policy_decision(id self, SEL cmd, id webView, id response,
  1678. void (^decisionHandler)(int)) {
  1679. if (objc_msgSend(response, sel_registerName("canShowMIMEType")) == 0) {
  1680. decisionHandler(WKNavigationActionPolicyDownload);
  1681. } else {
  1682. decisionHandler(WKNavigationResponsePolicyAllow);
  1683. }
  1684. }
  1685. WEBVIEW_API int webview_init(struct webview *w) {
  1686. w->priv.pool = objc_msgSend((id)objc_getClass("NSAutoreleasePool"),
  1687. sel_registerName("new"));
  1688. objc_msgSend((id)objc_getClass("NSApplication"),
  1689. sel_registerName("sharedApplication"));
  1690. Class __WKScriptMessageHandler = objc_allocateClassPair(
  1691. objc_getClass("NSObject"), "__WKScriptMessageHandler", 0);
  1692. class_addMethod(
  1693. __WKScriptMessageHandler,
  1694. sel_registerName("userContentController:didReceiveScriptMessage:"),
  1695. (IMP)webview_external_invoke, "v@:@@");
  1696. objc_registerClassPair(__WKScriptMessageHandler);
  1697. id scriptMessageHandler =
  1698. objc_msgSend((id)__WKScriptMessageHandler, sel_registerName("new"));
  1699. /***
  1700. _WKDownloadDelegate is an undocumented/private protocol with methods called
  1701. from WKNavigationDelegate
  1702. References:
  1703. https://github.com/WebKit/webkit/blob/master/Source/WebKit/UIProcess/API/Cocoa/_WKDownload.h
  1704. https://github.com/WebKit/webkit/blob/master/Source/WebKit/UIProcess/API/Cocoa/_WKDownloadDelegate.h
  1705. https://github.com/WebKit/webkit/blob/master/Tools/TestWebKitAPI/Tests/WebKitCocoa/Download.mm
  1706. ***/
  1707. Class __WKDownloadDelegate = objc_allocateClassPair(
  1708. objc_getClass("NSObject"), "__WKDownloadDelegate", 0);
  1709. class_addMethod(
  1710. __WKDownloadDelegate,
  1711. sel_registerName("_download:decideDestinationWithSuggestedFilename:"
  1712. "completionHandler:"),
  1713. (IMP)run_save_panel, "v@:@@?");
  1714. class_addMethod(__WKDownloadDelegate,
  1715. sel_registerName("_download:didFailWithError:"),
  1716. (IMP)download_failed, "v@:@@");
  1717. objc_registerClassPair(__WKDownloadDelegate);
  1718. id downloadDelegate =
  1719. objc_msgSend((id)__WKDownloadDelegate, sel_registerName("new"));
  1720. Class __WKPreferences = objc_allocateClassPair(objc_getClass("WKPreferences"),
  1721. "__WKPreferences", 0);
  1722. objc_property_attribute_t type = {"T", "c"};
  1723. objc_property_attribute_t ownership = {"N", ""};
  1724. objc_property_attribute_t attrs[] = {type, ownership};
  1725. class_replaceProperty(__WKPreferences, "developerExtrasEnabled", attrs, 2);
  1726. objc_registerClassPair(__WKPreferences);
  1727. id wkPref = objc_msgSend((id)__WKPreferences, sel_registerName("new"));
  1728. objc_msgSend(wkPref, sel_registerName("setValue:forKey:"),
  1729. objc_msgSend((id)objc_getClass("NSNumber"),
  1730. sel_registerName("numberWithBool:"), !!w->debug),
  1731. objc_msgSend((id)objc_getClass("NSString"),
  1732. sel_registerName("stringWithUTF8String:"),
  1733. "developerExtrasEnabled"));
  1734. id userController = objc_msgSend((id)objc_getClass("WKUserContentController"),
  1735. sel_registerName("new"));
  1736. objc_setAssociatedObject(userController, "webview", (id)(w),
  1737. OBJC_ASSOCIATION_ASSIGN);
  1738. objc_msgSend(
  1739. userController, sel_registerName("addScriptMessageHandler:name:"),
  1740. scriptMessageHandler,
  1741. objc_msgSend((id)objc_getClass("NSString"),
  1742. sel_registerName("stringWithUTF8String:"), "invoke"));
  1743. /***
  1744. In order to maintain compatibility with the other 'webviews' we need to
  1745. override window.external.invoke to call
  1746. webkit.messageHandlers.invoke.postMessage
  1747. ***/
  1748. id windowExternalOverrideScript = objc_msgSend(
  1749. (id)objc_getClass("WKUserScript"), sel_registerName("alloc"));
  1750. objc_msgSend(
  1751. windowExternalOverrideScript,
  1752. sel_registerName("initWithSource:injectionTime:forMainFrameOnly:"),
  1753. get_nsstring("window.external = this; invoke = function(arg){ "
  1754. "webkit.messageHandlers.invoke.postMessage(arg); };"),
  1755. WKUserScriptInjectionTimeAtDocumentStart, 0);
  1756. objc_msgSend(userController, sel_registerName("addUserScript:"),
  1757. windowExternalOverrideScript);
  1758. id config = objc_msgSend((id)objc_getClass("WKWebViewConfiguration"),
  1759. sel_registerName("new"));
  1760. id processPool = objc_msgSend(config, sel_registerName("processPool"));
  1761. objc_msgSend(processPool, sel_registerName("_setDownloadDelegate:"),
  1762. downloadDelegate);
  1763. objc_msgSend(config, sel_registerName("setProcessPool:"), processPool);
  1764. objc_msgSend(config, sel_registerName("setUserContentController:"),
  1765. userController);
  1766. objc_msgSend(config, sel_registerName("setPreferences:"), wkPref);
  1767. Class __NSWindowDelegate = objc_allocateClassPair(objc_getClass("NSObject"),
  1768. "__NSWindowDelegate", 0);
  1769. class_addProtocol(__NSWindowDelegate, objc_getProtocol("NSWindowDelegate"));
  1770. class_replaceMethod(__NSWindowDelegate, sel_registerName("windowWillClose:"),
  1771. (IMP)webview_window_will_close, "v@:@");
  1772. objc_registerClassPair(__NSWindowDelegate);
  1773. w->priv.windowDelegate =
  1774. objc_msgSend((id)__NSWindowDelegate, sel_registerName("new"));
  1775. objc_setAssociatedObject(w->priv.windowDelegate, "webview", (id)(w),
  1776. OBJC_ASSOCIATION_ASSIGN);
  1777. id nsTitle =
  1778. objc_msgSend((id)objc_getClass("NSString"),
  1779. sel_registerName("stringWithUTF8String:"), w->title);
  1780. CGRect r = CGRectMake(0, 0, w->width, w->height);
  1781. unsigned int style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
  1782. NSWindowStyleMaskMiniaturizable;
  1783. if (w->resizable) {
  1784. style = style | NSWindowStyleMaskResizable;
  1785. }
  1786. w->priv.window =
  1787. objc_msgSend((id)objc_getClass("NSWindow"), sel_registerName("alloc"));
  1788. objc_msgSend(w->priv.window,
  1789. sel_registerName("initWithContentRect:styleMask:backing:defer:"),
  1790. r, style, NSBackingStoreBuffered, 0);
  1791. objc_msgSend(w->priv.window, sel_registerName("autorelease"));
  1792. objc_msgSend(w->priv.window, sel_registerName("setTitle:"), nsTitle);
  1793. objc_msgSend(w->priv.window, sel_registerName("setDelegate:"),
  1794. w->priv.windowDelegate);
  1795. objc_msgSend(w->priv.window, sel_registerName("center"));
  1796. Class __WKUIDelegate =
  1797. objc_allocateClassPair(objc_getClass("NSObject"), "__WKUIDelegate", 0);
  1798. class_addProtocol(__WKUIDelegate, objc_getProtocol("WKUIDelegate"));
  1799. class_addMethod(__WKUIDelegate,
  1800. sel_registerName("webView:runOpenPanelWithParameters:"
  1801. "initiatedByFrame:completionHandler:"),
  1802. (IMP)run_open_panel, "v@:@@@?");
  1803. class_addMethod(__WKUIDelegate,
  1804. sel_registerName("webView:runJavaScriptAlertPanelWithMessage:"
  1805. "initiatedByFrame:completionHandler:"),
  1806. (IMP)run_alert_panel, "v@:@@@?");
  1807. class_addMethod(
  1808. __WKUIDelegate,
  1809. sel_registerName("webView:runJavaScriptConfirmPanelWithMessage:"
  1810. "initiatedByFrame:completionHandler:"),
  1811. (IMP)run_confirmation_panel, "v@:@@@?");
  1812. objc_registerClassPair(__WKUIDelegate);
  1813. id uiDel = objc_msgSend((id)__WKUIDelegate, sel_registerName("new"));
  1814. Class __WKNavigationDelegate = objc_allocateClassPair(
  1815. objc_getClass("NSObject"), "__WKNavigationDelegate", 0);
  1816. class_addProtocol(__WKNavigationDelegate,
  1817. objc_getProtocol("WKNavigationDelegate"));
  1818. class_addMethod(
  1819. __WKNavigationDelegate,
  1820. sel_registerName(
  1821. "webView:decidePolicyForNavigationResponse:decisionHandler:"),
  1822. (IMP)make_nav_policy_decision, "v@:@@?");
  1823. objc_registerClassPair(__WKNavigationDelegate);
  1824. id navDel = objc_msgSend((id)__WKNavigationDelegate, sel_registerName("new"));
  1825. w->priv.webview =
  1826. objc_msgSend((id)objc_getClass("WKWebView"), sel_registerName("alloc"));
  1827. objc_msgSend(w->priv.webview,
  1828. sel_registerName("initWithFrame:configuration:"), r, config);
  1829. objc_msgSend(w->priv.webview, sel_registerName("setUIDelegate:"), uiDel);
  1830. objc_msgSend(w->priv.webview, sel_registerName("setNavigationDelegate:"),
  1831. navDel);
  1832. id nsURL = objc_msgSend((id)objc_getClass("NSURL"),
  1833. sel_registerName("URLWithString:"),
  1834. get_nsstring(webview_check_url(w->url)));
  1835. objc_msgSend(w->priv.webview, sel_registerName("loadRequest:"),
  1836. objc_msgSend((id)objc_getClass("NSURLRequest"),
  1837. sel_registerName("requestWithURL:"), nsURL));
  1838. objc_msgSend(w->priv.webview, sel_registerName("setAutoresizesSubviews:"), 1);
  1839. objc_msgSend(w->priv.webview, sel_registerName("setAutoresizingMask:"),
  1840. (NSViewWidthSizable | NSViewHeightSizable));
  1841. objc_msgSend(objc_msgSend(w->priv.window, sel_registerName("contentView")),
  1842. sel_registerName("addSubview:"), w->priv.webview);
  1843. objc_msgSend(w->priv.window, sel_registerName("orderFrontRegardless"));
  1844. objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
  1845. sel_registerName("sharedApplication")),
  1846. sel_registerName("setActivationPolicy:"),
  1847. NSApplicationActivationPolicyRegular);
  1848. objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
  1849. sel_registerName("sharedApplication")),
  1850. sel_registerName("finishLaunching"));
  1851. objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
  1852. sel_registerName("sharedApplication")),
  1853. sel_registerName("activateIgnoringOtherApps:"), 1);
  1854. id menubar =
  1855. objc_msgSend((id)objc_getClass("NSMenu"), sel_registerName("alloc"));
  1856. objc_msgSend(menubar, sel_registerName("initWithTitle:"), get_nsstring(""));
  1857. objc_msgSend(menubar, sel_registerName("autorelease"));
  1858. id appName = objc_msgSend(objc_msgSend((id)objc_getClass("NSProcessInfo"),
  1859. sel_registerName("processInfo")),
  1860. sel_registerName("processName"));
  1861. id appMenuItem =
  1862. objc_msgSend((id)objc_getClass("NSMenuItem"), sel_registerName("alloc"));
  1863. objc_msgSend(appMenuItem,
  1864. sel_registerName("initWithTitle:action:keyEquivalent:"), appName,
  1865. NULL, get_nsstring(""));
  1866. id appMenu =
  1867. objc_msgSend((id)objc_getClass("NSMenu"), sel_registerName("alloc"));
  1868. objc_msgSend(appMenu, sel_registerName("initWithTitle:"), appName);
  1869. objc_msgSend(appMenu, sel_registerName("autorelease"));
  1870. objc_msgSend(appMenuItem, sel_registerName("setSubmenu:"), appMenu);
  1871. objc_msgSend(menubar, sel_registerName("addItem:"), appMenuItem);
  1872. id title =
  1873. objc_msgSend(get_nsstring("Hide "),
  1874. sel_registerName("stringByAppendingString:"), appName);
  1875. id item = create_menu_item(title, "hide:", "h");
  1876. objc_msgSend(appMenu, sel_registerName("addItem:"), item);
  1877. item = create_menu_item(get_nsstring("Hide Others"),
  1878. "hideOtherApplications:", "h");
  1879. objc_msgSend(item, sel_registerName("setKeyEquivalentModifierMask:"),
  1880. (NSEventModifierFlagOption | NSEventModifierFlagCommand));
  1881. objc_msgSend(appMenu, sel_registerName("addItem:"), item);
  1882. item =
  1883. create_menu_item(get_nsstring("Show All"), "unhideAllApplications:", "");
  1884. objc_msgSend(appMenu, sel_registerName("addItem:"), item);
  1885. objc_msgSend(appMenu, sel_registerName("addItem:"),
  1886. objc_msgSend((id)objc_getClass("NSMenuItem"),
  1887. sel_registerName("separatorItem")));
  1888. title = objc_msgSend(get_nsstring("Quit "),
  1889. sel_registerName("stringByAppendingString:"), appName);
  1890. item = create_menu_item(title, "terminate:", "q");
  1891. objc_msgSend(appMenu, sel_registerName("addItem:"), item);
  1892. id editMenuItem =
  1893. objc_msgSend((id)objc_getClass("NSMenuItem"), sel_registerName("alloc"));
  1894. objc_msgSend(editMenuItem,
  1895. sel_registerName("initWithTitle:action:keyEquivalent:"), get_nsstring("Edit"),
  1896. NULL, get_nsstring(""));
  1897. /***
  1898. Edit menu
  1899. ***/
  1900. id editMenu =
  1901. objc_msgSend((id)objc_getClass("NSMenu"), sel_registerName("alloc"));
  1902. objc_msgSend(editMenu, sel_registerName("initWithTitle:"), get_nsstring("Edit"));
  1903. objc_msgSend(editMenu, sel_registerName("autorelease"));
  1904. objc_msgSend(editMenuItem, sel_registerName("setSubmenu:"), editMenu);
  1905. objc_msgSend(menubar, sel_registerName("addItem:"), editMenuItem);
  1906. item = create_menu_item(get_nsstring("Undo"), "undo:", "z");
  1907. objc_msgSend(editMenu, sel_registerName("addItem:"), item);
  1908. item = create_menu_item(get_nsstring("Redo"), "redo:", "y");
  1909. objc_msgSend(editMenu, sel_registerName("addItem:"), item);
  1910. item = objc_msgSend((id)objc_getClass("NSMenuItem"), sel_registerName("separatorItem"));
  1911. objc_msgSend(editMenu, sel_registerName("addItem:"), item);
  1912. item = create_menu_item(get_nsstring("Cut"), "cut:", "x");
  1913. objc_msgSend(editMenu, sel_registerName("addItem:"), item);
  1914. item = create_menu_item(get_nsstring("Copy"), "copy:", "c");
  1915. objc_msgSend(editMenu, sel_registerName("addItem:"), item);
  1916. item = create_menu_item(get_nsstring("Paste"), "paste:", "v");
  1917. objc_msgSend(editMenu, sel_registerName("addItem:"), item);
  1918. item = create_menu_item(get_nsstring("Select All"), "selectAll:", "a");
  1919. objc_msgSend(editMenu, sel_registerName("addItem:"), item);
  1920. /***
  1921. Finalize menubar
  1922. ***/
  1923. objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
  1924. sel_registerName("sharedApplication")),
  1925. sel_registerName("setMainMenu:"), menubar);
  1926. w->priv.should_exit = 0;
  1927. return 0;
  1928. }
  1929. WEBVIEW_API int webview_loop(struct webview *w, int blocking) {
  1930. id until = (blocking ? objc_msgSend((id)objc_getClass("NSDate"),
  1931. sel_registerName("distantFuture"))
  1932. : objc_msgSend((id)objc_getClass("NSDate"),
  1933. sel_registerName("distantPast")));
  1934. id event = objc_msgSend(
  1935. objc_msgSend((id)objc_getClass("NSApplication"),
  1936. sel_registerName("sharedApplication")),
  1937. sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"),
  1938. ULONG_MAX, until,
  1939. objc_msgSend((id)objc_getClass("NSString"),
  1940. sel_registerName("stringWithUTF8String:"),
  1941. "kCFRunLoopDefaultMode"),
  1942. true);
  1943. if (event) {
  1944. objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
  1945. sel_registerName("sharedApplication")),
  1946. sel_registerName("sendEvent:"), event);
  1947. }
  1948. return w->priv.should_exit;
  1949. }
  1950. WEBVIEW_API int webview_eval(struct webview *w, const char *js) {
  1951. objc_msgSend(w->priv.webview,
  1952. sel_registerName("evaluateJavaScript:completionHandler:"),
  1953. get_nsstring(js), NULL);
  1954. return 0;
  1955. }
  1956. WEBVIEW_API void webview_set_title(struct webview *w, const char *title) {
  1957. objc_msgSend(w->priv.window, sel_registerName("setTitle"),
  1958. get_nsstring(title));
  1959. }
  1960. WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) {
  1961. unsigned long windowStyleMask = (unsigned long)objc_msgSend(
  1962. w->priv.window, sel_registerName("styleMask"));
  1963. int b = (((windowStyleMask & NSWindowStyleMaskFullScreen) ==
  1964. NSWindowStyleMaskFullScreen)
  1965. ? 1
  1966. : 0);
  1967. if (b != fullscreen) {
  1968. objc_msgSend(w->priv.window, sel_registerName("toggleFullScreen:"), NULL);
  1969. }
  1970. }
  1971. WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
  1972. uint8_t b, uint8_t a) {
  1973. id color = objc_msgSend((id)objc_getClass("NSColor"),
  1974. sel_registerName("colorWithRed:green:blue:alpha:"),
  1975. (float)r / 255.0, (float)g / 255.0, (float)b / 255.0,
  1976. (float)a / 255.0);
  1977. objc_msgSend(w->priv.window, sel_registerName("setBackgroundColor:"), color);
  1978. if (0.5 >= ((r / 255.0 * 299.0) + (g / 255.0 * 587.0) + (b / 255.0 * 114.0)) /
  1979. 1000.0) {
  1980. objc_msgSend(w->priv.window, sel_registerName("setAppearance:"),
  1981. objc_msgSend((id)objc_getClass("NSAppearance"),
  1982. sel_registerName("appearanceNamed:"),
  1983. get_nsstring("NSAppearanceNameVibrantDark")));
  1984. } else {
  1985. objc_msgSend(w->priv.window, sel_registerName("setAppearance:"),
  1986. objc_msgSend((id)objc_getClass("NSAppearance"),
  1987. sel_registerName("appearanceNamed:"),
  1988. get_nsstring("NSAppearanceNameVibrantLight")));
  1989. }
  1990. objc_msgSend(w->priv.window, sel_registerName("setOpaque:"), 0);
  1991. objc_msgSend(w->priv.window,
  1992. sel_registerName("setTitlebarAppearsTransparent:"), 1);
  1993. objc_msgSend(w->priv.webview, sel_registerName("_setDrawsBackground:"), 0);
  1994. }
  1995. WEBVIEW_API void webview_dialog(struct webview *w,
  1996. enum webview_dialog_type dlgtype, int flags,
  1997. const char *title, const char *arg,
  1998. char *result, size_t resultsz) {
  1999. if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
  2000. dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) {
  2001. id panel = (id)objc_getClass("NSSavePanel");
  2002. if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) {
  2003. id openPanel = objc_msgSend((id)objc_getClass("NSOpenPanel"),
  2004. sel_registerName("openPanel"));
  2005. if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) {
  2006. objc_msgSend(openPanel, sel_registerName("setCanChooseFiles:"), 0);
  2007. objc_msgSend(openPanel, sel_registerName("setCanChooseDirectories:"),
  2008. 1);
  2009. } else {
  2010. objc_msgSend(openPanel, sel_registerName("setCanChooseFiles:"), 1);
  2011. objc_msgSend(openPanel, sel_registerName("setCanChooseDirectories:"),
  2012. 0);
  2013. }
  2014. objc_msgSend(openPanel, sel_registerName("setResolvesAliases:"), 0);
  2015. objc_msgSend(openPanel, sel_registerName("setAllowsMultipleSelection:"),
  2016. 0);
  2017. panel = openPanel;
  2018. } else {
  2019. panel = objc_msgSend((id)objc_getClass("NSSavePanel"),
  2020. sel_registerName("savePanel"));
  2021. }
  2022. objc_msgSend(panel, sel_registerName("setCanCreateDirectories:"), 1);
  2023. objc_msgSend(panel, sel_registerName("setShowsHiddenFiles:"), 1);
  2024. objc_msgSend(panel, sel_registerName("setExtensionHidden:"), 0);
  2025. objc_msgSend(panel, sel_registerName("setCanSelectHiddenExtension:"), 0);
  2026. objc_msgSend(panel, sel_registerName("setTreatsFilePackagesAsDirectories:"),
  2027. 1);
  2028. objc_msgSend(
  2029. panel, sel_registerName("beginSheetModalForWindow:completionHandler:"),
  2030. w->priv.window, ^(id result) {
  2031. objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
  2032. sel_registerName("sharedApplication")),
  2033. sel_registerName("stopModalWithCode:"), result);
  2034. });
  2035. if (objc_msgSend(objc_msgSend((id)objc_getClass("NSApplication"),
  2036. sel_registerName("sharedApplication")),
  2037. sel_registerName("runModalForWindow:"),
  2038. panel) == (id)NSModalResponseOK) {
  2039. id url = objc_msgSend(panel, sel_registerName("URL"));
  2040. id path = objc_msgSend(url, sel_registerName("path"));
  2041. const char *filename =
  2042. (const char *)objc_msgSend(path, sel_registerName("UTF8String"));
  2043. strlcpy(result, filename, resultsz);
  2044. }
  2045. } else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) {
  2046. id a = objc_msgSend((id)objc_getClass("NSAlert"), sel_registerName("new"));
  2047. switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) {
  2048. case WEBVIEW_DIALOG_FLAG_INFO:
  2049. objc_msgSend(a, sel_registerName("setAlertStyle:"),
  2050. NSAlertStyleInformational);
  2051. break;
  2052. case WEBVIEW_DIALOG_FLAG_WARNING:
  2053. printf("Warning\n");
  2054. objc_msgSend(a, sel_registerName("setAlertStyle:"), NSAlertStyleWarning);
  2055. break;
  2056. case WEBVIEW_DIALOG_FLAG_ERROR:
  2057. printf("Error\n");
  2058. objc_msgSend(a, sel_registerName("setAlertStyle:"), NSAlertStyleCritical);
  2059. break;
  2060. }
  2061. objc_msgSend(a, sel_registerName("setShowsHelp:"), 0);
  2062. objc_msgSend(a, sel_registerName("setShowsSuppressionButton:"), 0);
  2063. objc_msgSend(a, sel_registerName("setMessageText:"), get_nsstring(title));
  2064. objc_msgSend(a, sel_registerName("setInformativeText:"), get_nsstring(arg));
  2065. objc_msgSend(a, sel_registerName("addButtonWithTitle:"),
  2066. get_nsstring("OK"));
  2067. objc_msgSend(a, sel_registerName("runModal"));
  2068. objc_msgSend(a, sel_registerName("release"));
  2069. }
  2070. }
  2071. static void webview_dispatch_cb(void *arg) {
  2072. struct webview_dispatch_arg *context = (struct webview_dispatch_arg *)arg;
  2073. (context->fn)(context->w, context->arg);
  2074. free(context);
  2075. }
  2076. WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
  2077. void *arg) {
  2078. struct webview_dispatch_arg *context = (struct webview_dispatch_arg *)malloc(
  2079. sizeof(struct webview_dispatch_arg));
  2080. context->w = w;
  2081. context->arg = arg;
  2082. context->fn = fn;
  2083. dispatch_async_f(dispatch_get_main_queue(), context, webview_dispatch_cb);
  2084. }
  2085. WEBVIEW_API void webview_terminate(struct webview *w) {
  2086. w->priv.should_exit = 1;
  2087. }
  2088. WEBVIEW_API void webview_exit(struct webview *w) {
  2089. id app = objc_msgSend((id)objc_getClass("NSApplication"),
  2090. sel_registerName("sharedApplication"));
  2091. objc_msgSend(app, sel_registerName("terminate:"), app);
  2092. }
  2093. WEBVIEW_API void webview_print_log(const char *s) { printf("%s\n", s); }
  2094. #endif /* WEBVIEW_COCOA */
  2095. #endif /* WEBVIEW_IMPLEMENTATION */
  2096. #ifdef __cplusplus
  2097. }
  2098. #endif
  2099. #endif /* WEBVIEW_H */