1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2014-2018. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 #if defined(_WIN32)
22 #include <wx/msw/private.h> // for wxSetInstance
23 #endif
24
25 #include "wxe_impl.h"
26
27 // Until fixed in emulator
28 #ifndef _WIN32
29 extern "C" {
30 extern void erts_thread_disable_fpe(void);
31 }
32 #endif
33
34 ErlDrvTid wxe_thread;
35
36 ErlDrvMutex *wxe_status_m;
37 ErlDrvCond *wxe_status_c;
38
39 int wxe_status = WXE_NOT_INITIATED;
40
41 ErlDrvMutex * wxe_batch_locker_m;
42 ErlDrvCond * wxe_batch_locker_c;
43 ErlDrvTermData init_caller = 0;
44
45 #ifdef __DARWIN__
46 extern "C" {
47 int erl_drv_stolen_main_thread_join(ErlDrvTid tid, void **respp);
48 int erl_drv_steal_main_thread(char *name,
49 ErlDrvTid *dtid,
50 void* (*func)(void*),
51 void* arg,
52 ErlDrvThreadOpts *opts);
53 }
54 #endif
55
56 void *wxe_main_loop(void * );
57
58 /* ************************************************************
59 * START AND STOP of driver thread
60 * ************************************************************/
61
start_native_gui(wxe_data * sd)62 int start_native_gui(wxe_data *sd)
63 {
64 int res;
65 wxe_status_m = erl_drv_mutex_create((char *) "wxe_status_m");
66 wxe_status_c = erl_drv_cond_create((char *)"wxe_status_c");
67
68 wxe_batch_locker_m = erl_drv_mutex_create((char *)"wxe_batch_locker_m");
69 wxe_batch_locker_c = erl_drv_cond_create((char *)"wxe_batch_locker_c");
70 init_caller = driver_connected(sd->port_handle);
71
72 #ifdef __DARWIN__
73 res = erl_drv_steal_main_thread((char *)"wxwidgets",
74 &wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL);
75 #else
76 ErlDrvThreadOpts *opts = erl_drv_thread_opts_create((char *)"wx thread");
77 opts->suggested_stack_size = 8192;
78 res = erl_drv_thread_create((char *)"wxwidgets",
79 &wxe_thread,wxe_main_loop,(void *) sd->pdl,opts);
80 erl_drv_thread_opts_destroy(opts);
81 #endif
82 if(res == 0) {
83 erl_drv_mutex_lock(wxe_status_m);
84 for(;wxe_status == WXE_NOT_INITIATED;) {
85 erl_drv_cond_wait(wxe_status_c, wxe_status_m);
86 }
87 erl_drv_mutex_unlock(wxe_status_m);
88 return wxe_status;
89 } else {
90 wxString msg;
91 msg.Printf(wxT("Erlang failed to create wxe-thread %d\r\n"), res);
92 send_msg("error", &msg);
93 return -1;
94 }
95 }
96
stop_native_gui(wxe_data * sd)97 void stop_native_gui(wxe_data *sd)
98 {
99 if(wxe_status == WXE_INITIATED) {
100 meta_command(WXE_SHUTDOWN, sd);
101 }
102 #ifdef __DARWIN__
103 erl_drv_stolen_main_thread_join(wxe_thread, NULL);
104 #else
105 erl_drv_thread_join(wxe_thread, NULL);
106 #endif
107 erl_drv_mutex_destroy(wxe_status_m);
108 erl_drv_cond_destroy(wxe_status_c);
109 erl_drv_mutex_destroy(wxe_batch_locker_m);
110 erl_drv_cond_destroy(wxe_batch_locker_c);
111 }
112
113 /* ************************************************************
114 * wxWidgets Thread
115 * ************************************************************/
116
wxe_main_loop(void * vpdl)117 void *wxe_main_loop(void *vpdl)
118 {
119 int result;
120 int argc = 1;
121 wxChar temp[128] = L"Erlang";
122
123 size_t app_len = 127;
124 char app_title_buf[128];
125 int res = erl_drv_getenv("WX_APP_TITLE", app_title_buf, &app_len);
126 if (res == 0) {
127 wxString title = wxString::FromUTF8(app_title_buf);
128 int size = title.Length() < 127 ? title.Length() : 126;
129 for(int i = 0; i < size; i++) {
130 temp[i] = title[i];
131 }
132 temp[size] = 0;
133 }
134
135 wxChar * argv[] = {(wxChar *)temp, NULL};
136 ErlDrvPDL pdl = (ErlDrvPDL) vpdl;
137
138 driver_pdl_inc_refc(pdl);
139
140 // Disable floating point execption if they are on.
141 // This should be done in emulator but it's not in yet.
142 #ifndef _WIN32
143 erts_thread_disable_fpe();
144 #else
145 // Setup that wxWidgets should look for cursors and icons in
146 // this dll and not in werl.exe (which is the default)
147 HMODULE WXEHandle = GetModuleHandle(_T("wxe_driver"));
148 wxSetInstance((HINSTANCE) WXEHandle);
149 #endif
150
151 wxe_ps_init();
152 result = wxEntry(argc, argv);
153 // fprintf(stderr, "WXWidgets quits main loop %d \r\n", result);
154 if(result >= 0 && wxe_status == WXE_INITIATED) {
155 /* We are done try to make a clean exit */
156 wxe_status = WXE_EXITED;
157 driver_pdl_dec_refc(pdl);
158 #ifndef __DARWIN__
159 erl_drv_thread_exit(NULL);
160 #endif
161 return NULL;
162 } else {
163 erl_drv_mutex_lock(wxe_status_m);
164 wxe_status = WXE_ERROR;
165 erl_drv_cond_signal(wxe_status_c);
166 erl_drv_mutex_unlock(wxe_status_m);
167 driver_pdl_dec_refc(pdl);
168 return NULL;
169 }
170 }
171