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.11 by gbeauche, 2004-12-19T15:14:22Z vs.
Revision 1.17 by asvitkine, 2012-03-27T03:43:28Z

# Line 1 | Line 1
1   /*
2   *  video.cpp - Video/graphics emulation
3   *
4 < *  SheepShaver (C) 1997-2004 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 143 | 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 157 | Line 167 | static int16 VideoOpen(uint32 pb, VidLoc
167          csSave->savePage = 0;
168          csSave->saveVidParms = 0;                       // Add the right table
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          // Find and set default gamma table
180          csSave->gammaTable = 0;
# Line 169 | Line 183 | static int16 VideoOpen(uint32 pb, VidLoc
183  
184          // Install and activate interrupt service
185          SheepVar32 theServiceID = 0;
186 <        VSLNewInterruptService(Host2MacAddr((uint8 *)csSave->regEntryID), FOURCC('v','b','l',' '), theServiceID.addr());
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;
# Line 199 | Line 213 | static bool allocate_gamma_table(VidLoca
213  
214   static int16 set_gamma(VidLocals *csSave, uint32 gamma)
215   {
202        return paramErr;
203
216          if (gamma == 0) { // Build linear ramp, 256 entries
217  
218                  // Allocate new table, if necessary
# Line 416 | 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  
422                        // 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  
444                        // Hotspot (!! this doesn't work)
445                        MacCursor[2] = ReadMacInt8(0x885);
446                        MacCursor[3] = ReadMacInt8(0x887);
447
469                          // Set new cursor image
470                          if (!video_can_change_cursor())
471                                  return controlErr;
# Line 452 | Line 473 | static int16 VideoControl(uint32 pb, Vid
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 517 | 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 598 | 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 708 | 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 836 | 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 885 | Line 996 | int16 VideoDoDriverIO(uint32 spaceID, ui
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  
# Line 926 | Line 1039 | int16 VideoDoDriverIO(uint32 spaceID, ui
1039  
1040                          private_data = new VidLocals;
1041                          private_data->gammaTable = 0;
1042 <                        Mac2Host_memcpy(&private_data->regEntryID, commandContents + 2, 16);    // DriverInitInfo.deviceEntry
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 && private_data->gammaTable)
1055 <                                Mac_sysfree(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;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines