]> git.xonotic.org Git - xonotic/darkplaces.git/blob - sys_sdl.c
Sys_Error(): don't leave a dead window covering the OS UI or crash dialog
[xonotic/darkplaces.git] / sys_sdl.c
1 #ifdef WIN32
2 #include <io.h> // Include this BEFORE darkplaces.h because it uses strncpy which trips DP_STATIC_ASSERT
3 #include "conio.h"
4 #else
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/time.h>
8 #endif
9
10 #ifdef __ANDROID__
11 #include <android/log.h>
12 #endif
13
14 #include <signal.h>
15
16 /*
17  * Include this BEFORE darkplaces.h because it breaks wrapping
18  * _Static_assert. Cloudwalk has no idea how or why so don't ask.
19  */
20 #include <SDL.h>
21
22 #include "darkplaces.h"
23
24 #ifdef WIN32
25 #ifdef _MSC_VER
26 #pragma comment(lib, "sdl2.lib")
27 #pragma comment(lib, "sdl2main.lib")
28 #endif
29 #endif
30
31 sys_t sys;
32
33 // =======================================================================
34 // General routines
35 // =======================================================================
36
37 void Sys_Shutdown (void)
38 {
39 #ifdef __ANDROID__
40         Sys_AllowProfiling(false);
41 #endif
42 #ifndef WIN32
43         fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~O_NONBLOCK);
44 #endif
45         fflush(stdout);
46         SDL_Quit();
47 }
48
49 static qbool nocrashdialog;
50 void Sys_Error (const char *error, ...)
51 {
52         va_list argptr;
53         char string[MAX_INPUTLINE];
54
55 // change stdin to non blocking
56 #ifndef WIN32
57         fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~O_NONBLOCK);
58 #endif
59
60         va_start (argptr,error);
61         dpvsnprintf (string, sizeof (string), error, argptr);
62         va_end (argptr);
63
64         Con_Printf(CON_ERROR "Engine Error: %s\n", string);
65         
66         // don't want a dead window left blocking the OS UI or the crash dialog
67         Host_Shutdown();
68
69         if(!nocrashdialog)
70                 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Engine Error", string, NULL);
71
72         exit (1);
73 }
74
75 void Sys_Print(const char *text)
76 {
77 #ifdef __ANDROID__
78         if (developer.integer > 0)
79         {
80                 __android_log_write(ANDROID_LOG_DEBUG, sys.argv[0], text);
81         }
82 #else
83         if(sys.outfd < 0)
84                 return;
85 #ifndef WIN32
86         // BUG: for some reason, NDELAY also affects stdout (1) when used on stdin (0).
87         // this is because both go to /dev/tty by default!
88         {
89                 int origflags = fcntl (sys.outfd, F_GETFL, 0);
90                 fcntl (sys.outfd, F_SETFL, origflags & ~O_NONBLOCK);
91 #endif
92 #ifdef WIN32
93 #define write _write
94 #endif
95                 while(*text)
96                 {
97                         fs_offset_t written = (fs_offset_t)write(sys.outfd, text, (int)strlen(text));
98                         if(written <= 0)
99                                 break; // sorry, I cannot do anything about this error - without an output
100                         text += written;
101                 }
102 #ifndef WIN32
103                 fcntl (sys.outfd, F_SETFL, origflags);
104         }
105 #endif
106         //fprintf(stdout, "%s", text);
107 #endif
108 }
109
110 char *Sys_ConsoleInput(void)
111 {
112         static char text[MAX_INPUTLINE];
113         int len = 0;
114 #ifdef WIN32
115         int c;
116
117         // read a line out
118         while (_kbhit ())
119         {
120                 c = _getch ();
121                 _putch (c);
122                 if (c == '\r')
123                 {
124                         text[len] = 0;
125                         _putch ('\n');
126                         len = 0;
127                         return text;
128                 }
129                 if (c == 8)
130                 {
131                         if (len)
132                         {
133                                 _putch (' ');
134                                 _putch (c);
135                                 len--;
136                                 text[len] = 0;
137                         }
138                         continue;
139                 }
140                 text[len] = c;
141                 len++;
142                 text[len] = 0;
143                 if (len == sizeof (text))
144                         len = 0;
145         }
146 #else
147         fd_set fdset;
148         struct timeval timeout;
149         FD_ZERO(&fdset);
150         FD_SET(0, &fdset); // stdin
151         timeout.tv_sec = 0;
152         timeout.tv_usec = 0;
153         if (select (1, &fdset, NULL, NULL, &timeout) != -1 && FD_ISSET(0, &fdset))
154         {
155                 len = read (0, text, sizeof(text));
156                 if (len >= 1)
157                 {
158                         // rip off the \n and terminate
159                         text[len-1] = 0;
160                         return text;
161                 }
162         }
163 #endif
164         return NULL;
165 }
166
167 char *Sys_GetClipboardData (void)
168 {
169         char *data = NULL;
170         char *cliptext;
171
172         cliptext = SDL_GetClipboardText();
173         if (cliptext != NULL) {
174                 size_t allocsize;
175                 allocsize = min(MAX_INPUTLINE, strlen(cliptext) + 1);
176                 data = (char *)Z_Malloc (allocsize);
177                 strlcpy (data, cliptext, allocsize);
178                 SDL_free(cliptext);
179         }
180
181         return data;
182 }
183
184 int main (int argc, char *argv[])
185 {
186         signal(SIGFPE, SIG_IGN);
187
188 #ifdef __ANDROID__
189         Sys_AllowProfiling(true);
190 #endif
191
192         sys.selffd = -1;
193         sys.argc = argc;
194         sys.argv = (const char **)argv;
195
196         // Sys_Error this early in startup might screw with automated
197         // workflows or something if we show the dialog by default.
198         nocrashdialog = true;
199
200         Sys_ProvideSelfFD();
201
202         // COMMANDLINEOPTION: -nocrashdialog disables "Engine Error" crash dialog boxes
203         if(!Sys_CheckParm("-nocrashdialog"))
204                 nocrashdialog = false;
205         // COMMANDLINEOPTION: sdl: -noterminal disables console output on stdout
206         if(Sys_CheckParm("-noterminal"))
207                 sys.outfd = -1;
208         // COMMANDLINEOPTION: sdl: -stderr moves console output to stderr
209         else if(Sys_CheckParm("-stderr"))
210                 sys.outfd = 2;
211         else
212                 sys.outfd = 1;
213
214 #ifndef WIN32
215         fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | O_NONBLOCK);
216 #endif
217
218         // we don't know which systems we'll want to init, yet...
219         SDL_Init(0);
220
221         // used by everything
222         Memory_Init();
223
224         Host_Main();
225
226         Sys_Quit(0);
227         
228         return 0;
229 }
230
231 qbool sys_supportsdlgetticks = true;
232 unsigned int Sys_SDL_GetTicks (void)
233 {
234         return SDL_GetTicks();
235 }
236 void Sys_SDL_Delay (unsigned int milliseconds)
237 {
238         SDL_Delay(milliseconds);
239 }