/
SDL_QuartzWM.m
420 lines (328 loc) · 11.8 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2003 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
#include "SDL_config.h"
23
24
25
#include "SDL_QuartzVideo.h"
26
27
28
29
30
struct WMcursor {
Cursor curs;
};
31
void QZ_FreeWMCursor (_THIS, WMcursor *cursor) {
32
33
34
35
36
37
if ( cursor != NULL )
free (cursor);
}
/* Use the Carbon cursor routines for now */
38
WMcursor* QZ_CreateWMCursor (_THIS, Uint8 *data, Uint8 *mask,
39
40
41
42
43
44
45
46
47
48
49
int w, int h, int hot_x, int hot_y) {
WMcursor *cursor;
int row, bytes;
/* Allocate the cursor memory */
cursor = (WMcursor *)malloc(sizeof(WMcursor));
if ( cursor == NULL ) {
SDL_OutOfMemory();
return(NULL);
}
memset(cursor, 0, sizeof(*cursor));
50
51
52
53
54
55
56
if (w > 16)
w = 16;
if (h > 16)
h = 16;
57
58
59
60
61
62
63
64
65
66
67
68
69
bytes = (w+7)/8;
for ( row=0; row<h; ++row ) {
memcpy(&cursor->curs.data[row], data, bytes);
data += bytes;
}
for ( row=0; row<h; ++row ) {
memcpy(&cursor->curs.mask[row], mask, bytes);
mask += bytes;
}
cursor->curs.hotSpot.h = hot_x;
cursor->curs.hotSpot.v = hot_y;
70
return(cursor);
71
72
}
73
74
75
76
77
78
79
80
void QZ_ShowMouse (_THIS) {
if (!cursor_visible) {
[ NSCursor unhide ];
cursor_visible = YES;
}
}
void QZ_HideMouse (_THIS) {
81
82
BOOL isInGameWin = QZ_IsMouseInWindow (this);
if (isInGameWin && cursor_visible) {
83
84
85
86
87
[ NSCursor hide ];
cursor_visible = NO;
}
}
88
BOOL QZ_IsMouseInWindow (_THIS) {
89
90
91
92
93
94
if (mode_flags & SDL_FULLSCREEN) return YES;
else {
NSPoint p = [ qz_window mouseLocationOutsideOfEventStream ];
p.y -= 1.0f; /* Apparently y goes from 1 to h, not from 0 to h-1 (i.e. the "location of the mouse" seems to be defined as "the location of the top left corner of the mouse pointer's hot pixel" */
return NSPointInRect(p, [ window_view frame ]);
}
95
96
}
97
int QZ_ShowWMCursor (_THIS, WMcursor *cursor) {
98
99
if ( cursor == NULL) {
100
101
102
if ( cursor_should_be_visible ) {
QZ_HideMouse (this);
cursor_should_be_visible = NO;
103
QZ_ChangeGrabState (this, QZ_HIDECURSOR);
104
105
106
107
}
}
else {
SetCursor(&cursor->curs);
108
109
110
if ( ! cursor_should_be_visible ) {
QZ_ShowMouse (this);
cursor_should_be_visible = YES;
111
QZ_ChangeGrabState (this, QZ_SHOWCURSOR);
112
113
114
115
116
117
}
}
return 1;
}
118
119
120
121
122
123
124
/*
Coordinate conversion functions, for convenience
Cocoa sets the origin at the lower left corner of the window/screen
SDL, CoreGraphics/WindowServer, and QuickDraw use the origin at the upper left corner
The routines were written so they could be called before SetVideoMode() has finished;
this might have limited usefulness at the moment, but the extra cost is trivial.
*/
125
126
/* Convert Cocoa screen coordinate to Cocoa window coordinate */
127
void QZ_PrivateGlobalToLocal (_THIS, NSPoint *p) {
128
129
130
131
132
133
*p = [ qz_window convertScreenToBase:*p ];
}
/* Convert Cocoa window coordinate to Cocoa screen coordinate */
134
void QZ_PrivateLocalToGlobal (_THIS, NSPoint *p) {
135
136
137
138
139
*p = [ qz_window convertBaseToScreen:*p ];
}
/* Convert SDL coordinate to Cocoa coordinate */
140
void QZ_PrivateSDLToCocoa (_THIS, NSPoint *p) {
141
142
143
if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */
144
p->y = CGDisplayPixelsHigh (display_id) - p->y;
145
}
146
else {
147
148
*p = [ window_view convertPoint:*p toView: nil ];
149
150
151
152
153
/* We need a workaround in OpenGL mode */
if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
p->y = [window_view frame].size.height - p->y;
}
154
155
156
}
}
157
/* Convert Cocoa coordinate to SDL coordinate */
158
void QZ_PrivateCocoaToSDL (_THIS, NSPoint *p) {
159
160
161
if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */
162
p->y = CGDisplayPixelsHigh (display_id) - p->y;
163
164
}
else {
165
166
167
*p = [ window_view convertPoint:*p fromView: nil ];
168
169
/* We need a workaround in OpenGL mode */
if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
170
p->y = [window_view frame].size.height - p->y;
171
}
172
}
173
174
175
}
/* Convert SDL coordinate to window server (CoreGraphics) coordinate */
176
CGPoint QZ_PrivateSDLToCG (_THIS, NSPoint *p) {
177
178
179
180
CGPoint cgp;
if ( ! CGDisplayIsCaptured (display_id) ) { /* not captured => not fullscreen => local coord */
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
int height;
QZ_PrivateSDLToCocoa (this, p);
QZ_PrivateLocalToGlobal (this, p);
height = CGDisplayPixelsHigh (display_id);
p->y = height - p->y;
}
cgp.x = p->x;
cgp.y = p->y;
return cgp;
}
197
#if 0 /* Dead code */
198
/* Convert window server (CoreGraphics) coordinate to SDL coordinate */
199
void QZ_PrivateCGToSDL (_THIS, NSPoint *p) {
200
201
202
203
204
205
206
207
208
209
210
211
212
if ( ! CGDisplayIsCaptured (display_id) ) { /* not captured => not fullscreen => local coord */
int height;
/* Convert CG Global to Cocoa Global */
height = CGDisplayPixelsHigh (display_id);
p->y = height - p->y;
QZ_PrivateGlobalToLocal (this, p);
QZ_PrivateCocoaToSDL (this, p);
}
}
213
#endif /* Dead code */
214
215
void QZ_PrivateWarpCursor (_THIS, int x, int y) {
216
217
218
219
220
NSPoint p;
CGPoint cgp;
p = NSMakePoint (x, y);
221
222
223
224
225
cgp = QZ_PrivateSDLToCG (this, &p);
/* this is the magic call that fixes cursor "freezing" after warp */
CGSetLocalEventsSuppressionInterval (0.0);
CGWarpMouseCursorPosition (cgp);
226
227
}
228
void QZ_WarpWMCursor (_THIS, Uint16 x, Uint16 y) {
229
230
/* Only allow warping when in foreground */
231
if ( ! [ NSApp isActive ] )
232
233
234
return;
/* Do the actual warp */
235
if (grab_state != QZ_INVISIBLE_GRAB) QZ_PrivateWarpCursor (this, x, y);
236
237
238
/* Generate the mouse moved event */
SDL_PrivateMouseMotion (0, 0, x, y);
239
240
}
241
242
void QZ_MoveWMCursor (_THIS, int x, int y) { }
void QZ_CheckMouseMode (_THIS) { }
243
244
void QZ_SetCaption (_THIS, const char *title, const char *icon) {
245
246
if ( qz_window != nil ) {
247
248
NSString *string;
if ( title != NULL ) {
249
string = [ [ NSString alloc ] initWithUTF8String:title ];
250
[ qz_window setTitle:string ];
251
252
253
[ string release ];
}
if ( icon != NULL ) {
254
string = [ [ NSString alloc ] initWithUTF8String:icon ];
255
[ qz_window setMiniwindowTitle:string ];
256
257
258
[ string release ];
}
}
259
260
}
261
void QZ_SetIcon (_THIS, SDL_Surface *icon, Uint8 *mask)
262
{
263
264
265
NSBitmapImageRep *imgrep;
NSImage *img;
SDL_Surface *mergedSurface;
266
int i,j;
267
268
269
270
271
272
273
274
275
276
277
NSAutoreleasePool *pool;
SDL_Rect rrect;
NSSize imgSize = {icon->w, icon->h};
pool = [ [ NSAutoreleasePool alloc ] init ];
SDL_GetClipRect(icon, &rrect);
/* create a big endian RGBA surface */
mergedSurface = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,
icon->w, icon->h, 32, 0xff<<24, 0xff<<16, 0xff<<8, 0xff<<0);
if (mergedSurface==NULL) {
278
279
280
NSLog(@"Error creating surface for merge");
goto freePool;
}
281
282
283
284
285
286
287
288
if (mergedSurface->pitch !=
mergedSurface->format->BytesPerPixel * mergedSurface->w) {
SDL_SetError ("merged surface has wrong format");
SDL_FreeSurface (mergedSurface);
goto freePool;
}
289
290
291
292
293
294
if (SDL_BlitSurface(icon,&rrect,mergedSurface,&rrect)) {
NSLog(@"Error blitting to mergedSurface");
goto freePool;
}
if (mask) {
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
Uint32 *pixels = mergedSurface->pixels;
for (i = 0; i < mergedSurface->h; i++) {
for (j = 0; j < mergedSurface->w; j++) {
int index = i * mergedSurface->w + j;
int mindex = index >> 3;
int bindex = 7 - (index & 0x7);
if (mask[mindex] & (1 << bindex))
pixels[index] |= 0x000000FF;
else
pixels[index] &= 0xFFFFFF00;
}
}
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
}
imgrep = [ [ NSBitmapImageRep alloc]
initWithBitmapDataPlanes:(unsigned char **)&mergedSurface->pixels
pixelsWide:icon->w pixelsHigh:icon->h bitsPerSample:8 samplesPerPixel:4
hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:icon->w<<2 bitsPerPixel:32 ];
img = [ [ NSImage alloc ] initWithSize:imgSize ];
[ img addRepresentation: imgrep ];
[ NSApp setApplicationIconImage:img ];
[ img release ];
[ imgrep release ];
SDL_FreeSurface(mergedSurface);
326
freePool:
327
[pool release];
328
329
}
330
int QZ_IconifyWindow (_THIS) {
331
332
333
if ( ! [ qz_window isMiniaturized ] ) {
[ qz_window miniaturize:nil ];
334
335
336
return 1;
}
else {
337
SDL_SetError ("window already iconified");
338
339
340
341
342
return 0;
}
}
/*
343
int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info) {
344
info->nsWindowPtr = qz_window;
345
346
347
return 0;
}*/
348
void QZ_ChangeGrabState (_THIS, int action) {
349
350
351
352
353
354
355
/*
Figure out what the next state should be based on the action.
Ignore actions that can't change the current state.
*/
if ( grab_state == QZ_UNGRABBED ) {
if ( action == QZ_ENABLE_GRAB ) {
356
if ( cursor_should_be_visible )
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
grab_state = QZ_VISIBLE_GRAB;
else
grab_state = QZ_INVISIBLE_GRAB;
}
}
else if ( grab_state == QZ_VISIBLE_GRAB ) {
if ( action == QZ_DISABLE_GRAB )
grab_state = QZ_UNGRABBED;
else if ( action == QZ_HIDECURSOR )
grab_state = QZ_INVISIBLE_GRAB;
}
else {
assert( grab_state == QZ_INVISIBLE_GRAB );
if ( action == QZ_DISABLE_GRAB )
grab_state = QZ_UNGRABBED;
else if ( action == QZ_SHOWCURSOR )
grab_state = QZ_VISIBLE_GRAB;
}
/* now apply the new state */
if (grab_state == QZ_UNGRABBED) {
CGAssociateMouseAndMouseCursorPosition (1);
}
else if (grab_state == QZ_VISIBLE_GRAB) {
CGAssociateMouseAndMouseCursorPosition (1);
}
else {
assert( grab_state == QZ_INVISIBLE_GRAB );
QZ_PrivateWarpCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2);
CGAssociateMouseAndMouseCursorPosition (0);
}
}
394
SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode) {
395
396
397
398
399
400
401
402
403
404
405
406
407
int doGrab = grab_mode & SDL_GRAB_ON;
/*int fullscreen = grab_mode & SDL_GRAB_FULLSCREEN;*/
if ( this->screen == NULL ) {
SDL_SetError ("QZ_GrabInput: screen is NULL");
return SDL_GRAB_OFF;
}
if ( ! video_set ) {
/*SDL_SetError ("QZ_GrabInput: video is not set, grab will take effect on mode switch"); */
current_grab_mode = grab_mode;
return grab_mode; /* Will be set later on mode switch */
408
}
409
410
411
412
413
414
if ( grab_mode != SDL_GRAB_QUERY ) {
if ( doGrab )
QZ_ChangeGrabState (this, QZ_ENABLE_GRAB);
else
QZ_ChangeGrabState (this, QZ_DISABLE_GRAB);
415
416
417
418
current_grab_mode = doGrab ? SDL_GRAB_ON : SDL_GRAB_OFF;
}
419
return current_grab_mode;
420
}