///////////////////////////////////////////////////////////////////////// // $Id: carbon.cc,v 1.10 2002-04-20 07:19:35 vruppert Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2001 MandrakeSoft S.A. // // MandrakeSoft S.A. // 43, rue d'Aboukir // 75002 Paris - France // http://www.linux-mandrake.com/ // http://www.mandrakesoft.com/ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // carbon.cc -- bochs GUI file for MacOS X with Carbon API // written by David Batterham // with contributions from Tim Senecal // port to Carbon API by Emmanuel Maillard // BOCHS INCLUDES #include "bochs.h" #include "icon_bochs.h" #include "font/vga.bitmap.h" // MAC OS INCLUDES #include #include // CONSTANTS #define rMBarID 128 #define mApple 128 #define iAbout 1 #define mFile 129 #define iQuit 1 #define mEdit 130 #define mBochs 131 #define iFloppy 1 #define iCursor 3 #define iTool 4 #define iMenuBar 5 #define iFullScreen 6 #define iConsole 7 #define iSnapshot 9 #define iReset 10 const MenuCommand kCommandFloppy = FOUR_CHAR_CODE ('FLPY'); const MenuCommand kCommandCursor = FOUR_CHAR_CODE ('CRSR'); const MenuCommand kCommandTool = FOUR_CHAR_CODE ('TOOL'); const MenuCommand kCommandMenuBar = FOUR_CHAR_CODE ('MENU'); const MenuCommand kCommandFullScreen = FOUR_CHAR_CODE ('SCRN'); const MenuCommand kCommandSnapshot = FOUR_CHAR_CODE ('SNAP'); const MenuCommand kCommandReset = FOUR_CHAR_CODE ('RSET'); #define SLEEP_TIME 0 // Number of ticks to surrender the processor during a WaitNextEvent() // Change this to 15 or higher if you don't want Bochs to hog the processor! #define FONT_WIDTH 8 #define FONT_HEIGHT 16 #define WINBITMAP(w) GetPortBitMapForCopyBits(GetWindowPort(w)) // (((GrafPtr)(w))->portBits) #define ASCII_1_MASK 0x00FF0000 #define ASCII_2_MASK 0x000000FF const RGBColor black = {0, 0, 0}; const RGBColor white = {0xFFFF, 0xFFFF, 0xFFFF}; const RGBColor medGrey = {0xCCCC, 0xCCCC, 0xCCCC}; const RGBColor ltGrey = {0xEEEE, 0xEEEE, 0xEEEE}; // GLOBALS WindowPtr win, toolwin, fullwin, backdrop, hidden, SouixWin; WindowGroupRef fullwinGroup; bx_gui_c *thisGUI; SInt16 gOldMBarHeight; Boolean menubarVisible = true, cursorVisible = true; Boolean windowUpdatesPending = true, mouseMoved = false; RgnHandle mBarRgn, cnrRgn; unsigned mouse_button_state = 0; CTabHandle gCTable; PixMapHandle gTile; BitMap *vgafont[256]; Rect srcTextRect, srcTileRect; Point scrCenter = {300, 240}; Ptr KCHR; short gheaderbar_y; Point prevPt; unsigned width, height, gMinTop, gMaxTop, gLeft; GWorldPtr gOffWorld; ProcessSerialNumber gProcessSerNum; // HEADERBAR STUFF int numPixMaps = 0, toolPixMaps = 0; unsigned bx_bitmap_left_xorigin = 2; // pixels from left unsigned bx_bitmap_right_xorigin = 2; // pixels from right //PixMapHandle bx_pixmap[BX_MAX_PIXMAPS]; CIconHandle bx_cicn[BX_MAX_PIXMAPS]; struct { CIconHandle cicn; // PixMapHandle pm; unsigned xdim; unsigned ydim; unsigned xorigin; unsigned yorigin; unsigned alignment; void (*f)(void); } bx_tool_pixmap[BX_MAX_PIXMAPS]; // Carbon Event Handlers pascal OSStatus CEvtHandleWindowToolClick (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); pascal OSStatus CEvtHandleWindowToolUpdate (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); pascal OSStatus CEvtHandleWindowBackdropUpdate (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); pascal OSStatus CEvtHandleWindowEmulatorClick (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); pascal OSStatus CEvtHandleWindowEmulatorUpdate (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); pascal OSStatus CEvtHandleWindowEmulatorKeys (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); pascal OSStatus CEvtHandleApplicationAppleEvent (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); pascal OSStatus CEvtHandleApplicationMouseMoved (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); pascal OSStatus CEvtHandleApplicationMouseUp (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); pascal OSStatus CEvtHandleApplicationMenuClick (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); pascal OSStatus CEvtHandleApplicationMenus (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); // Event handlers BX_CPP_INLINE void HandleKey(EventRecord *event, Bit32u keyState); BX_CPP_INLINE void HandleToolClick(Point where); // Show/hide UI elements void HidePointer(void); void ShowPointer(void); void HideTools(void); void ShowTools(void); void HideMenubar(void); void ShowMenubar(void); // void HideConsole(void); // void ShowConsole(void); // Initialisation void FixWindow(void); void MacPanic(void); void InitToolbox(void); void CreateTile(void); void CreateMenus(void); void CreateWindows(void); void CreateKeyMap(void); void CreateVGAFont(void); BitMap *CreateBitMap(unsigned width, unsigned height); PixMapHandle CreatePixMap(unsigned left, unsigned top, unsigned width, unsigned height, unsigned depth, CTabHandle clut); unsigned char reverse_bitorder(unsigned char); static pascal OSErr QuitAppleEventHandler(const AppleEvent *appleEvt, AppleEvent* reply, SInt32 refcon); extern bx_gui_c bx_gui; #define BX_GUI_THIS bx_gui. #define LOG_THIS BX_GUI_THIS // Carbon Event Handlers pascal OSStatus CEvtHandleWindowToolClick (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { Point wheresMyMouse; GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &wheresMyMouse); HiliteWindow(win, true); HandleToolClick(wheresMyMouse); return noErr; // Report success } pascal OSStatus CEvtHandleWindowToolUpdate (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { thisGUI->show_headerbar(); return noErr; // Report success } pascal OSStatus CEvtHandleWindowBackdropUpdate (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { Rect box; Pattern qdBlackPattern; WindowRef myWindow; GetEventParameter (theEvent, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &myWindow); GetQDGlobalsBlack(&qdBlackPattern); GetWindowPortBounds(myWindow, &box); FillRect(&box, &qdBlackPattern); return noErr; // Report success } // Translate MouseDowns in a handled window into Bochs events // Main ::HANDLE_EVENTS will feed all mouse updates to Bochs pascal OSStatus CEvtHandleWindowEmulatorClick (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { UInt32 keyModifiers; GetEventParameter (theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &keyModifiers); // if (!IsWindowActive(win)) // { // SelectWindow(win); // } if (keyModifiers & cmdKey) mouse_button_state |= 0x02; else mouse_button_state |= 0x01; return noErr; // Report success } pascal OSStatus CEvtHandleWindowEmulatorUpdate (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { Rect box; Pattern qdBlackPattern; WindowRef myWindow; GetEventParameter (theEvent, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &myWindow); GetWindowPortBounds(myWindow, &box); bx_vga.redraw_area(box.left, box.top, box.right, box.bottom); return noErr; // Report success } pascal OSStatus CEvtHandleWindowEmulatorKeys (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { EventRecord event; int oldMods=0; if(ConvertEventRefToEventRecord(theEvent, &event)) { int key = event.message & charCodeMask; switch(event.what) { case keyDown: case autoKey: oldMods = event.modifiers; HandleKey(&event, BX_KEY_PRESSED); break; case keyUp: event.modifiers = oldMods; HandleKey(&event, BX_KEY_RELEASED); break; } } else BX_PANIC(("Can't convert keyboard event")); return noErr; } #if 0 // This stuff does work... it gets called, but converting the record // and then calling AEProcessAppleEvent consistently results in noOutstandingHLE(err result -608) // And its going to take more work to get RunApplicationLoop to work... pascal OSStatus CEvtHandleApplicationAppleEvent (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { EventRecord eventRec; fprintf(stderr, "# Carbon apple event handler called\n"); if(ConvertEventRefToEventRecord(theEvent, &eventRec)) { fprintf(stderr, "# Calling AEProcessAppleEvent\n"); OSStatus result = AEProcessAppleEvent(&eventRec); fprintf(stderr, "# Received AE result: %i\n", result); returm result; } else BX_PANIC(("Can't convert apple event")); return noErr; // Report success } #endif // Only have our application deal with mouseEvents when we catch the movement pascal OSStatus CEvtHandleApplicationMouseMoved (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { mouseMoved = true; return eventNotHandledErr; } pascal OSStatus CEvtHandleApplicationMouseUp (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { UInt32 keyModifiers; GetEventParameter (theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &keyModifiers); if (keyModifiers & cmdKey) mouse_button_state &= ~0x02; else mouse_button_state &= ~0x01; return eventNotHandledErr; // Don't want to eat all the mouseups } // Catch MouseDown's in the menubar, trigger menu browsing pascal OSStatus CEvtHandleApplicationMenuClick (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { short part; WindowPtr whichWindow; Point wheresMyMouse; GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &wheresMyMouse); part = FindWindow(wheresMyMouse, &whichWindow); if(part == inMenuBar) { // MenuSelect will actually trigger an event cascade, // Triggering command events for any selected menu item MenuSelect(wheresMyMouse); return noErr; } return eventNotHandledErr; // Don't want to eat all the clicks } pascal OSStatus CEvtHandleApplicationMenus (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { HICommand commandStruct; OSErr err = noErr; short i; DialogPtr theDlog; GetEventParameter (theEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &commandStruct); switch(commandStruct.commandID) { case kHICommandAbout: theDlog = GetNewDialog(128, NULL, (WindowPtr)-1); ModalDialog(NULL, &i); DisposeDialog(theDlog); break; case kHICommandQuit: BX_PANIC(("User terminated")); break; case kCommandFloppy: //DiskEject(1); break; case kCommandCursor: if (cursorVisible) HidePointer(); else ShowPointer(); break; case kCommandTool: if (IsWindowVisible(toolwin)) HideTools(); else ShowTools(); break; case kCommandMenuBar: if (menubarVisible) HideMenubar(); else ShowMenubar(); break; case kCommandFullScreen: if (IsWindowVisible(toolwin) || menubarVisible) { if (menubarVisible) HideMenubar(); if (IsWindowVisible(toolwin)) HideTools(); } else { if (!menubarVisible) ShowMenubar(); if (!IsWindowVisible(toolwin)) ShowTools(); } break; /* // Codewarrior programatic console that isn't available under Carbon without Codewarrior case iConsole: if (IsWindowVisible(SouixWin)) HideConsole(); else ShowConsole(); break; */ case kCommandSnapshot: //the following will break if snapshot is not last bitmap button instantiated bx_tool_pixmap[toolPixMaps-1].f(); break; } return noErr; // Report success } //this routine moves the initial window position so that it is entirely onscreen //it is needed for os 8.x with appearance managaer void FixWindow(void) { RgnHandle wStruct; Rect wRect; RgnHandle tStruct; Rect tRect; short MinVal; wStruct = NewRgn(); tStruct = NewRgn(); GetWindowRegion(win, kWindowStructureRgn, wStruct); GetRegionBounds(wStruct, &wRect); GetWindowRegion(toolwin, kWindowStructureRgn, tStruct); GetRegionBounds(tStruct, &tRect); if (wRect.left < 2) { gLeft = gLeft + (2 - wRect.left); } MinVal = tRect.bottom+2; //MinVal = MinVal + GetMBarHeight(); if (wRect.top < MinVal) { // gMinTop = gMinTop + (MinVal - wRect.top); gMaxTop = gMaxTop + (MinVal - wRect.top); } MoveWindow(win, gLeft, gMaxTop, false); DisposeRgn(wStruct); DisposeRgn(tStruct); } void MacPanic(void) { StopAlert(200, NULL); } void InitToolbox(void) { OSErr err; // gQuitFlag = false; InitCursor(); #if 0 // Our handler gets called... but I can't AEProcesAppleEvent successfully upon it? EventTypeSpec appleEvent = { kEventClassAppleEvent, kEventAppleEvent }; InstallApplicationEventHandler(NewEventHandlerUPP(CEvtHandleApplicationAppleEvent), 1, &appleEvent, 0, NULL); #endif err = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(QuitAppleEventHandler), 0, false); if (err != noErr) ExitToShell(); } static pascal OSErr QuitAppleEventHandler(const AppleEvent *appleEvt, AppleEvent* reply, SInt32 refcon) { //gQuitFlag = true; BX_PANIC(("User terminated")); return (noErr); } void CreateTile(void) { GDHandle saveDevice; CGrafPtr savePort; OSErr err; if (bx_options.Oprivate_colormap->get ()) { GetGWorld(&savePort, &saveDevice); err = NewGWorld(&gOffWorld, 8, &srcTileRect, gCTable, NULL, useTempMem); if (err != noErr) BX_PANIC(("mac: can't create gOffWorld")); SetGWorld(gOffWorld, NULL); gTile = GetGWorldPixMap(gOffWorld); if (gTile != NULL) { NoPurgePixels(gTile); LockPixels(gTile); (**gTile).rowBytes = 0x8000 | srcTileRect.right; (**gCTable).ctFlags = (**gCTable).ctFlags | 0x4000; //use palette manager indexes (**gTile).pmTable = gCTable; } else BX_PANIC(("mac: can't create gTile")); SetGWorld(savePort, saveDevice); } else { gTile = CreatePixMap(0, 0, srcTileRect.right, srcTileRect.bottom, 8, gCTable); if (gTile == NULL) BX_PANIC(("mac: can't create gTile")); } } void CreateMenus(void) { Handle menu; menu = GetNewMBar(rMBarID); // get our menus from resource if (menu != nil) { SetMenuBar(menu); DrawMenuBar(); } else BX_PANIC(("can't create menu")); SetMenuItemCommandID (GetMenuRef(mApple), iAbout, kHICommandAbout); SetMenuItemCommandID (GetMenuRef(mFile), iQuit, kHICommandQuit); SetMenuItemCommandID (GetMenuRef(mBochs), iFloppy, kCommandFloppy); SetMenuItemCommandID (GetMenuRef(mBochs), iCursor, kCommandCursor); SetMenuItemCommandID (GetMenuRef(mBochs), iTool, kCommandTool); SetMenuItemCommandID (GetMenuRef(mBochs), iMenuBar, kCommandMenuBar); SetMenuItemCommandID (GetMenuRef(mBochs), iFullScreen, kCommandFullScreen); SetMenuItemCommandID (GetMenuRef(mBochs), iSnapshot, kCommandSnapshot); SetMenuItemCommandID (GetMenuRef(mBochs), iReset, kCommandReset); EventTypeSpec commandEvents = {kEventClassCommand, kEventCommandProcess}; EventTypeSpec menuEvents = {kEventClassMouse, kEventMouseDown}; InstallApplicationEventHandler(NewEventHandlerUPP(CEvtHandleApplicationMenus), 1, &commandEvents, 0, NULL); InstallApplicationEventHandler(NewEventHandlerUPP(CEvtHandleApplicationMenuClick), 1, &menuEvents, 0, NULL); } void CreateWindows(void) { int l, t, r, b; Rect winRect; Rect screenBitsBounds; EventTypeSpec eventClick = { kEventClassWindow, kEventWindowHandleContentClick }; EventTypeSpec eventUpdate = { kEventClassWindow, kEventWindowDrawContent }; EventTypeSpec keyboardEvents[3] = { { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyRepeat }, { kEventClassKeyboard, kEventRawKeyUp }}; // Create a backdrop window for fullscreen mode GetRegionBounds(GetGrayRgn(), &screenBitsBounds); SetRect(&winRect, 0, 0, screenBitsBounds.right, screenBitsBounds.bottom + GetMBarHeight()); CreateNewWindow(kDocumentWindowClass, (kWindowStandardHandlerAttribute ), &winRect, &backdrop); if (backdrop == NULL) {BX_PANIC(("mac: can't create backdrop window"));} InstallWindowEventHandler(backdrop, NewEventHandlerUPP(CEvtHandleWindowBackdropUpdate), 1, &eventUpdate, NULL, NULL); InstallWindowEventHandler(backdrop, NewEventHandlerUPP(CEvtHandleWindowEmulatorClick), 1, &eventClick, NULL, NULL); InstallWindowEventHandler(backdrop, NewEventHandlerUPP(CEvtHandleWindowEmulatorKeys), 3, keyboardEvents, 0, NULL); width = 640; height = 480; gLeft = 4; gMinTop = 44; gMaxTop = 44 + gheaderbar_y; l = (screenBitsBounds.right - width) /2; //(qd.screenBits.bounds.right - width)/2; r = l + width; t = (screenBitsBounds.bottom - height)/2; b = t + height; // Create a moveable tool window for the "headerbar" SetRect(&winRect, 0, 20, screenBitsBounds.right , 22+gheaderbar_y); //qd.screenBits.bounds.right, 22+gheaderbar_y); CreateNewWindow(kFloatingWindowClass, kWindowStandardHandlerAttribute ,&winRect, &toolwin); if (toolwin == NULL) {BX_PANIC(("mac: can't create tool window"));} SetWindowTitleWithCFString (toolwin, CFSTR("MacBochs 586")); // Set title InstallWindowEventHandler(toolwin, NewEventHandlerUPP(CEvtHandleWindowToolClick), 1, &eventClick, NULL, NULL); InstallWindowEventHandler(toolwin, NewEventHandlerUPP(CEvtHandleWindowToolUpdate), 1, &eventUpdate, NULL, NULL); // Create the emulator window for full screen mode SetRect(&winRect, l, t, r, b); CreateNewWindow(kPlainWindowClass, (kWindowStandardHandlerAttribute), &winRect, &fullwin); if (fullwin == NULL) BX_PANIC(("mac: can't create fullscreen emulator window")); InstallWindowEventHandler(fullwin, NewEventHandlerUPP(CEvtHandleWindowEmulatorUpdate), 1, &eventUpdate, NULL, NULL); InstallWindowEventHandler(fullwin, NewEventHandlerUPP(CEvtHandleWindowEmulatorClick), 1, &eventClick, NULL, NULL); InstallWindowEventHandler(fullwin, NewEventHandlerUPP(CEvtHandleWindowEmulatorKeys), 3, keyboardEvents, 0, NULL); // Create the regular emulator window SetRect(&winRect, gLeft, gMaxTop, gLeft+width, gMaxTop+height); CreateNewWindow(kDocumentWindowClass, (kWindowStandardHandlerAttribute | kWindowCollapseBoxAttribute), &winRect, &win); if (win == NULL) BX_PANIC(("mac: can't create emulator window")); SetWindowTitleWithCFString (win, CFSTR("MacBochs 586")); // Set title InstallWindowEventHandler(win, NewEventHandlerUPP(CEvtHandleWindowEmulatorUpdate), 1, &eventUpdate, NULL, NULL); InstallWindowEventHandler(win, NewEventHandlerUPP(CEvtHandleWindowEmulatorClick), 1, &eventClick, NULL, NULL); InstallWindowEventHandler(win, NewEventHandlerUPP(CEvtHandleWindowEmulatorKeys), 3, keyboardEvents, 0, NULL); // Group the fullscreen and backdrop windows together, since they also share the same click // event handler they will effectively act as a single window for layering and events CreateWindowGroup((kWindowGroupAttrLayerTogether | kWindowGroupAttrSharedActivation), &fullwinGroup); SetWindowGroupName(fullwinGroup, CFSTR("net.sourceforge.bochs.windowgroups.fullscreen")); // This *can't* be the right way, then again groups aren't yet the right way // For the life of me I couldn't find a right way of making sure my created group stayed // below the layer of Floating Windows. But with the windows we have there's no current // harm from making it part of the same group. SetWindowGroup(toolwin, fullwinGroup); SetWindowGroup(fullwin, fullwinGroup); SetWindowGroup(backdrop, fullwinGroup); FixWindow(); hidden = fullwin; ShowWindow(toolwin); ShowWindow(win); HiliteWindow(win, true); SetPort(GetWindowPort(win)); } // ::SPECIFIC_INIT() // // Called from gui.cc, once upon program startup, to allow for the // specific GUI code (X11, BeOS, ...) to be initialized. // // th: a 'this' pointer to the gui class. If a function external to the // class needs access, store this pointer and use later. // argc, argv: not used right now, but the intention is to pass native GUI // specific options from the command line. (X11 options, BeOS options,...) // // tilewidth, tileheight: for optimization, graphics_tile_update() passes // only updated regions of the screen to the gui code to be redrawn. // These define the dimensions of a region (tile). // headerbar_y: A headerbar (toolbar) is display on the top of the // VGA window, showing floppy status, and other information. It // always assumes the width of the current VGA mode width, but // it's height is defined by this parameter. void bx_gui_c::specific_init(bx_gui_c *th, int argc, char **argv, unsigned tilewidth, unsigned tileheight, unsigned headerbar_y) { th->put("MGUI"); InitToolbox(); //SouixWin = FrontWindow(); atexit(MacPanic); thisGUI = th; gheaderbar_y = headerbar_y; CreateKeyMap(); gCTable = GetCTable(128); BX_ASSERT (gCTable != NULL); (*gCTable)->ctSeed = GetCTSeed(); SetRect(&srcTextRect, 0, 0, FONT_WIDTH, FONT_HEIGHT); SetRect(&srcTileRect, 0, 0, tilewidth, tileheight); CreateMenus(); CreateVGAFont(); CreateTile(); CreateWindows(); EventTypeSpec mouseUpEvent = { kEventClassMouse, kEventMouseUp }; EventTypeSpec mouseMoved[2] = { { kEventClassMouse, kEventMouseMoved }, { kEventClassMouse, kEventMouseDragged } }; InstallApplicationEventHandler(NewEventHandlerUPP(CEvtHandleApplicationMouseUp), 1, &mouseUpEvent, 0, NULL); InstallApplicationEventHandler(NewEventHandlerUPP(CEvtHandleApplicationMouseMoved), 2, mouseMoved, 0, NULL); GetCurrentProcess(&gProcessSerNum); GetMouse(&prevPt); UNUSED(argc); UNUSED(argv); //HideWindow(SouixWin); } // HandleKey() // // Handles keyboard-related events. BX_CPP_INLINE void HandleKey(EventRecord *event, Bit32u keyState) { int key; UInt32 trans; static UInt32 transState = 0; key = event->message & charCodeMask; // if (event->modifiers & cmdKey) // { // // Like MenuSelect, MenuKey also triggers a cascade of // // events that results in sending a command event // MenuKey(key); // } // else if (FrontWindow() == SouixWin) // { // SIOUXHandleOneEvent(event); // } // else // { if (event->modifiers & shiftKey) bx_devices.keyboard->gen_scancode(BX_KEY_SHIFT_L | keyState); if (event->modifiers & controlKey) bx_devices.keyboard->gen_scancode(BX_KEY_CTRL_L | keyState); if (event->modifiers & optionKey) bx_devices.keyboard->gen_scancode(BX_KEY_ALT_L | keyState); key = (event->message & keyCodeMask) >> 8; trans = KeyTranslate(KCHR, key, &transState); // KeyTranslate maps Mac virtual key codes to any type of character code // you like (in this case, Bochs key codes). Much nicer than a huge switch // statement! if (trans > 0) bx_devices.keyboard->gen_scancode(trans | keyState); if (event->modifiers & shiftKey) bx_devices.keyboard->gen_scancode(BX_KEY_SHIFT_L | BX_KEY_RELEASED); if (event->modifiers & controlKey) bx_devices.keyboard->gen_scancode(BX_KEY_CTRL_L | BX_KEY_RELEASED); if (event->modifiers & optionKey) bx_devices.keyboard->gen_scancode(BX_KEY_ALT_L | BX_KEY_RELEASED); // } } // HandleToolClick() // // Handles mouse clicks in the Bochs tool window BX_CPP_INLINE void HandleToolClick(Point where) { unsigned i; int xorigin; Rect bounds; Rect toolwinRect; GetWindowPortBounds (toolwin, &toolwinRect); SetPort(GetWindowPort(toolwin)); GlobalToLocal(&where); for (i=0; ishow_headerbar(); } BX_CPP_INLINE void ResetPointer(void) { // this appears to work well, especially when combined with // mouse processing on the MouseMoved events if(CGWarpMouseCursorPosition(CGPointMake(scrCenter.h, scrCenter.v))) { fprintf(stderr, "# Failed to warp cursor"); } } // ::HANDLE_EVENTS() // // Called periodically (vga_update_interval in .bochsrc) so the // the gui code can poll for keyboard, mouse, and other // relevant events. void bx_gui_c::handle_events(void) { EventRecord event; Point mousePt; int dx, dy; int oldMods=0; unsigned curstate; GrafPtr oldport; curstate = mouse_button_state; //so we can compare the old and the new mouse state if (WaitNextEvent(everyEvent, &event, SLEEP_TIME, NULL)) { switch(event.what) { /* // This event is just redundant case nullEvent: // These events are all covered by installed carbon event handlers case mouseDown: case mouseUp: case keyDown: case autoKey: case keyUp: case updateEvt: break; */ case diskEvt: // floppyA_handler(); break; case kHighLevelEvent: fprintf(stderr, "# Classic apple event handler called\n"); AEProcessAppleEvent(&event); default: break; } } // Only update mouse if we're not in the dock // and we are the frontmost app. ProcessSerialNumber frontProcessSerNum; Boolean isSameProcess; GetFrontProcess(&frontProcessSerNum); SameProcess(&frontProcessSerNum, &gProcessSerNum, &isSameProcess); if(isSameProcess && !IsWindowCollapsed(win)) { GetPort(&oldport); SetPort(GetWindowPort(win)); GetMouse(&mousePt); if(menubarVisible && cursorVisible) { // Don't track the mouse if we're working with the main window // and we're outside the window if(mouseMoved && (mousePt.v < 0 || mousePt.v > height || mousePt.h < 0 || mousePt.h > width) && (prevPt.v < 0 || prevPt.v > height || prevPt.h < 0 || prevPt.h > width)) { mouseMoved = false; } /* // Limit mouse action to window // Grr, any better ways to sync host and bochs cursor? if(mousePt.h < 0) { mousePt.h = 0; } else if(mousePt.h > width) { mousePt.h = width; } if(mousePt.v < 0) { mousePt.v = 0; } else if(mousePt.v > height) { mousePt.v = height; } */ } //if mouse has moved, or button has changed state if (mouseMoved || (curstate != mouse_button_state)) { if(mouseMoved) { CGMouseDelta CGdX, CGdY; CGGetLastMouseDelta( &CGdX, &CGdY ); dx = CGdX; dy = - CGdY; // Windows has an opposing grid } else { dx = 0; dy = 0; } bx_devices.keyboard->mouse_motion(dx, dy, mouse_button_state); if (!cursorVisible && mouseMoved) { SetPt(&scrCenter, 300, 240); LocalToGlobal(&scrCenter); ResetPointer(); //next getmouse should be 300, 240 SetPt(&mousePt, 300, 240); } mouseMoved = false; } prevPt = mousePt; SetPort(oldport); } } // ::FLUSH() // // Called periodically, requesting that the gui code flush all pending // screen update requests. void bx_gui_c::flush(void) { // an opportunity to make the Window Manager happy. // not needed on the macintosh.... // Unless you don't want to needlessly update the dock icon // umpteen zillion times a second for each tile. // A further note, UpdateCollapsedWindowDockTile is not // recommended for animation. Setup like this my performance // seems reasonable for little fuss. if(windowUpdatesPending && IsWindowCollapsed(win)) { UpdateCollapsedWindowDockTile(win); } windowUpdatesPending = false; } // ::CLEAR_SCREEN() // // Called to request that the VGA region is cleared. Don't // clear the area that defines the headerbar. void bx_gui_c::clear_screen(void) { Rect r; Pattern qdBlackPattern; GetQDGlobalsBlack(&qdBlackPattern); SetPort(GetWindowPort(win)); RGBForeColor(&black); RGBBackColor(&white); GetWindowPortBounds(win, &r); FillRect (&r, &qdBlackPattern); windowUpdatesPending = true; } // ::TEXT_UPDATE() // // Called in a VGA text mode, to update the screen with // new content. // // old_text: array of character/attributes making up the contents // of the screen from the last call. See below // new_text: array of character/attributes making up the current // contents, which should now be displayed. See below // // format of old_text & new_text: each is 80*nrows*2 bytes long. // This represents 80 characters wide by 'nrows' high, with // each character being 2 bytes. The first by is the // character value, the second is the attribute byte. // I currently don't handle the attribute byte. // // cursor_x: new x location of cursor // cursor_y: new y location of cursor void bx_gui_c::text_update(Bit8u *old_text, Bit8u *new_text, unsigned long cursor_x, unsigned long cursor_y, Bit16u cursor_state, unsigned nrows) { int i; unsigned char achar; int x, y; static int previ; int cursori; Rect destRect; RGBColor fgColor, bgColor; GrafPtr oldPort; GrafPtr winGrafPtr = GetWindowPort(win); unsigned nchars, ncols; GetPort(&oldPort); SetPort(GetWindowPort(win)); ncols = width/8; //current cursor position cursori = (cursor_y*ncols + cursor_x)*2; // Number of characters on screen, variable number of rows nchars = ncols*nrows; for (i=0; i> 4].rgb; // RGBForeColor(&fgColor); // RGBBackColor(&bgColor); if (bx_options.Oprivate_colormap->get ()) { PmForeColor(new_text[i+1] & 0x0F); PmBackColor((new_text[i+1] & 0xF0) >> 4); } else { fgColor = (**gCTable).ctTable[new_text[i+1] & 0x0F].rgb; bgColor = (**gCTable).ctTable[(new_text[i+1] & 0xF0) >> 4].rgb; RGBForeColor(&fgColor); RGBBackColor(&bgColor); } x = ((i/2) % ncols)*FONT_WIDTH; y = ((i/2) / ncols)*FONT_HEIGHT; SetRect(&destRect, x, y, x+FONT_WIDTH, y+FONT_HEIGHT); CopyBits( vgafont[achar], WINBITMAP(win), &srcTextRect, &destRect, srcCopy, NULL); if (i == cursori) //invert the current cursor block { InvertRect(&destRect); } } } //previous cursor position previ = cursori; SetPort(oldPort); windowUpdatesPending = true; } int bx_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes) { return 0; } int bx_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len) { return 0; } // ::PALETTE_CHANGE() // // Allocate a color in the native GUI, for this color, and put // it in the colormap location 'index'. // returns: 0=no screen update needed (color map change has direct effect) // 1=screen updated needed (redraw using current colormap) Boolean bx_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue) { PaletteHandle thePal, oldpal; GDHandle saveDevice; CGrafPtr savePort; if (bx_options.Oprivate_colormap->get ()) { GetGWorld(&savePort, &saveDevice); SetGWorld(gOffWorld, NULL); } (**gCTable).ctTable[index].value = index; (**gCTable).ctTable[index].rgb.red = (red << 8); (**gCTable).ctTable[index].rgb.green = (green << 8); (**gCTable).ctTable[index].rgb.blue = (blue << 8); SetEntries(index, index, (**gCTable).ctTable); CTabChanged(gCTable); if (bx_options.Oprivate_colormap->get ()) { SetGWorld(savePort, saveDevice); thePal = NewPalette(index, gCTable, pmTolerant, 0x5000); oldpal = GetPalette(win); SetPalette(win, thePal, false); SetPalette(fullwin, thePal, false); SetPalette(hidden, thePal, false); } return(0); } // ::GRAPHICS_TILE_UPDATE() // // Called to request that a tile of graphics be drawn to the // screen, since info in this region has changed. // // tile: array of 8bit values representing a block of pixels with // dimension equal to the 'tilewidth' & 'tileheight' parameters to // ::specific_init(). Each value specifies an index into the // array of colors you allocated for ::palette_change() // x0: x origin of tile // y0: y origin of tile // // note: origin of tile and of window based on (0,0) being in the upper // left of the window. void bx_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0) { Rect destRect; /* GDHandle saveDevice; CGrafPtr savePort; GetGWorld(&savePort, &saveDevice); SetGWorld(gOffWorld, NULL); */ // SetPort - Otherwise an update happens to the headerbar and ooomph, we're drawing weirdly on the screen SetPort(GetWindowPort(win)); destRect = srcTileRect; OffsetRect(&destRect, x0, y0); (**gTile).baseAddr = (Ptr)tile; CopyBits( & (** ((BitMapHandle)gTile) ), WINBITMAP(win), &srcTileRect, &destRect, srcCopy, NULL); windowUpdatesPending = true; // SetGWorld(savePort, saveDevice); } // ::DIMENSION_UPDATE() // // Called when the VGA mode changes it's X,Y dimensions. // Resize the window to this size, but you need to add on // the height of the headerbar to the Y value. // // x: new VGA x size // y: new VGA y size (add headerbar_y parameter from ::specific_init(). void bx_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight) { if (fheight > 0) { if (fheight != 16) { y = y * 16 / fheight; } } if (x != width || y != height) { #if 1 SizeWindow(win, x, y, false); #endif #if 0 // Animates the resizing, cute, but gratuitous Rect box, frame; GetWindowBounds(win, kWindowStructureRgn, &frame); GetWindowPortBounds(win, &box); frame.right = frame.right - box.right + x; frame.bottom = frame.bottom - box.bottom + y; TransitionWindow(win, kWindowSlideTransitionEffect, kWindowResizeTransitionAction, &frame); #endif SizeWindow(fullwin, x, y, false); SizeWindow(hidden, x, y, false); width = x; height = y; } windowUpdatesPending = true; } // ::CREATE_BITMAP() // // Create a monochrome bitmap of size 'xdim' by 'ydim', which will // be drawn in the headerbar. Return an integer ID to the bitmap, // with which the bitmap can be referenced later. // // bmap: packed 8 pixels-per-byte bitmap. The pixel order is: // bit0 is the left most pixel, bit7 is the right most pixel. // xdim: x dimension of bitmap // ydim: y dimension of bitmap // rewritten by tim senecal to use the cicn (color icon) resources instead unsigned bx_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim) { unsigned i; unsigned char *data; long row_bytes, bytecount; bx_cicn[numPixMaps] = GetCIcon(numPixMaps+128); numPixMaps++; return(numPixMaps-1); } // ::HEADERBAR_BITMAP() // // Called to install a bitmap in the bochs headerbar (toolbar). // // bmap_id: will correspond to an ID returned from // ::create_bitmap(). 'alignment' is either BX_GRAVITY_LEFT // or BX_GRAVITY_RIGHT, meaning install the bitmap in the next // available leftmost or rightmost space. // f: a 'C' function pointer to callback when the mouse is clicked in // the boundaries of this bitmap. unsigned bx_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void)) { unsigned hb_index; toolPixMaps++; hb_index = toolPixMaps-1; // bx_tool_pixmap[hb_index].pm = bx_pixmap[bmap_id]; bx_tool_pixmap[hb_index].cicn = bx_cicn[bmap_id]; bx_tool_pixmap[hb_index].alignment = alignment; bx_tool_pixmap[hb_index].f = f; if (alignment == BX_GRAVITY_LEFT) { bx_tool_pixmap[hb_index].xorigin = bx_bitmap_left_xorigin; bx_tool_pixmap[hb_index].yorigin = 0; // bx_bitmap_left_xorigin += (**bx_pixmap[bmap_id]).bounds.right; bx_bitmap_left_xorigin += 34; } else { // bx_bitmap_right_xorigin += (**bx_pixmap[bmap_id]).bounds.right; bx_bitmap_right_xorigin += 34; bx_tool_pixmap[hb_index].xorigin = bx_bitmap_right_xorigin; bx_tool_pixmap[hb_index].yorigin = 0; } return(hb_index); } // ::SHOW_HEADERBAR() // // Show (redraw) the current headerbar, which is composed of // currently installed bitmaps. void bx_gui_c::show_headerbar(void) { Rect destRect; Rect r; GetWindowPortBounds(toolwin, &r); int i, xorigin; Pattern qdBlackPattern; GetQDGlobalsBlack(&qdBlackPattern); SetPort(GetWindowPort(toolwin)); RGBForeColor(&medGrey); FillRect(&r, &qdBlackPattern); //&qd.black); for (i=0; iportRect); CopyBits(&win->portBits, &win->portBits, &win->portRect, &win->portRect, srcCopy, NULL); ClosePicture(); val = ZeroScrap(); HLock((Handle)ScreenShot); PutScrap(GetHandleSize((Handle)ScreenShot), 'PICT', *ScreenShot); HUnlock((Handle)ScreenShot); KillPicture(ScreenShot); } #endif // HidePointer() // // Hides the Mac mouse pointer void HidePointer() { HiliteMenu(0); HideCursor(); SetPort(GetWindowPort(win)); SetPt(&scrCenter, 300, 240); LocalToGlobal(&scrCenter); ResetPointer(); GetMouse(&prevPt); cursorVisible = false; CheckMenuItem(GetMenuHandle(mBochs), iCursor, false); } // ShowPointer() // // Shows the Mac mouse pointer void ShowPointer() { InitCursor(); cursorVisible = true; CheckMenuItem(GetMenuHandle(mBochs), iCursor, true); //CheckItem(GetMenuHandle(mBochs), iCursor, true); } // HideTools() // // Hides the Bochs toolbar void HideTools() { HideWindow(toolwin); if (menubarVisible) { MoveWindow(win, gLeft, gMinTop, false); } else { MoveWindow(hidden, gLeft, gMinTop, false); } CheckMenuItem(GetMenuHandle(mBochs), iTool, false); HiliteWindow(win, true); } // ShowTools() // // Shows the Bochs toolbar void ShowTools() { if (menubarVisible) { MoveWindow(win, gLeft, gMaxTop, false); } else { MoveWindow(hidden, gLeft, gMaxTop, false); } ShowWindow(toolwin); BringToFront(toolwin); SelectWindow(toolwin); HiliteWindow(win, true); // thisGUI->show_headerbar(); CheckMenuItem(GetMenuHandle(mBochs), iTool, true); HiliteWindow(win, true); } // HideMenubar() // // Hides the menubar (obviously) void HideMenubar() { HideMenuBar(); HideWindow(win); ShowWindow(backdrop); hidden = win; win = fullwin; ShowWindow(win); SelectWindow(win); menubarVisible = false; CheckMenuItem(GetMenuHandle(mBochs), iMenuBar, false); } // ShowMenubar() // // Makes the menubar visible again so other programs will display correctly. void ShowMenubar() { HideWindow(backdrop); win = hidden; hidden = fullwin; HideWindow(hidden); ShowWindow(win); HiliteWindow(win, true); ShowMenuBar(); menubarVisible = true; CheckMenuItem(GetMenuHandle(mBochs), iMenuBar, true); } void HideConsole() { HideWindow(SouixWin); CheckMenuItem(GetMenuHandle(mBochs), iConsole, false); } void ShowConsole() { ShowWindow(SouixWin); SelectWindow(SouixWin); CheckMenuItem(GetMenuHandle(mBochs), iConsole, true); } // CreateKeyMap() // // Create a KCHR data structure to map Mac virtual key codes to Bochs key codes void CreateKeyMap(void) { const unsigned char KCHRHeader [258] = { 0, 1 }; const unsigned char KCHRTable [130] = { 0, 1, BX_KEY_A, BX_KEY_S, BX_KEY_D, BX_KEY_F, BX_KEY_H, BX_KEY_G, BX_KEY_Z, BX_KEY_X, BX_KEY_C, BX_KEY_V, 0, BX_KEY_B, BX_KEY_Q, BX_KEY_W, BX_KEY_E, BX_KEY_R, BX_KEY_Y, BX_KEY_T, BX_KEY_1, BX_KEY_2, BX_KEY_3, BX_KEY_4, BX_KEY_6, BX_KEY_5, BX_KEY_EQUALS, BX_KEY_9, BX_KEY_7, BX_KEY_MINUS, BX_KEY_8, BX_KEY_0, BX_KEY_RIGHT_BRACKET, BX_KEY_O, BX_KEY_U, BX_KEY_LEFT_BRACKET, BX_KEY_I, BX_KEY_P, BX_KEY_ENTER, BX_KEY_L, BX_KEY_J, BX_KEY_SINGLE_QUOTE, BX_KEY_K, BX_KEY_SEMICOLON, BX_KEY_BACKSLASH, BX_KEY_COMMA, BX_KEY_SLASH, BX_KEY_N, BX_KEY_M, BX_KEY_PERIOD, BX_KEY_TAB, BX_KEY_SPACE, BX_KEY_GRAVE, BX_KEY_BACKSPACE, 0, BX_KEY_ESC, 0, // 0x36 0, // 0x37 0, // 0x38 0, // 0x39 0, // 0x3A 0, // 0x3B 0, // 0x3C 0, // 0x3D 0, // 0x3E 0, // 0x3F 0, // 0x40 BX_KEY_PERIOD, // KP_PERIOD 0, // 0x42 BX_KEY_KP_MULTIPLY, 0, // 0x44 BX_KEY_KP_ADD, 0, // 0x46 BX_KEY_KP_DELETE, 0, // 0x48 0, // 0x49 0, // 0x4A BX_KEY_KP_DIVIDE, BX_KEY_KP_ENTER, 0, // 0x4D BX_KEY_KP_SUBTRACT, 0, // 0x4F 0, // 0x50 0, // 0x51 (kp equals) 0, // 0x52 (kp 0) 0, // 0x53 (kp 1) BX_KEY_KP_DOWN, // 0x54 (kp 2) 0, // 0x55 (kp 3) BX_KEY_KP_LEFT, // 0x56 (kp 4) BX_KEY_KP_5, BX_KEY_KP_RIGHT, // 0x58 (kp 6) 0, // 0x59 (kp 7) 0, // 0x5A BX_KEY_KP_UP, // 0x5B (kp 8) 0, // 0x5C (kp 9) 0, // 0x5D 0, // 0x5E 0, // 0x5F BX_KEY_F5, BX_KEY_F6, BX_KEY_F7, BX_KEY_F3, BX_KEY_F8, BX_KEY_F9, 0, // 0x66 BX_KEY_F11, 0, // 0x68 0, // 0x69 (print screen) 0, // 0x6A 0, // 0x6B (scroll lock) 0, // 0x6C BX_KEY_F10, 0, // 0x6E BX_KEY_F12, 0, // 0x70 0, // 0x71 (pause) BX_KEY_INSERT, BX_KEY_HOME, BX_KEY_PAGE_UP, BX_KEY_DELETE, BX_KEY_F4, BX_KEY_END, BX_KEY_F2, BX_KEY_PAGE_DOWN, BX_KEY_F1, BX_KEY_LEFT, BX_KEY_RIGHT, BX_KEY_DOWN, BX_KEY_UP }; KCHR = NewPtrClear(390); if (KCHR == NULL) BX_PANIC(("mac: can't allocate memory for key map")); BlockMove(KCHRHeader, KCHR, sizeof(KCHRHeader)); BlockMove(KCHRTable, Ptr(KCHR + sizeof(KCHRHeader)), sizeof(KCHRTable)); } // CreateVGAFont() // // Create an array of PixMaps for the PC screen font void CreateVGAFont(void) { int i, x; unsigned char *fontData, curPixel; long row_bytes, bytecount; for (i=0; i<256; i++) { vgafont[i] = CreateBitMap(FONT_WIDTH, FONT_HEIGHT); row_bytes = (*(vgafont[i])).rowBytes; bytecount = row_bytes * FONT_HEIGHT; fontData = (unsigned char *)NewPtrClear(bytecount); for (x=0; x<16; x++) { //curPixel = ~(bx_vgafont[i].data[x]); curPixel = (bx_vgafont[i].data[x]); fontData[x*row_bytes] = reverse_bitorder(curPixel); } vgafont[i]->baseAddr = Ptr(fontData); } } // CreateBitMap() // Allocate a new bitmap and fill in the fields with appropriate // values. BitMap *CreateBitMap(unsigned width, unsigned height) { BitMap *bm; long row_bytes; row_bytes = (( width + 31) >> 5) << 2; bm = (BitMap *)calloc(1, sizeof(BitMap)); if (bm == NULL) BX_PANIC(("mac: can't allocate memory for pixmap")); SetRect(&bm->bounds, 0, 0, width, height); bm->rowBytes = row_bytes; // Quickdraw allocates a new color table by default, but we want to // use one we created earlier. return bm; } // CreatePixMap() // Allocate a new pixmap handle and fill in the fields with appropriate // values. PixMapHandle CreatePixMap(unsigned left, unsigned top, unsigned width, unsigned height, unsigned depth, CTabHandle clut) { PixMapHandle pm; long row_bytes; row_bytes = (((long) depth * ((long) width) + 31) >> 5) << 2; pm = NewPixMap(); if (pm == NULL) BX_PANIC(("mac: can't allocate memory for pixmap")); (**pm).bounds.left = left; (**pm).bounds.top = top; (**pm).bounds.right = left+width; (**pm).bounds.bottom = top+height; (**pm).pixelSize = depth; (**pm).rowBytes = row_bytes | 0x8000; DisposeCTable((**pm).pmTable); (**pm).pmTable = clut; // Quickdraw allocates a new color table by default, but we want to // use one we created earlier. return pm; } unsigned char reverse_bitorder(unsigned char b) { unsigned char ret=0; for (unsigned i=0; i<8; i++) { ret |= (b & 0x01) << (7-i); b >>= 1; } return(ret); } void bx_gui_c::mouse_enabled_changed_specific (Boolean val) { }