1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../SDL_internal.h"
22 #include "SDL_hints.h"
23 #include "SDL_assert.h"
24
25 /* General quit handling code for SDL */
26
27 #ifdef HAVE_SIGNAL_H
28 #include <signal.h>
29 #endif
30
31 #include "SDL_events.h"
32 #include "SDL_events_c.h"
33
34 #if defined(HAVE_SIGNAL_H) || defined(HAVE_SIGACTION)
35 #define HAVE_SIGNAL_SUPPORT 1
36 #endif
37
38 #ifdef HAVE_SIGNAL_SUPPORT
39 static SDL_bool disable_signals = SDL_FALSE;
40 static SDL_bool send_quit_pending = SDL_FALSE;
41
42 #ifdef SDL_BACKGROUNDING_SIGNAL
43 static SDL_bool send_backgrounding_pending = SDL_FALSE;
44 #endif
45
46 #ifdef SDL_FOREGROUNDING_SIGNAL
47 static SDL_bool send_foregrounding_pending = SDL_FALSE;
48 #endif
49
50 static void
SDL_HandleSIG(int sig)51 SDL_HandleSIG(int sig)
52 {
53 /* Reset the signal handler */
54 signal(sig, SDL_HandleSIG);
55
56 /* Send a quit event next time the event loop pumps. */
57 /* We can't send it in signal handler; malloc() might be interrupted! */
58 if ((sig == SIGINT) || (sig == SIGTERM)) {
59 send_quit_pending = SDL_TRUE;
60 }
61
62 #ifdef SDL_BACKGROUNDING_SIGNAL
63 else if (sig == SDL_BACKGROUNDING_SIGNAL) {
64 send_backgrounding_pending = SDL_TRUE;
65 }
66 #endif
67
68 #ifdef SDL_FOREGROUNDING_SIGNAL
69 else if (sig == SDL_FOREGROUNDING_SIGNAL) {
70 send_foregrounding_pending = SDL_TRUE;
71 }
72 #endif
73 }
74
75 static void
SDL_EventSignal_Init(const int sig)76 SDL_EventSignal_Init(const int sig)
77 {
78 #ifdef HAVE_SIGACTION
79 struct sigaction action;
80
81 sigaction(sig, NULL, &action);
82 #ifdef HAVE_SA_SIGACTION
83 if ( action.sa_handler == SIG_DFL && (void (*)(int))action.sa_sigaction == SIG_DFL ) {
84 #else
85 if ( action.sa_handler == SIG_DFL ) {
86 #endif
87 action.sa_handler = SDL_HandleSIG;
88 sigaction(sig, &action, NULL);
89 }
90 #elif HAVE_SIGNAL_H
91 void (*ohandler) (int) = signal(sig, SDL_HandleSIG);
92 if (ohandler != SIG_DFL) {
93 signal(sig, ohandler);
94 }
95 #endif
96 }
97
98 static void
99 SDL_EventSignal_Quit(const int sig)
100 {
101 #ifdef HAVE_SIGACTION
102 struct sigaction action;
103 sigaction(sig, NULL, &action);
104 if ( action.sa_handler == SDL_HandleSIG ) {
105 action.sa_handler = SIG_DFL;
106 sigaction(sig, &action, NULL);
107 }
108 #elif HAVE_SIGNAL_H
109 void (*ohandler) (int) = signal(sig, SIG_DFL);
110 if (ohandler != SDL_HandleSIG) {
111 signal(sig, ohandler);
112 }
113 #endif /* HAVE_SIGNAL_H */
114 }
115
116 /* Public functions */
117 static int
118 SDL_QuitInit_Internal(void)
119 {
120 /* Both SIGINT and SIGTERM are translated into quit interrupts */
121 /* and SDL can be built to simulate iOS/Android semantics with arbitrary signals. */
122 SDL_EventSignal_Init(SIGINT);
123 SDL_EventSignal_Init(SIGTERM);
124
125 #ifdef SDL_BACKGROUNDING_SIGNAL
126 SDL_EventSignal_Init(SDL_BACKGROUNDING_SIGNAL);
127 #endif
128
129 #ifdef SDL_FOREGROUNDING_SIGNAL
130 SDL_EventSignal_Init(SDL_FOREGROUNDING_SIGNAL);
131 #endif
132
133 /* That's it! */
134 return 0;
135 }
136
137 static void
138 SDL_QuitQuit_Internal(void)
139 {
140 SDL_EventSignal_Quit(SIGINT);
141 SDL_EventSignal_Quit(SIGTERM);
142
143 #ifdef SDL_BACKGROUNDING_SIGNAL
144 SDL_EventSignal_Quit(SDL_BACKGROUNDING_SIGNAL);
145 #endif
146
147 #ifdef SDL_FOREGROUNDING_SIGNAL
148 SDL_EventSignal_Quit(SDL_FOREGROUNDING_SIGNAL);
149 #endif
150 }
151 #endif
152
153 int
154 SDL_QuitInit(void)
155 {
156 #ifdef HAVE_SIGNAL_SUPPORT
157 if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) {
158 return SDL_QuitInit_Internal();
159 }
160 #endif
161 return 0;
162 }
163
164 void
165 SDL_QuitQuit(void)
166 {
167 #ifdef HAVE_SIGNAL_SUPPORT
168 if (!disable_signals) {
169 SDL_QuitQuit_Internal();
170 }
171 #endif
172 }
173
174 void
175 SDL_SendPendingSignalEvents(void)
176 {
177 #ifdef HAVE_SIGNAL_SUPPORT
178 if (send_quit_pending) {
179 SDL_SendQuit();
180 SDL_assert(!send_quit_pending);
181 }
182
183 #ifdef SDL_BACKGROUNDING_SIGNAL
184 if (send_backgrounding_pending) {
185 send_backgrounding_pending = SDL_FALSE;
186 SDL_OnApplicationWillResignActive();
187 }
188 #endif
189
190 #ifdef SDL_FOREGROUNDING_SIGNAL
191 if (send_foregrounding_pending) {
192 send_foregrounding_pending = SDL_FALSE;
193 SDL_OnApplicationDidBecomeActive();
194 }
195 #endif
196 #endif
197 }
198
199 /* This function returns 1 if it's okay to close the application window */
200 int
201 SDL_SendQuit(void)
202 {
203 #ifdef HAVE_SIGNAL_SUPPORT
204 send_quit_pending = SDL_FALSE;
205 #endif
206 return SDL_SendAppEvent(SDL_QUIT);
207 }
208
209 /* vi: set ts=4 sw=4 expandtab: */
210