/
SDL_QuartzWM.m
407 lines (314 loc) · 11.1 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
*/
23
24
#include "SDL_QuartzVideo.h"
25
26
27
28
29
struct WMcursor {
Cursor curs;
};
30
void QZ_FreeWMCursor (_THIS, WMcursor *cursor) {
31
32
33
34
35
36
if ( cursor != NULL )
free (cursor);
}
/* Use the Carbon cursor routines for now */
37
WMcursor* QZ_CreateWMCursor (_THIS, Uint8 *data, Uint8 *mask,
38
39
40
41
42
43
44
45
46
47
48
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));
49
50
51
52
53
54
55
if (w > 16)
w = 16;
if (h > 16)
h = 16;
56
57
58
59
60
61
62
63
64
65
66
67
68
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;
69
return(cursor);
70
71
}
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
void QZ_ShowMouse (_THIS) {
if (!cursor_visible) {
[ NSCursor unhide ];
cursor_visible = YES;
}
}
void QZ_HideMouse (_THIS) {
if (cursor_visible) {
[ NSCursor hide ];
cursor_visible = NO;
}
}
int QZ_ShowWMCursor (_THIS, WMcursor *cursor) {
87
88
if ( cursor == NULL) {
89
90
91
if ( cursor_should_be_visible ) {
QZ_HideMouse (this);
cursor_should_be_visible = NO;
92
QZ_ChangeGrabState (this, QZ_HIDECURSOR);
93
94
95
96
}
}
else {
SetCursor(&cursor->curs);
97
98
99
if ( ! cursor_should_be_visible ) {
QZ_ShowMouse (this);
cursor_should_be_visible = YES;
100
QZ_ChangeGrabState (this, QZ_SHOWCURSOR);
101
102
103
104
105
106
}
}
return 1;
}
107
108
109
110
111
112
113
/*
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.
*/
114
115
/* Convert Cocoa screen coordinate to Cocoa window coordinate */
116
void QZ_PrivateGlobalToLocal (_THIS, NSPoint *p) {
117
118
119
120
121
122
*p = [ qz_window convertScreenToBase:*p ];
}
/* Convert Cocoa window coordinate to Cocoa screen coordinate */
123
void QZ_PrivateLocalToGlobal (_THIS, NSPoint *p) {
124
125
126
127
128
*p = [ qz_window convertBaseToScreen:*p ];
}
/* Convert SDL coordinate to Cocoa coordinate */
129
void QZ_PrivateSDLToCocoa (_THIS, NSPoint *p) {
130
131
132
if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */
133
p->y = CGDisplayPixelsHigh (display_id) - p->y - 1;
134
}
135
else {
136
137
NSPoint newPoint;
138
139
140
141
newPoint = [ window_view convertPoint:*p toView:[ qz_window contentView ] ];
*p = newPoint;
142
143
144
}
}
145
/* Convert Cocoa coordinate to SDL coordinate */
146
void QZ_PrivateCocoaToSDL (_THIS, NSPoint *p) {
147
148
149
150
151
152
153
154
155
156
157
158
159
if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */
p->y = CGDisplayPixelsHigh (display_id) - p->y - 1;
}
else {
NSPoint newPoint;
newPoint = [ window_view convertPoint:*p fromView:[ qz_window contentView ] ];
*p = newPoint;
}
160
161
162
}
/* Convert SDL coordinate to window server (CoreGraphics) coordinate */
163
CGPoint QZ_PrivateSDLToCG (_THIS, NSPoint *p) {
164
165
166
167
CGPoint cgp;
if ( ! CGDisplayIsCaptured (display_id) ) { /* not captured => not fullscreen => local coord */
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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;
}
184
#if 0 /* Dead code */
185
/* Convert window server (CoreGraphics) coordinate to SDL coordinate */
186
void QZ_PrivateCGToSDL (_THIS, NSPoint *p) {
187
188
189
190
191
192
193
194
195
196
197
198
199
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);
}
}
200
#endif /* Dead code */
201
202
void QZ_PrivateWarpCursor (_THIS, int x, int y) {
203
204
205
206
207
NSPoint p;
CGPoint cgp;
p = NSMakePoint (x, y);
208
209
210
211
212
cgp = QZ_PrivateSDLToCG (this, &p);
/* this is the magic call that fixes cursor "freezing" after warp */
CGSetLocalEventsSuppressionInterval (0.0);
CGWarpMouseCursorPosition (cgp);
213
214
}
215
void QZ_WarpWMCursor (_THIS, Uint16 x, Uint16 y) {
216
217
/* Only allow warping when in foreground */
218
if ( ! [ NSApp isActive ] )
219
220
221
return;
/* Do the actual warp */
222
QZ_PrivateWarpCursor (this, x, y);
223
224
225
/* Generate the mouse moved event */
SDL_PrivateMouseMotion (0, 0, x, y);
226
227
}
228
229
void QZ_MoveWMCursor (_THIS, int x, int y) { }
void QZ_CheckMouseMode (_THIS) { }
230
231
void QZ_SetCaption (_THIS, const char *title, const char *icon) {
232
233
if ( qz_window != nil ) {
234
235
236
NSString *string;
if ( title != NULL ) {
string = [ [ NSString alloc ] initWithCString:title ];
237
[ qz_window setTitle:string ];
238
239
240
241
[ string release ];
}
if ( icon != NULL ) {
string = [ [ NSString alloc ] initWithCString:icon ];
242
[ qz_window setMiniwindowTitle:string ];
243
244
245
[ string release ];
}
}
246
247
}
248
void QZ_SetIcon (_THIS, SDL_Surface *icon, Uint8 *mask)
249
{
250
251
252
NSBitmapImageRep *imgrep;
NSImage *img;
SDL_Surface *mergedSurface;
253
int i,j;
254
255
256
257
258
259
260
261
262
263
264
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) {
265
266
267
NSLog(@"Error creating surface for merge");
goto freePool;
}
268
269
270
271
272
273
274
275
if (mergedSurface->pitch !=
mergedSurface->format->BytesPerPixel * mergedSurface->w) {
SDL_SetError ("merged surface has wrong format");
SDL_FreeSurface (mergedSurface);
goto freePool;
}
276
277
278
279
280
281
if (SDL_BlitSurface(icon,&rrect,mergedSurface,&rrect)) {
NSLog(@"Error blitting to mergedSurface");
goto freePool;
}
if (mask) {
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
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;
}
}
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
}
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);
313
freePool:
314
[pool release];
315
316
}
317
int QZ_IconifyWindow (_THIS) {
318
319
320
if ( ! [ qz_window isMiniaturized ] ) {
[ qz_window miniaturize:nil ];
321
322
323
return 1;
}
else {
324
SDL_SetError ("window already iconified");
325
326
327
328
329
return 0;
}
}
/*
330
int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info) {
331
info->nsWindowPtr = qz_window;
332
333
334
return 0;
}*/
335
void QZ_ChangeGrabState (_THIS, int action) {
336
337
338
339
340
341
342
/*
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 ) {
343
if ( cursor_should_be_visible )
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
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);
}
}
381
SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode) {
382
383
384
385
386
387
388
389
390
391
392
393
394
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 */
395
}
396
397
398
399
400
401
if ( grab_mode != SDL_GRAB_QUERY ) {
if ( doGrab )
QZ_ChangeGrabState (this, QZ_ENABLE_GRAB);
else
QZ_ChangeGrabState (this, QZ_DISABLE_GRAB);
402
403
404
405
current_grab_mode = doGrab ? SDL_GRAB_ON : SDL_GRAB_OFF;
}
406
return current_grab_mode;
407
}