1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2021 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 | |
23 | /* General event handling code for SDL */ |
24 | |
25 | #include "SDL.h" |
26 | #include "SDL_events.h" |
27 | #include "SDL_thread.h" |
28 | #include "SDL_events_c.h" |
29 | #include "../timer/SDL_timer_c.h" |
30 | #if !SDL_JOYSTICK_DISABLED |
31 | #include "../joystick/SDL_joystick_c.h" |
32 | #endif |
33 | #include "../video/SDL_sysvideo.h" |
34 | #include "SDL_syswm.h" |
35 | |
36 | #undef SDL_PRIs64 |
37 | #ifdef __WIN32__ |
38 | #define SDL_PRIs64 "I64d" |
39 | #else |
40 | #define SDL_PRIs64 "lld" |
41 | #endif |
42 | |
43 | /* An arbitrary limit so we don't have unbounded growth */ |
44 | #define SDL_MAX_QUEUED_EVENTS 65535 |
45 | |
46 | typedef struct SDL_EventWatcher { |
47 | SDL_EventFilter callback; |
48 | void *userdata; |
49 | SDL_bool removed; |
50 | } SDL_EventWatcher; |
51 | |
52 | static SDL_mutex *SDL_event_watchers_lock; |
53 | static SDL_EventWatcher SDL_EventOK; |
54 | static SDL_EventWatcher *SDL_event_watchers = NULL; |
55 | static int SDL_event_watchers_count = 0; |
56 | static SDL_bool SDL_event_watchers_dispatching = SDL_FALSE; |
57 | static SDL_bool SDL_event_watchers_removed = SDL_FALSE; |
58 | |
59 | typedef struct { |
60 | Uint32 bits[8]; |
61 | } SDL_DisabledEventBlock; |
62 | |
63 | static SDL_DisabledEventBlock *SDL_disabled_events[256]; |
64 | static Uint32 SDL_userevents = SDL_USEREVENT; |
65 | |
66 | /* Private data -- event queue */ |
67 | typedef struct _SDL_EventEntry |
68 | { |
69 | SDL_Event event; |
70 | SDL_SysWMmsg msg; |
71 | struct _SDL_EventEntry *prev; |
72 | struct _SDL_EventEntry *next; |
73 | } SDL_EventEntry; |
74 | |
75 | typedef struct _SDL_SysWMEntry |
76 | { |
77 | SDL_SysWMmsg msg; |
78 | struct _SDL_SysWMEntry *next; |
79 | } SDL_SysWMEntry; |
80 | |
81 | static struct |
82 | { |
83 | SDL_mutex *lock; |
84 | SDL_atomic_t active; |
85 | SDL_atomic_t count; |
86 | int max_events_seen; |
87 | SDL_EventEntry *head; |
88 | SDL_EventEntry *tail; |
89 | SDL_EventEntry *free; |
90 | SDL_SysWMEntry *wmmsg_used; |
91 | SDL_SysWMEntry *wmmsg_free; |
92 | } SDL_EventQ = { NULL, { 1 }, { 0 }, 0, NULL, NULL, NULL, NULL, NULL }; |
93 | |
94 | |
95 | #if !SDL_JOYSTICK_DISABLED |
96 | |
97 | static SDL_bool SDL_update_joysticks = SDL_TRUE; |
98 | |
99 | static void |
100 | SDL_CalculateShouldUpdateJoysticks() |
101 | { |
102 | if (SDL_GetHintBoolean(SDL_HINT_AUTO_UPDATE_JOYSTICKS, SDL_TRUE) && |
103 | (!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) { |
104 | SDL_update_joysticks = SDL_TRUE; |
105 | } else { |
106 | SDL_update_joysticks = SDL_FALSE; |
107 | } |
108 | } |
109 | |
110 | static void SDLCALL |
111 | SDL_AutoUpdateJoysticksChanged(void *userdata, const char *name, const char *oldValue, const char *hint) |
112 | { |
113 | SDL_CalculateShouldUpdateJoysticks(); |
114 | } |
115 | |
116 | #endif /* !SDL_JOYSTICK_DISABLED */ |
117 | |
118 | |
119 | #if !SDL_SENSOR_DISABLED |
120 | |
121 | static SDL_bool SDL_update_sensors = SDL_TRUE; |
122 | |
123 | static void |
124 | SDL_CalculateShouldUpdateSensors() |
125 | { |
126 | if (SDL_GetHintBoolean(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_TRUE) && |
127 | !SDL_disabled_events[SDL_SENSORUPDATE >> 8]) { |
128 | SDL_update_sensors = SDL_TRUE; |
129 | } else { |
130 | SDL_update_sensors = SDL_FALSE; |
131 | } |
132 | } |
133 | |
134 | static void SDLCALL |
135 | SDL_AutoUpdateSensorsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) |
136 | { |
137 | SDL_CalculateShouldUpdateSensors(); |
138 | } |
139 | |
140 | #endif /* !SDL_SENSOR_DISABLED */ |
141 | |
142 | |
143 | /* 0 (default) means no logging, 1 means logging, 2 means logging with mouse and finger motion */ |
144 | static int SDL_DoEventLogging = 0; |
145 | |
146 | static void SDLCALL |
147 | SDL_EventLoggingChanged(void *userdata, const char *name, const char *oldValue, const char *hint) |
148 | { |
149 | SDL_DoEventLogging = (hint && *hint) ? SDL_max(SDL_min(SDL_atoi(hint), 2), 0) : 0; |
150 | } |
151 | |
152 | static void |
153 | SDL_LogEvent(const SDL_Event *event) |
154 | { |
155 | char name[32]; |
156 | char details[128]; |
157 | |
158 | /* mouse/finger motion are spammy, ignore these if they aren't demanded. */ |
159 | if ( (SDL_DoEventLogging < 2) && |
160 | ( (event->type == SDL_MOUSEMOTION) || |
161 | (event->type == SDL_FINGERMOTION) ) ) { |
162 | return; |
163 | } |
164 | |
165 | /* this is to make SDL_snprintf() calls cleaner. */ |
166 | #define uint unsigned int |
167 | |
168 | name[0] = '\0'; |
169 | details[0] = '\0'; |
170 | |
171 | /* !!! FIXME: This code is kinda ugly, sorry. */ |
172 | |
173 | if ((event->type >= SDL_USEREVENT) && (event->type <= SDL_LASTEVENT)) { |
174 | char plusstr[16]; |
175 | SDL_strlcpy(name, "SDL_USEREVENT" , sizeof (name)); |
176 | if (event->type > SDL_USEREVENT) { |
177 | SDL_snprintf(plusstr, sizeof (plusstr), "+%u" , ((uint) event->type) - SDL_USEREVENT); |
178 | } else { |
179 | plusstr[0] = '\0'; |
180 | } |
181 | SDL_snprintf(details, sizeof (details), "%s (timestamp=%u windowid=%u code=%d data1=%p data2=%p)" , |
182 | plusstr, (uint) event->user.timestamp, (uint) event->user.windowID, |
183 | (int) event->user.code, event->user.data1, event->user.data2); |
184 | } |
185 | |
186 | switch (event->type) { |
187 | #define SDL_EVENT_CASE(x) case x: SDL_strlcpy(name, #x, sizeof (name)); |
188 | SDL_EVENT_CASE(SDL_FIRSTEVENT) SDL_strlcpy(details, " (THIS IS PROBABLY A BUG!)" , sizeof (details)); break; |
189 | SDL_EVENT_CASE(SDL_QUIT) SDL_snprintf(details, sizeof (details), " (timestamp=%u)" , (uint) event->quit.timestamp); break; |
190 | SDL_EVENT_CASE(SDL_APP_TERMINATING) break; |
191 | SDL_EVENT_CASE(SDL_APP_LOWMEMORY) break; |
192 | SDL_EVENT_CASE(SDL_APP_WILLENTERBACKGROUND) break; |
193 | SDL_EVENT_CASE(SDL_APP_DIDENTERBACKGROUND) break; |
194 | SDL_EVENT_CASE(SDL_APP_WILLENTERFOREGROUND) break; |
195 | SDL_EVENT_CASE(SDL_APP_DIDENTERFOREGROUND) break; |
196 | SDL_EVENT_CASE(SDL_KEYMAPCHANGED) break; |
197 | SDL_EVENT_CASE(SDL_CLIPBOARDUPDATE) break; |
198 | SDL_EVENT_CASE(SDL_RENDER_TARGETS_RESET) break; |
199 | SDL_EVENT_CASE(SDL_RENDER_DEVICE_RESET) break; |
200 | |
201 | SDL_EVENT_CASE(SDL_WINDOWEVENT) { |
202 | char name2[64]; |
203 | switch(event->window.event) { |
204 | case SDL_WINDOWEVENT_NONE: SDL_strlcpy(name2, "SDL_WINDOWEVENT_NONE (THIS IS PROBABLY A BUG!)" , sizeof (name2)); break; |
205 | #define SDL_WINDOWEVENT_CASE(x) case x: SDL_strlcpy(name2, #x, sizeof (name2)); break |
206 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_SHOWN); |
207 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_HIDDEN); |
208 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_EXPOSED); |
209 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MOVED); |
210 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_RESIZED); |
211 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_SIZE_CHANGED); |
212 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MINIMIZED); |
213 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MAXIMIZED); |
214 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_RESTORED); |
215 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_ENTER); |
216 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_LEAVE); |
217 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_FOCUS_GAINED); |
218 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_FOCUS_LOST); |
219 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_CLOSE); |
220 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_TAKE_FOCUS); |
221 | SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_HIT_TEST); |
222 | #undef SDL_WINDOWEVENT_CASE |
223 | default: SDL_strlcpy(name2, "UNKNOWN (bug? fixme?)" , sizeof (name2)); break; |
224 | } |
225 | SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u event=%s data1=%d data2=%d)" , |
226 | (uint) event->window.timestamp, (uint) event->window.windowID, name2, (int) event->window.data1, (int) event->window.data2); |
227 | break; |
228 | } |
229 | |
230 | SDL_EVENT_CASE(SDL_SYSWMEVENT) |
231 | /* !!! FIXME: we don't delve further at the moment. */ |
232 | SDL_snprintf(details, sizeof (details), " (timestamp=%u)" , (uint) event->syswm.timestamp); |
233 | break; |
234 | |
235 | #define PRINT_KEY_EVENT(event) \ |
236 | SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u state=%s repeat=%s scancode=%u keycode=%u mod=%u)", \ |
237 | (uint) event->key.timestamp, (uint) event->key.windowID, \ |
238 | event->key.state == SDL_PRESSED ? "pressed" : "released", \ |
239 | event->key.repeat ? "true" : "false", \ |
240 | (uint) event->key.keysym.scancode, \ |
241 | (uint) event->key.keysym.sym, \ |
242 | (uint) event->key.keysym.mod) |
243 | SDL_EVENT_CASE(SDL_KEYDOWN) PRINT_KEY_EVENT(event); break; |
244 | SDL_EVENT_CASE(SDL_KEYUP) PRINT_KEY_EVENT(event); break; |
245 | #undef PRINT_KEY_EVENT |
246 | |
247 | SDL_EVENT_CASE(SDL_TEXTEDITING) |
248 | SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u text='%s' start=%d length=%d)" , |
249 | (uint) event->edit.timestamp, (uint) event->edit.windowID, |
250 | event->edit.text, (int) event->edit.start, (int) event->edit.length); |
251 | break; |
252 | |
253 | SDL_EVENT_CASE(SDL_TEXTINPUT) |
254 | SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u text='%s')" , (uint) event->text.timestamp, (uint) event->text.windowID, event->text.text); |
255 | break; |
256 | |
257 | |
258 | SDL_EVENT_CASE(SDL_MOUSEMOTION) |
259 | SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u state=%u x=%d y=%d xrel=%d yrel=%d)" , |
260 | (uint) event->motion.timestamp, (uint) event->motion.windowID, |
261 | (uint) event->motion.which, (uint) event->motion.state, |
262 | (int) event->motion.x, (int) event->motion.y, |
263 | (int) event->motion.xrel, (int) event->motion.yrel); |
264 | break; |
265 | |
266 | #define PRINT_MBUTTON_EVENT(event) \ |
267 | SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u button=%u state=%s clicks=%u x=%d y=%d)", \ |
268 | (uint) event->button.timestamp, (uint) event->button.windowID, \ |
269 | (uint) event->button.which, (uint) event->button.button, \ |
270 | event->button.state == SDL_PRESSED ? "pressed" : "released", \ |
271 | (uint) event->button.clicks, (int) event->button.x, (int) event->button.y) |
272 | SDL_EVENT_CASE(SDL_MOUSEBUTTONDOWN) PRINT_MBUTTON_EVENT(event); break; |
273 | SDL_EVENT_CASE(SDL_MOUSEBUTTONUP) PRINT_MBUTTON_EVENT(event); break; |
274 | #undef PRINT_MBUTTON_EVENT |
275 | |
276 | |
277 | SDL_EVENT_CASE(SDL_MOUSEWHEEL) |
278 | SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u x=%d y=%d direction=%s)" , |
279 | (uint) event->wheel.timestamp, (uint) event->wheel.windowID, |
280 | (uint) event->wheel.which, (int) event->wheel.x, (int) event->wheel.y, |
281 | event->wheel.direction == SDL_MOUSEWHEEL_NORMAL ? "normal" : "flipped" ); |
282 | break; |
283 | |
284 | SDL_EVENT_CASE(SDL_JOYAXISMOTION) |
285 | SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d axis=%u value=%d)" , |
286 | (uint) event->jaxis.timestamp, (int) event->jaxis.which, |
287 | (uint) event->jaxis.axis, (int) event->jaxis.value); |
288 | break; |
289 | |
290 | SDL_EVENT_CASE(SDL_JOYBALLMOTION) |
291 | SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d ball=%u xrel=%d yrel=%d)" , |
292 | (uint) event->jball.timestamp, (int) event->jball.which, |
293 | (uint) event->jball.ball, (int) event->jball.xrel, (int) event->jball.yrel); |
294 | break; |
295 | |
296 | SDL_EVENT_CASE(SDL_JOYHATMOTION) |
297 | SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d hat=%u value=%u)" , |
298 | (uint) event->jhat.timestamp, (int) event->jhat.which, |
299 | (uint) event->jhat.hat, (uint) event->jhat.value); |
300 | break; |
301 | |
302 | #define PRINT_JBUTTON_EVENT(event) \ |
303 | SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d button=%u state=%s)", \ |
304 | (uint) event->jbutton.timestamp, (int) event->jbutton.which, \ |
305 | (uint) event->jbutton.button, event->jbutton.state == SDL_PRESSED ? "pressed" : "released") |
306 | SDL_EVENT_CASE(SDL_JOYBUTTONDOWN) PRINT_JBUTTON_EVENT(event); break; |
307 | SDL_EVENT_CASE(SDL_JOYBUTTONUP) PRINT_JBUTTON_EVENT(event); break; |
308 | #undef PRINT_JBUTTON_EVENT |
309 | |
310 | #define PRINT_JOYDEV_EVENT(event) SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d)", (uint) event->jdevice.timestamp, (int) event->jdevice.which) |
311 | SDL_EVENT_CASE(SDL_JOYDEVICEADDED) PRINT_JOYDEV_EVENT(event); break; |
312 | SDL_EVENT_CASE(SDL_JOYDEVICEREMOVED) PRINT_JOYDEV_EVENT(event); break; |
313 | #undef PRINT_JOYDEV_EVENT |
314 | |
315 | SDL_EVENT_CASE(SDL_CONTROLLERAXISMOTION) |
316 | SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d axis=%u value=%d)" , |
317 | (uint) event->caxis.timestamp, (int) event->caxis.which, |
318 | (uint) event->caxis.axis, (int) event->caxis.value); |
319 | break; |
320 | |
321 | #define PRINT_CBUTTON_EVENT(event) \ |
322 | SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d button=%u state=%s)", \ |
323 | (uint) event->cbutton.timestamp, (int) event->cbutton.which, \ |
324 | (uint) event->cbutton.button, event->cbutton.state == SDL_PRESSED ? "pressed" : "released") |
325 | SDL_EVENT_CASE(SDL_CONTROLLERBUTTONDOWN) PRINT_CBUTTON_EVENT(event); break; |
326 | SDL_EVENT_CASE(SDL_CONTROLLERBUTTONUP) PRINT_CBUTTON_EVENT(event); break; |
327 | #undef PRINT_CBUTTON_EVENT |
328 | |
329 | #define PRINT_CONTROLLERDEV_EVENT(event) SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d)", (uint) event->cdevice.timestamp, (int) event->cdevice.which) |
330 | SDL_EVENT_CASE(SDL_CONTROLLERDEVICEADDED) PRINT_CONTROLLERDEV_EVENT(event); break; |
331 | SDL_EVENT_CASE(SDL_CONTROLLERDEVICEREMOVED) PRINT_CONTROLLERDEV_EVENT(event); break; |
332 | SDL_EVENT_CASE(SDL_CONTROLLERDEVICEREMAPPED) PRINT_CONTROLLERDEV_EVENT(event); break; |
333 | #undef PRINT_CONTROLLERDEV_EVENT |
334 | |
335 | #define PRINT_FINGER_EVENT(event) \ |
336 | SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" fingerid=%"SDL_PRIs64" x=%f y=%f dx=%f dy=%f pressure=%f)", \ |
337 | (uint) event->tfinger.timestamp, (long long)event->tfinger.touchId, \ |
338 | (long long)event->tfinger.fingerId, event->tfinger.x, event->tfinger.y, \ |
339 | event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure) |
340 | SDL_EVENT_CASE(SDL_FINGERDOWN) PRINT_FINGER_EVENT(event); break; |
341 | SDL_EVENT_CASE(SDL_FINGERUP) PRINT_FINGER_EVENT(event); break; |
342 | SDL_EVENT_CASE(SDL_FINGERMOTION) PRINT_FINGER_EVENT(event); break; |
343 | #undef PRINT_FINGER_EVENT |
344 | |
345 | #define PRINT_DOLLAR_EVENT(event) \ |
346 | SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" gestureid=%"SDL_PRIs64" numfingers=%u error=%f x=%f y=%f)", \ |
347 | (uint) event->dgesture.timestamp, (long long)event->dgesture.touchId, \ |
348 | (long long)event->dgesture.gestureId, (uint) event->dgesture.numFingers, \ |
349 | event->dgesture.error, event->dgesture.x, event->dgesture.y); |
350 | SDL_EVENT_CASE(SDL_DOLLARGESTURE) PRINT_DOLLAR_EVENT(event); break; |
351 | SDL_EVENT_CASE(SDL_DOLLARRECORD) PRINT_DOLLAR_EVENT(event); break; |
352 | #undef PRINT_DOLLAR_EVENT |
353 | |
354 | SDL_EVENT_CASE(SDL_MULTIGESTURE) |
355 | SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%" SDL_PRIs64" dtheta=%f ddist=%f x=%f y=%f numfingers=%u)" , |
356 | (uint) event->mgesture.timestamp, (long long)event->mgesture.touchId, |
357 | event->mgesture.dTheta, event->mgesture.dDist, |
358 | event->mgesture.x, event->mgesture.y, (uint) event->mgesture.numFingers); |
359 | break; |
360 | |
361 | #define PRINT_DROP_EVENT(event) SDL_snprintf(details, sizeof (details), " (file='%s' timestamp=%u windowid=%u)", event->drop.file, (uint) event->drop.timestamp, (uint) event->drop.windowID) |
362 | SDL_EVENT_CASE(SDL_DROPFILE) PRINT_DROP_EVENT(event); break; |
363 | SDL_EVENT_CASE(SDL_DROPTEXT) PRINT_DROP_EVENT(event); break; |
364 | SDL_EVENT_CASE(SDL_DROPBEGIN) PRINT_DROP_EVENT(event); break; |
365 | SDL_EVENT_CASE(SDL_DROPCOMPLETE) PRINT_DROP_EVENT(event); break; |
366 | #undef PRINT_DROP_EVENT |
367 | |
368 | #define PRINT_AUDIODEV_EVENT(event) SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%u iscapture=%s)", (uint) event->adevice.timestamp, (uint) event->adevice.which, event->adevice.iscapture ? "true" : "false"); |
369 | SDL_EVENT_CASE(SDL_AUDIODEVICEADDED) PRINT_AUDIODEV_EVENT(event); break; |
370 | SDL_EVENT_CASE(SDL_AUDIODEVICEREMOVED) PRINT_AUDIODEV_EVENT(event); break; |
371 | #undef PRINT_AUDIODEV_EVENT |
372 | |
373 | #undef SDL_EVENT_CASE |
374 | |
375 | default: |
376 | if (!name[0]) { |
377 | SDL_strlcpy(name, "UNKNOWN" , sizeof (name)); |
378 | SDL_snprintf(details, sizeof (details), " #%u! (Bug? FIXME?)" , (uint) event->type); |
379 | } |
380 | break; |
381 | } |
382 | |
383 | if (name[0]) { |
384 | SDL_Log("SDL EVENT: %s%s" , name, details); |
385 | } |
386 | |
387 | #undef uint |
388 | } |
389 | |
390 | |
391 | |
392 | /* Public functions */ |
393 | |
394 | void |
395 | SDL_StopEventLoop(void) |
396 | { |
397 | const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS" ); |
398 | int i; |
399 | SDL_EventEntry *entry; |
400 | SDL_SysWMEntry *wmmsg; |
401 | |
402 | if (SDL_EventQ.lock) { |
403 | SDL_LockMutex(SDL_EventQ.lock); |
404 | } |
405 | |
406 | SDL_AtomicSet(&SDL_EventQ.active, 0); |
407 | |
408 | if (report && SDL_atoi(report)) { |
409 | SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n" , |
410 | SDL_EventQ.max_events_seen); |
411 | } |
412 | |
413 | /* Clean out EventQ */ |
414 | for (entry = SDL_EventQ.head; entry; ) { |
415 | SDL_EventEntry *next = entry->next; |
416 | SDL_free(entry); |
417 | entry = next; |
418 | } |
419 | for (entry = SDL_EventQ.free; entry; ) { |
420 | SDL_EventEntry *next = entry->next; |
421 | SDL_free(entry); |
422 | entry = next; |
423 | } |
424 | for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) { |
425 | SDL_SysWMEntry *next = wmmsg->next; |
426 | SDL_free(wmmsg); |
427 | wmmsg = next; |
428 | } |
429 | for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) { |
430 | SDL_SysWMEntry *next = wmmsg->next; |
431 | SDL_free(wmmsg); |
432 | wmmsg = next; |
433 | } |
434 | |
435 | SDL_AtomicSet(&SDL_EventQ.count, 0); |
436 | SDL_EventQ.max_events_seen = 0; |
437 | SDL_EventQ.head = NULL; |
438 | SDL_EventQ.tail = NULL; |
439 | SDL_EventQ.free = NULL; |
440 | SDL_EventQ.wmmsg_used = NULL; |
441 | SDL_EventQ.wmmsg_free = NULL; |
442 | |
443 | /* Clear disabled event state */ |
444 | for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) { |
445 | SDL_free(SDL_disabled_events[i]); |
446 | SDL_disabled_events[i] = NULL; |
447 | } |
448 | |
449 | if (SDL_event_watchers_lock) { |
450 | SDL_DestroyMutex(SDL_event_watchers_lock); |
451 | SDL_event_watchers_lock = NULL; |
452 | } |
453 | if (SDL_event_watchers) { |
454 | SDL_free(SDL_event_watchers); |
455 | SDL_event_watchers = NULL; |
456 | SDL_event_watchers_count = 0; |
457 | } |
458 | SDL_zero(SDL_EventOK); |
459 | |
460 | if (SDL_EventQ.lock) { |
461 | SDL_UnlockMutex(SDL_EventQ.lock); |
462 | SDL_DestroyMutex(SDL_EventQ.lock); |
463 | SDL_EventQ.lock = NULL; |
464 | } |
465 | } |
466 | |
467 | /* This function (and associated calls) may be called more than once */ |
468 | int |
469 | SDL_StartEventLoop(void) |
470 | { |
471 | /* We'll leave the event queue alone, since we might have gotten |
472 | some important events at launch (like SDL_DROPFILE) |
473 | |
474 | FIXME: Does this introduce any other bugs with events at startup? |
475 | */ |
476 | |
477 | /* Create the lock and set ourselves active */ |
478 | #if !SDL_THREADS_DISABLED |
479 | if (!SDL_EventQ.lock) { |
480 | SDL_EventQ.lock = SDL_CreateMutex(); |
481 | if (SDL_EventQ.lock == NULL) { |
482 | return -1; |
483 | } |
484 | } |
485 | |
486 | if (!SDL_event_watchers_lock) { |
487 | SDL_event_watchers_lock = SDL_CreateMutex(); |
488 | if (SDL_event_watchers_lock == NULL) { |
489 | return -1; |
490 | } |
491 | } |
492 | #endif /* !SDL_THREADS_DISABLED */ |
493 | |
494 | /* Process most event types */ |
495 | SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE); |
496 | SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE); |
497 | SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE); |
498 | #if 0 /* Leave these events enabled so apps can respond to items being dragged onto them at startup */ |
499 | SDL_EventState(SDL_DROPFILE, SDL_DISABLE); |
500 | SDL_EventState(SDL_DROPTEXT, SDL_DISABLE); |
501 | #endif |
502 | |
503 | SDL_AtomicSet(&SDL_EventQ.active, 1); |
504 | |
505 | return 0; |
506 | } |
507 | |
508 | |
509 | /* Add an event to the event queue -- called with the queue locked */ |
510 | static int |
511 | SDL_AddEvent(SDL_Event * event) |
512 | { |
513 | SDL_EventEntry *entry; |
514 | const int initial_count = SDL_AtomicGet(&SDL_EventQ.count); |
515 | int final_count; |
516 | |
517 | if (initial_count >= SDL_MAX_QUEUED_EVENTS) { |
518 | SDL_SetError("Event queue is full (%d events)" , initial_count); |
519 | return 0; |
520 | } |
521 | |
522 | if (SDL_EventQ.free == NULL) { |
523 | entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry)); |
524 | if (!entry) { |
525 | return 0; |
526 | } |
527 | } else { |
528 | entry = SDL_EventQ.free; |
529 | SDL_EventQ.free = entry->next; |
530 | } |
531 | |
532 | if (SDL_DoEventLogging) { |
533 | SDL_LogEvent(event); |
534 | } |
535 | |
536 | entry->event = *event; |
537 | if (event->type == SDL_SYSWMEVENT) { |
538 | entry->msg = *event->syswm.msg; |
539 | entry->event.syswm.msg = &entry->msg; |
540 | } |
541 | |
542 | if (SDL_EventQ.tail) { |
543 | SDL_EventQ.tail->next = entry; |
544 | entry->prev = SDL_EventQ.tail; |
545 | SDL_EventQ.tail = entry; |
546 | entry->next = NULL; |
547 | } else { |
548 | SDL_assert(!SDL_EventQ.head); |
549 | SDL_EventQ.head = entry; |
550 | SDL_EventQ.tail = entry; |
551 | entry->prev = NULL; |
552 | entry->next = NULL; |
553 | } |
554 | |
555 | final_count = SDL_AtomicAdd(&SDL_EventQ.count, 1) + 1; |
556 | if (final_count > SDL_EventQ.max_events_seen) { |
557 | SDL_EventQ.max_events_seen = final_count; |
558 | } |
559 | |
560 | return 1; |
561 | } |
562 | |
563 | /* Remove an event from the queue -- called with the queue locked */ |
564 | static void |
565 | SDL_CutEvent(SDL_EventEntry *entry) |
566 | { |
567 | if (entry->prev) { |
568 | entry->prev->next = entry->next; |
569 | } |
570 | if (entry->next) { |
571 | entry->next->prev = entry->prev; |
572 | } |
573 | |
574 | if (entry == SDL_EventQ.head) { |
575 | SDL_assert(entry->prev == NULL); |
576 | SDL_EventQ.head = entry->next; |
577 | } |
578 | if (entry == SDL_EventQ.tail) { |
579 | SDL_assert(entry->next == NULL); |
580 | SDL_EventQ.tail = entry->prev; |
581 | } |
582 | |
583 | entry->next = SDL_EventQ.free; |
584 | SDL_EventQ.free = entry; |
585 | SDL_assert(SDL_AtomicGet(&SDL_EventQ.count) > 0); |
586 | SDL_AtomicAdd(&SDL_EventQ.count, -1); |
587 | } |
588 | |
589 | /* Lock the event queue, take a peep at it, and unlock it */ |
590 | int |
591 | SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action, |
592 | Uint32 minType, Uint32 maxType) |
593 | { |
594 | int i, used; |
595 | |
596 | /* Don't look after we've quit */ |
597 | if (!SDL_AtomicGet(&SDL_EventQ.active)) { |
598 | /* We get a few spurious events at shutdown, so don't warn then */ |
599 | if (action != SDL_ADDEVENT) { |
600 | SDL_SetError("The event system has been shut down" ); |
601 | } |
602 | return (-1); |
603 | } |
604 | /* Lock the event queue */ |
605 | used = 0; |
606 | if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) { |
607 | if (action == SDL_ADDEVENT) { |
608 | for (i = 0; i < numevents; ++i) { |
609 | used += SDL_AddEvent(&events[i]); |
610 | } |
611 | } else { |
612 | SDL_EventEntry *entry, *next; |
613 | SDL_SysWMEntry *wmmsg, *wmmsg_next; |
614 | Uint32 type; |
615 | |
616 | if (action == SDL_GETEVENT) { |
617 | /* Clean out any used wmmsg data |
618 | FIXME: Do we want to retain the data for some period of time? |
619 | */ |
620 | for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) { |
621 | wmmsg_next = wmmsg->next; |
622 | wmmsg->next = SDL_EventQ.wmmsg_free; |
623 | SDL_EventQ.wmmsg_free = wmmsg; |
624 | } |
625 | SDL_EventQ.wmmsg_used = NULL; |
626 | } |
627 | |
628 | for (entry = SDL_EventQ.head; entry && (!events || used < numevents); entry = next) { |
629 | next = entry->next; |
630 | type = entry->event.type; |
631 | if (minType <= type && type <= maxType) { |
632 | if (events) { |
633 | events[used] = entry->event; |
634 | if (entry->event.type == SDL_SYSWMEVENT) { |
635 | /* We need to copy the wmmsg somewhere safe. |
636 | For now we'll guarantee it's valid at least until |
637 | the next call to SDL_PeepEvents() |
638 | */ |
639 | if (SDL_EventQ.wmmsg_free) { |
640 | wmmsg = SDL_EventQ.wmmsg_free; |
641 | SDL_EventQ.wmmsg_free = wmmsg->next; |
642 | } else { |
643 | wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg)); |
644 | } |
645 | wmmsg->msg = *entry->event.syswm.msg; |
646 | wmmsg->next = SDL_EventQ.wmmsg_used; |
647 | SDL_EventQ.wmmsg_used = wmmsg; |
648 | events[used].syswm.msg = &wmmsg->msg; |
649 | } |
650 | |
651 | if (action == SDL_GETEVENT) { |
652 | SDL_CutEvent(entry); |
653 | } |
654 | } |
655 | ++used; |
656 | } |
657 | } |
658 | } |
659 | if (SDL_EventQ.lock) { |
660 | SDL_UnlockMutex(SDL_EventQ.lock); |
661 | } |
662 | } else { |
663 | return SDL_SetError("Couldn't lock event queue" ); |
664 | } |
665 | return (used); |
666 | } |
667 | |
668 | SDL_bool |
669 | SDL_HasEvent(Uint32 type) |
670 | { |
671 | return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0); |
672 | } |
673 | |
674 | SDL_bool |
675 | SDL_HasEvents(Uint32 minType, Uint32 maxType) |
676 | { |
677 | return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0); |
678 | } |
679 | |
680 | void |
681 | SDL_FlushEvent(Uint32 type) |
682 | { |
683 | SDL_FlushEvents(type, type); |
684 | } |
685 | |
686 | void |
687 | SDL_FlushEvents(Uint32 minType, Uint32 maxType) |
688 | { |
689 | /* !!! FIXME: we need to manually SDL_free() the strings in TEXTINPUT and |
690 | drag'n'drop events if we're flushing them without passing them to the |
691 | app, but I don't know if this is the right place to do that. */ |
692 | |
693 | /* Don't look after we've quit */ |
694 | if (!SDL_AtomicGet(&SDL_EventQ.active)) { |
695 | return; |
696 | } |
697 | |
698 | /* Make sure the events are current */ |
699 | #if 0 |
700 | /* Actually, we can't do this since we might be flushing while processing |
701 | a resize event, and calling this might trigger further resize events. |
702 | */ |
703 | SDL_PumpEvents(); |
704 | #endif |
705 | |
706 | /* Lock the event queue */ |
707 | if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) { |
708 | SDL_EventEntry *entry, *next; |
709 | Uint32 type; |
710 | for (entry = SDL_EventQ.head; entry; entry = next) { |
711 | next = entry->next; |
712 | type = entry->event.type; |
713 | if (minType <= type && type <= maxType) { |
714 | SDL_CutEvent(entry); |
715 | } |
716 | } |
717 | if (SDL_EventQ.lock) { |
718 | SDL_UnlockMutex(SDL_EventQ.lock); |
719 | } |
720 | } |
721 | } |
722 | |
723 | /* Run the system dependent event loops */ |
724 | void |
725 | SDL_PumpEvents(void) |
726 | { |
727 | SDL_VideoDevice *_this = SDL_GetVideoDevice(); |
728 | |
729 | /* Release any keys held down from last frame */ |
730 | SDL_ReleaseAutoReleaseKeys(); |
731 | |
732 | /* Get events from the video subsystem */ |
733 | if (_this) { |
734 | _this->PumpEvents(_this); |
735 | } |
736 | |
737 | #if !SDL_JOYSTICK_DISABLED |
738 | /* Check for joystick state change */ |
739 | if (SDL_update_joysticks) { |
740 | SDL_JoystickUpdate(); |
741 | } |
742 | #endif |
743 | |
744 | #if !SDL_SENSOR_DISABLED |
745 | /* Check for sensor state change */ |
746 | if (SDL_update_sensors) { |
747 | SDL_SensorUpdate(); |
748 | } |
749 | #endif |
750 | |
751 | SDL_SendPendingSignalEvents(); /* in case we had a signal handler fire, etc. */ |
752 | } |
753 | |
754 | /* Public functions */ |
755 | |
756 | int |
757 | SDL_PollEvent(SDL_Event * event) |
758 | { |
759 | return SDL_WaitEventTimeout(event, 0); |
760 | } |
761 | |
762 | int |
763 | SDL_WaitEvent(SDL_Event * event) |
764 | { |
765 | return SDL_WaitEventTimeout(event, -1); |
766 | } |
767 | |
768 | int |
769 | SDL_WaitEventTimeout(SDL_Event * event, int timeout) |
770 | { |
771 | Uint32 expiration = 0; |
772 | |
773 | if (timeout > 0) |
774 | expiration = SDL_GetTicks() + timeout; |
775 | |
776 | for (;;) { |
777 | SDL_PumpEvents(); |
778 | switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) { |
779 | case -1: |
780 | return 0; |
781 | case 0: |
782 | if (timeout == 0) { |
783 | /* Polling and no events, just return */ |
784 | return 0; |
785 | } |
786 | if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) { |
787 | /* Timeout expired and no events */ |
788 | return 0; |
789 | } |
790 | SDL_Delay(1); |
791 | break; |
792 | default: |
793 | /* Has events */ |
794 | return 1; |
795 | } |
796 | } |
797 | } |
798 | |
799 | int |
800 | SDL_PushEvent(SDL_Event * event) |
801 | { |
802 | event->common.timestamp = SDL_GetTicks(); |
803 | |
804 | if (SDL_EventOK.callback || SDL_event_watchers_count > 0) { |
805 | if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) { |
806 | if (SDL_EventOK.callback && !SDL_EventOK.callback(SDL_EventOK.userdata, event)) { |
807 | if (SDL_event_watchers_lock) { |
808 | SDL_UnlockMutex(SDL_event_watchers_lock); |
809 | } |
810 | return 0; |
811 | } |
812 | |
813 | if (SDL_event_watchers_count > 0) { |
814 | /* Make sure we only dispatch the current watcher list */ |
815 | int i, event_watchers_count = SDL_event_watchers_count; |
816 | |
817 | SDL_event_watchers_dispatching = SDL_TRUE; |
818 | for (i = 0; i < event_watchers_count; ++i) { |
819 | if (!SDL_event_watchers[i].removed) { |
820 | SDL_event_watchers[i].callback(SDL_event_watchers[i].userdata, event); |
821 | } |
822 | } |
823 | SDL_event_watchers_dispatching = SDL_FALSE; |
824 | |
825 | if (SDL_event_watchers_removed) { |
826 | for (i = SDL_event_watchers_count; i--; ) { |
827 | if (SDL_event_watchers[i].removed) { |
828 | --SDL_event_watchers_count; |
829 | if (i < SDL_event_watchers_count) { |
830 | SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i])); |
831 | } |
832 | } |
833 | } |
834 | SDL_event_watchers_removed = SDL_FALSE; |
835 | } |
836 | } |
837 | |
838 | if (SDL_event_watchers_lock) { |
839 | SDL_UnlockMutex(SDL_event_watchers_lock); |
840 | } |
841 | } |
842 | } |
843 | |
844 | if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) { |
845 | return -1; |
846 | } |
847 | |
848 | SDL_GestureProcessEvent(event); |
849 | |
850 | return 1; |
851 | } |
852 | |
853 | void |
854 | SDL_SetEventFilter(SDL_EventFilter filter, void *userdata) |
855 | { |
856 | if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) { |
857 | /* Set filter and discard pending events */ |
858 | SDL_EventOK.callback = filter; |
859 | SDL_EventOK.userdata = userdata; |
860 | SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT); |
861 | |
862 | if (SDL_event_watchers_lock) { |
863 | SDL_UnlockMutex(SDL_event_watchers_lock); |
864 | } |
865 | } |
866 | } |
867 | |
868 | SDL_bool |
869 | SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata) |
870 | { |
871 | SDL_EventWatcher event_ok; |
872 | |
873 | if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) { |
874 | event_ok = SDL_EventOK; |
875 | |
876 | if (SDL_event_watchers_lock) { |
877 | SDL_UnlockMutex(SDL_event_watchers_lock); |
878 | } |
879 | } else { |
880 | SDL_zero(event_ok); |
881 | } |
882 | |
883 | if (filter) { |
884 | *filter = event_ok.callback; |
885 | } |
886 | if (userdata) { |
887 | *userdata = event_ok.userdata; |
888 | } |
889 | return event_ok.callback ? SDL_TRUE : SDL_FALSE; |
890 | } |
891 | |
892 | void |
893 | SDL_AddEventWatch(SDL_EventFilter filter, void *userdata) |
894 | { |
895 | if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) { |
896 | SDL_EventWatcher *event_watchers; |
897 | |
898 | event_watchers = SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers)); |
899 | if (event_watchers) { |
900 | SDL_EventWatcher *watcher; |
901 | |
902 | SDL_event_watchers = event_watchers; |
903 | watcher = &SDL_event_watchers[SDL_event_watchers_count]; |
904 | watcher->callback = filter; |
905 | watcher->userdata = userdata; |
906 | watcher->removed = SDL_FALSE; |
907 | ++SDL_event_watchers_count; |
908 | } |
909 | |
910 | if (SDL_event_watchers_lock) { |
911 | SDL_UnlockMutex(SDL_event_watchers_lock); |
912 | } |
913 | } |
914 | } |
915 | |
916 | void |
917 | SDL_DelEventWatch(SDL_EventFilter filter, void *userdata) |
918 | { |
919 | if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) { |
920 | int i; |
921 | |
922 | for (i = 0; i < SDL_event_watchers_count; ++i) { |
923 | if (SDL_event_watchers[i].callback == filter && SDL_event_watchers[i].userdata == userdata) { |
924 | if (SDL_event_watchers_dispatching) { |
925 | SDL_event_watchers[i].removed = SDL_TRUE; |
926 | SDL_event_watchers_removed = SDL_TRUE; |
927 | } else { |
928 | --SDL_event_watchers_count; |
929 | if (i < SDL_event_watchers_count) { |
930 | SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i])); |
931 | } |
932 | } |
933 | break; |
934 | } |
935 | } |
936 | |
937 | if (SDL_event_watchers_lock) { |
938 | SDL_UnlockMutex(SDL_event_watchers_lock); |
939 | } |
940 | } |
941 | } |
942 | |
943 | void |
944 | SDL_FilterEvents(SDL_EventFilter filter, void *userdata) |
945 | { |
946 | if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) { |
947 | SDL_EventEntry *entry, *next; |
948 | for (entry = SDL_EventQ.head; entry; entry = next) { |
949 | next = entry->next; |
950 | if (!filter(userdata, &entry->event)) { |
951 | SDL_CutEvent(entry); |
952 | } |
953 | } |
954 | if (SDL_EventQ.lock) { |
955 | SDL_UnlockMutex(SDL_EventQ.lock); |
956 | } |
957 | } |
958 | } |
959 | |
960 | Uint8 |
961 | SDL_EventState(Uint32 type, int state) |
962 | { |
963 | const SDL_bool isdnd = ((state == SDL_DISABLE) || (state == SDL_ENABLE)) && |
964 | ((type == SDL_DROPFILE) || (type == SDL_DROPTEXT)); |
965 | Uint8 current_state; |
966 | Uint8 hi = ((type >> 8) & 0xff); |
967 | Uint8 lo = (type & 0xff); |
968 | |
969 | if (SDL_disabled_events[hi] && |
970 | (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) { |
971 | current_state = SDL_DISABLE; |
972 | } else { |
973 | current_state = SDL_ENABLE; |
974 | } |
975 | |
976 | if (state != current_state) |
977 | { |
978 | switch (state) { |
979 | case SDL_DISABLE: |
980 | /* Disable this event type and discard pending events */ |
981 | if (!SDL_disabled_events[hi]) { |
982 | SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock)); |
983 | if (!SDL_disabled_events[hi]) { |
984 | /* Out of memory, nothing we can do... */ |
985 | break; |
986 | } |
987 | } |
988 | SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31)); |
989 | SDL_FlushEvent(type); |
990 | break; |
991 | case SDL_ENABLE: |
992 | SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31)); |
993 | break; |
994 | default: |
995 | /* Querying state... */ |
996 | break; |
997 | } |
998 | |
999 | #if !SDL_JOYSTICK_DISABLED |
1000 | if (state == SDL_DISABLE || state == SDL_ENABLE) { |
1001 | SDL_CalculateShouldUpdateJoysticks(); |
1002 | } |
1003 | #endif |
1004 | #if !SDL_SENSOR_DISABLED |
1005 | if (state == SDL_DISABLE || state == SDL_ENABLE) { |
1006 | SDL_CalculateShouldUpdateSensors(); |
1007 | } |
1008 | #endif |
1009 | } |
1010 | |
1011 | /* turn off drag'n'drop support if we've disabled the events. |
1012 | This might change some UI details at the OS level. */ |
1013 | if (isdnd) { |
1014 | SDL_ToggleDragAndDropSupport(); |
1015 | } |
1016 | |
1017 | return current_state; |
1018 | } |
1019 | |
1020 | Uint32 |
1021 | SDL_RegisterEvents(int numevents) |
1022 | { |
1023 | Uint32 event_base; |
1024 | |
1025 | if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) { |
1026 | event_base = SDL_userevents; |
1027 | SDL_userevents += numevents; |
1028 | } else { |
1029 | event_base = (Uint32)-1; |
1030 | } |
1031 | return event_base; |
1032 | } |
1033 | |
1034 | int |
1035 | SDL_SendAppEvent(SDL_EventType eventType) |
1036 | { |
1037 | int posted; |
1038 | |
1039 | posted = 0; |
1040 | if (SDL_GetEventState(eventType) == SDL_ENABLE) { |
1041 | SDL_Event event; |
1042 | event.type = eventType; |
1043 | posted = (SDL_PushEvent(&event) > 0); |
1044 | } |
1045 | return (posted); |
1046 | } |
1047 | |
1048 | int |
1049 | SDL_SendSysWMEvent(SDL_SysWMmsg * message) |
1050 | { |
1051 | int posted; |
1052 | |
1053 | posted = 0; |
1054 | if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) { |
1055 | SDL_Event event; |
1056 | SDL_memset(&event, 0, sizeof(event)); |
1057 | event.type = SDL_SYSWMEVENT; |
1058 | event.syswm.msg = message; |
1059 | posted = (SDL_PushEvent(&event) > 0); |
1060 | } |
1061 | /* Update internal event state */ |
1062 | return (posted); |
1063 | } |
1064 | |
1065 | int |
1066 | SDL_SendKeymapChangedEvent(void) |
1067 | { |
1068 | return SDL_SendAppEvent(SDL_KEYMAPCHANGED); |
1069 | } |
1070 | |
1071 | int |
1072 | SDL_SendLocaleChangedEvent(void) |
1073 | { |
1074 | return SDL_SendAppEvent(SDL_LOCALECHANGED); |
1075 | } |
1076 | |
1077 | int |
1078 | SDL_EventsInit(void) |
1079 | { |
1080 | #if !SDL_JOYSTICK_DISABLED |
1081 | SDL_AddHintCallback(SDL_HINT_AUTO_UPDATE_JOYSTICKS, SDL_AutoUpdateJoysticksChanged, NULL); |
1082 | #endif |
1083 | #if !SDL_SENSOR_DISABLED |
1084 | SDL_AddHintCallback(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_AutoUpdateSensorsChanged, NULL); |
1085 | #endif |
1086 | SDL_AddHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL); |
1087 | if (SDL_StartEventLoop() < 0) { |
1088 | SDL_DelHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL); |
1089 | return -1; |
1090 | } |
1091 | |
1092 | SDL_QuitInit(); |
1093 | |
1094 | return 0; |
1095 | } |
1096 | |
1097 | void |
1098 | SDL_EventsQuit(void) |
1099 | { |
1100 | SDL_QuitQuit(); |
1101 | SDL_StopEventLoop(); |
1102 | SDL_DelHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL); |
1103 | #if !SDL_JOYSTICK_DISABLED |
1104 | SDL_DelHintCallback(SDL_HINT_AUTO_UPDATE_JOYSTICKS, SDL_AutoUpdateJoysticksChanged, NULL); |
1105 | #endif |
1106 | #if !SDL_SENSOR_DISABLED |
1107 | SDL_DelHintCallback(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_AutoUpdateSensorsChanged, NULL); |
1108 | #endif |
1109 | } |
1110 | |
1111 | /* vi: set ts=4 sw=4 expandtab: */ |
1112 | |