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.16 by asvitkine, 2008-06-25T02:52:22Z

# 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 416 | 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  
422                        // 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  
444                        // Hotspot (!! this doesn't work)
445                        MacCursor[2] = ReadMacInt8(0x885);
446                        MacCursor[3] = ReadMacInt8(0x887);
447
471                          // Set new cursor image
472                          if (!video_can_change_cursor())
473                                  return controlErr;
# Line 452 | Line 475 | static int16 VideoControl(uint32 pb, Vid
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 517 | 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 708 | 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 836 | 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 885 | Line 998 | int16 VideoDoDriverIO(uint32 spaceID, ui
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  
# Line 926 | Line 1041 | int16 VideoDoDriverIO(uint32 spaceID, ui
1041  
1042                          private_data = new VidLocals;
1043                          private_data->gammaTable = 0;
1044 <                        Mac2Host_memcpy(&private_data->regEntryID, commandContents + 2, 16);    // DriverInitInfo.deviceEntry
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 && private_data->gammaTable)
1057 <                                Mac_sysfree(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;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines