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 
23 /* Window event handling code for SDL */
24 
25 #include "SDL_events.h"
26 #include "SDL_events_c.h"
27 #include "SDL_mouse_c.h"
28 
29 
30 static int SDLCALL
RemovePendingSizeChangedAndResizedEvents(void * userdata,SDL_Event * event)31 RemovePendingSizeChangedAndResizedEvents(void * userdata, SDL_Event *event)
32 {
33     SDL_Event *new_event = (SDL_Event *)userdata;
34 
35     if (event->type == SDL_WINDOWEVENT &&
36         (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED ||
37          event->window.event == SDL_WINDOWEVENT_RESIZED) &&
38         event->window.windowID == new_event->window.windowID) {
39         /* We're about to post a new size event, drop the old one */
40         return 0;
41     }
42     return 1;
43 }
44 
45 static int SDLCALL
RemovePendingMoveEvents(void * userdata,SDL_Event * event)46 RemovePendingMoveEvents(void * userdata, SDL_Event *event)
47 {
48     SDL_Event *new_event = (SDL_Event *)userdata;
49 
50     if (event->type == SDL_WINDOWEVENT &&
51         event->window.event == SDL_WINDOWEVENT_MOVED &&
52         event->window.windowID == new_event->window.windowID) {
53         /* We're about to post a new move event, drop the old one */
54         return 0;
55     }
56     return 1;
57 }
58 
59 static int SDLCALL
RemovePendingExposedEvents(void * userdata,SDL_Event * event)60 RemovePendingExposedEvents(void * userdata, SDL_Event *event)
61 {
62     SDL_Event *new_event = (SDL_Event *)userdata;
63 
64     if (event->type == SDL_WINDOWEVENT &&
65         event->window.event == SDL_WINDOWEVENT_EXPOSED &&
66         event->window.windowID == new_event->window.windowID) {
67         /* We're about to post a new exposed event, drop the old one */
68         return 0;
69     }
70     return 1;
71 }
72 
73 int
SDL_SendWindowEvent(SDL_Window * window,Uint8 windowevent,int data1,int data2)74 SDL_SendWindowEvent(SDL_Window * window, Uint8 windowevent, int data1,
75                     int data2)
76 {
77     int posted;
78 
79     if (!window) {
80         return 0;
81     }
82     switch (windowevent) {
83     case SDL_WINDOWEVENT_SHOWN:
84         if (window->flags & SDL_WINDOW_SHOWN) {
85             return 0;
86         }
87         window->flags &= ~(SDL_WINDOW_HIDDEN | SDL_WINDOW_MINIMIZED);
88         window->flags |= SDL_WINDOW_SHOWN;
89         SDL_OnWindowShown(window);
90         break;
91     case SDL_WINDOWEVENT_HIDDEN:
92         if (!(window->flags & SDL_WINDOW_SHOWN)) {
93             return 0;
94         }
95         window->flags &= ~SDL_WINDOW_SHOWN;
96         window->flags |= SDL_WINDOW_HIDDEN;
97         SDL_OnWindowHidden(window);
98         break;
99     case SDL_WINDOWEVENT_MOVED:
100         if (SDL_WINDOWPOS_ISUNDEFINED(data1) ||
101             SDL_WINDOWPOS_ISUNDEFINED(data2)) {
102             return 0;
103         }
104         if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
105             window->windowed.x = data1;
106             window->windowed.y = data2;
107         }
108         if (data1 == window->x && data2 == window->y) {
109             return 0;
110         }
111         window->x = data1;
112         window->y = data2;
113         break;
114     case SDL_WINDOWEVENT_RESIZED:
115         if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
116             window->windowed.w = data1;
117             window->windowed.h = data2;
118         }
119         if (data1 == window->w && data2 == window->h) {
120             return 0;
121         }
122         window->w = data1;
123         window->h = data2;
124         SDL_OnWindowResized(window);
125         break;
126     case SDL_WINDOWEVENT_MINIMIZED:
127         if (window->flags & SDL_WINDOW_MINIMIZED) {
128             return 0;
129         }
130         window->flags &= ~SDL_WINDOW_MAXIMIZED;
131         window->flags |= SDL_WINDOW_MINIMIZED;
132         SDL_OnWindowMinimized(window);
133         break;
134     case SDL_WINDOWEVENT_MAXIMIZED:
135         if (window->flags & SDL_WINDOW_MAXIMIZED) {
136             return 0;
137         }
138         window->flags &= ~SDL_WINDOW_MINIMIZED;
139         window->flags |= SDL_WINDOW_MAXIMIZED;
140         break;
141     case SDL_WINDOWEVENT_RESTORED:
142         if (!(window->flags & (SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED))) {
143             return 0;
144         }
145         window->flags &= ~(SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED);
146         SDL_OnWindowRestored(window);
147         break;
148     case SDL_WINDOWEVENT_ENTER:
149         if (window->flags & SDL_WINDOW_MOUSE_FOCUS) {
150             return 0;
151         }
152         window->flags |= SDL_WINDOW_MOUSE_FOCUS;
153         SDL_OnWindowEnter(window);
154         break;
155     case SDL_WINDOWEVENT_LEAVE:
156         if (!(window->flags & SDL_WINDOW_MOUSE_FOCUS)) {
157             return 0;
158         }
159         window->flags &= ~SDL_WINDOW_MOUSE_FOCUS;
160         SDL_OnWindowLeave(window);
161         break;
162     case SDL_WINDOWEVENT_FOCUS_GAINED:
163         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
164             return 0;
165         }
166         window->flags |= SDL_WINDOW_INPUT_FOCUS;
167         SDL_OnWindowFocusGained(window);
168         break;
169     case SDL_WINDOWEVENT_FOCUS_LOST:
170         if (!(window->flags & SDL_WINDOW_INPUT_FOCUS)) {
171             return 0;
172         }
173         window->flags &= ~SDL_WINDOW_INPUT_FOCUS;
174         SDL_OnWindowFocusLost(window);
175         break;
176     }
177 
178     /* Post the event, if desired */
179     posted = 0;
180     if (SDL_GetEventState(SDL_WINDOWEVENT) == SDL_ENABLE) {
181         SDL_Event event;
182         event.type = SDL_WINDOWEVENT;
183         event.window.event = windowevent;
184         event.window.data1 = data1;
185         event.window.data2 = data2;
186         event.window.windowID = window->id;
187 
188         /* Fixes queue overflow with resize events that aren't processed */
189         if (windowevent == SDL_WINDOWEVENT_SIZE_CHANGED) {
190             SDL_FilterEvents(RemovePendingSizeChangedAndResizedEvents, &event);
191         }
192         if (windowevent == SDL_WINDOWEVENT_MOVED) {
193             SDL_FilterEvents(RemovePendingMoveEvents, &event);
194         }
195         if (windowevent == SDL_WINDOWEVENT_EXPOSED) {
196             SDL_FilterEvents(RemovePendingExposedEvents, &event);
197         }
198         posted = (SDL_PushEvent(&event) > 0);
199     }
200 
201     if (windowevent == SDL_WINDOWEVENT_CLOSE) {
202         if ( !window->prev && !window->next ) {
203             /* This is the last window in the list so send the SDL_QUIT event */
204             SDL_SendQuit();
205         }
206     }
207 
208     return (posted);
209 }
210 
211 /* vi: set ts=4 sw=4 expandtab: */
212