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 ErlNifTid wxe_thread;
28 
29 ErlNifMutex *wxe_status_m;
30 ErlNifCond  *wxe_status_c;
31 
32 int wxe_status = WXE_NOT_INITIATED;
33 
34 ErlNifMutex * wxe_batch_locker_m;
35 ErlNifCond  * wxe_batch_locker_c;
36 ErlNifPid init_caller;
37 
38 #ifdef __DARWIN__
39 extern "C" {
40   int erl_drv_stolen_main_thread_join(ErlNifTid tid, void **respp);
41   int erl_drv_steal_main_thread(char *name,
42 				ErlNifTid *dtid,
43 				void* (*func)(void*),
44 				void* arg,
45 				ErlNifThreadOpts *opts);
46 }
47 #endif
48 
49 void *wxe_main_loop(void * );
50 
51 /* ************************************************************
52  *  START AND STOP of driver thread
53  * ************************************************************/
54 
start_native_gui(ErlNifEnv * env)55 int start_native_gui(ErlNifEnv *env)
56 {
57   int res;
58   wxe_status_m = enif_mutex_create((char *) "wxe_status_m");
59   wxe_status_c = enif_cond_create((char *)"wxe_status_c");
60 
61   wxe_batch_locker_m = enif_mutex_create((char *)"wxe_batch_locker_m");
62   wxe_batch_locker_c = enif_cond_create((char *)"wxe_batch_locker_c");
63   enif_self(env, &init_caller);
64 
65 #ifdef __DARWIN__
66   res = erl_drv_steal_main_thread((char *)"wxwidgets",
67 				  &wxe_thread,wxe_main_loop,(void *) NULL,NULL);
68 #else
69   ErlNifThreadOpts *opts = enif_thread_opts_create((char *)"wx thread");
70   opts->suggested_stack_size = 8192;
71   res = enif_thread_create((char *)"wxwidgets",
72                            &wxe_thread,wxe_main_loop,(void *) NULL,opts);
73   enif_thread_opts_destroy(opts);
74 #endif
75   if(res == 0) {
76     enif_mutex_lock(wxe_status_m);
77     for(;wxe_status == WXE_NOT_INITIATED;) {
78       enif_cond_wait(wxe_status_c, wxe_status_m);
79     }
80     enif_mutex_unlock(wxe_status_m);
81     return wxe_status;
82   } else {
83     wxString msg;
84     msg.Printf(wxT("Erlang failed to create wxe-thread %d\r\n"), res);
85     send_msg("error", &msg);
86     return -1;
87   }
88 }
89 
stop_native_gui(ErlNifEnv * env)90 void stop_native_gui(ErlNifEnv* env)
91 {
92   if(wxe_status == WXE_INITIATED) {
93     meta_command(env, WXE_SHUTDOWN, NULL);
94   }
95 #ifdef __DARWIN__
96   erl_drv_stolen_main_thread_join(wxe_thread, NULL);
97 #else
98   enif_thread_join(wxe_thread, NULL);
99 #endif
100   enif_mutex_destroy(wxe_status_m);
101   enif_cond_destroy(wxe_status_c);
102   enif_mutex_destroy(wxe_batch_locker_m);
103   enif_cond_destroy(wxe_batch_locker_c);
104 }
105 
106 /* ************************************************************
107  *  wxWidgets Thread
108  * ************************************************************/
109 
wxe_main_loop(void * _unused)110 void *wxe_main_loop(void * _unused)
111 {
112   int result;
113   int  argc = 1;
114   wxChar temp[128] = L"Erlang";
115 
116   size_t app_len = 127;
117   char app_title_buf[128];
118   int res = enif_getenv("WX_APP_TITLE", app_title_buf, &app_len);
119   if (res == 0) {
120     wxString title = wxString::FromUTF8(app_title_buf);
121     int size = title.Length() < 127 ? title.Length() : 126;
122     for(int i = 0; i < size; i++) {
123       temp[i] = title[i];
124     }
125     temp[size] = 0;
126   }
127 
128   wxChar * argv[] = {(wxChar *)temp, NULL};
129 
130 #ifdef _WIN32
131   // Setup that wxWidgets should look for cursors and icons in
132   // this dll and not in werl.exe (which is the default)
133   HMODULE WXEHandle = GetModuleHandle(_T("wxe_driver"));
134   wxSetInstance((HINSTANCE) WXEHandle);
135 #endif
136 
137   wxe_ps_init();
138   result = wxEntry(argc, argv);
139   // fprintf(stderr, "WXWidgets quits main loop %d \r\n", result);
140   if(result >= 0 && wxe_status == WXE_INITIATED) {
141     /* We are done try to make a clean exit */
142     wxe_status = WXE_EXITED;
143 #ifndef __DARWIN__
144     enif_thread_exit(NULL);
145 #endif
146     return NULL;
147   } else {
148     enif_mutex_lock(wxe_status_m);
149     wxe_status = WXE_ERROR;
150     enif_cond_signal(wxe_status_c);
151     enif_mutex_unlock(wxe_status_m);
152     // driver_pdl_dec_refc(pdl);
153     return NULL;
154   }
155 }
156