Mercurial > sdl-ios-xcode
annotate src/video/ggi/SDL_ggivideo.c @ 563:04dcaf3da918
Massive Quartz input enhancements from Darrell Walisser. His email:
Enclosed is a patch that addresses the following:
--Various minor cleanups.
Removed dead/obsolete code, made some style cleanups
--Mouse Events
Now keep track of what button(s) were pressed so we know when to send
the mouse up event. This fixes the case where the mouse is dragged
outside of the game window and released (in which case we want to send
the mouse up event even though the mouse is outside the game window).
--Input Grabbing
Here is my take on the grabbing situation, which is the basis for the
new implementation.
There are 3 grab states, ungrabbed (UG), visible (VG), and invisible
(IG). Both VG and IG keep the mouse constrained to the window and
produce relative motion events. In VG the cursor is visible (duh), in
IG it is not. In VG, absolute motion events also work.
There are 6 actions that can affect grabbing:
1. Set Fullscreen/Window (F/W). In fullscreen, a visible grab should do
nothing. However, a fullscreen visible grab can be treated just like a
windowed visible grab, which is what I have done to help simplify
things.
2. Cursor hide/show (H/S). If the cursor is hidden when grabbing, the
grab is an invisible grab. If the cursor is visible, the grab should
just constrain the mouse to the window.
3. Input grab/ungrab(G/U). If grabbed, the cursor should be confined to
the window as should the keyboard input. On Mac OS X, the keyboard
input is implicitly grabbed by confining the cursor, except for
command-tab which can switch away from the application. Should the
window come to the foreground if the application is deactivated and
grab input is called? This isn't necessary in this implementation
because the grab state will be asserted upon activation.
Using my notation, these are all the cases that need to be handled
(state + action = new state).
UG+U = UG
UG+G = VG or IG, if cursor is visible or not
UG+H = UG
UG+S = UG
VG+U = UG
VG+G = VG
VG+H = IG
VG+S = VG
IG+U = UG
IG+G = IG
IG+H = IG
IG+S = VG
The cases that result in the same state can be ignored in the code,
which cuts it down to just 5 cases.
Another issue is what happens when the app loses/gains input focus from
deactivate/activate or iconify/deiconify. I think that if input focus
is ever lost (outside of SDL's control), the grab state should be
suspended and the cursor should become visible and active again. When
regained, the cursor should reappear in its original location and/or
grab state. This way, when reactivating the cursor is still in the same
position as before so apps shouldn't get confused when the next motion
event comes in. This is what I've done in this patch.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 27 Dec 2002 20:52:41 +0000 |
parents | f6ffac90895c |
children | b8d311d90021 |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
297
f6ffac90895c
Updated copyright information for 2002
Sam Lantinga <slouken@libsdl.org>
parents:
252
diff
changeset
|
3 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Library General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Library General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Library General Public | |
16 License along with this library; if not, write to the Free | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
17
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
22 | |
23 #ifdef SAVE_RCSID | |
24 static char rcsid = | |
25 "@(#) $Id$"; | |
26 #endif | |
27 | |
28 /* GGI-based SDL video driver implementation. | |
29 */ | |
30 | |
31 #include <stdlib.h> | |
32 #include <stdio.h> | |
33 #include <fcntl.h> | |
34 #include <unistd.h> | |
35 #include <sys/mman.h> | |
36 | |
37 #include <ggi/ggi.h> | |
38 #include <ggi/gii.h> | |
39 | |
40 #include "SDL.h" | |
41 #include "SDL_error.h" | |
42 #include "SDL_video.h" | |
43 #include "SDL_mouse.h" | |
44 #include "SDL_sysvideo.h" | |
45 #include "SDL_pixels_c.h" | |
46 #include "SDL_events_c.h" | |
47 #include "SDL_ggivideo.h" | |
48 #include "SDL_ggimouse_c.h" | |
49 #include "SDL_ggievents_c.h" | |
50 | |
51 | |
52 struct private_hwdata | |
53 { | |
54 ggi_visual_t vis; | |
55 }; | |
56 | |
57 ggi_visual_t VIS; | |
58 | |
59 /* Initialization/Query functions */ | |
60 static int GGI_VideoInit(_THIS, SDL_PixelFormat *vformat); | |
61 static SDL_Rect **GGI_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); | |
62 static SDL_Surface *GGI_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); | |
63 static int GGI_SetColors(_THIS, int firstcolor, int ncolors, | |
64 SDL_Color *colors); | |
65 static void GGI_VideoQuit(_THIS); | |
66 | |
67 /* Hardware surface functions */ | |
68 static int GGI_AllocHWSurface(_THIS, SDL_Surface *surface); | |
69 static int GGI_LockHWSurface(_THIS, SDL_Surface *surface); | |
70 static void GGI_UnlockHWSurface(_THIS, SDL_Surface *surface); | |
71 static void GGI_FreeHWSurface(_THIS, SDL_Surface *surface); | |
72 | |
73 /* GGI driver bootstrap functions */ | |
74 | |
75 static int GGI_Available(void) | |
76 { | |
77 ggi_visual_t *vis; | |
17
4f22a992f5e9
Fixed crash in GGI detection
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
78 |
4f22a992f5e9
Fixed crash in GGI detection
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
79 vis = NULL; |
4f22a992f5e9
Fixed crash in GGI detection
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
80 if (ggiInit() == 0) { |
4f22a992f5e9
Fixed crash in GGI detection
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
81 vis = ggiOpen(NULL); |
4f22a992f5e9
Fixed crash in GGI detection
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
82 if (vis != NULL) { |
4f22a992f5e9
Fixed crash in GGI detection
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
83 ggiClose(vis); |
4f22a992f5e9
Fixed crash in GGI detection
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
84 } |
0 | 85 } |
86 return (vis != NULL); | |
87 } | |
88 | |
89 static void GGI_DeleteDevice(SDL_VideoDevice *device) | |
90 { | |
91 free(device->hidden); | |
92 free(device); | |
93 } | |
94 | |
95 static SDL_VideoDevice *GGI_CreateDevice(int devindex) | |
96 { | |
97 SDL_VideoDevice *device; | |
98 | |
99 /* Initialize all variables that we clean on shutdown */ | |
100 device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice)); | |
101 if ( device ) { | |
102 memset(device, 0, (sizeof *device)); | |
103 device->hidden = (struct SDL_PrivateVideoData *) | |
104 malloc((sizeof *device->hidden)); | |
105 } | |
106 if ( (device == NULL) || (device->hidden == NULL) ) { | |
107 SDL_OutOfMemory(); | |
108 if ( device ) { | |
109 free(device); | |
110 } | |
111 return(0); | |
112 } | |
113 memset(device->hidden, 0, (sizeof *device->hidden)); | |
114 | |
115 /* Set the function pointers */ | |
116 device->VideoInit = GGI_VideoInit; | |
117 device->ListModes = GGI_ListModes; | |
118 device->SetVideoMode = GGI_SetVideoMode; | |
119 device->SetColors = GGI_SetColors; | |
120 device->UpdateRects = NULL; | |
121 device->VideoQuit = GGI_VideoQuit; | |
122 device->AllocHWSurface = GGI_AllocHWSurface; | |
123 device->CheckHWBlit = NULL; | |
124 device->FillHWRect = NULL; | |
125 device->SetHWColorKey = NULL; | |
126 device->SetHWAlpha = NULL; | |
127 device->LockHWSurface = GGI_LockHWSurface; | |
128 device->UnlockHWSurface = GGI_UnlockHWSurface; | |
129 device->FlipHWSurface = NULL; | |
130 device->FreeHWSurface = GGI_FreeHWSurface; | |
131 device->SetCaption = NULL; | |
132 device->SetIcon = NULL; | |
133 device->IconifyWindow = NULL; | |
134 device->GrabInput = NULL; | |
135 device->GetWMInfo = NULL; | |
136 device->InitOSKeymap = GGI_InitOSKeymap; | |
137 device->PumpEvents = GGI_PumpEvents; | |
138 | |
139 device->free = GGI_DeleteDevice; | |
140 | |
141 return device; | |
142 } | |
143 | |
144 VideoBootStrap GGI_bootstrap = { | |
145 "ggi", "General Graphics Interface (GGI)", | |
146 GGI_Available, GGI_CreateDevice | |
147 }; | |
148 | |
149 | |
150 static SDL_Rect video_mode; | |
151 static SDL_Rect *SDL_modelist[4] = { NULL, NULL, NULL, NULL }; | |
152 | |
153 int GGI_VideoInit(_THIS, SDL_PixelFormat *vformat) | |
154 { | |
155 ggi_mode mode = | |
156 { | |
157 1, | |
158 { GGI_AUTO, GGI_AUTO }, | |
159 { GGI_AUTO, GGI_AUTO }, | |
160 { 0, 0 }, | |
161 GT_AUTO, | |
162 { GGI_AUTO, GGI_AUTO } | |
163 }; | |
164 struct private_hwdata *priv; | |
165 ggi_color pal[256], map[256]; | |
166 const ggi_directbuffer *db; | |
167 int err, num_bufs; | |
168 ggi_pixel white, black; | |
169 | |
170 priv = malloc(sizeof(struct private_hwdata)); | |
171 if (priv == NULL) | |
172 { | |
173 SDL_SetError("Unhandled GGI mode type!\n"); | |
174 GGI_VideoQuit(NULL); | |
175 } | |
176 | |
177 if (ggiInit() != 0) | |
178 { | |
179 SDL_SetError("Unable to initialize GGI!\n"); | |
180 GGI_VideoQuit(NULL); | |
181 } | |
182 | |
183 VIS = ggiOpen(NULL); | |
184 if (VIS == NULL) | |
185 { | |
186 SDL_SetError("Unable to open default GGI visual!\n"); | |
187 ggiExit(); | |
188 GGI_VideoQuit(NULL); | |
189 } | |
190 | |
191 ggiSetFlags(VIS, GGIFLAG_ASYNC); | |
192 | |
193 /* Validate mode, autodetecting any GGI_AUTO or GT_AUTO fields */ | |
194 ggiCheckMode(VIS, &mode); | |
195 | |
196 /* At this point we should have a valid mode - try to set it */ | |
197 err = ggiSetMode(VIS, &mode); | |
198 | |
199 /* If we couldn't set _any_ modes, something is very wrong */ | |
200 if (err) | |
201 { | |
202 SDL_SetError("Can't set a mode!\n"); | |
203 ggiClose(VIS); | |
204 ggiExit(); | |
205 GGI_VideoQuit(NULL); | |
206 } | |
207 | |
208 /* Set a palette for palletized modes */ | |
209 if (GT_SCHEME(mode.graphtype) == GT_PALETTE) | |
210 { | |
211 ggiSetColorfulPalette(VIS); | |
212 ggiGetPalette(VIS, 0, 1 << vformat->BitsPerPixel, pal); | |
213 } | |
214 | |
215 /* Now we try to get the DirectBuffer info, which determines whether | |
216 * SDL can access hardware surfaces directly. */ | |
217 | |
218 num_bufs = ggiDBGetNumBuffers(VIS); | |
219 | |
220 if (num_bufs > 0) | |
221 { | |
222 db = ggiDBGetBuffer(VIS, 0); /* Only handle one DB for now */ | |
223 | |
224 vformat->BitsPerPixel = db->buffer.plb.pixelformat->depth; | |
225 | |
226 vformat->Rmask = db->buffer.plb.pixelformat->red_mask; | |
227 vformat->Gmask = db->buffer.plb.pixelformat->green_mask; | |
228 vformat->Bmask = db->buffer.plb.pixelformat->blue_mask; | |
229 | |
230 /* Fill in our hardware acceleration capabilities */ | |
231 | |
232 this->info.wm_available = 0; | |
233 this->info.hw_available = 1; | |
234 this->info.video_mem = db->buffer.plb.stride * mode.virt.y; | |
235 } | |
236 | |
237 video_mode.x = 0; | |
238 video_mode.y = 0; | |
239 video_mode.w = mode.virt.x; | |
240 video_mode.h = mode.virt.y; | |
241 SDL_modelist[((vformat->BitsPerPixel + 7) / 8) - 1] = &video_mode; | |
242 | |
243 /* We're done! */ | |
244 return(0); | |
245 } | |
246 | |
247 static SDL_Rect **GGI_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) | |
248 { | |
249 return(&SDL_modelist[((format->BitsPerPixel + 7) / 8) - 1]); | |
250 } | |
251 | |
252 /* Various screen update functions available */ | |
253 static void GGI_DirectUpdate(_THIS, int numrects, SDL_Rect *rects); | |
254 | |
255 SDL_Surface *GGI_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags) | |
256 { | |
257 ggi_mode mode = | |
258 { | |
259 1, | |
260 { GGI_AUTO, GGI_AUTO }, | |
261 { GGI_AUTO, GGI_AUTO }, | |
262 { 0, 0 }, | |
263 GT_AUTO, | |
264 { GGI_AUTO, GGI_AUTO } | |
265 }; | |
266 const ggi_directbuffer *db; | |
267 ggi_color pal[256]; | |
268 int err; | |
269 | |
270 fprintf(stderr, "GGI_SetVideoMode()\n"); | |
271 | |
272 mode.visible.x = mode.virt.x = width; | |
273 mode.visible.y = mode.virt.y = height; | |
274 | |
275 /* Translate requested SDL bit depth into a GGI mode */ | |
276 switch (bpp) | |
277 { | |
278 case 1: mode.graphtype = GT_1BIT; break; | |
279 case 2: mode.graphtype = GT_2BIT; break; | |
280 case 4: mode.graphtype = GT_4BIT; break; | |
281 case 8: mode.graphtype = GT_8BIT; break; | |
282 case 15: mode.graphtype = GT_15BIT; break; | |
283 case 16: mode.graphtype = GT_16BIT; break; | |
284 case 24: mode.graphtype = GT_24BIT; break; | |
285 case 32: mode.graphtype = GT_32BIT; break; | |
286 default: | |
287 SDL_SetError("Unknown SDL bit depth, using GT_AUTO....\n"); | |
288 mode.graphtype = GT_AUTO; | |
289 } | |
290 | |
291 /* Validate mode, autodetecting any GGI_AUTO or GT_AUTO fields */ | |
292 ggiCheckMode(VIS, &mode); | |
293 | |
294 /* At this point we should have a valid mode - try to set it */ | |
295 err = ggiSetMode(VIS, &mode); | |
296 | |
297 /* If we couldn't set _any_ modes, something is very wrong */ | |
298 if (err) | |
299 { | |
300 SDL_SetError("Can't set a mode!\n"); | |
301 ggiClose(VIS); | |
302 ggiExit(); | |
303 GGI_VideoQuit(NULL); | |
304 } | |
305 | |
306 /* Set a palette for palletized modes */ | |
307 if (GT_SCHEME(mode.graphtype) == GT_PALETTE) | |
308 { | |
309 ggiSetColorfulPalette(VIS); | |
310 ggiGetPalette(VIS, 0, 1 << bpp, pal); | |
311 } | |
312 | |
313 db = ggiDBGetBuffer(VIS, 0); | |
314 | |
315 /* Set up the new mode framebuffer */ | |
316 current->flags = (SDL_FULLSCREEN | SDL_HWSURFACE); | |
317 current->w = mode.virt.x; | |
318 current->h = mode.virt.y; | |
319 current->pitch = db->buffer.plb.stride; | |
320 current->pixels = db->read; | |
321 | |
322 /* Set the blit function */ | |
323 this->UpdateRects = GGI_DirectUpdate; | |
324 | |
325 /* We're done */ | |
326 return(current); | |
327 } | |
328 | |
329 static int GGI_AllocHWSurface(_THIS, SDL_Surface *surface) | |
330 { | |
331 return(-1); | |
332 } | |
333 static void GGI_FreeHWSurface(_THIS, SDL_Surface *surface) | |
334 { | |
335 return; | |
336 } | |
337 static int GGI_LockHWSurface(_THIS, SDL_Surface *surface) | |
338 { | |
339 return(0); | |
340 } | |
341 static void GGI_UnlockHWSurface(_THIS, SDL_Surface *surface) | |
342 { | |
343 return; | |
344 } | |
345 | |
346 static void GGI_DirectUpdate(_THIS, int numrects, SDL_Rect *rects) | |
347 { | |
348 int i; | |
349 | |
350 /* ggiFlush(VIS); */ | |
351 | |
352 for (i = 0; i < numrects; i++) | |
353 { | |
354 ggiFlushRegion(VIS, rects[i].x, rects[i].y, rects[i].w, rects[i].h); | |
355 } | |
356 return; | |
357 } | |
358 | |
359 int GGI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) | |
360 { | |
361 int i; | |
362 ggi_color pal[256]; | |
363 | |
364 /* Set up the colormap */ | |
365 for (i = 0; i < ncolors; i++) | |
366 { | |
367 pal[i].r = (colors[i].r << 8) | colors[i].r; | |
368 pal[i].g = (colors[i].g << 8) | colors[i].g; | |
369 pal[i].b = (colors[i].b << 8) | colors[i].b; | |
370 } | |
371 | |
372 ggiSetPalette(VIS, firstcolor, ncolors, pal); | |
373 | |
374 return 1; | |
375 } | |
376 | |
377 void GGI_VideoQuit(_THIS) | |
378 { | |
379 } | |
380 void GGI_FinalQuit(void) | |
381 { | |
382 } |