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.3 by gbeauche, 2003-09-29T20:31:47Z vs.
Revision 1.16 by asvitkine, 2008-06-25T02:52:22Z

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines