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