SDL-1.2.14
[sdl_omap.git] / src / video / maccommon / SDL_macwm.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 Sam Lantinga
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 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     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 #if defined(__APPLE__) && defined(__MACH__)
25 #include <Carbon/Carbon.h>
26 #elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
27 #include <Carbon.h>
28 #else
29 #include <Windows.h>
30 #include <Strings.h>
31 #endif
32
33 #if SDL_MACCLASSIC_GAMMA_SUPPORT
34 #include <Devices.h>
35 #include <Files.h>
36 #include <MacTypes.h>
37 #include <QDOffscreen.h>
38 #include <Quickdraw.h>
39 #include <Video.h>
40 #endif
41
42 #include "SDL_stdinc.h"
43 #include "SDL_macwm_c.h"
44
45 void Mac_SetCaption(_THIS, const char *title, const char *icon)
46 {
47         /* Don't convert C to P string in place, because it may be read-only */
48         Str255          ptitle; /* MJS */
49         ptitle[0] = strlen (title);
50         SDL_memcpy(ptitle+1, title, ptitle[0]); /* MJS */
51         if (SDL_Window)
52                 SetWTitle(SDL_Window, ptitle); /* MJS */
53 }
54
55 #if SDL_MACCLASSIC_GAMMA_SUPPORT
56 /*
57  * ADC Gamma Ramp support...
58  *
59  * Mac Gamma Ramp code was originally from sample code provided by
60  *  Apple Developer Connection, and not written specifically for SDL:
61  * "Contains: Functions to enable Mac OS device gamma adjustments using 3 channel 256 element 8 bit gamma ramps
62  *  Written by: Geoff Stahl (ggs)
63  *  Copyright: Copyright (c) 1999 Apple Computer, Inc., All Rights Reserved
64  *  Disclaimer: You may incorporate this sample code into your applications without
65  *              restriction, though the sample code has been provided "AS IS" and the
66  *              responsibility for its operation is 100% yours.  However, what you are
67  *              not permitted to do is to redistribute the source as "DSC Sample Code"
68  *              after having made changes. If you're going to re-distribute the source,
69  *              we require that you make it clear in the source that the code was
70  *              descended from Apple Sample Code, but that you've made changes."
71  * (The sample code has been integrated into this file, and thus is modified from the original Apple sources.)
72  */
73
74 typedef struct recDeviceGamma                                                                                   /* storage for device handle and gamma table */
75 {
76         GDHandle hGD;                                                                                           /* handle to device */
77         GammaTblPtr pDeviceGamma;                                                                       /* pointer to device gamma table */
78 } recDeviceGamma;
79 typedef recDeviceGamma * precDeviceGamma;
80
81 typedef struct recSystemGamma                                                                                   /* storage for system devices and gamma tables */
82 {
83         short numDevices;                                                                                       /* number of devices */
84         precDeviceGamma * devGamma;                                                                     /* array of pointers to device gamma records */
85 } recSystemGamma;
86 typedef recSystemGamma * precSystemGamma;
87
88 static Ptr CopyGammaTable (GammaTblPtr pTableGammaIn)
89 {
90         GammaTblPtr             pTableGammaOut = NULL;
91         short                   tableSize, dataWidth;
92
93         if (pTableGammaIn)                                                                                              /* if there is a table to copy  */
94         {
95                 dataWidth = (pTableGammaIn->gDataWidth + 7) / 8;                        /* number of bytes per entry */
96                 tableSize = sizeof (GammaTbl) + pTableGammaIn->gFormulaSize +
97                                         (pTableGammaIn->gChanCnt * pTableGammaIn->gDataCnt * dataWidth);
98                 pTableGammaOut = (GammaTblPtr) NewPtr (tableSize);                      /* allocate new table */
99                 if (pTableGammaOut)                                                                                     
100                         BlockMove( (Ptr)pTableGammaIn, (Ptr)pTableGammaOut, tableSize); /* move everything */
101         }
102         return (Ptr)pTableGammaOut;                                                                             /* return whatever we allocated, could be NULL */
103 }
104
105 static OSErr GetGammaTable (GDHandle hGD, GammaTblPtr * ppTableGammaOut)
106 {
107         VDGammaRecord   DeviceGammaRec;
108         CntrlParam              cParam;
109         OSErr                   err;
110         
111         cParam.ioCompletion = NULL;                                                                             /* set up control params */
112         cParam.ioNamePtr = NULL;
113         cParam.ioVRefNum = 0;
114         cParam.ioCRefNum = (**hGD).gdRefNum;
115         cParam.csCode = cscGetGamma;                                                                    /* Get Gamma commnd to device */
116         *(Ptr *)cParam.csParam = (Ptr) &DeviceGammaRec;                                 /* record for gamma */
117
118         err = PBStatusSync( (ParmBlkPtr)&cParam );                                              /* get gamma */
119         
120         *ppTableGammaOut = (GammaTblPtr)(DeviceGammaRec.csGTable);              /* pull table out of record */
121         
122         return err;     
123 }
124
125 static Ptr GetDeviceGamma (GDHandle hGD)
126 {
127         GammaTblPtr             pTableGammaDevice = NULL;
128         GammaTblPtr             pTableGammaReturn = NULL;       
129         OSErr                   err;
130         
131         err = GetGammaTable (hGD, &pTableGammaDevice);                                  /* get a pointer to the devices table */
132         if ((noErr == err) && pTableGammaDevice)                                                /* if succesful */
133                 pTableGammaReturn = (GammaTblPtr) CopyGammaTable (pTableGammaDevice); /* copy to global */
134
135         return (Ptr) pTableGammaReturn;
136 }
137
138 static void DisposeGammaTable (Ptr pGamma)
139 {
140         if (pGamma)
141                 DisposePtr((Ptr) pGamma);                                                                       /* get rid of it */
142 }
143
144 static void DisposeSystemGammas (Ptr* ppSystemGammas)
145 {
146         precSystemGamma pSysGammaIn;
147         if (ppSystemGammas)
148         {
149                 pSysGammaIn = (precSystemGamma) *ppSystemGammas;
150                 if (pSysGammaIn)
151                 {
152                         short i;
153                         for (i = 0; i < pSysGammaIn->numDevices; i++)           /* for all devices */
154                                 if (pSysGammaIn->devGamma [i])                                          /* if pointer is valid */
155                                 {
156                                         DisposeGammaTable ((Ptr) pSysGammaIn->devGamma [i]->pDeviceGamma); /* dump gamma table */
157                                         DisposePtr ((Ptr) pSysGammaIn->devGamma [i]);                                      /* dump device info */
158                                 }
159                         DisposePtr ((Ptr) pSysGammaIn->devGamma);                               /* dump device pointer array             */
160                         DisposePtr ((Ptr) pSysGammaIn);                                                 /* dump system structure */
161                         *ppSystemGammas = NULL;
162                 }       
163         }
164 }
165
166 static Boolean GetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp)
167 {
168         GammaTblPtr             pTableGammaTemp = NULL;
169         long                    indexChan, indexEntry;
170         OSErr                   err;
171         
172         if (pRamp)                                                                                                                      /* ensure pRamp is allocated */
173         {
174                 err = GetGammaTable (hGD, &pTableGammaTemp);                                    /* get a pointer to the current gamma */
175                 if ((noErr == err) && pTableGammaTemp)                                                  /* if successful */
176                 {                                                                                                                       
177                         /* fill ramp */
178                         unsigned char * pEntry = (unsigned char *) &pTableGammaTemp->gFormulaData + pTableGammaTemp->gFormulaSize; /* base of table */
179                         short bytesPerEntry = (pTableGammaTemp->gDataWidth + 7) / 8; /* size, in bytes, of the device table entries */
180                         short shiftRightValue = pTableGammaTemp->gDataWidth - 8;         /* number of right shifts device -> ramp */
181                         short channels = pTableGammaTemp->gChanCnt;     
182                         short entries = pTableGammaTemp->gDataCnt;                                                                      
183                         if (3 == channels)                                                                                      /* RGB format */
184                         {                                                                                                                       /* note, this will create runs of entries if dest. is bigger (not linear interpolate) */
185                                 for (indexChan = 0; indexChan < channels; indexChan++)
186                                         for (indexEntry = 0; indexEntry < 256; indexEntry++)
187                                                 *((unsigned char *) pRamp + (indexChan * 256) + indexEntry) = 
188                                                   *(pEntry + indexChan * entries * bytesPerEntry + indexEntry * entries * bytesPerEntry / 256) >> shiftRightValue;
189                         }
190                         else                                                                                                            /* single channel format */
191                         {
192                                 for (indexChan = 0; indexChan < 768; indexChan += 256)  /* repeat for all 3 channels (step by ramp size) */
193                                         for (indexEntry = 0; indexEntry < 256; indexEntry++) /* for all entries set vramp value */
194                                                 *((unsigned char *) pRamp + indexChan + indexEntry) = 
195                                                   *(pEntry + indexEntry * entries * bytesPerEntry / 256) >> shiftRightValue;
196                         }
197                         return true;
198                 }
199         }
200         return false;
201 }
202
203 static Ptr GetSystemGammas (void)
204 {
205         precSystemGamma pSysGammaOut;                                                                   /* return pointer to system device gamma info */
206         short devCount = 0;                                                                                             /* number of devices attached */
207         Boolean fail = false;
208         GDHandle hGDevice;
209         
210         pSysGammaOut = (precSystemGamma) NewPtr (sizeof (recSystemGamma)); /* allocate for structure */
211         
212         hGDevice = GetDeviceList ();                                                    /* top of device list */
213         do                                                                                                                              /* iterate */
214         {
215                 devCount++;                                                                                                     /* count devices                                         */
216                 hGDevice = GetNextDevice (hGDevice);                                            /* next device */
217         } while (hGDevice);
218         
219         pSysGammaOut->devGamma = (precDeviceGamma *) NewPtr (sizeof (precDeviceGamma) * devCount); /* allocate for array of pointers to device records */
220         if (pSysGammaOut)
221         {
222                 pSysGammaOut->numDevices = devCount;                                            /* stuff count */
223                 
224                 devCount = 0;                                                                                           /* reset iteration */
225                 hGDevice = GetDeviceList ();
226                 do
227                 {
228                         pSysGammaOut->devGamma [devCount] = (precDeviceGamma) NewPtr (sizeof (recDeviceGamma));   /* new device record */
229                         if (pSysGammaOut->devGamma [devCount])                                  /* if we actually allocated memory */
230                         {
231                                 pSysGammaOut->devGamma [devCount]->hGD = hGDevice;                                                                                /* stuff handle */
232                                 pSysGammaOut->devGamma [devCount]->pDeviceGamma = (GammaTblPtr)GetDeviceGamma (hGDevice); /* copy gamma table */
233                         }
234                         else                                                                                                    /* otherwise dump record on exit */
235                          fail = true;
236                         devCount++;                                                                                             /* next device */
237                         hGDevice = GetNextDevice (hGDevice);                                            
238                 } while (hGDevice);
239         }
240         if (!fail)                                                                                                              /* if we did not fail */
241                 return (Ptr) pSysGammaOut;                                                                      /* return pointer to structure */
242         else
243         {
244                 DisposeSystemGammas ((Ptr *) &pSysGammaOut);                                    /* otherwise dump the current structures (dispose does error checking) */
245                 return NULL;                                                                                            /* could not complete */
246         }
247 }
248
249 static void RestoreDeviceGamma (GDHandle hGD, Ptr pGammaTable)
250 {
251         VDSetEntryRecord setEntriesRec;
252         VDGammaRecord   gameRecRestore;
253         CTabHandle      hCTabDeviceColors;
254         Ptr                             csPtr;
255         OSErr                   err = noErr;
256         
257         if (pGammaTable)                                                                                                /* if we have a table to restore                                                                 */
258         {
259                 gameRecRestore.csGTable = pGammaTable;                                          /* setup restore record */
260                 csPtr = (Ptr) &gameRecRestore;
261                 err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr);     /* restore gamma */
262
263                 if ((noErr == err) && (8 == (**(**hGD).gdPMap).pixelSize))      /* if successful and on an 8 bit device */
264                 {
265                         hCTabDeviceColors = (**(**hGD).gdPMap).pmTable;                 /* do SetEntries to force CLUT update */
266                         setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable;
267                         setEntriesRec.csStart = 0;
268                         setEntriesRec.csCount = (**hCTabDeviceColors).ctSize;
269                         csPtr = (Ptr) &setEntriesRec;
270                         
271                         err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr); /* SetEntries in CLUT */
272                 }
273         }
274 }
275
276 static void RestoreSystemGammas (Ptr pSystemGammas)
277 {
278         short i;
279         precSystemGamma pSysGammaIn = (precSystemGamma) pSystemGammas;
280         if (pSysGammaIn)
281                 for (i = 0; i < pSysGammaIn->numDevices; i++)                   /* for all devices */
282                         RestoreDeviceGamma (pSysGammaIn->devGamma [i]->hGD, (Ptr) pSysGammaIn->devGamma [i]->pDeviceGamma);     /* restore gamma */
283 }
284
285 static Ptr CreateEmptyGammaTable (short channels, short entries, short bits)
286 {
287         GammaTblPtr             pTableGammaOut = NULL;
288         short                   tableSize, dataWidth;
289
290         dataWidth = (bits + 7) / 8;                                                                             /* number of bytes per entry */
291         tableSize = sizeof (GammaTbl) + (channels * entries * dataWidth);
292         pTableGammaOut = (GammaTblPtr) NewPtrClear (tableSize);                 /* allocate new tabel */
293
294         if (pTableGammaOut)                                                                                             /* if we successfully allocated */
295         {
296                 pTableGammaOut->gVersion = 0;                                                           /* set parameters based on input */
297                 pTableGammaOut->gType = 0;
298                 pTableGammaOut->gFormulaSize = 0;
299                 pTableGammaOut->gChanCnt = channels;
300                 pTableGammaOut->gDataCnt = entries;
301                 pTableGammaOut->gDataWidth = bits;
302         }
303         return (Ptr)pTableGammaOut;                                                                             /* return whatever we allocated */
304 }
305
306 static Boolean SetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp)
307 {
308         VDSetEntryRecord setEntriesRec;
309         VDGammaRecord   gameRecRestore;
310         GammaTblPtr             pTableGammaNew;
311         GammaTblPtr             pTableGammaCurrent = NULL;
312         CTabHandle      hCTabDeviceColors;
313         Ptr                             csPtr;
314         OSErr                   err;
315         short                   dataBits, entries, channels = 3;                                                /* force three channels in the gamma table */
316         
317         if (pRamp)                                                                                                                              /* ensure pRamp is allocated */
318         {
319                 err= GetGammaTable (hGD, &pTableGammaCurrent);                                          /* get pointer to current table */
320                 if ((noErr == err) && pTableGammaCurrent)
321                 {
322                         dataBits = pTableGammaCurrent->gDataWidth;                                              /* table must have same data width */
323                         entries = pTableGammaCurrent->gDataCnt;                                                 /* table must be same size */
324                         pTableGammaNew = (GammaTblPtr) CreateEmptyGammaTable (channels, entries, dataBits); /* our new table */
325                         if (pTableGammaNew)                                                                                             /* if successful fill table */
326                         {       
327                                 unsigned char * pGammaBase = (unsigned char *) &pTableGammaNew->gFormulaData + pTableGammaNew->gFormulaSize; /* base of table */
328                                 if ((256 == entries) && (8 == dataBits))                                                /* simple case: direct mapping */
329                                         BlockMove ((Ptr)pRamp, (Ptr)pGammaBase, channels * entries); /* move everything */
330                                 else                                                                                                            /* tough case handle entry, channel and data size disparities */
331                                 {
332                                         short indexChan, indexEntry;
333                                         short bytesPerEntry = (dataBits + 7) / 8;                               /* size, in bytes, of the device table entries */
334                                         short shiftRightValue = 8 - dataBits;                                   /* number of right shifts ramp -> device */
335                                         shiftRightValue += ((bytesPerEntry - 1) * 8);                   /* multibyte entries and the need to map a byte at a time most sig. to least sig. */
336                                         for (indexChan = 0; indexChan < channels; indexChan++) /* for all the channels */
337                                                 for (indexEntry = 0; indexEntry < entries; indexEntry++) /* for all the entries */
338                                                 {
339                                                         short currentShift = shiftRightValue;                   /* reset current bit shift */
340                                                         long temp = *((unsigned char *)pRamp + (indexChan << 8) + (indexEntry << 8) / entries); /* get data from ramp */
341                                                         short indexByte;
342                                                         for (indexByte = 0; indexByte < bytesPerEntry; indexByte++) /* for all bytes */
343                                                         {
344                                                                 if (currentShift < 0)                                           /* shift data correctly for current byte */
345                                                                         *(pGammaBase++) = temp << -currentShift;
346                                                                 else
347                                                                         *(pGammaBase++) = temp >> currentShift;
348                                                                 currentShift -= 8;                                                      /* increment shift to align to next less sig. byte */
349                                                         }
350                                                 }
351                                 }
352                                 
353                                 /* set gamma */
354                                 gameRecRestore.csGTable = (Ptr) pTableGammaNew;                         /* setup restore record */
355                                 csPtr = (Ptr) &gameRecRestore;
356                                 err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr);     /* restore gamma (note, display drivers may delay returning from this until VBL) */
357                                 
358                                 if ((8 == (**(**hGD).gdPMap).pixelSize) && (noErr == err))      /* if successful and on an 8 bit device */
359                                 {
360                                         hCTabDeviceColors = (**(**hGD).gdPMap).pmTable;                 /* do SetEntries to force CLUT update */
361                                         setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable;
362                                         setEntriesRec.csStart = 0;
363                                         setEntriesRec.csCount = (**hCTabDeviceColors).ctSize;
364                                         csPtr = (Ptr) &setEntriesRec;
365                                         err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr);   /* SetEntries in CLUT */
366                                 }
367                                 DisposeGammaTable ((Ptr) pTableGammaNew);                                       /* dump table */
368                                 if (noErr == err)
369                                         return true;
370                         }
371                 }
372         }
373         else                                                                                                                                    /* set NULL gamma -> results in linear map */
374         {
375                 gameRecRestore.csGTable = (Ptr) NULL;                                                           /* setup restore record */
376                 csPtr = (Ptr) &gameRecRestore;
377                 err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr);                     /* restore gamma */
378                 
379                 if ((8 == (**(**hGD).gdPMap).pixelSize) && (noErr == err))                      /* if successful and on an 8 bit device */
380                 {
381                         hCTabDeviceColors = (**(**hGD).gdPMap).pmTable;                                 /* do SetEntries to force CLUT update */
382                         setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable;
383                         setEntriesRec.csStart = 0;
384                         setEntriesRec.csCount = (**hCTabDeviceColors).ctSize;
385                         csPtr = (Ptr) &setEntriesRec;
386                         err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr);   /* SetEntries in CLUT */
387                 }
388                 if (noErr == err)
389                         return true;
390         }
391         return false;                                                                                                                   /* memory allocation or device control failed if we get here */
392 }
393
394 /* end of ADC Gamma Ramp support code... */
395
396 static Ptr systemGammaPtr;
397
398 void Mac_QuitGamma(_THIS)
399 {
400         if (systemGammaPtr)
401         {
402                 RestoreSystemGammas(systemGammaPtr);
403                 DisposeSystemGammas(&systemGammaPtr);
404         }
405 }
406
407 static unsigned char shiftedRamp[3 * 256];
408
409 int Mac_SetGammaRamp(_THIS, Uint16 *ramp)
410 {
411         int i;
412         if (!systemGammaPtr)
413                 systemGammaPtr = GetSystemGammas();
414         for (i = 0; i < 3 * 256; i++)
415         {
416                 shiftedRamp[i] = ramp[i] >> 8;
417         }
418
419         if (SetDeviceGammaRampGD(GetMainDevice(), (Ptr) shiftedRamp))
420                 return 0;
421         else
422                 return -1;
423 }
424
425 int Mac_GetGammaRamp(_THIS, Uint16 *ramp)
426 {
427         if (GetDeviceGammaRampGD(GetMainDevice(), (Ptr) shiftedRamp))
428         {
429                 int i;
430                 for (i = 0; i < 3 * 256; i++)
431                 {
432                         ramp[i] = shiftedRamp[i] << 8;
433                 }
434                 return 0;
435         }
436         else
437                 return -1;
438 }
439
440 #endif  /* SDL_MACCLASSIC_GAMMA_SUPPORT */
441
442