SDL_windowevents.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "SDL_internal.h"
  19. // Window event handling code for SDL
  20. #include "SDL_events_c.h"
  21. #include "SDL_mouse_c.h"
  22. static bool SDLCALL RemoveSupercededWindowEvents(void *userdata, SDL_Event *event)
  23. {
  24. SDL_Event *new_event = (SDL_Event *)userdata;
  25. if (event->type == new_event->type &&
  26. event->window.windowID == new_event->window.windowID) {
  27. // We're about to post a new move event, drop the old one
  28. return false;
  29. }
  30. return true;
  31. }
  32. bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data1, int data2)
  33. {
  34. bool posted = false;
  35. if (!window) {
  36. return false;
  37. }
  38. SDL_assert(SDL_ObjectValid(window, SDL_OBJECT_TYPE_WINDOW));
  39. if (window->is_destroying && windowevent != SDL_EVENT_WINDOW_DESTROYED) {
  40. return false;
  41. }
  42. switch (windowevent) {
  43. case SDL_EVENT_WINDOW_SHOWN:
  44. if (!(window->flags & SDL_WINDOW_HIDDEN)) {
  45. return false;
  46. }
  47. window->flags &= ~(SDL_WINDOW_HIDDEN | SDL_WINDOW_MINIMIZED);
  48. break;
  49. case SDL_EVENT_WINDOW_HIDDEN:
  50. if (window->flags & SDL_WINDOW_HIDDEN) {
  51. return false;
  52. }
  53. window->flags |= SDL_WINDOW_HIDDEN;
  54. break;
  55. case SDL_EVENT_WINDOW_EXPOSED:
  56. window->flags &= ~SDL_WINDOW_OCCLUDED;
  57. break;
  58. case SDL_EVENT_WINDOW_MOVED:
  59. window->undefined_x = false;
  60. window->undefined_y = false;
  61. window->last_position_pending = false;
  62. if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  63. window->windowed.x = data1;
  64. window->windowed.y = data2;
  65. if (!(window->flags & SDL_WINDOW_MAXIMIZED) && !window->tiled) {
  66. window->floating.x = data1;
  67. window->floating.y = data2;
  68. }
  69. }
  70. if (data1 == window->x && data2 == window->y) {
  71. return false;
  72. }
  73. window->x = data1;
  74. window->y = data2;
  75. break;
  76. case SDL_EVENT_WINDOW_RESIZED:
  77. window->last_size_pending = false;
  78. if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  79. window->windowed.w = data1;
  80. window->windowed.h = data2;
  81. if (!(window->flags & SDL_WINDOW_MAXIMIZED) && !window->tiled) {
  82. window->floating.w = data1;
  83. window->floating.h = data2;
  84. }
  85. }
  86. if (data1 == window->w && data2 == window->h) {
  87. SDL_CheckWindowPixelSizeChanged(window);
  88. return false;
  89. }
  90. window->w = data1;
  91. window->h = data2;
  92. break;
  93. case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
  94. if (data1 == window->last_pixel_w && data2 == window->last_pixel_h) {
  95. return false;
  96. }
  97. window->last_pixel_w = data1;
  98. window->last_pixel_h = data2;
  99. break;
  100. case SDL_EVENT_WINDOW_MINIMIZED:
  101. if (window->flags & SDL_WINDOW_MINIMIZED) {
  102. return false;
  103. }
  104. window->flags &= ~SDL_WINDOW_MAXIMIZED;
  105. window->flags |= SDL_WINDOW_MINIMIZED;
  106. break;
  107. case SDL_EVENT_WINDOW_MAXIMIZED:
  108. if (window->flags & SDL_WINDOW_MAXIMIZED) {
  109. return false;
  110. }
  111. window->flags &= ~SDL_WINDOW_MINIMIZED;
  112. window->flags |= SDL_WINDOW_MAXIMIZED;
  113. break;
  114. case SDL_EVENT_WINDOW_RESTORED:
  115. if (!(window->flags & (SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED))) {
  116. return false;
  117. }
  118. window->flags &= ~(SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED);
  119. break;
  120. case SDL_EVENT_WINDOW_MOUSE_ENTER:
  121. if (window->flags & SDL_WINDOW_MOUSE_FOCUS) {
  122. return false;
  123. }
  124. window->flags |= SDL_WINDOW_MOUSE_FOCUS;
  125. break;
  126. case SDL_EVENT_WINDOW_MOUSE_LEAVE:
  127. if (!(window->flags & SDL_WINDOW_MOUSE_FOCUS)) {
  128. return false;
  129. }
  130. window->flags &= ~SDL_WINDOW_MOUSE_FOCUS;
  131. break;
  132. case SDL_EVENT_WINDOW_FOCUS_GAINED:
  133. if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  134. return false;
  135. }
  136. window->flags |= SDL_WINDOW_INPUT_FOCUS;
  137. break;
  138. case SDL_EVENT_WINDOW_FOCUS_LOST:
  139. if (!(window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  140. return false;
  141. }
  142. window->flags &= ~SDL_WINDOW_INPUT_FOCUS;
  143. break;
  144. case SDL_EVENT_WINDOW_DISPLAY_CHANGED:
  145. if (data1 == 0 || (SDL_DisplayID)data1 == window->last_displayID) {
  146. return false;
  147. }
  148. window->last_displayID = (SDL_DisplayID)data1;
  149. break;
  150. case SDL_EVENT_WINDOW_OCCLUDED:
  151. if (window->flags & SDL_WINDOW_OCCLUDED) {
  152. return false;
  153. }
  154. window->flags |= SDL_WINDOW_OCCLUDED;
  155. break;
  156. case SDL_EVENT_WINDOW_ENTER_FULLSCREEN:
  157. if (window->flags & SDL_WINDOW_FULLSCREEN) {
  158. return false;
  159. }
  160. window->flags |= SDL_WINDOW_FULLSCREEN;
  161. break;
  162. case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN:
  163. if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  164. return false;
  165. }
  166. window->flags &= ~SDL_WINDOW_FULLSCREEN;
  167. break;
  168. default:
  169. break;
  170. }
  171. // Post the event, if desired
  172. if (SDL_EventEnabled(windowevent)) {
  173. SDL_Event event;
  174. event.type = windowevent;
  175. event.common.timestamp = 0;
  176. event.window.data1 = data1;
  177. event.window.data2 = data2;
  178. event.window.windowID = window->id;
  179. // Fixes queue overflow with move/resize events that aren't processed
  180. if (windowevent == SDL_EVENT_WINDOW_MOVED ||
  181. windowevent == SDL_EVENT_WINDOW_RESIZED ||
  182. windowevent == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED ||
  183. windowevent == SDL_EVENT_WINDOW_SAFE_AREA_CHANGED ||
  184. windowevent == SDL_EVENT_WINDOW_EXPOSED ||
  185. windowevent == SDL_EVENT_WINDOW_OCCLUDED) {
  186. SDL_FilterEvents(RemoveSupercededWindowEvents, &event);
  187. }
  188. posted = SDL_PushEvent(&event);
  189. }
  190. switch (windowevent) {
  191. case SDL_EVENT_WINDOW_SHOWN:
  192. SDL_OnWindowShown(window);
  193. break;
  194. case SDL_EVENT_WINDOW_HIDDEN:
  195. SDL_OnWindowHidden(window);
  196. break;
  197. case SDL_EVENT_WINDOW_MOVED:
  198. SDL_OnWindowMoved(window);
  199. break;
  200. case SDL_EVENT_WINDOW_RESIZED:
  201. SDL_OnWindowResized(window);
  202. break;
  203. case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
  204. SDL_OnWindowPixelSizeChanged(window);
  205. break;
  206. case SDL_EVENT_WINDOW_MINIMIZED:
  207. SDL_OnWindowMinimized(window);
  208. break;
  209. case SDL_EVENT_WINDOW_MAXIMIZED:
  210. SDL_OnWindowMaximized(window);
  211. break;
  212. case SDL_EVENT_WINDOW_RESTORED:
  213. SDL_OnWindowRestored(window);
  214. break;
  215. case SDL_EVENT_WINDOW_MOUSE_ENTER:
  216. SDL_OnWindowEnter(window);
  217. break;
  218. case SDL_EVENT_WINDOW_MOUSE_LEAVE:
  219. SDL_OnWindowLeave(window);
  220. break;
  221. case SDL_EVENT_WINDOW_FOCUS_GAINED:
  222. SDL_OnWindowFocusGained(window);
  223. break;
  224. case SDL_EVENT_WINDOW_FOCUS_LOST:
  225. SDL_OnWindowFocusLost(window);
  226. break;
  227. case SDL_EVENT_WINDOW_DISPLAY_CHANGED:
  228. SDL_OnWindowDisplayChanged(window);
  229. break;
  230. default:
  231. break;
  232. }
  233. if (windowevent == SDL_EVENT_WINDOW_CLOSE_REQUESTED && !window->parent) {
  234. int toplevel_count = 0;
  235. SDL_Window *n;
  236. for (n = SDL_GetVideoDevice()->windows; n; n = n->next) {
  237. if (!n->parent && !(n->flags & SDL_WINDOW_HIDDEN)) {
  238. ++toplevel_count;
  239. }
  240. }
  241. if (toplevel_count <= 1) {
  242. if (SDL_GetHintBoolean(SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE, true)) {
  243. SDL_SendQuit(); // This is the last toplevel window in the list so send the SDL_EVENT_QUIT event
  244. }
  245. }
  246. }
  247. return posted;
  248. }