Skip to content

Latest commit

 

History

History
443 lines (358 loc) · 14 KB

SDL_QuartzWM.m

File metadata and controls

443 lines (358 loc) · 14 KB
 
1
2
/*
SDL - Simple DirectMedia Layer
Dec 8, 2008
Dec 8, 2008
3
Copyright (C) 1997-2009 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
Dec 14, 2001
Dec 14, 2001
20
slouken@libsdl.org
Feb 21, 2006
Feb 21, 2006
22
#include "SDL_config.h"
Jan 4, 2004
Jan 4, 2004
24
#include "SDL_QuartzVideo.h"
Jul 15, 2007
Jul 15, 2007
25
#include "SDL_QuartzWM.h"
Jan 4, 2004
Jan 4, 2004
26
Dec 27, 2002
Dec 27, 2002
27
Jan 4, 2004
Jan 4, 2004
28
void QZ_FreeWMCursor (_THIS, WMcursor *cursor) {
Jun 24, 2006
Jun 24, 2006
30
31
if ( cursor != NULL ) {
[ cursor->nscursor release ];
32
free (cursor);
Jun 24, 2006
Jun 24, 2006
33
}
Jan 4, 2004
Jan 4, 2004
36
WMcursor* QZ_CreateWMCursor (_THIS, Uint8 *data, Uint8 *mask,
Jun 1, 2002
Jun 1, 2002
37
38
int w, int h, int hot_x, int hot_y) {
WMcursor *cursor;
Jun 24, 2006
Jun 24, 2006
39
40
41
42
43
44
45
46
NSBitmapImageRep *imgrep;
NSImage *img;
unsigned char *planes[5];
int i;
NSAutoreleasePool *pool;
pool = [ [ NSAutoreleasePool alloc ] init ];
Jun 1, 2002
Jun 1, 2002
47
/* Allocate the cursor memory */
May 1, 2006
May 1, 2006
48
cursor = (WMcursor *)SDL_malloc(sizeof(WMcursor));
Jun 24, 2006
Jun 24, 2006
49
if (cursor == NULL) goto outOfMemory;
Aug 22, 2011
Aug 22, 2011
50
Jun 24, 2006
Jun 24, 2006
51
/* create the image representation and get the pointers to its storage */
Aug 22, 2011
Aug 22, 2011
52
imgrep = [ [ [ NSBitmapImageRep alloc ] initWithBitmapDataPlanes: NULL pixelsWide: w pixelsHigh: h bitsPerSample: 1 samplesPerPixel: 2 hasAlpha: YES isPlanar: YES colorSpaceName: NSDeviceWhiteColorSpace bytesPerRow: (w+7)/8 bitsPerPixel: 0 ] autorelease ];
Jun 24, 2006
Jun 24, 2006
53
54
if (imgrep == nil) goto outOfMemory;
[ imgrep getBitmapDataPlanes: planes ];
Sep 4, 2001
Sep 4, 2001
55
Jun 24, 2006
Jun 24, 2006
56
57
/* copy data and mask, extending the mask to all black pixels because the inversion effect doesn't work with Cocoa's alpha-blended cursors */
for (i = 0; i < (w+7)/8*h; i++) {
Aug 22, 2011
Aug 22, 2011
58
planes[0][i] = data[i] ^ 0xFF;
Jun 24, 2006
Jun 24, 2006
59
planes[1][i] = mask[i] | data[i];
Jun 1, 2002
Jun 1, 2002
60
}
Aug 22, 2011
Aug 22, 2011
61
Jun 24, 2006
Jun 24, 2006
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/* create image and cursor */
img = [ [ [ NSImage alloc ] initWithSize: NSMakeSize(w, h) ] autorelease ];
if (img == nil) goto outOfMemory;
[ img addRepresentation: imgrep ];
if (system_version < 0x1030) { /* on 10.2, cursors must be 16*16 */
if (w > 16 || h > 16) { /* too big: scale it down */
[ img setScalesWhenResized: YES ];
hot_x = hot_x*16/w;
hot_y = hot_y*16/h;
}
else { /* too small (or just right): extend it (from the bottom left corner, so hot_y must be adjusted) */
hot_y += 16 - h;
}
[ img setSize: NSMakeSize(16, 16) ];
Jun 1, 2002
Jun 1, 2002
76
}
Jun 24, 2006
Jun 24, 2006
77
78
cursor->nscursor = [ [ NSCursor alloc ] initWithImage: img hotSpot: NSMakePoint(hot_x, hot_y) ];
if (cursor->nscursor == nil) goto outOfMemory;
Jun 1, 2002
Jun 1, 2002
79
Jun 24, 2006
Jun 24, 2006
80
[ pool release ];
Sep 4, 2001
Sep 4, 2001
81
return(cursor);
Jun 24, 2006
Jun 24, 2006
82
83
84
85
86
87
outOfMemory:
[ pool release ];
if (cursor != NULL) SDL_free(cursor);
SDL_OutOfMemory();
return(NULL);
Jul 15, 2007
Jul 15, 2007
90
91
void QZ_UpdateCursor (_THIS) {
BOOL state;
Jan 4, 2004
Jan 4, 2004
92
Jul 15, 2007
Jul 15, 2007
93
94
95
96
97
98
99
100
101
102
103
104
if (cursor_should_be_visible || !(SDL_GetAppState() & SDL_APPMOUSEFOCUS)) {
state = YES;
} else {
state = NO;
}
if (state != cursor_visible) {
if (state) {
[ NSCursor unhide ];
} else {
[ NSCursor hide ];
}
cursor_visible = state;
Jan 4, 2004
Jan 4, 2004
105
106
107
}
}
Jan 7, 2004
Jan 7, 2004
108
BOOL QZ_IsMouseInWindow (_THIS) {
Jul 14, 2007
Jul 14, 2007
109
if (qz_window == nil || (mode_flags & SDL_FULLSCREEN)) return YES; /*fullscreen*/
Nov 28, 2005
Nov 28, 2005
110
111
112
113
114
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 ]);
}
Jan 7, 2004
Jan 7, 2004
115
116
}
Jan 4, 2004
Jan 4, 2004
117
int QZ_ShowWMCursor (_THIS, WMcursor *cursor) {
118
119
if ( cursor == NULL) {
Jan 4, 2004
Jan 4, 2004
120
121
if ( cursor_should_be_visible ) {
cursor_should_be_visible = NO;
Dec 27, 2002
Dec 27, 2002
122
QZ_ChangeGrabState (this, QZ_HIDECURSOR);
Jul 15, 2007
Jul 15, 2007
124
QZ_UpdateCursor(this);
Jul 15, 2007
Jul 15, 2007
127
128
129
130
131
132
if (qz_window ==nil || (mode_flags & SDL_FULLSCREEN)) {
[ cursor->nscursor set ];
}
else {
[ qz_window invalidateCursorRectsForView: [ qz_window contentView ] ];
}
Jan 4, 2004
Jan 4, 2004
133
134
if ( ! cursor_should_be_visible ) {
cursor_should_be_visible = YES;
Dec 27, 2002
Dec 27, 2002
135
QZ_ChangeGrabState (this, QZ_SHOWCURSOR);
Jul 15, 2007
Jul 15, 2007
137
QZ_UpdateCursor(this);
138
139
140
141
142
}
return 1;
}
Oct 5, 2002
Oct 5, 2002
143
144
145
146
147
148
149
/*
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.
*/
Jan 22, 2002
Jan 22, 2002
151
/* Convert Cocoa screen coordinate to Cocoa window coordinate */
Jan 4, 2004
Jan 4, 2004
152
void QZ_PrivateGlobalToLocal (_THIS, NSPoint *p) {
Jan 22, 2002
Jan 22, 2002
153
Dec 11, 2009
Dec 11, 2009
154
155
if ( ! CGDisplayIsCaptured (display_id) )
*p = [ qz_window convertScreenToBase:*p ];
Jan 22, 2002
Jan 22, 2002
156
157
158
159
}
/* Convert Cocoa window coordinate to Cocoa screen coordinate */
Jan 4, 2004
Jan 4, 2004
160
void QZ_PrivateLocalToGlobal (_THIS, NSPoint *p) {
Jan 22, 2002
Jan 22, 2002
161
Dec 11, 2009
Dec 11, 2009
162
163
if ( ! CGDisplayIsCaptured (display_id) )
*p = [ qz_window convertBaseToScreen:*p ];
Jan 22, 2002
Jan 22, 2002
164
165
166
}
/* Convert SDL coordinate to Cocoa coordinate */
Jan 4, 2004
Jan 4, 2004
167
void QZ_PrivateSDLToCocoa (_THIS, NSPoint *p) {
Jan 22, 2002
Jan 22, 2002
168
169
170
if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */
Mar 22, 2004
Mar 22, 2004
171
p->y = CGDisplayPixelsHigh (display_id) - p->y;
Jan 22, 2002
Jan 22, 2002
172
}
Aug 20, 2004
Aug 20, 2004
174
175
*p = [ window_view convertPoint:*p toView: nil ];
Sep 21, 2009
Sep 21, 2009
176
p->y = [window_view frame].size.height - p->y;
Jan 22, 2002
Jan 22, 2002
180
/* Convert Cocoa coordinate to SDL coordinate */
Jan 4, 2004
Jan 4, 2004
181
void QZ_PrivateCocoaToSDL (_THIS, NSPoint *p) {
Jan 22, 2002
Jan 22, 2002
182
Aug 10, 2003
Aug 10, 2003
183
184
if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */
Mar 22, 2004
Mar 22, 2004
185
p->y = CGDisplayPixelsHigh (display_id) - p->y;
Aug 10, 2003
Aug 10, 2003
186
187
}
else {
Mar 22, 2004
Mar 22, 2004
188
Aug 20, 2004
Aug 20, 2004
189
*p = [ window_view convertPoint:*p fromView: nil ];
Sep 21, 2009
Sep 21, 2009
190
p->y = [window_view frame].size.height - p->y;
Aug 10, 2003
Aug 10, 2003
191
}
Jan 22, 2002
Jan 22, 2002
192
193
194
}
/* Convert SDL coordinate to window server (CoreGraphics) coordinate */
Jan 4, 2004
Jan 4, 2004
195
CGPoint QZ_PrivateSDLToCG (_THIS, NSPoint *p) {
Jan 22, 2002
Jan 22, 2002
196
197
198
199
CGPoint cgp;
if ( ! CGDisplayIsCaptured (display_id) ) { /* not captured => not fullscreen => local coord */
Jan 22, 2002
Jan 22, 2002
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
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;
}
Aug 10, 2003
Aug 10, 2003
216
#if 0 /* Dead code */
Jan 22, 2002
Jan 22, 2002
217
/* Convert window server (CoreGraphics) coordinate to SDL coordinate */
Jan 4, 2004
Jan 4, 2004
218
void QZ_PrivateCGToSDL (_THIS, NSPoint *p) {
Jan 22, 2002
Jan 22, 2002
219
220
221
222
223
224
225
226
227
228
229
230
231
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);
}
}
Aug 10, 2003
Aug 10, 2003
232
#endif /* Dead code */
Jan 22, 2002
Jan 22, 2002
233
Jan 4, 2004
Jan 4, 2004
234
void QZ_PrivateWarpCursor (_THIS, int x, int y) {
Aug 22, 2011
Aug 22, 2011
235
CGEventSourceRef evsrc = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
Jan 22, 2002
Jan 22, 2002
236
237
238
239
NSPoint p;
CGPoint cgp;
p = NSMakePoint (x, y);
Dec 27, 2002
Dec 27, 2002
240
241
242
cgp = QZ_PrivateSDLToCG (this, &p);
/* this is the magic call that fixes cursor "freezing" after warp */
Aug 22, 2011
Aug 22, 2011
243
CGEventSourceSetLocalEventsSuppressionInterval(evsrc, 0.0);
Dec 27, 2002
Dec 27, 2002
244
CGWarpMouseCursorPosition (cgp);
Aug 22, 2011
Aug 22, 2011
245
CFRelease(evsrc);
Jan 22, 2002
Jan 22, 2002
246
247
}
Jan 4, 2004
Jan 4, 2004
248
void QZ_WarpWMCursor (_THIS, Uint16 x, Uint16 y) {
Jan 22, 2002
Jan 22, 2002
249
250
/* Only allow warping when in foreground */
Jan 4, 2004
Jan 4, 2004
251
if ( ! [ NSApp isActive ] )
252
253
254
return;
/* Do the actual warp */
Dec 21, 2005
Dec 21, 2005
255
if (grab_state != QZ_INVISIBLE_GRAB) QZ_PrivateWarpCursor (this, x, y);
Dec 27, 2002
Dec 27, 2002
256
257
258
/* Generate the mouse moved event */
SDL_PrivateMouseMotion (0, 0, x, y);
Jan 4, 2004
Jan 4, 2004
261
262
void QZ_MoveWMCursor (_THIS, int x, int y) { }
void QZ_CheckMouseMode (_THIS) { }
Jan 4, 2004
Jan 4, 2004
264
void QZ_SetCaption (_THIS, const char *title, const char *icon) {
Aug 21, 2001
Aug 21, 2001
266
if ( qz_window != nil ) {
Jun 11, 2001
Jun 11, 2001
267
268
NSString *string;
if ( title != NULL ) {
Aug 30, 2004
Aug 30, 2004
269
string = [ [ NSString alloc ] initWithUTF8String:title ];
Aug 21, 2001
Aug 21, 2001
270
[ qz_window setTitle:string ];
Jun 11, 2001
Jun 11, 2001
271
272
273
[ string release ];
}
if ( icon != NULL ) {
Aug 30, 2004
Aug 30, 2004
274
string = [ [ NSString alloc ] initWithUTF8String:icon ];
Aug 21, 2001
Aug 21, 2001
275
[ qz_window setMiniwindowTitle:string ];
Jun 11, 2001
Jun 11, 2001
276
277
278
[ string release ];
}
}
Jan 4, 2004
Jan 4, 2004
281
void QZ_SetIcon (_THIS, SDL_Surface *icon, Uint8 *mask)
Jan 18, 2002
Jan 18, 2002
282
{
Oct 5, 2002
Oct 5, 2002
283
284
285
286
NSBitmapImageRep *imgrep;
NSImage *img;
SDL_Surface *mergedSurface;
NSAutoreleasePool *pool;
May 11, 2006
May 11, 2006
287
288
289
290
Uint8 *pixels;
SDL_bool iconSrcAlpha;
Uint8 iconAlphaValue;
int i, j, maskPitch, index;
Oct 5, 2002
Oct 5, 2002
291
292
293
pool = [ [ NSAutoreleasePool alloc ] init ];
May 11, 2006
May 11, 2006
294
295
296
297
imgrep = [ [ [ NSBitmapImageRep alloc ] initWithBitmapDataPlanes: NULL pixelsWide: icon->w pixelsHigh: icon->h bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES isPlanar: NO colorSpaceName: NSDeviceRGBColorSpace bytesPerRow: 4*icon->w bitsPerPixel: 32 ] autorelease ];
if (imgrep == nil) goto freePool;
pixels = [ imgrep bitmapData ];
SDL_memset(pixels, 0, 4*icon->w*icon->h); /* make the background, which will survive in colorkeyed areas, completely transparent */
Oct 5, 2002
Oct 5, 2002
298
May 11, 2006
May 11, 2006
299
300
301
302
303
304
305
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define BYTEORDER_DEPENDENT_RGBA_MASKS 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
#else
#define BYTEORDER_DEPENDENT_RGBA_MASKS 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
#endif
mergedSurface = SDL_CreateRGBSurfaceFrom(pixels, icon->w, icon->h, 32, 4*icon->w, BYTEORDER_DEPENDENT_RGBA_MASKS);
if (mergedSurface == NULL) goto freePool;
Feb 1, 2003
Feb 1, 2003
306
May 11, 2006
May 11, 2006
307
308
309
310
311
312
313
314
/* blit, with temporarily cleared SRCALPHA flag because we want to copy, not alpha-blend */
iconSrcAlpha = ((icon->flags & SDL_SRCALPHA) != 0);
iconAlphaValue = icon->format->alpha;
SDL_SetAlpha(icon, 0, 255);
SDL_BlitSurface(icon, NULL, mergedSurface, NULL);
if (iconSrcAlpha) SDL_SetAlpha(icon, SDL_SRCALPHA, iconAlphaValue);
SDL_FreeSurface(mergedSurface);
Oct 5, 2002
Oct 5, 2002
315
May 11, 2006
May 11, 2006
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
/* apply mask, source alpha, and premultiply color values by alpha */
maskPitch = (icon->w+7)/8;
for (i = 0; i < icon->h; i++) {
for (j = 0; j < icon->w; j++) {
index = i*4*icon->w + j*4;
if (!(mask[i*maskPitch + j/8] & (128 >> j%8))) {
pixels[index + 3] = 0;
}
else {
if (iconSrcAlpha) {
if (icon->format->Amask == 0) pixels[index + 3] = icon->format->alpha;
}
else {
pixels[index + 3] = 255;
}
}
if (pixels[index + 3] < 255) {
pixels[index + 0] = (Uint16)pixels[index + 0]*pixels[index + 3]/255;
pixels[index + 1] = (Uint16)pixels[index + 1]*pixels[index + 3]/255;
pixels[index + 2] = (Uint16)pixels[index + 2]*pixels[index + 3]/255;
Feb 1, 2003
Feb 1, 2003
336
337
}
}
Oct 5, 2002
Oct 5, 2002
338
339
}
May 11, 2006
May 11, 2006
340
341
img = [ [ [ NSImage alloc ] initWithSize: NSMakeSize(icon->w, icon->h) ] autorelease ];
if (img == nil) goto freePool;
Oct 5, 2002
Oct 5, 2002
342
343
344
[ img addRepresentation: imgrep ];
[ NSApp setApplicationIconImage:img ];
Jan 18, 2002
Jan 18, 2002
345
freePool:
May 11, 2006
May 11, 2006
346
[ pool release ];
Jan 4, 2004
Jan 4, 2004
349
int QZ_IconifyWindow (_THIS) {
Aug 21, 2001
Aug 21, 2001
351
352
if ( ! [ qz_window isMiniaturized ] ) {
[ qz_window miniaturize:nil ];
Dec 29, 2007
Dec 29, 2007
353
354
355
356
if ( ! [ qz_window isMiniaturized ] ) {
SDL_SetError ("window iconification failed");
return 0;
}
357
358
359
return 1;
}
else {
Oct 5, 2002
Oct 5, 2002
360
SDL_SetError ("window already iconified");
361
362
363
364
365
return 0;
}
}
/*
Jan 4, 2004
Jan 4, 2004
366
int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info) {
Aug 21, 2001
Aug 21, 2001
367
info->nsWindowPtr = qz_window;
368
369
370
return 0;
}*/
Jan 4, 2004
Jan 4, 2004
371
void QZ_ChangeGrabState (_THIS, int action) {
Dec 27, 2002
Dec 27, 2002
372
373
374
375
376
377
378
/*
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 ) {
Jan 4, 2004
Jan 4, 2004
379
if ( cursor_should_be_visible )
Dec 27, 2002
Dec 27, 2002
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
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);
}
}
Jan 4, 2004
Jan 4, 2004
417
SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode) {
Dec 27, 2002
Dec 27, 2002
419
420
421
422
423
424
425
426
427
428
429
430
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 */
Dec 27, 2002
Dec 27, 2002
432
433
434
435
436
437
if ( grab_mode != SDL_GRAB_QUERY ) {
if ( doGrab )
QZ_ChangeGrabState (this, QZ_ENABLE_GRAB);
else
QZ_ChangeGrabState (this, QZ_DISABLE_GRAB);
Dec 27, 2002
Dec 27, 2002
439
440
441
current_grab_mode = doGrab ? SDL_GRAB_ON : SDL_GRAB_OFF;
}
Oct 5, 2002
Oct 5, 2002
442
return current_grab_mode;