ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/video.cpp
(Generate patch)

Comparing SheepShaver/src/video.cpp (file contents):
Revision 1.1.1.1 by cebix, 2002-02-04T16:58:13Z vs.
Revision 1.18 by asvitkine, 2012-03-28T03:30:49Z

# Line 1 | Line 1
1   /*
2   *  video.cpp - Video/graphics emulation
3   *
4 < *  SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer
4 > *  SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 21 | Line 21
21   /*
22   * TODO
23   * - check for supported modes ???
24 * - window mode "hardware" cursor hotspot
24   */
25  
26   #include <stdio.h>
# Line 35 | Line 34
34   #include "macos_util.h"
35   #include "user_strings.h"
36   #include "version.h"
37 + #include "thunks.h"
38  
39   #define DEBUG 0
40   #include "debug.h"
# Line 73 | Line 73 | static long save_conf_mode = APPLE_8_BIT
73   // Function pointers of imported functions
74   typedef int16 (*iocic_ptr)(void *, int16);
75   static uint32 iocic_tvect = 0;
76 < static inline int16 IOCommandIsComplete(void *arg1, int16 arg2)
76 > static inline int16 IOCommandIsComplete(uintptr arg1, int16 arg2)
77   {
78 <        return (int16)CallMacOS2(iocic_ptr, iocic_tvect, arg1, arg2);
78 >        return (int16)CallMacOS2(iocic_ptr, iocic_tvect, (void *)arg1, arg2);
79   }
80   typedef int16 (*vslnewis_ptr)(void *, uint32, uint32 *);
81   static uint32 vslnewis_tvect = 0;
82 < static inline int16 VSLNewInterruptService(void *arg1, uint32 arg2, uint32 *arg3)
82 > static inline int16 VSLNewInterruptService(uintptr arg1, uint32 arg2, uintptr arg3)
83   {
84 <        return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, arg1, arg2, arg3);
84 >        return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, (void *)arg1, arg2, (uint32 *)arg3);
85   }
86   typedef int16 (*vsldisposeis_ptr)(uint32);
87   static uint32 vsldisposeis_tvect = 0;
# Line 97 | Line 97 | int16 VSLDoInterruptService(uint32 arg1)
97   }
98   typedef void (*nqdmisc_ptr)(uint32, void *);
99   static uint32 nqdmisc_tvect = 0;
100 < void NQDMisc(uint32 arg1, void *arg2)
100 > void NQDMisc(uint32 arg1, uintptr arg2)
101   {
102 <        CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, arg2);
102 >        CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, (void *)arg2);
103   }
104  
105  
# Line 142 | Line 142 | bool VideoSnapshot(int xsize, int ysize,
142  
143  
144   /*
145 + *  Determine whether we should use the hardware or software cursor, and return true for the former, false for the latter.
146 + *  Currently we use the hardware cursor if we can, but perhaps this can be made a preference someday.
147 + */
148 +
149 + static bool UseHardwareCursor(void)
150 + {
151 +        return video_can_change_cursor();
152 + }
153 +
154 +
155 + /*
156   *  Video driver open routine
157   */
158  
# Line 155 | Line 166 | static int16 VideoOpen(uint32 pb, VidLoc
166          csSave->saveMode = VModes[cur_mode].viAppleMode;
167          csSave->savePage = 0;
168          csSave->saveVidParms = 0;                       // Add the right table
158        csSave->gammaTable = NULL;                      // No gamma table yet
159        csSave->maxGammaTableSize = 0;
169          csSave->luminanceMapping = false;
170 +        csSave->cursorHardware = UseHardwareCursor();
171          csSave->cursorX = 0;
172          csSave->cursorY = 0;
173          csSave->cursorVisible = 0;
174          csSave->cursorSet = 0;
175 +        csSave->cursorHotFlag = false;
176 +        csSave->cursorHotX = 0;
177 +        csSave->cursorHotY = 0;
178  
179 <        // Activate default gamma table
179 >        // Find and set default gamma table
180 >        csSave->gammaTable = 0;
181 >        csSave->maxGammaTableSize = 0;
182          set_gamma(csSave, 0);
183  
184          // Install and activate interrupt service
185 <        csSave->vslServiceID = 0;
186 <        VSLNewInterruptService(csSave->regEntryID, FOURCC('v','b','l',' '), &(csSave->vslServiceID));
185 >        SheepVar32 theServiceID = 0;
186 >        VSLNewInterruptService(csSave->regEntryID, FOURCC('v','b','l',' '), theServiceID.addr());
187 >        csSave->vslServiceID = theServiceID.value();
188          D(bug(" Interrupt ServiceID %08lx\n", csSave->vslServiceID));
189          csSave->interruptsEnabled = true;
190  
# Line 180 | Line 196 | static int16 VideoOpen(uint32 pb, VidLoc
196   *  Video driver control routine
197   */
198  
199 < static int16 set_gamma(VidLocals *csSave, uint32 gamma)
199 > static bool allocate_gamma_table(VidLocals *csSave, uint32 size)
200   {
201 <        GammaTbl *clientGamma = (GammaTbl *)gamma;
202 <        GammaTbl *gammaTable = csSave->gammaTable;
201 >        if (size > csSave->maxGammaTableSize) {
202 >                if (csSave->gammaTable) {
203 >                        Mac_sysfree(csSave->gammaTable);
204 >                        csSave->gammaTable = 0;
205 >                        csSave->maxGammaTableSize = 0;
206 >                }
207 >                if ((csSave->gammaTable = Mac_sysalloc(size)) == 0)
208 >                        return false;
209 >                csSave->maxGammaTableSize = size;
210 >        }
211 >        return true;
212 > }
213  
214 <        if (clientGamma == NULL) {
214 > static int16 set_gamma(VidLocals *csSave, uint32 gamma)
215 > {
216 >        if (gamma == 0) { // Build linear ramp, 256 entries
217  
218 <                // No gamma table supplied, build linear ramp
219 <                uint32 linearRampSize = sizeof(GammaTbl) + 256 - 2;    
220 <                uint8 *correctionData;
221 <
222 <                // Allocate new gamma table if existing gamma table is smaller than required.
223 <                if (linearRampSize > csSave->maxGammaTableSize) {
224 <                        delete[] csSave->gammaTable;
225 <                        csSave->gammaTable = (GammaTbl *)new uint8[linearRampSize];
226 <                        csSave->maxGammaTableSize = linearRampSize;
227 <                        gammaTable = csSave->gammaTable;
228 <                }
201 <                
202 <                gammaTable->gVersion = 0;                       // A version 0 style of the GammaTbl structure
203 <                gammaTable->gType = 0;                          // Frame buffer hardware invariant
204 <                gammaTable->gFormulaSize = 0;           // No formula data, just correction data
205 <                gammaTable->gChanCnt = 1;                       // Apply same correction to Red, Green, & Blue
206 <                gammaTable->gDataCnt = 256;                     // gDataCnt == 2^^gDataWidth
207 <                gammaTable->gDataWidth = 8;                     // 8 bits of significant data per entry
208 <
209 <                // Find the starting address of the correction data.  This can be computed by starting at
210 <                // the address of gFormula[0] and adding the gFormulaSize.
211 <                correctionData = (uint8 *)((uint32)&gammaTable->gFormulaData[0] + gammaTable->gFormulaSize);
218 >                // Allocate new table, if necessary
219 >                if (!allocate_gamma_table(csSave, SIZEOF_GammaTbl + 256))
220 >                        return memFullErr;
221 >
222 >                // Initialize header
223 >                WriteMacInt16(csSave->gammaTable + gVersion, 0);                // A  version 0 style of the GammaTbl structure
224 >                WriteMacInt16(csSave->gammaTable + gType, 0);                   // Frame buffer hardware invariant
225 >                WriteMacInt16(csSave->gammaTable + gFormulaSize, 0);    // No formula data, just correction data
226 >                WriteMacInt16(csSave->gammaTable + gChanCnt, 1);                // Apply same correction to Red, Green, & Blue
227 >                WriteMacInt16(csSave->gammaTable + gDataCnt, 256);              // gDataCnt == 2^^gDataWidth
228 >                WriteMacInt16(csSave->gammaTable + gDataWidth, 8);              // 8 bits of significant data per entry
229  
230                  // Build the linear ramp
231 <                for (int i=0; i<gammaTable->gDataCnt; i++)
232 <                        *correctionData++ = i;          
231 >                uint32 p = csSave->gammaTable + gFormulaData;
232 >                for (int i=0; i<256; i++)
233 >                        WriteMacInt8(p + i, i);
234  
235 <        } else {
235 >        } else { // User-supplied gamma table
236  
237 <                // User supplied a gamma table, so make sure it is a valid one
238 <                if (clientGamma->gVersion != 0)
237 >                // Validate header
238 >                if (ReadMacInt16(gamma + gVersion) != 0)
239                          return paramErr;
240 <                if (clientGamma->gType != 0)
240 >                if (ReadMacInt16(gamma + gType) != 0)
241                          return paramErr;
242 <                if ((clientGamma->gChanCnt != 1) && (clientGamma->gChanCnt != 3))
242 >                int chan_cnt = ReadMacInt16(gamma + gChanCnt);
243 >                if (chan_cnt != 1 && chan_cnt != 3)
244                          return paramErr;
245 <                if (clientGamma->gDataWidth > 8)
245 >                int data_width = ReadMacInt16(gamma + gDataWidth);
246 >                if (data_width > 8)
247                          return paramErr;
248 <                if (clientGamma->gDataCnt != (1 << clientGamma->gDataWidth))
248 >                int data_cnt = ReadMacInt16(gamma + gDataCnt);
249 >                if (data_cnt != (1 << data_width))
250                          return paramErr;
251  
252 <                uint32 tableSize = sizeof(GammaTbl)                                             // fixed size header
253 <                                + clientGamma->gFormulaSize                                             // add formula size
254 <                                + clientGamma->gChanCnt * clientGamma->gDataCnt // assume 1 byte/entry
255 <                                - 2;                                                                                    // correct gFormulaData[0] counted twice
256 <
257 <                // Allocate new gamma table if existing gamma table is smaller than required.
258 <                if (tableSize > csSave->maxGammaTableSize) {
238 <                        delete[] csSave->gammaTable;
239 <                        csSave->gammaTable = (GammaTbl *)new uint8[tableSize];
240 <                        csSave->maxGammaTableSize = tableSize;
241 <                        gammaTable = csSave->gammaTable;
242 <                }
243 <
244 <                // Copy gamma table header              
245 <                *gammaTable = *clientGamma;
246 <                
247 <                // Copy the formula data (if any)
248 <                uint8 *newData = (uint8 *)&gammaTable->gFormulaData[0];         // Point to newGamma's formula data
249 <                uint8 *clientData = (uint8 *)&clientGamma->gFormulaData[0];     // Point to clientGamma's formula data
250 <                for (int i=0; i<gammaTable->gFormulaSize; i++)
251 <                        *newData++ = *clientData++;
252 <
253 <                // Copy the correction data. Convientiently, after copying the formula data, the 'newData'
254 <                // pointer and the 'clientData' pointer are pointing to the their respective starting points
255 <                // of their correction data.
256 <                for (int i=0; i<gammaTable->gChanCnt; i++)
257 <                        for (int j=0; j<gammaTable->gDataCnt; j++)              
258 <                                *newData++ = *clientData++;
252 >                // Allocate new table, if necessary
253 >                int size = SIZEOF_GammaTbl + ReadMacInt16(gamma + gFormulaSize) + chan_cnt * data_cnt;
254 >                if (!allocate_gamma_table(csSave, size))
255 >                        return memFullErr;
256 >
257 >                // Copy table
258 >                Mac2Mac_memcpy(csSave->gammaTable, gamma, size);
259          }
260          return noErr;
261   }
# Line 285 | Line 285 | static int16 VideoControl(uint32 pb, Vid
285                  case cscSetEntries: {                                                   // SetEntries
286                          D(bug("SetEntries\n"));                                
287                          if (VModes[cur_mode].viAppleMode > APPLE_8_BIT) return controlErr;
288 <                        ColorSpec *s_pal = (ColorSpec *)Mac2HostAddr(ReadMacInt32(param + csTable));
289 <                        int16 start = ReadMacInt16(param + csStart);
290 <                        int16 count = ReadMacInt16(param + csCount);
291 <                        if (s_pal == NULL || count > 256) return controlErr;
288 >                        uint32 s_pal = ReadMacInt32(param + csTable);
289 >                        uint16 start = ReadMacInt16(param + csStart);
290 >                        uint16 count = ReadMacInt16(param + csCount);
291 >                        if (s_pal == 0 || count > 256) return controlErr;
292  
293                          // Preparations for gamma correction
294                          bool do_gamma = false;
# Line 296 | Line 296 | static int16 VideoControl(uint32 pb, Vid
296                          uint8 *green_gamma = NULL;
297                          uint8 *blue_gamma = NULL;
298                          int gamma_data_width = 0;
299 <                        if (display_type == DIS_SCREEN && csSave->gammaTable != NULL) { // Windows are gamma-corrected by BeOS
300 <                                do_gamma = true;
301 <                                GammaTbl *gamma = csSave->gammaTable;
302 <                                gamma_data_width = gamma->gDataWidth;
303 <                                red_gamma = (uint8 *)&gamma->gFormulaData + gamma->gFormulaSize;
304 <                                if (gamma->gChanCnt == 1) {
305 <                                        green_gamma = blue_gamma = red_gamma;
306 <                                } else {
307 <                                        green_gamma = red_gamma + gamma->gDataCnt;
308 <                                        blue_gamma = red_gamma + 2 * gamma->gDataCnt;
299 >                        if (csSave->gammaTable) {
300 > #ifdef __BEOS__
301 >                                // Windows are gamma-corrected by BeOS
302 >                                const bool can_do_gamma = (display_type == DIS_SCREEN);
303 > #else
304 >                                const bool can_do_gamma = true;
305 > #endif
306 >                                if (can_do_gamma) {
307 >                                        uint32 gamma_table = csSave->gammaTable;
308 >                                        red_gamma = Mac2HostAddr(gamma_table + gFormulaData + ReadMacInt16(gamma_table + gFormulaSize));
309 >                                        int chan_cnt = ReadMacInt16(gamma_table + gChanCnt);
310 >                                        if (chan_cnt == 1)
311 >                                                green_gamma = blue_gamma = red_gamma;
312 >                                        else {
313 >                                                int ofs = ReadMacInt16(gamma_table + gDataCnt);
314 >                                                green_gamma = red_gamma + ofs;
315 >                                                blue_gamma = green_gamma + ofs;
316 >                                        }
317 >                                        gamma_data_width = ReadMacInt16(gamma_table + gDataWidth);
318 >                                        do_gamma = true;
319                                  }
320                          }
321  
322                          // Set palette
323                          rgb_color *d_pal;
324 <                        if (start == -1) {                      // Indexed
324 >                        if (start == 0xffff) {                  // Indexed
325                                  for (int i=0; i<=count; i++) {
326 <                                        d_pal = &(mac_pal[(*s_pal).value]);
327 <                                        uint8 red = (*s_pal).red >> 8;
328 <                                        uint8 green = (*s_pal).green >> 8;
329 <                                        uint8 blue = (*s_pal).blue >> 8;
326 >                                        d_pal = mac_pal + (ReadMacInt16(s_pal + csValue) & 0xff);
327 >                                        uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8;
328 >                                        uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8;
329 >                                        uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8;
330                                          if (csSave->luminanceMapping)
331                                                  red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
332                                          if (do_gamma) {
# Line 327 | Line 337 | static int16 VideoControl(uint32 pb, Vid
337                                          (*d_pal).red = red;
338                                          (*d_pal).green = green;
339                                          (*d_pal).blue = blue;
340 <                                        s_pal++;
340 >                                        s_pal += 8;
341                                  }
342 <                        } else {                                                                // Sequential
343 <                                d_pal = &(mac_pal[start]);
342 >                        } else {                                                // Sequential
343 >                                d_pal = mac_pal + start;
344                                  for (int i=0; i<=count; i++) {
345 <                                        uint8 red = (*s_pal).red >> 8;
346 <                                        uint8 green = (*s_pal).green >> 8;
347 <                                        uint8 blue = (*s_pal).blue >> 8;
345 >                                        uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8;
346 >                                        uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8;
347 >                                        uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8;
348                                          if (csSave->luminanceMapping)
349                                                  red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
350                                          if (do_gamma) {
# Line 345 | Line 355 | static int16 VideoControl(uint32 pb, Vid
355                                          (*d_pal).red = red;
356                                          (*d_pal).green = green;
357                                          (*d_pal).blue = blue;
358 <                                        d_pal++; s_pal++;
358 >                                        d_pal++;
359 >                                        s_pal += 8;
360                                  }
361                          }
362                          video_set_palette();
363                          return noErr;
364                  }
365  
366 <                case cscSetGamma:                                                       // SetGamma
367 <                        D(bug("SetGamma\n"));
368 <                        return set_gamma(csSave, ReadMacInt32(param));
366 >                case cscSetGamma: {                                                     // SetGamma
367 >                        uint32 user_table = ReadMacInt32(param + csGTable);
368 >                        D(bug("SetGamma %08x\n", user_table));
369 >                        return set_gamma(csSave, user_table);
370 >                }
371  
372                  case cscGrayPage: {                                                     // GrayPage
373 <                        D(bug("GrayPage\n"));
374 <                        uint32 *screen = (uint32 *)csSave->saveBaseAddr;
375 <                        uint32 pattern;
376 <                        uint32 row_bytes = VModes[cur_mode].viRowBytes;
377 <                        switch (VModes[cur_mode].viAppleMode) {
378 <                                case APPLE_8_BIT:
379 <                                        pattern=0xff00ff00;
380 <                                        for (int i=0;i<VModes[cur_mode].viYsize;i++) {
381 <                                                for (int j=0;j<(VModes[cur_mode].viXsize>>2);j++)
382 <                                                        screen[j] = pattern;
383 <                                                pattern = ~pattern;
384 <                                                screen = (uint32 *)((uint32)screen + row_bytes);
385 <                                        }
386 <                                        break;
387 <                                case APPLE_16_BIT:
388 <                                        pattern=0xffff0000;
389 <                                        for (int i=0;i<VModes[cur_mode].viYsize;i++) {
390 <                                                for (int j=0;j<(VModes[cur_mode].viXsize>>1);j++)
391 <                                                        screen[j]=pattern;
392 <                                                pattern = ~pattern;
393 <                                                screen = (uint32 *)((uint32)screen + row_bytes);
394 <                                        }
395 <                                        break;
383 <                                case APPLE_32_BIT:
384 <                                        pattern=0xffffffff;
385 <                                        for (int i=0;i<VModes[cur_mode].viYsize;i++) {
386 <                                                for (int j=0;j<VModes[cur_mode].viXsize;j++) {
387 <                                                        screen[j]=pattern;
388 <                                                        pattern = ~pattern;
389 <                                                }
390 <                                                screen = (uint32 *)((uint32)screen + row_bytes);
391 <                                        }
392 <                                        break;
373 >                        D(bug("GrayPage %d\n", ReadMacInt16(param + csPage)));
374 >                        if (ReadMacInt16(param + csPage))
375 >                                return paramErr;
376 >
377 >                        uint32 pattern[6] = {
378 >                                0xaaaaaaaa,             // 1 bpp
379 >                                0xcccccccc,             // 2 bpp
380 >                                0xf0f0f0f0,             // 4 bpp
381 >                                0xff00ff00,             // 8 bpp
382 >                                0xffff0000,             // 16 bpp
383 >                                0xffffffff              // 32 bpp
384 >                        };
385 >                        uint32 p = csSave->saveBaseAddr;
386 >                        uint32 pat = pattern[VModes[cur_mode].viAppleMode - APPLE_1_BIT];
387 >                        bool invert = (VModes[cur_mode].viAppleMode == APPLE_32_BIT);
388 >                        for (uint32 y=0; y<VModes[cur_mode].viYsize; y++) {
389 >                                for (uint32 x=0; x<VModes[cur_mode].viRowBytes; x+=4) {
390 >                                        WriteMacInt32(p + x, pat);
391 >                                        if (invert)
392 >                                                pat = ~pat;
393 >                                }
394 >                                p += VModes[cur_mode].viRowBytes;
395 >                                pat = ~pat;
396                          }
397                          return noErr;
398                  }
# Line 425 | Line 428 | static int16 VideoControl(uint32 pb, Vid
428  
429                  case cscSetHardwareCursor: {
430   //                      D(bug("SetHardwareCursor\n"));
431 +
432 +                        if (!csSave->cursorHardware)
433 +                                return controlErr;
434 +
435                          csSave->cursorSet = false;
436                          bool changed = false;
437  
431                        // Get cursor data even on a screen, to set the right cursor image when switching back to a window
438                          // Image
439                          uint32 cursor = ReadMacInt32(param);    // Pointer to CursorImage
440                          uint32 pmhandle = ReadMacInt32(cursor + ciCursorPixMap);
441                          if (pmhandle == 0 || ReadMacInt32(pmhandle) == 0)
442                                  return controlErr;
443                          uint32 pixmap = ReadMacInt32(pmhandle);
444 <                        if (memcmp(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32)) {
445 <                                memcpy(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32);
446 <                                changed = true;
447 <                        }
444 >
445 >                        // XXX: only certain image formats are handled properly at the moment
446 >                        uint16 rowBytes = ReadMacInt16(pixmap + 4) & 0x7FFF;
447 >                        if (rowBytes != 2)
448 >                                return controlErr;
449  
450                          // Mask
451                          uint32 bmhandle = ReadMacInt32(cursor + ciCursorBitMask);
452                          if (bmhandle == 0 || ReadMacInt32(bmhandle) == 0)
453                                  return controlErr;
454                          uint32 bitmap = ReadMacInt32(bmhandle);
455 +
456 +                        // Get cursor data even on a screen, to set the right cursor image when switching back to a window.
457 +                        // Hotspot is stale, but will be fixed by the next call to DrawHardwareCursor, which is likely to
458 +                        // occur immediately hereafter.
459 +
460 +                        if (memcmp(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32)) {
461 +                                memcpy(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32);
462 +                                changed = true;
463 +                        }
464                          if (memcmp(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32)) {
465                                  memcpy(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32);
466                                  changed = true;
467                          }
468  
453                        // Hotspot (!! this doesn't work)
454                        MacCursor[2] = ReadMacInt8(0x885);
455                        MacCursor[3] = ReadMacInt8(0x887);
456
469                          // Set new cursor image
470 <                        if (display_type == DIS_SCREEN)
470 >                        if (!video_can_change_cursor())
471                                  return controlErr;
472                          if (changed)
473                                  video_set_cursor();
474  
475                          csSave->cursorSet = true;
476 +                        csSave->cursorHotFlag = true;
477                          return noErr;
478                  }
479  
480 <                case cscDrawHardwareCursor:
480 >                case cscDrawHardwareCursor: {
481   //                      D(bug("DrawHardwareCursor\n"));
482 +
483 +                        if (!csSave->cursorHardware)
484 +                                return controlErr;
485 +
486 +                        int32 oldX = csSave->cursorX;
487 +                        int32 oldY = csSave->cursorY;
488 +                        uint32 oldVisible = csSave->cursorVisible;
489 +
490                          csSave->cursorX = ReadMacInt32(param + csCursorX);
491                          csSave->cursorY = ReadMacInt32(param + csCursorY);
492                          csSave->cursorVisible = ReadMacInt32(param + csCursorVisible);
493 +                        bool changed = (csSave->cursorVisible != oldVisible);
494 +
495 +                        // If this is the first DrawHardwareCursor call since the cursor was last set (via SetHardwareCursor),
496 +                        // attempt to set an appropriate cursor hotspot.  SetHardwareCursor itself does not know what the
497 +                        // hotspot should be; it knows only the cursor image and mask.  The hotspot is known only to the caller,
498 +                        // and we have to try to infer it here.  The usual sequence of calls when changing the cursor is:
499 +                        //
500 +                        //      DrawHardwareCursor with (oldX, oldY, invisible)
501 +                        //      SetHardwareCursor with (cursor)
502 +                        //      DrawHardwareCursor with (newX, newY, visible)
503 +                        //
504 +                        // The key thing to note is that the sequence is intended not to change the current screen pixel location
505 +                        // indicated by the hotspot.  Thus, the difference between (newX, newY) and (oldX, oldY) reflects precisely
506 +                        // the difference between the old cursor hotspot and the new one.  For example, if you change from a
507 +                        // cursor whose hotspot is (1, 1) to one whose hotspot is (7, 4), then you must adjust the cursor position
508 +                        // by (-6, -3) in order for the same screen pixel to remain under the new hotspot.
509 +                        //
510 +                        // Alas, on rare occasions this heuristic can fail, and if you did nothing else you could even get stuck
511 +                        // with the wrong hotspot from then on.  To address that possibility, we force the hotspot to (1, 1)
512 +                        // whenever the cursor being drawn is the standard arrow.  Thus, while it is very unlikely that you will
513 +                        // ever have the wrong hotspot, if you do, it is easy to recover.
514 +
515 +                        if (csSave->cursorHotFlag) {
516 +                                csSave->cursorHotFlag = false;
517 +                                D(bug("old hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY));
518 +
519 +                                static uint8 arrow[] = {
520 +                                        0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, 0x78, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x7F, 0x00,
521 +                                        0x7F, 0x80, 0x7C, 0x00, 0x6C, 0x00, 0x46, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
522 +                                };
523 +                                if (memcmp(MacCursor + 4, arrow, 32) == 0) {
524 +                                        csSave->cursorHotX = 1;
525 +                                        csSave->cursorHotY = 1;
526 +                                } else if (csSave->cursorX != oldX || csSave->cursorY != oldY) {
527 +                                        int32 hotX = csSave->cursorHotX + (oldX - csSave->cursorX);
528 +                                        int32 hotY = csSave->cursorHotY + (oldY - csSave->cursorY);
529 +
530 +                                        if (0 <= hotX && hotX <= 15 && 0 <= hotY && hotY <= 15) {
531 +                                                csSave->cursorHotX = hotX;
532 +                                                csSave->cursorHotY = hotY;
533 +                                        }
534 +                                }
535 +                                if (MacCursor[2] != csSave->cursorHotX || MacCursor[3] != csSave->cursorHotY) {
536 +                                        MacCursor[2] = csSave->cursorHotX;
537 +                                        MacCursor[3] = csSave->cursorHotY;
538 +                                        changed = true;
539 +                                }
540 +                                D(bug("new hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY));
541 +                        }
542 +
543 +                        if (changed && video_can_change_cursor())
544 +                                video_set_cursor();
545 +
546                          return noErr;
547 +                }
548  
549                  case 43: {      // Driver Gestalt
550                          uint32 sel = ReadMacInt32(pb + csParam);
# Line 526 | Line 601 | static uint32 max_depth(uint32 id)
601          return max;
602   }
603  
604 + // Get X/Y size of specified resolution
605 + static void get_size_of_resolution(int id, uint32 &x, uint32 &y)
606 + {
607 +        VideoInfo *p = VModes;
608 +        while (p->viType != DIS_INVALID) {
609 +                if (p->viAppleID == id) {
610 +                        x = p->viXsize;
611 +                        y = p->viYsize;
612 +                        return;
613 +                }
614 +                p++;
615 +        }
616 +        x = y = 0;
617 + }
618 +
619   static int16 VideoStatus(uint32 pb, VidLocals *csSave)
620   {
621          int16 code = ReadMacInt16(pb + csCode);
# Line 545 | Line 635 | static int16 VideoStatus(uint32 pb, VidL
635  
636                  case cscGetEntries: {                                           // GetEntries
637                          D(bug("GetEntries\n"));
638 <                        ColorSpec *d_pal = (ColorSpec *)Mac2HostAddr(ReadMacInt32(param + csTable));
639 <                        int16 start = ReadMacInt16(param + csStart);
640 <                        int16 count = ReadMacInt16(param + csCount);
638 >                        uint32 d_pal = ReadMacInt32(param + csTable);
639 >                        uint16 start = ReadMacInt16(param + csStart);
640 >                        uint16 count = ReadMacInt16(param + csCount);
641                          rgb_color *s_pal;
642                          if ((VModes[cur_mode].viAppleMode == APPLE_32_BIT)||
643                                  (VModes[cur_mode].viAppleMode == APPLE_16_BIT)) {
644                                  D(bug("ERROR: GetEntries in direct mode \n"));
645                                  return statusErr;
646                          }
647 <                        if (start >= 0) {       // indexed get
648 <                                s_pal = &(mac_pal[start]);
647 >
648 >                        if (start == 0xffff) {          // Indexed
649                                  for (uint16 i=0;i<count;i++) {
650 <                                        (*d_pal).red=(uint16)((*s_pal).red)*0x101;
651 <                                        (*d_pal).green=(uint16)((*s_pal).green)*0x101;
652 <                                        (*d_pal).blue=(uint16)((*s_pal).blue)*0x101;
653 <                                        d_pal++; s_pal++;
650 >                                        s_pal = mac_pal + (ReadMacInt16(d_pal + csValue) & 0xff);
651 >                                        uint8 red = (*s_pal).red;
652 >                                        uint8 green = (*s_pal).green;
653 >                                        uint8 blue = (*s_pal).blue;
654 >                                        WriteMacInt16(d_pal + csRed, red * 0x0101);
655 >                                        WriteMacInt16(d_pal + csGreen, green * 0x0101);
656 >                                        WriteMacInt16(d_pal + csBlue, blue * 0x0101);
657 >                                        d_pal += 8;
658                                  }
659 <                        } else {                                                                // selected set
659 >                        } else {                                        // Sequential
660 >                                if (start + count > 255)
661 >                                        return paramErr;
662 >                                s_pal = mac_pal + start;
663                                  for (uint16 i=0;i<count;i++) {
664 <                                        s_pal = &(mac_pal[(*d_pal).value]);
665 <                                        (*d_pal).red=(uint16)((*s_pal).red)*0x101;
666 <                                        (*d_pal).green=(uint16)((*s_pal).green)*0x101;
667 <                                        (*d_pal).blue=(uint16)((*s_pal).blue)*0x101;
668 <                                        d_pal++;
664 >                                        uint8 red = (*s_pal).red;
665 >                                        uint8 green = (*s_pal).green;
666 >                                        uint8 blue = (*s_pal).blue;
667 >                                        s_pal++;
668 >                                        WriteMacInt16(d_pal + csRed, red * 0x0101);
669 >                                        WriteMacInt16(d_pal + csGreen, green * 0x0101);
670 >                                        WriteMacInt16(d_pal + csBlue, blue * 0x0101);
671 >                                        d_pal += 8;
672                                  }
673                          };
674                          return noErr;
# Line 597 | Line 697 | static int16 VideoStatus(uint32 pb, VidL
697                  case cscGetGamma:                                                       // GetGamma
698                          D(bug("GetGamma\n"));
699                          WriteMacInt32(param, (uint32)csSave->gammaTable);
700 <                        return statusErr;
700 >                        return noErr;
701  
702                  case cscGetDefaultMode:                                         // GetDefaultMode
703                          D(bug("GetDefaultMode\n"));
# Line 687 | Line 787 | static int16 VideoStatus(uint32 pb, VidL
787                                          WriteMacInt32(param + csVerticalLines, 768);
788                                          WriteMacInt32(param + csRefreshRate, 75<<16);
789                                          break;
790 +                                case APPLE_1152x768:
791 +                                        WriteMacInt32(param + csHorizontalPixels, 1152);
792 +                                        WriteMacInt32(param + csVerticalLines, 768);
793 +                                        WriteMacInt32(param + csRefreshRate, 75<<16);
794 +                                        break;
795                                  case APPLE_1152x900:
796                                          WriteMacInt32(param + csHorizontalPixels, 1152);
797                                          WriteMacInt32(param + csVerticalLines, 900);
# Line 702 | Line 807 | static int16 VideoStatus(uint32 pb, VidL
807                                          WriteMacInt32(param + csVerticalLines, 1200);
808                                          WriteMacInt32(param + csRefreshRate, 75<<16);
809                                          break;
810 +                                case APPLE_CUSTOM: {
811 +                                        uint32 x, y;
812 +                                        get_size_of_resolution(work_id, x, y);
813 +                                        WriteMacInt32(param + csHorizontalPixels, x);
814 +                                        WriteMacInt32(param + csVerticalLines, y);
815 +                                        WriteMacInt32(param + csRefreshRate, 75<<16);
816 +                                        break;
817 +                                }
818                          }
819                          return noErr;
820                  }
# Line 805 | Line 918 | static int16 VideoStatus(uint32 pb, VidL
918                                                  case APPLE_1024x768:
919                                                          timing = timingVESA_1024x768_75hz;
920                                                          break;
921 +                                                case APPLE_1152x768:
922 +                                                        timing = timingApple_1152x870_75hz; // FIXME
923 +                                                        break;
924                                                  case APPLE_1152x900:
925                                                          timing = timingApple_1152x870_75hz;
926                                                          break;
# Line 827 | Line 943 | static int16 VideoStatus(uint32 pb, VidL
943  
944                  case cscSupportsHardwareCursor:
945                          D(bug("SupportsHardwareCursor\n"));
946 <                        WriteMacInt32(param, 1);
946 >                        WriteMacInt32(param, csSave->cursorHardware);
947                          return noErr;
948  
949                  case cscGetHardwareCursorDrawState:
950                          D(bug("GetHardwareCursorDrawState\n"));
951 +
952 +                        if (!csSave->cursorHardware)
953 +                                return statusErr;
954 +
955                          WriteMacInt32(param + csCursorX, csSave->cursorX);
956                          WriteMacInt32(param + csCursorY, csSave->cursorY);
957                          WriteMacInt32(param + csCursorVisible, csSave->cursorVisible);
# Line 865 | Line 985 | static int16 VideoClose(uint32 pb, VidLo
985   *  Native (PCI) driver entry
986   */
987  
988 < int16 VideoDoDriverIO(void *spaceID, void *commandID, void *commandContents, uint32 commandCode, uint32 commandKind)
988 > int16 VideoDoDriverIO(uint32 spaceID, uint32 commandID, uint32 commandContents, uint32 commandCode, uint32 commandKind)
989   {
990 < //      D(bug("VideoDoDriverIO space %p, command %p, contents %p, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind));
990 > //      D(bug("VideoDoDriverIO space %08x, command %08x, contents %08x, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind));
991          int16 err = noErr;
992  
993          switch (commandCode) {
994                  case kInitializeCommand:
995                  case kReplaceCommand:
996 <                        if (private_data != NULL)       // Might be left over from a reboot
997 <                                delete private_data->gammaTable;
996 >                        if (private_data != NULL) {     // Might be left over from a reboot
997 >                                if (private_data->gammaTable)
998 >                                        Mac_sysfree(private_data->gammaTable);
999 >                                if (private_data->regEntryID)
1000 >                                        Mac_sysfree(private_data->regEntryID);
1001 >                        }
1002                          delete private_data;
1003  
1004 <                        iocic_tvect = (uint32)FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete");
1004 >                        iocic_tvect = FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete");
1005                          D(bug("IOCommandIsComplete TVECT at %08lx\n", iocic_tvect));
1006                          if (iocic_tvect == 0) {
1007                                  printf("FATAL: VideoDoDriverIO(): Can't find IOCommandIsComplete()\n");
1008                                  err = -1;
1009                                  break;
1010                          }
1011 <                        vslnewis_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService");
1011 >                        vslnewis_tvect = FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService");
1012                          D(bug("VSLNewInterruptService TVECT at %08lx\n", vslnewis_tvect));
1013                          if (vslnewis_tvect == 0) {
1014                                  printf("FATAL: VideoDoDriverIO(): Can't find VSLNewInterruptService()\n");
1015                                  err = -1;
1016                                  break;
1017                          }
1018 <                        vsldisposeis_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService");
1018 >                        vsldisposeis_tvect = FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService");
1019                          D(bug("VSLDisposeInterruptService TVECT at %08lx\n", vsldisposeis_tvect));
1020                          if (vsldisposeis_tvect == 0) {
1021                                  printf("FATAL: VideoDoDriverIO(): Can't find VSLDisposeInterruptService()\n");
1022                                  err = -1;
1023                                  break;
1024                          }
1025 <                        vsldois_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService");
1025 >                        vsldois_tvect = FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService");
1026                          D(bug("VSLDoInterruptService TVECT at %08lx\n", vsldois_tvect));
1027                          if (vsldois_tvect == 0) {
1028                                  printf("FATAL: VideoDoDriverIO(): Can't find VSLDoInterruptService()\n");
1029                                  err = -1;
1030                                  break;
1031                          }
1032 <                        nqdmisc_tvect = (uint32)FindLibSymbol("\014InterfaceLib", "\007NQDMisc");
1032 >                        nqdmisc_tvect = FindLibSymbol("\014InterfaceLib", "\007NQDMisc");
1033                          D(bug("NQDMisc TVECT at %08lx\n", nqdmisc_tvect));
1034                          if (nqdmisc_tvect == 0) {
1035                                  printf("FATAL: VideoDoDriverIO(): Can't find NQDMisc()\n");
# Line 914 | Line 1038 | int16 VideoDoDriverIO(void *spaceID, voi
1038                          }
1039  
1040                          private_data = new VidLocals;
1041 <                        private_data->gammaTable = NULL;
1042 <                        memcpy(private_data->regEntryID, (uint8 *)commandContents + 2, 16);     // DriverInitInfo.deviceEntry
1041 >                        private_data->gammaTable = 0;
1042 >                        private_data->regEntryID = Mac_sysalloc(sizeof(RegEntryID));
1043 >                        if (private_data->regEntryID == 0) {
1044 >                                printf("FATAL: VideoDoDriverIO(): Can't allocate service owner\n");
1045 >                                err = -1;
1046 >                                break;
1047 >                        }
1048 >                        Mac2Mac_memcpy(private_data->regEntryID, commandContents + 2, 16);      // DriverInitInfo.deviceEntry
1049                          private_data->interruptsEnabled = false;        // Disable interrupts
1050                          break;
1051  
1052                  case kFinalizeCommand:
1053                  case kSupersededCommand:
1054 <                        if (private_data != NULL)
1055 <                                delete private_data->gammaTable;
1054 >                        if (private_data != NULL) {
1055 >                                if (private_data->gammaTable)
1056 >                                        Mac_sysfree(private_data->gammaTable);
1057 >                                if (private_data->regEntryID)
1058 >                                        Mac_sysfree(private_data->regEntryID);
1059 >                        }
1060                          delete private_data;
1061                          private_data = NULL;
1062                          break;
1063  
1064                  case kOpenCommand:
1065 <                        err = VideoOpen((uint32)commandContents, private_data);
1065 >                        err = VideoOpen(commandContents, private_data);
1066                          break;
1067  
1068                  case kCloseCommand:
1069 <                        err = VideoClose((uint32)commandContents, private_data);
1069 >                        err = VideoClose(commandContents, private_data);
1070                          break;
1071  
1072                  case kControlCommand:
1073 <                        err = VideoControl((uint32)commandContents, private_data);
1073 >                        err = VideoControl(commandContents, private_data);
1074                          break;
1075  
1076                  case kStatusCommand:
1077 <                        err = VideoStatus((uint32)commandContents, private_data);
1077 >                        err = VideoStatus(commandContents, private_data);
1078                          break;
1079  
1080                  case kReadCommand:

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines