1 ////////////////////////////////////////////////////////////////////////
2 // $Id: carbon.cc,v 1.39 2008/03/14 18:23:33 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2001 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 ////////////////////////////////////////////////////////////////////////
29 // carbon.cc -- bochs GUI file for MacOS X with Carbon API
30 // written by David Batterham <drbatter@progsoc.uts.edu.au>
31 // with contributions from Tim Senecal
32 // port to Carbon API by Emmanuel Maillard <e.rsz@libertysurf.fr>
33 // Carbon polishing by Jeremy Parsons (Br'fin) <brefin@mac.com>
34 // slight overhaul of Carbon key event, graphics and window handling
35 // and SIM->notify alert support by Chris Thomas <cjack@cjack.com>
37 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
38 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
39 // is used to know when we are exporting symbols and when we are importing.
44 #define Float32 KLUDGE_Float32
45 #define Float64 KLUDGE_Float64
53 #include "icon_bochs.h"
54 #include "font/vga.bitmap.h"
55 #include "bxversion.h"
58 #include <Carbon/Carbon.h>
59 #include <ApplicationServices/ApplicationServices.h>
61 // NOTE about use of Boolean versus bx_bool:
62 // Boolean is defined as unsigned char in the Carbon headers, so when
63 // you are talking to the Carbon API, it expects to find Boolean variables
64 // and pointers to Booleans. The rest of Bochs uses bx_bool to represent
65 // booleans, which are defined to be 32 bit unsigned, so member function
66 // definitions and booleans outside this file will be bx_bools. "Boolean"
67 // should only be used in Carbon specific code such as in this file.
93 RESET_TOOL_BUTTON
= 5,
94 CONFIGURE_TOOL_BUTTON
,
101 const MenuCommand kCommandFloppy
= FOUR_CHAR_CODE ('FLPY');
102 const MenuCommand kCommandCursor
= FOUR_CHAR_CODE ('CRSR');
103 const MenuCommand kCommandTool
= FOUR_CHAR_CODE ('TOOL');
104 const MenuCommand kCommandMenuBar
= FOUR_CHAR_CODE ('MENU');
105 const MenuCommand kCommandFullScreen
= FOUR_CHAR_CODE ('SCRN');
106 const MenuCommand kCommandSnapshot
= FOUR_CHAR_CODE ('SNAP');
107 const MenuCommand kCommandReset
= FOUR_CHAR_CODE ('RSET');
109 #define SLEEP_TIME 0 // Number of ticks to surrender the processor during a WaitNextEvent()
110 // Change this to 15 or higher if you don't want Bochs to hog the processor!
115 #define WINBITMAP(w) GetPortBitMapForCopyBits(GetWindowPort(w)) // (((GrafPtr)(w))->portBits)
117 #define ASCII_1_MASK 0x00FF0000
118 #define ASCII_2_MASK 0x000000FF
120 const RGBColor black
= {0, 0, 0};
121 const RGBColor white
= {0xFFFF, 0xFFFF, 0xFFFF};
122 const RGBColor medGrey
= {0xCCCC, 0xCCCC, 0xCCCC};
123 const RGBColor ltGrey
= {0xEEEE, 0xEEEE, 0xEEEE};
127 WindowPtr win
, toolwin
, fullwin
, backdrop
, hidden
, SouixWin
;
128 WindowGroupRef fullwinGroup
;
129 SInt16 gOldMBarHeight
;
130 Boolean menubarVisible
= true, cursorVisible
= true;
131 Boolean windowUpdatesPending
= true, mouseMoved
= false;
132 RgnHandle mBarRgn
, cnrRgn
;
133 unsigned mouse_button_state
= 0;
136 BitMap
*vgafont
[256];
137 Rect srcTextRect
, srcTileRect
;
138 Point scrCenter
= {300, 240};
142 unsigned width
, height
, gMinTop
, gMaxTop
, gLeft
;
145 ProcessSerialNumber gProcessSerNum
;
146 static unsigned vga_bpp
=8;
147 static EventModifiers oldMods
= 0;
148 static unsigned int text_rows
=25, text_cols
=80;
153 } last_screen_state
= TEXT_MODE
, screen_state
= TEXT_MODE
;
156 #define TOOL_SPACING 10
157 #define TOOL_MARGIN_SPACE 4
158 int numPixMaps
= 0, toolPixMaps
= 0;
159 unsigned bx_bitmap_left_xorigin
= 2+TOOL_SPACING
; // pixels from left
160 unsigned bx_bitmap_right_xorigin
= 2+TOOL_SPACING
; // pixels from right
161 //PixMapHandle bx_pixmap[BX_MAX_PIXMAPS];
162 CIconHandle bx_cicn
[BX_MAX_PIXMAPS
];
164 struct __bx_tool_pixmap
{
174 } bx_tool_pixmap
[BX_MAX_PIXMAPS
];
176 // Carbon Event Handlers
177 pascal OSStatus
CEvtHandleWindowToolCommand (EventHandlerCallRef nextHandler
, EventRef theEvent
, void* userData
);
178 pascal OSStatus
CEvtHandleWindowToolUpdate (EventHandlerCallRef nextHandler
, EventRef theEvent
, void* userData
);
179 pascal OSStatus
CEvtHandleWindowBackdropUpdate (EventHandlerCallRef nextHandler
, EventRef theEvent
, void* userData
);
180 pascal OSStatus
CEvtHandleWindowEmulatorClick (EventHandlerCallRef nextHandler
, EventRef theEvent
, void* userData
);
181 pascal OSStatus
CEvtHandleWindowEmulatorUpdate (EventHandlerCallRef nextHandler
, EventRef theEvent
, void* userData
);
182 pascal OSStatus
CEvtHandleWindowEmulatorKeys (EventHandlerCallRef nextHandler
, EventRef theEvent
, void* userData
);
183 pascal OSStatus
CEvtHandleApplicationAppleEvent (EventHandlerCallRef nextHandler
, EventRef theEvent
, void* userData
);
184 pascal OSStatus
CEvtHandleApplicationMouseMoved (EventHandlerCallRef nextHandler
, EventRef theEvent
, void* userData
);
185 pascal OSStatus
CEvtHandleApplicationMouseUp (EventHandlerCallRef nextHandler
, EventRef theEvent
, void* userData
);
186 pascal OSStatus
CEvtHandleApplicationMenuClick (EventHandlerCallRef nextHandler
, EventRef theEvent
, void* userData
);
187 pascal OSStatus
CEvtHandleApplicationMenus (EventHandlerCallRef nextHandler
, EventRef theEvent
, void* userData
);
190 OSStatus
HandleKey(EventRef theEvent
, Bit32u keyState
);
191 static BxEvent
* CarbonSiminterfaceCallback(void *theClass
, BxEvent
*event
);
192 static bxevent_handler old_callback
= NULL
;
193 static void *old_callback_arg
= NULL
;
195 // Show/hide UI elements
196 void HidePointer(void);
197 void ShowPointer(void);
198 void HideTools(void);
199 void ShowTools(void);
200 void HideMenubar(void);
201 void ShowMenubar(void);
202 // void HideConsole(void);
203 // void ShowConsole(void);
205 void UpdateTools(void);
208 void InitToolbox(void);
209 void CreateTile(void);
210 void CreateMenus(void);
211 void CreateWindows(void);
212 void CreateKeyMap(void);
213 void CreateVGAFont(unsigned char *vga_charmap
);
214 BitMap
*CreateBitMap(unsigned width
, unsigned height
);
215 PixMapHandle
CreatePixMap(unsigned left
, unsigned top
, unsigned width
,
216 unsigned height
, unsigned depth
, CTabHandle clut
);
217 unsigned char reverse_bitorder(unsigned char);
219 static pascal OSErr
QuitAppleEventHandler(const AppleEvent
*appleEvt
, AppleEvent
* reply
, SInt32 refcon
);
221 class bx_carbon_gui_c
: public bx_gui_c
{
223 bx_carbon_gui_c (void) {}
224 DECLARE_GUI_VIRTUAL_METHODS()
225 virtual void beep_on(float frequency
);
226 virtual void beep_off();
229 // declare one instance of the gui object and call macro to insert the
231 static bx_carbon_gui_c
*theGui
= NULL
;
232 IMPLEMENT_GUI_PLUGIN_CODE(carbon
)
234 #define LOG_THIS theGui->
236 // Carbon Event Handlers
238 pascal OSStatus
CEvtHandleWindowToolCommand (EventHandlerCallRef nextHandler
,
242 HICommand commandStruct
;
245 GetEventParameter (theEvent
, kEventParamDirectObject
,
246 typeHICommand
, NULL
, sizeof(HICommand
),
247 NULL
, &commandStruct
);
249 theCommandID
= commandStruct
.commandID
;
251 if(theCommandID
< toolPixMaps
) {
252 bx_tool_pixmap
[theCommandID
].f();
255 return noErr
; // Report success
258 pascal OSStatus
CEvtHandleWindowToolUpdate (EventHandlerCallRef nextHandler
,
262 theGui
->show_headerbar();
264 return noErr
; // Report success
267 pascal OSStatus
CEvtHandleWindowBackdropUpdate (EventHandlerCallRef nextHandler
,
274 GetEventParameter (theEvent
, kEventParamDirectObject
, typeWindowRef
,
275 NULL
, sizeof(WindowRef
), NULL
, &myWindow
);
277 GetWindowPortBounds(myWindow
, &box
);
278 BackColor(blackColor
);
281 return noErr
; // Report success
284 // Translate MouseDowns in a handled window into Bochs events
285 // Main ::HANDLE_EVENTS will feed all mouse updates to Bochs
286 pascal OSStatus
CEvtHandleWindowEmulatorClick (EventHandlerCallRef nextHandler
,
291 GetEventParameter (theEvent
, kEventParamKeyModifiers
, typeUInt32
,
292 NULL
, sizeof(UInt32
), NULL
, &keyModifiers
);
294 //if (!IsWindowActive(win))
296 // SelectWindow(win);
299 if (keyModifiers
& cmdKey
)
300 mouse_button_state
|= 0x02;
302 mouse_button_state
|= 0x01;
304 return noErr
; // Report success
307 pascal OSStatus
CEvtHandleWindowEmulatorUpdate (EventHandlerCallRef nextHandler
,
312 Pattern qdBlackPattern
;
315 GetEventParameter (theEvent
, kEventParamDirectObject
, typeWindowRef
,
316 NULL
, sizeof(WindowRef
), NULL
, &myWindow
);
318 GetWindowPortBounds(myWindow
, &box
);
319 DEV_vga_redraw_area(box
.left
, box
.top
, box
.right
, box
.bottom
);
321 return noErr
; // Report success
324 pascal OSStatus
CEvtHandleWindowEmulatorKeys (EventHandlerCallRef nextHandler
,
329 OSStatus outStatus
= eventNotHandledErr
;
331 kind
= GetEventKind(theEvent
);
334 case kEventRawKeyDown
:
335 case kEventRawKeyRepeat
:
336 outStatus
= HandleKey(theEvent
, BX_KEY_PRESSED
);
339 outStatus
= HandleKey(theEvent
, BX_KEY_RELEASED
);
347 // This stuff does work... it gets called, but converting the record
348 // and then calling AEProcessAppleEvent consistently results in noOutstandingHLE(err result -608)
349 // And its going to take more work to get RunApplicationLoop to work...
350 pascal OSStatus
CEvtHandleApplicationAppleEvent (EventHandlerCallRef nextHandler
,
354 EventRecord eventRec
;
356 fprintf(stderr
, "# Carbon apple event handler called\n");
357 if(ConvertEventRefToEventRecord(theEvent
, &eventRec
))
359 fprintf(stderr
, "# Calling AEProcessAppleEvent\n");
360 OSStatus result
= AEProcessAppleEvent(&eventRec
);
361 fprintf(stderr
, "# Received AE result: %i\n", result
);
365 BX_PANIC(("Can't convert apple event"));
367 return noErr
; // Report success
371 // Only have our application deal with mouseEvents when we catch the movement
372 pascal OSStatus
CEvtHandleApplicationMouseMoved (EventHandlerCallRef nextHandler
,
378 return eventNotHandledErr
;
381 pascal OSStatus
CEvtHandleApplicationMouseUp (EventHandlerCallRef nextHandler
,
386 GetEventParameter (theEvent
, kEventParamKeyModifiers
, typeUInt32
,
387 NULL
, sizeof(UInt32
), NULL
, &keyModifiers
);
389 if (keyModifiers
& cmdKey
)
390 mouse_button_state
&= ~0x02;
392 mouse_button_state
&= ~0x01;
394 return eventNotHandledErr
; // Don't want to eat all the mouseups
397 // Catch MouseDown's in the menubar, trigger menu browsing
398 pascal OSStatus
CEvtHandleApplicationMenuClick (EventHandlerCallRef nextHandler
,
403 WindowPtr whichWindow
;
406 GetEventParameter (theEvent
, kEventParamMouseLocation
, typeQDPoint
,
407 NULL
, sizeof(Point
), NULL
, &wheresMyMouse
);
409 part
= FindWindow(wheresMyMouse
, &whichWindow
);
411 if(part
== inMenuBar
)
413 // MenuSelect will actually trigger an event cascade,
414 // Triggering command events for any selected menu item
415 MenuSelect(wheresMyMouse
);
419 return eventNotHandledErr
; // Don't want to eat all the clicks
422 pascal OSStatus
CEvtHandleApplicationMenus (EventHandlerCallRef nextHandler
,
426 HICommand commandStruct
;
431 GetEventParameter (theEvent
, kEventParamDirectObject
,
432 typeHICommand
, NULL
, sizeof(HICommand
),
433 NULL
, &commandStruct
);
435 switch(commandStruct
.commandID
)
437 case kHICommandAbout
:
439 DialogRef aboutDialog
;
440 DialogItemIndex index
;
441 CFStringRef cf_version
;
443 sprintf(version
, "Bochs x86 Emulator version %s (MacOS X port)", VER_STRING
);
444 cf_version
= CFStringCreateWithCString(NULL
, version
, kCFStringEncodingASCII
);
446 AlertStdCFStringAlertParamRec aboutParam
= {0};
447 aboutParam
.version
= kStdCFStringAlertVersionOne
;
448 aboutParam
.position
= kWindowDefaultPosition
;
449 aboutParam
.defaultButton
= kAlertStdAlertOKButton
;
454 NULL
, /* can be NULL */
455 &aboutParam
, /* can be NULL */
460 NULL
, /* can be NULL */
462 CFRelease(cf_version
);
482 if (IsWindowVisible(toolwin
))
488 case kCommandMenuBar
:
495 case kCommandFullScreen
:
496 if (IsWindowVisible(toolwin
) || menubarVisible
)
500 if (IsWindowVisible(toolwin
))
507 if (!IsWindowVisible(toolwin
))
513 // Codewarrior programatic console that isn't available under Carbon without Codewarrior
515 if (IsWindowVisible(SouixWin))
521 case kCommandSnapshot
:
522 bx_tool_pixmap
[SNAPSHOT_TOOL_BUTTON
].f();
526 bx_tool_pixmap
[RESET_TOOL_BUTTON
].f();
530 bx_tool_pixmap
[COPY_TOOL_BUTTON
].f();
533 case kHICommandPaste
:
534 bx_tool_pixmap
[PASTE_TOOL_BUTTON
].f();
538 return noErr
; // Report success
543 StopAlert(200, NULL
);
546 void InitToolbox(void)
549 // gQuitFlag = false;
554 // Our handler gets called... but I can't AEProcesAppleEvent successfully upon it?
555 EventTypeSpec appleEvent
= { kEventClassAppleEvent
, kEventAppleEvent
};
556 InstallApplicationEventHandler(NewEventHandlerUPP(CEvtHandleApplicationAppleEvent
),
557 1, &appleEvent
, 0, NULL
);
560 err
= AEInstallEventHandler(kCoreEventClass
, kAEQuitApplication
,
561 NewAEEventHandlerUPP(QuitAppleEventHandler
), 0, false);
566 static pascal OSErr
QuitAppleEventHandler(const AppleEvent
*appleEvt
, AppleEvent
* reply
, SInt32 refcon
)
569 BX_PANIC(("User terminated"));
573 void CreateTile(void)
579 long theRowBytes
= ((((long) (vga_bpp
==24?32:(((vga_bpp
+1)>>1)<<1)) * ((long) (srcTileRect
.right
-srcTileRect
.left
)) + 31) >> 5) << 2);
581 // if (SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get())
583 GetGWorld(&savePort
, &saveDevice
);
587 p_f
= k1MonochromePixelFormat
;
590 p_f
= k2IndexedPixelFormat
;
593 p_f
= k4IndexedPixelFormat
;
596 p_f
= k8IndexedPixelFormat
;
599 p_f
= k16LE555PixelFormat
;
602 p_f
= k16LE565PixelFormat
;
605 //p_f = k24BGRPixelFormat;
608 p_f
= k32ARGBPixelFormat
;//k32BGRAPixelFormat;
612 BX_ASSERT((gMyBuffer
= (Ptr
)malloc(theRowBytes
* (srcTileRect
.bottom
- srcTileRect
.top
))) != NULL
);
613 err
= NewGWorldFromPtr(&gOffWorld
, p_f
,
614 &srcTileRect
, vga_bpp
>8 ? NULL
: gCTable
, NULL
, keepLocal
, gMyBuffer
, theRowBytes
);
615 if (err
!= noErr
|| gOffWorld
== NULL
)
616 BX_PANIC(("mac: can't create gOffWorld; err=%hd", err
));
618 SetGWorld(gOffWorld
, NULL
);
619 RGBForeColor(&black
);
620 RGBBackColor(&white
);
622 gTile
= GetGWorldPixMap(gOffWorld
);
626 NoPurgePixels(gTile
);
627 if (!LockPixels(gTile
))
628 BX_ERROR(("mac: can't LockPixels gTile"));
629 if ((**gTile
).pixelType
!= RGBDirect
&& (**gTile
).pmTable
!= gCTable
)
631 DisposeCTable(gCTable
);
632 gCTable
= (**gTile
).pmTable
;
635 (**gCTable
).ctFlags
|= 0x4000; //use palette manager indexes
636 CTabChanged(gCTable
);
639 BX_PANIC(("mac: can't create gTile"));
641 SetGWorld(savePort
, saveDevice
);
646 gTile = CreatePixMap(0, 0, srcTileRect.right, srcTileRect.bottom, 8, gCTable);
648 BX_PANIC(("mac: can't create gTile"));
652 void CreateMenus(void)
656 menu
= GetNewMBar(rMBarID
); // get our menus from resource
663 BX_PANIC(("can't create menu"));
665 SetMenuItemCommandID (GetMenuRef(mApple
), iAbout
, kHICommandAbout
);
666 SetMenuItemCommandID (GetMenuRef(mFile
), iQuit
, kHICommandQuit
);
667 SetMenuItemCommandID (GetMenuRef(mEdit
), iCopy
, kHICommandCopy
);
668 SetMenuItemCommandID (GetMenuRef(mEdit
), iPaste
, kHICommandPaste
);
669 SetMenuItemCommandID (GetMenuRef(mBochs
), iFloppy
, kCommandFloppy
);
670 SetMenuItemCommandID (GetMenuRef(mBochs
), iCursor
, kCommandCursor
);
671 SetMenuItemCommandID (GetMenuRef(mBochs
), iTool
, kCommandTool
);
672 SetMenuItemCommandID (GetMenuRef(mBochs
), iMenuBar
, kCommandMenuBar
);
673 SetMenuItemCommandID (GetMenuRef(mBochs
), iFullScreen
, kCommandFullScreen
);
674 SetMenuItemCommandID (GetMenuRef(mBochs
), iSnapshot
, kCommandSnapshot
);
675 SetMenuItemCommandID (GetMenuRef(mBochs
), iReset
, kCommandReset
);
677 DisableMenuItem(GetMenuRef(mEdit
), iUndo
);
678 DisableMenuItem(GetMenuRef(mEdit
), iCut
);
679 DisableMenuItem(GetMenuRef(mEdit
), iClear
);
680 DisableMenuItem(GetMenuRef(mBochs
), iFloppy
);
682 EventTypeSpec commandEvents
= {kEventClassCommand
, kEventCommandProcess
};
683 EventTypeSpec menuEvents
= {kEventClassMouse
, kEventMouseDown
};
684 InstallApplicationEventHandler(NewEventHandlerUPP(CEvtHandleApplicationMenus
),
685 1, &commandEvents
, 0, NULL
);
686 InstallApplicationEventHandler(NewEventHandlerUPP(CEvtHandleApplicationMenuClick
),
687 1, &menuEvents
, 0, NULL
);
690 void CreateWindows(void)
694 Rect positioningBounds
;
696 EventTypeSpec eventClick
= { kEventClassWindow
, kEventWindowHandleContentClick
};
697 EventTypeSpec eventUpdate
= { kEventClassWindow
, kEventWindowDrawContent
};
698 EventTypeSpec keyboardEvents
[3] = {
699 { kEventClassKeyboard
, kEventRawKeyDown
}, { kEventClassKeyboard
, kEventRawKeyRepeat
},
700 { kEventClassKeyboard
, kEventRawKeyUp
}};
701 EventTypeSpec eventCommand
= { kEventClassCommand
, kEventCommandProcess
};
703 // Create a backdrop window for fullscreen mode
704 // GetRegionBounds(GetGrayRgn(), &screenBounds);
706 // Fullscreen mode only really wants to be on one screen
707 screenBounds
= (**GetMainDevice()).gdRect
;
708 GetAvailableWindowPositioningBounds(GetMainDevice(), &positioningBounds
);
710 SetRect(&winRect
, 0, 0, screenBounds
.right
, screenBounds
.bottom
+ GetMBarHeight());
711 CreateNewWindow(kPlainWindowClass
, (kWindowStandardHandlerAttribute
), &winRect
, &backdrop
);
712 if (backdrop
== NULL
)
713 {BX_PANIC(("mac: can't create backdrop window"));}
714 InstallWindowEventHandler(backdrop
, NewEventHandlerUPP(CEvtHandleWindowBackdropUpdate
), 1, &eventUpdate
, NULL
, NULL
);
715 InstallWindowEventHandler(backdrop
, NewEventHandlerUPP(CEvtHandleWindowEmulatorClick
), 1, &eventClick
, NULL
, NULL
);
716 InstallWindowEventHandler(backdrop
, NewEventHandlerUPP(CEvtHandleWindowEmulatorKeys
), 3, keyboardEvents
, 0, NULL
);
720 gLeft
= positioningBounds
.left
;
721 gMinTop
= positioningBounds
.top
;
722 gMaxTop
= gMinTop
+ gheaderbar_y
;
724 // Create a moveable tool window for the "headerbar"
725 winRect
.top
= positioningBounds
.top
+ 10;
726 winRect
.left
= positioningBounds
.left
;
727 winRect
.bottom
= winRect
.top
+ gheaderbar_y
;
728 winRect
.right
= positioningBounds
.right
;
730 CreateNewWindow(kFloatingWindowClass
, kWindowStandardHandlerAttribute
, &winRect
, &toolwin
);
732 {BX_PANIC(("mac: can't create tool window"));}
734 // Use an Aqua-savvy window background
735 SetThemeWindowBackground(toolwin
, kThemeBrushUtilityWindowBackgroundActive
, false);
737 SetWindowTitleWithCFString (toolwin
, CFSTR("MacBochs Hardware Controls")); // Set title
738 //InstallWindowEventHandler(toolwin, NewEventHandlerUPP(CEvtHandleWindowToolClick), 1, &eventClick, NULL, NULL);
739 InstallWindowEventHandler(toolwin
, NewEventHandlerUPP(CEvtHandleWindowToolCommand
), 1, &eventCommand
, NULL
, NULL
);
740 InstallWindowEventHandler(toolwin
, NewEventHandlerUPP(CEvtHandleWindowToolUpdate
), 1, &eventUpdate
, NULL
, NULL
);
742 // Create the emulator window for full screen mode
743 winRect
.left
= (screenBounds
.right
- width
) /2; //(qd.screenBits.bounds.right - width)/2;
744 winRect
.right
= winRect
.left
+ width
;
745 winRect
.top
= (screenBounds
.bottom
- height
)/2;
746 winRect
.bottom
= winRect
.top
+ height
;
748 CreateNewWindow(kPlainWindowClass
, (kWindowStandardHandlerAttribute
), &winRect
, &fullwin
);
750 BX_PANIC(("mac: can't create fullscreen emulator window"));
752 InstallWindowEventHandler(fullwin
, NewEventHandlerUPP(CEvtHandleWindowEmulatorUpdate
), 1, &eventUpdate
, NULL
, NULL
);
753 InstallWindowEventHandler(fullwin
, NewEventHandlerUPP(CEvtHandleWindowEmulatorClick
), 1, &eventClick
, NULL
, NULL
); InstallWindowEventHandler(fullwin
, NewEventHandlerUPP(CEvtHandleWindowEmulatorKeys
), 3, keyboardEvents
, 0, NULL
);
755 // Create the regular emulator window
756 winRect
.left
= gLeft
;
757 winRect
.top
= gMaxTop
;
758 winRect
.right
= winRect
.left
+ width
;
759 winRect
.bottom
= winRect
.top
+ height
;
761 CreateNewWindow(kDocumentWindowClass
,
762 (kWindowStandardHandlerAttribute
| kWindowCollapseBoxAttribute
),
765 BX_PANIC(("mac: can't create emulator window"));
767 SetWindowTitleWithCFString (win
, CFSTR("MacBochs x86 PC")); // Set title
768 InstallWindowEventHandler(win
, NewEventHandlerUPP(CEvtHandleWindowEmulatorUpdate
), 1, &eventUpdate
, NULL
, NULL
);
769 InstallWindowEventHandler(win
, NewEventHandlerUPP(CEvtHandleWindowEmulatorClick
), 1, &eventClick
, NULL
, NULL
);
770 InstallWindowEventHandler(win
, NewEventHandlerUPP(CEvtHandleWindowEmulatorKeys
), 3, keyboardEvents
, 0, NULL
);
772 // Group the fullscreen and backdrop windows together, since they also share the same click
773 // event handler they will effectively act as a single window for layering and events
775 CreateWindowGroup((kWindowGroupAttrLayerTogether
| kWindowGroupAttrSharedActivation
), &fullwinGroup
);
776 SetWindowGroupName(fullwinGroup
, CFSTR("net.sourceforge.bochs.windowgroups.fullscreen"));
778 // This *can't* be the right way, then again groups aren't yet the right way
779 // For the life of me I couldn't find a right way of making sure my created group stayed
780 // below the layer of Floating Windows. But with the windows we have there's no current
781 // harm from making it part of the same group.
782 SetWindowGroup(toolwin
, fullwinGroup
);
783 SetWindowGroup(fullwin
, fullwinGroup
);
784 SetWindowGroup(backdrop
, fullwinGroup
);
786 RepositionWindow(win
, NULL
, kWindowCenterOnMainScreen
);
793 SetPortWindowPort(win
);
798 // Called from gui.cc, once upon program startup, to allow for the
799 // specific GUI code (X11, BeOS, ...) to be initialized.
801 // argc, argv: not used right now, but the intention is to pass native GUI
802 // specific options from the command line. (X11 options, BeOS options,...)
804 // tilewidth, tileheight: for optimization, graphics_tile_update() passes
805 // only updated regions of the screen to the gui code to be redrawn.
806 // These define the dimensions of a region (tile).
807 // headerbar_y: A headerbar (toolbar) is display on the top of the
808 // VGA window, showing floppy status, and other information. It
809 // always assumes the width of the current VGA mode width, but
810 // it's height is defined by this parameter.
812 void bx_carbon_gui_c::specific_init(int argc
, char **argv
, unsigned tilewidth
, unsigned tileheight
,
813 unsigned headerbar_y
)
823 gheaderbar_y
= headerbar_y
+ TOOL_MARGIN_SPACE
+ TOOL_MARGIN_SPACE
;
827 gCTable
= GetCTable(128);
828 BX_ASSERT (gCTable
!= NULL
);
829 CTabChanged(gCTable
); //(*gCTable)->ctSeed = GetCTSeed();
830 SetRect(&srcTileRect
, 0, 0, tilewidth
, tileheight
);
832 for(i
=0; i
<256; i
++) {
836 CreateVGAFont(vga_charmap
);
840 EventTypeSpec mouseUpEvent
= { kEventClassMouse
, kEventMouseUp
};
841 EventTypeSpec mouseMoved
[2] = { { kEventClassMouse
, kEventMouseMoved
},
842 { kEventClassMouse
, kEventMouseDragged
} };
843 InstallApplicationEventHandler(NewEventHandlerUPP(CEvtHandleApplicationMouseUp
),
844 1, &mouseUpEvent
, 0, NULL
);
845 InstallApplicationEventHandler(NewEventHandlerUPP(CEvtHandleApplicationMouseMoved
),
846 2, mouseMoved
, 0, NULL
);
848 if (GetCurrentProcess(&gProcessSerNum
) == noErr
)
849 SetFrontProcess(&gProcessSerNum
);
853 // redirect notify callback to X11 specific code
854 SIM
->get_notify_callback(&old_callback
, &old_callback_arg
);
855 SIM
->set_notify_callback(CarbonSiminterfaceCallback
, NULL
);
860 // loads keymap for x11
861 if (SIM
->get_param_bool(BXPN_KBD_USEMAPPING
)->get()) {
862 bx_keymap
.loadKeymap(NULL
); // I have no function to convert X windows symbols
868 // Handles keyboard-related events.
870 OSStatus
HandleKey(EventRef theEvent
, Bit32u keyState
)
877 static UInt32 transState
= 0;
879 status
= GetEventParameter (theEvent
,
880 kEventParamKeyModifiers
,
882 sizeof(UInt32
), NULL
,
886 status
= GetEventParameter (theEvent
,
889 sizeof(UInt32
), NULL
,
894 // key = event->message & charCodeMask;
896 // Let our menus process command keys
897 if(modifiers
& cmdKey
)
899 status
= eventNotHandledErr
;
903 /* if (modifiers & shiftKey)
904 DEV_kbd_gen_scancode(BX_KEY_SHIFT_L | keyState);
905 if (modifiers & controlKey)
906 DEV_kbd_gen_scancode(BX_KEY_CTRL_L | keyState);
907 if (modifiers & optionKey)
908 DEV_kbd_gen_scancode(BX_KEY_ALT_L | keyState);*/
910 // key = (event->message & keyCodeMask) >> 8;
912 trans
= KeyTranslate(KCHR
, key
, &transState
);
913 if ((trans
== BX_KEY_PRINT
) && ((oldMods
& optionKey
) || (oldMods
& rightOptionKey
)))
914 trans
= BX_KEY_ALT_SYSREQ
;
915 if ((trans
== BX_KEY_PAUSE
) && ((oldMods
& controlKey
) || (oldMods
& rightControlKey
)))
916 trans
= BX_KEY_CTRL_BREAK
;
917 // KeyTranslate maps Mac virtual key codes to any type of character code
918 // you like (in this case, Bochs key codes). Much nicer than a huge switch
922 DEV_kbd_gen_scancode(trans
| keyState
);
924 /* if (modifiers & shiftKey)
925 DEV_kbd_gen_scancode(BX_KEY_SHIFT_L | BX_KEY_RELEASED);
926 if (modifiers & controlKey)
927 DEV_kbd_gen_scancode(BX_KEY_CTRL_L | BX_KEY_RELEASED);
928 if (modifiers & optionKey)
929 DEV_kbd_gen_scancode(BX_KEY_ALT_L | BX_KEY_RELEASED);*/
937 BX_CPP_INLINE
void ResetPointer(void)
939 // this appears to work well, especially when combined with
940 // mouse processing on the MouseMoved events
941 if(CGWarpMouseCursorPosition(CGPointMake(scrCenter
.h
, scrCenter
.v
)))
943 fprintf(stderr
, "# Failed to warp cursor");
949 // Called periodically (vga_update_interval in .bochsrc) so the
950 // the gui code can poll for keyboard, mouse, and other
953 void bx_carbon_gui_c::handle_events(void)
958 EventModifiers newMods
;
962 curstate
= mouse_button_state
; //so we can compare the old and the new mouse state
964 if (WaitNextEvent(everyEvent
, &event
, SLEEP_TIME
, NULL
))
969 // This event is just redundant
972 // These events are all covered by installed carbon event handlers
982 // floppyA_handler();
985 case kHighLevelEvent
:
986 // fprintf(stderr, "# Classic apple event handler called\n");
987 AEProcessAppleEvent(&event
);
988 show_headerbar(); // Update if necessary (example, clipboard change)
995 else if (oldMods
!= (newMods
= (event
.modifiers
& 0xfe00)))
997 if ((newMods
^ oldMods
) & shiftKey
)
998 DEV_kbd_gen_scancode(BX_KEY_SHIFT_L
| ((newMods
& shiftKey
)?BX_KEY_PRESSED
:BX_KEY_RELEASED
));
999 if ((newMods
^ oldMods
) & alphaLock
)
1000 DEV_kbd_gen_scancode(BX_KEY_CAPS_LOCK
| ((newMods
& alphaLock
)?BX_KEY_PRESSED
:BX_KEY_RELEASED
));
1001 if ((newMods
^ oldMods
) & optionKey
)
1002 DEV_kbd_gen_scancode(BX_KEY_ALT_L
| ((newMods
& optionKey
)?BX_KEY_PRESSED
:BX_KEY_RELEASED
));
1003 if ((newMods
^ oldMods
) & controlKey
)
1004 DEV_kbd_gen_scancode(BX_KEY_CTRL_L
| ((newMods
& controlKey
)?BX_KEY_PRESSED
:BX_KEY_RELEASED
));
1005 if ((newMods
^ oldMods
) & rightShiftKey
)
1006 DEV_kbd_gen_scancode(BX_KEY_SHIFT_R
| ((newMods
& rightShiftKey
)?BX_KEY_PRESSED
:BX_KEY_RELEASED
));
1007 if ((newMods
^ oldMods
) & rightOptionKey
)
1008 DEV_kbd_gen_scancode(BX_KEY_ALT_R
| ((newMods
& rightOptionKey
)?BX_KEY_PRESSED
:BX_KEY_RELEASED
));
1009 if ((newMods
^ oldMods
) & rightControlKey
)
1010 DEV_kbd_gen_scancode(BX_KEY_CTRL_R
| ((newMods
& rightControlKey
)?BX_KEY_PRESSED
:BX_KEY_RELEASED
));
1015 // Only update mouse if we're not in the dock
1016 // and we are the frontmost app.
1017 ProcessSerialNumber frontProcessSerNum
;
1018 Boolean isSameProcess
;
1020 GetFrontProcess(&frontProcessSerNum
);
1021 SameProcess(&frontProcessSerNum
, &gProcessSerNum
, &isSameProcess
);
1023 if(isSameProcess
&& !IsWindowCollapsed(win
))
1026 SetPortWindowPort(win
);
1030 if(menubarVisible
&& cursorVisible
)
1032 // Don't track the mouse if we're working with the main window
1033 // and we're outside the window
1035 (mousePt
.v
< 0 || mousePt
.v
> height
|| mousePt
.h
< 0 || mousePt
.h
> width
) &&
1036 (prevPt
.v
< 0 || prevPt
.v
> height
|| prevPt
.h
< 0 || prevPt
.h
> width
))
1041 // Limit mouse action to window
1042 // Grr, any better ways to sync host and bochs cursor?
1043 if(mousePt.h < 0) { mousePt.h = 0; }
1044 else if(mousePt.h > width) { mousePt.h = width; }
1045 if(mousePt.v < 0) { mousePt.v = 0; }
1046 else if(mousePt.v > height) { mousePt.v = height; }
1050 //if mouse has moved, or button has changed state
1051 if (mouseMoved
|| (curstate
!= mouse_button_state
))
1055 CGMouseDelta CGdX
, CGdY
;
1056 CGGetLastMouseDelta(&CGdX
, &CGdY
);
1058 dy
= - CGdY
; // Windows has an opposing grid
1066 DEV_mouse_motion(dx
, dy
, mouse_button_state
);
1068 if (!cursorVisible
&& mouseMoved
)
1070 SetPt(&scrCenter
, 300, 240);
1071 LocalToGlobal(&scrCenter
);
1072 ResetPointer(); //next getmouse should be 300, 240
1073 SetPt(&mousePt
, 300, 240);
1087 // Called periodically, requesting that the gui code flush all pending
1088 // screen update requests.
1090 void bx_carbon_gui_c::flush(void)
1092 // an opportunity to make the Window Manager happy.
1093 // not needed on the macintosh....
1095 // Unless you don't want to needlessly update the dock icon
1096 // umpteen zillion times a second for each tile.
1097 // A further note, UpdateCollapsedWindowDockTile is not
1098 // recommended for animation. Setup like this my performance
1099 // seems reasonable for little fuss.
1100 if(windowUpdatesPending
)
1102 if(IsWindowCollapsed(win
))
1104 UpdateCollapsedWindowDockTile(win
);
1106 if(last_screen_state
!= screen_state
)
1108 last_screen_state
= screen_state
;
1112 windowUpdatesPending
= false;
1118 // Called to request that the VGA region is cleared. Don't
1119 // clear the area that defines the headerbar.
1121 void bx_carbon_gui_c::clear_screen(void)
1125 SetPortWindowPort(win
);
1127 RGBForeColor(&black
);
1128 RGBBackColor(&white
);
1129 GetWindowPortBounds(win
, &r
);
1132 windowUpdatesPending
= true;
1139 // Called in a VGA text mode, to update the screen with
1142 // old_text: array of character/attributes making up the contents
1143 // of the screen from the last call. See below
1144 // new_text: array of character/attributes making up the current
1145 // contents, which should now be displayed. See below
1147 // format of old_text & new_text: each is tm_info.line_offset*text_rows
1148 // bytes long. Each character consists of 2 bytes. The first by is
1149 // the character value, the second is the attribute byte.
1151 // cursor_x: new x location of cursor
1152 // cursor_y: new y location of cursor
1153 // tm_info: this structure contains information for additional
1154 // features in text mode (cursor shape, line offset,...)
1156 void bx_carbon_gui_c::text_update(Bit8u
*old_text
, Bit8u
*new_text
,
1157 unsigned long cursor_x
, unsigned long cursor_y
,
1158 bx_vga_tminfo_t tm_info
)
1160 unsigned char cAttr
, cChar
;
1162 RGBColor fgColor
, bgColor
;
1163 GrafPtr oldPort
, savePort
;
1164 GDHandle saveDevice
;
1165 GrafPtr winGrafPtr
= GetWindowPort(win
);
1167 Bit8u
*old_line
, *new_line
;
1168 unsigned int curs
, hchars
, offset
, rows
, x
, xc
, y
, yc
;
1169 bx_bool forceUpdate
= 0, blink_mode
, blink_state
;
1170 static unsigned prev_cursor_x
=0;
1171 static unsigned prev_cursor_y
=0;
1173 screen_state
= TEXT_MODE
;
1175 // first check if the screen needs to be redrawn completely
1176 blink_mode
= (tm_info
.blink_flags
& BX_TEXT_BLINK_MODE
) > 0;
1177 blink_state
= (tm_info
.blink_flags
& BX_TEXT_BLINK_STATE
) > 0;
1179 if (tm_info
.blink_flags
& BX_TEXT_BLINK_TOGGLE
)
1182 if (charmap_updated
== 1) {
1183 CreateVGAFont(vga_charmap
);
1184 charmap_updated
= 0;
1188 // invalidate character at previous and new cursor location
1189 if((prev_cursor_y
< text_rows
) && (prev_cursor_x
< text_cols
)) {
1190 curs
= prev_cursor_y
* tm_info
.line_offset
+ prev_cursor_x
* 2;
1191 old_text
[curs
] = ~new_text
[curs
];
1193 if((tm_info
.cs_start
<= tm_info
.cs_end
) && (tm_info
.cs_start
< font_height
) &&
1194 (cursor_y
< text_rows
) && (cursor_x
< text_cols
)) {
1195 curs
= cursor_y
* tm_info
.line_offset
+ cursor_x
* 2;
1196 old_text
[curs
] = ~new_text
[curs
];
1203 SetPortWindowPort(win
);
1209 new_line
= new_text
;
1210 old_line
= old_text
;
1212 offset
= y
* tm_info
.line_offset
;
1214 if (forceUpdate
|| (old_text
[0] != new_text
[0])
1215 || (old_text
[1] != new_text
[1])) {
1216 cChar
= new_text
[0];
1217 cAttr
= new_text
[1];
1220 cAttr
= new_text
[1] & 0x7F;
1221 if (!blink_state
&& (new_text
[1] & 0x80))
1222 cAttr
= (cAttr
& 0x70) | (cAttr
>> 4);
1224 if (offset
== curs
) {
1225 cAttr
= (cAttr
>> 4) | (cAttr
<< 4);
1228 if (SIM
->get_param_bool(BXPN_PRIVATE_COLORMAP
)->get()) {
1229 PmForeColor(new_text
[1] & 0x0F);
1231 PmBackColor((new_text
[1] & 0x70) >> 4);
1232 if (!blink_state
&& (new_text
[1] & 0x80))
1233 PmForeColor((new_text
[1] & 0x70) >> 4);
1235 PmBackColor((new_text
[1] & 0xF0) >> 4);
1238 fgColor
= (**gCTable
).ctTable
[new_text
[1] & 0x0F].rgb
;
1239 bgColor
= (**gCTable
).ctTable
[(new_text
[1] & 0xF0) >> 4].rgb
;
1241 RGBForeColor(&fgColor
);
1242 RGBBackColor(&bgColor
);
1245 xc
= x
* font_width
;
1246 yc
= y
* font_height
;
1248 SetRect(&destRect
, xc
, yc
,
1249 xc
+font_width
, yc
+font_height
);
1251 CopyBits(vgafont
[cChar
], WINBITMAP(win
),
1252 &srcTextRect
, &destRect
, srcCopy
, NULL
);
1254 if ((theError
= QDError()) != noErr
)
1255 BX_ERROR(("mac: CopyBits returned %hd", theError
));
1263 new_text
= new_line
+ tm_info
.line_offset
;
1264 old_text
= old_line
+ tm_info
.line_offset
;
1267 //previous cursor position
1268 prev_cursor_x
= cursor_x
;
1269 prev_cursor_y
= cursor_y
;
1273 windowUpdatesPending
= true;
1276 int bx_carbon_gui_c::get_clipboard_text(Bit8u
**bytes
, Bit32s
*nbytes
)
1279 ScrapFlavorFlags theScrapFlags
;
1283 GetCurrentScrap(&theScrap
);
1285 // Make sure there is text to paste
1286 err
= GetScrapFlavorFlags(theScrap
, kScrapFlavorTypeText
, &theScrapFlags
);
1289 GetScrapFlavorSize(theScrap
, kScrapFlavorTypeText
, &theScrapSize
);
1290 *nbytes
= theScrapSize
;
1291 *bytes
= new Bit8u
[1 + *nbytes
];
1292 BX_INFO (("found %d bytes on the clipboard", *nbytes
));
1293 err
= GetScrapFlavorData(theScrap
, kScrapFlavorTypeText
, &theScrapSize
, *bytes
);
1294 BX_INFO (("first byte is 0x%02x", *bytes
[0]));
1298 BX_INFO (("No text found on clipboard..."));
1300 return (err
== noErr
);
1303 int bx_carbon_gui_c::set_clipboard_text(char *text_snapshot
, Bit32u len
)
1307 // Clear out the existing clipboard
1308 ClearCurrentScrap();
1310 GetCurrentScrap(&theScrap
);
1311 PutScrapFlavor (theScrap
, kScrapFlavorTypeText
, kScrapFlavorMaskNone
, len
, text_snapshot
);
1316 // ::PALETTE_CHANGE()
1318 // Allocate a color in the native GUI, for this color, and put
1319 // it in the colormap location 'index'.
1320 // returns: 0=no screen update needed (color map change has direct effect)
1321 // 1=screen updated needed (redraw using current colormap)
1323 bx_bool
bx_carbon_gui_c::palette_change(unsigned index
, unsigned red
, unsigned green
, unsigned blue
)
1325 PaletteHandle thePal
, oldpal
;
1326 GDHandle saveDevice
;
1330 /* if (gOffWorld != NULL) //(SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get())
1332 GetGWorld(&savePort, &saveDevice);
1334 SetGWorld(gOffWorld, NULL);
1336 if ((**gTile
).pixelType
!= RGBDirect
)
1339 SetPortWindowPort(win
);
1341 (**gCTable
).ctTable
[index
].value
= index
;
1342 (**gCTable
).ctTable
[index
].rgb
.red
= (red
<< 8);
1343 (**gCTable
).ctTable
[index
].rgb
.green
= (green
<< 8);
1344 (**gCTable
).ctTable
[index
].rgb
.blue
= (blue
<< 8);
1346 SetEntries(index
, index
, (**gCTable
).ctTable
);
1348 CTabChanged(gCTable
);
1352 /* if (gOffWorld != NULL) //(SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get())
1353 SetGWorld(savePort, saveDevice);*/
1354 if (SIM
->get_param_bool(BXPN_PRIVATE_COLORMAP
)->get())
1357 thePal
= NewPalette(index
, gCTable
, pmTolerant
, 0x5000);
1358 oldpal
= GetPalette(win
);
1360 SetPalette(win
, thePal
, false);
1361 SetPalette(fullwin
, thePal
, false);
1362 SetPalette(hidden
, thePal
, false);
1366 return((**gTile
).pixelType
!= RGBDirect
);
1370 // ::GRAPHICS_TILE_UPDATE()
1372 // Called to request that a tile of graphics be drawn to the
1373 // screen, since info in this region has changed.
1375 // tile: array of 8bit values representing a block of pixels with
1376 // dimension equal to the 'tilewidth' & 'tileheight' parameters to
1377 // ::specific_init(). Each value specifies an index into the
1378 // array of colors you allocated for ::palette_change()
1379 // x0: x origin of tile
1380 // y0: y origin of tile
1382 // note: origin of tile and of window based on (0,0) being in the upper
1383 // left of the window.
1385 void bx_carbon_gui_c::graphics_tile_update(Bit8u
*tile
, unsigned x0
, unsigned y0
)
1390 GDHandle saveDevice
;
1394 /* if (gOffWorld != NULL)
1396 GetGWorld(&savePort, &saveDevice);
1398 SetGWorld(gOffWorld, NULL);
1401 screen_state
= GRAPHIC_MODE
;
1403 // SetPort - Otherwise an update happens to the headerbar and ooomph, we're drawing weirdly on the screen
1405 SetPortWindowPort(win
);
1406 destRect
= srcTileRect
;
1407 OffsetRect(&destRect
, x0
, y0
);
1409 //(**gTile).baseAddr = (Ptr)tile;
1410 if ((theError
= LockPortBits(gOffWorld
)) != noErr
)
1411 BX_PANIC(("mac: LockPortBits returned %hd", theError
));
1412 if ((theBaseAddr
= GetPixBaseAddr(gTile
)) == NULL
)
1413 BX_PANIC(("mac: gTile has NULL baseAddr (offscreen buffer purged)"));
1414 else if (vga_bpp
== 24 || vga_bpp
== 32)
1416 for (unsigned iY
= 0; iY
< (srcTileRect
.bottom
-srcTileRect
.top
); iY
++)
1418 Bit8u
*iA
= ((Bit8u
*)theBaseAddr
) + iY
* GetPixRowBytes(gTile
);
1419 for (unsigned iX
= 0; iX
< (srcTileRect
.right
-srcTileRect
.left
); iX
++)
1421 iA
[iX
*4 + 3] = tile
[((srcTileRect
.right
-srcTileRect
.left
)*iY
+iX
)*(vga_bpp
>>3)];
1422 iA
[iX
*4 + 2] = tile
[((srcTileRect
.right
-srcTileRect
.left
)*iY
+iX
)*(vga_bpp
>>3) + 1];
1423 iA
[iX
*4 + 1] = tile
[((srcTileRect
.right
-srcTileRect
.left
)*iY
+iX
)*(vga_bpp
>>3) + 2];
1424 iA
[iX
*4] = vga_bpp
== 24 ? 0 : tile
[((srcTileRect
.right
-srcTileRect
.left
)*iY
+iX
)*4 + 3];
1429 BlockMoveData(tile
, theBaseAddr
, (srcTileRect
.bottom
-srcTileRect
.top
) * GetPixRowBytes(gTile
));
1430 if ((theError
= UnlockPortBits(gOffWorld
)) != noErr
)
1431 BX_ERROR(("mac: UnlockPortBits returned %hd", theError
));
1432 RGBForeColor(&black
);
1433 RGBBackColor(&white
);
1434 CopyBits(GetPortBitMapForCopyBits(gOffWorld
), WINBITMAP(win
),
1435 &srcTileRect
, &destRect
, srcCopy
, NULL
);
1436 if ((theError
= QDError()) != noErr
)
1437 BX_ERROR(("mac: CopyBits returned %hd", theError
));
1439 windowUpdatesPending
= true;
1440 /* if (gOffWorld != NULL)
1441 SetGWorld(savePort, saveDevice);*/
1446 // ::DIMENSION_UPDATE()
1448 // Called when the VGA mode changes it's X,Y dimensions.
1449 // Resize the window to this size, but you need to add on
1450 // the height of the headerbar to the Y value.
1452 // x: new VGA x size
1453 // y: new VGA y size (add headerbar_y parameter from ::specific_init().
1454 // fheight: new VGA character height in text mode
1455 // fwidth : new VGA character width in text mode
1456 // bpp : bits per pixel in graphics mode
1458 void bx_carbon_gui_c::dimension_update(unsigned x
, unsigned y
, unsigned fheight
, unsigned fwidth
, unsigned bpp
)
1460 if ((bpp
!= 1) && (bpp
!= 2) && (bpp
!= 4) && (bpp
!= 8) && (bpp
!= 15) && (bpp
!= 16) && (bpp
!= 24) && (bpp
!= 32)) {
1461 BX_PANIC(("%d bpp graphics mode not supported yet", bpp
));
1466 DisposeGWorld(gOffWorld
);
1467 if ((gCTable
== NULL
) || (*gCTable
== NULL
) || (*gCTable
== (void *)-1))
1468 gCTable
= GetCTable(128);
1474 text_cols
= x
/ fwidth
;
1475 text_rows
= y
/ fheight
;
1476 if(fwidth
!= font_width
|| fheight
!= font_height
) {
1477 font_width
= fwidth
;
1478 font_height
= fheight
;
1479 CreateVGAFont(vga_charmap
);
1483 if (x
!= width
|| y
!= height
)
1486 SizeWindow(win
, x
, y
, false);
1490 // Animates the resizing, cute, but gratuitous
1492 GetWindowBounds(win
, kWindowStructureRgn
, &frame
);
1493 GetWindowPortBounds(win
, &box
);
1494 frame
.right
= frame
.right
- box
.right
+ x
;
1495 frame
.bottom
= frame
.bottom
- box
.bottom
+ y
;
1497 TransitionWindow(win
, kWindowSlideTransitionEffect
, kWindowResizeTransitionAction
, &frame
);
1499 SizeWindow(fullwin
, x
, y
, false);
1500 SizeWindow(hidden
, x
, y
, false);
1505 windowUpdatesPending
= true;
1513 // ::CREATE_BITMAP()
1515 // Create a monochrome bitmap of size 'xdim' by 'ydim', which will
1516 // be drawn in the headerbar. Return an integer ID to the bitmap,
1517 // with which the bitmap can be referenced later.
1519 // bmap: packed 8 pixels-per-byte bitmap. The pixel order is:
1520 // bit0 is the left most pixel, bit7 is the right most pixel.
1521 // xdim: x dimension of bitmap
1522 // ydim: y dimension of bitmap
1524 // rewritten by tim senecal to use the cicn (color icon) resources instead
1526 // We need to have a cicn resource for each and every call to create_bitmap
1527 // If this fails, it is probably because more icons were added to bochs and
1528 // we need to create more cicns in bochs.r to match with create_bitmap calls in
1530 unsigned bx_carbon_gui_c::create_bitmap(const unsigned char *bmap
, unsigned xdim
, unsigned ydim
)
1533 unsigned char *data
;
1534 long row_bytes
, bytecount
;
1536 bx_cicn
[numPixMaps
] = GetCIcon(numPixMaps
+128);
1537 // BX_ASSERT(bx_cicn[numPixMaps]);
1541 return(numPixMaps
-1);
1545 // ::HEADERBAR_BITMAP()
1547 // Called to install a bitmap in the bochs headerbar (toolbar).
1549 // bmap_id: will correspond to an ID returned from
1550 // ::create_bitmap(). 'alignment' is either BX_GRAVITY_LEFT
1551 // or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
1552 // available leftmost or rightmost space.
1553 // f: a 'C' function pointer to callback when the mouse is clicked in
1554 // the boundaries of this bitmap.
1556 unsigned bx_carbon_gui_c::headerbar_bitmap(unsigned bmap_id
, unsigned alignment
, void (*f
)(void))
1560 GetWindowPortBounds(toolwin
, &r
);
1561 int xorigin
, yorigin
= TOOL_MARGIN_SPACE
;
1562 ControlButtonContentInfo info
;
1565 hb_index
= toolPixMaps
-1;
1566 //bx_tool_pixmap[hb_index].pm = bx_pixmap[bmap_id];
1567 //bx_tool_pixmap[hb_index].cicn = bx_cicn[bmap_id];
1568 bx_tool_pixmap
[hb_index
].alignment
= alignment
;
1569 bx_tool_pixmap
[hb_index
].f
= f
;
1571 if (alignment
== BX_GRAVITY_LEFT
)
1573 bx_tool_pixmap
[hb_index
].xorigin
= bx_bitmap_left_xorigin
;
1574 bx_tool_pixmap
[hb_index
].yorigin
= TOOL_MARGIN_SPACE
;
1575 // bx_bitmap_left_xorigin += (**bx_pixmap[bmap_id]).bounds.right;
1576 bx_bitmap_left_xorigin
+= 32 + TOOL_SPACING
;
1577 xorigin
= bx_tool_pixmap
[hb_index
].xorigin
;
1581 // bx_bitmap_right_xorigin += (**bx_pixmap[bmap_id]).bounds.right;
1582 bx_bitmap_right_xorigin
+= 32;
1583 bx_tool_pixmap
[hb_index
].xorigin
= bx_bitmap_right_xorigin
;
1584 bx_tool_pixmap
[hb_index
].yorigin
= TOOL_MARGIN_SPACE
;
1585 xorigin
= r
.right
- bx_tool_pixmap
[hb_index
].xorigin
;
1586 bx_bitmap_right_xorigin
+= TOOL_SPACING
;
1589 SetRect(&destRect
, xorigin
, yorigin
, xorigin
+32, yorigin
+32);
1591 info
.contentType
= kControlContentCIconHandle
;
1592 info
.u
.cIconHandle
= bx_cicn
[bmap_id
];
1594 CreateIconControl(toolwin
, &destRect
, &info
, false, &(bx_tool_pixmap
[hb_index
].control
));
1595 SetControlCommandID(bx_tool_pixmap
[hb_index
].control
, hb_index
);
1599 // ::SHOW_HEADERBAR()
1601 // Show (redraw) the current headerbar, which is composed of
1602 // currently installed bitmaps.
1604 void bx_carbon_gui_c::show_headerbar(void)
1607 DrawControls(toolwin
);
1611 // ::REPLACE_BITMAP()
1613 // Replace the bitmap installed in the headerbar ID slot 'hbar_id',
1614 // with the one specified by 'bmap_id'. 'bmap_id' will have
1615 // been generated by ::create_bitmap(). The old and new bitmap
1616 // must be of the same size. This allows the bitmap the user
1617 // sees to change, when some action occurs. For example when
1618 // the user presses on the floppy icon, it then displays
1619 // the ejected status.
1621 // hbar_id: headerbar slot ID
1622 // bmap_id: bitmap ID
1624 void bx_carbon_gui_c::replace_bitmap(unsigned hbar_id
, unsigned bmap_id
)
1626 //bx_tool_pixmap[hbar_id].pm = bx_pixmap[bmap_id];
1627 //bx_tool_pixmap[hbar_id].cicn = bx_cicn[bmap_id];
1628 ControlButtonContentInfo info
;
1630 info
.contentType
= kControlContentCIconHandle
;
1631 info
.u
.cIconHandle
= bx_cicn
[bmap_id
];
1633 SetControlData(bx_tool_pixmap
[hbar_id
].control
,
1634 kControlEntireControl
, kControlIconContentTag
, sizeof(ControlButtonContentInfo
), &info
);
1641 // Called before bochs terminates, to allow for a graceful
1642 // exit from the native GUI mechanism.
1644 void bx_carbon_gui_c::exit(void)
1646 if (!menubarVisible
)
1647 ShowMenubar(); // Make the menubar visible again
1650 // Make the clipboard all happy before we go
1651 CallInScrapPromises();
1655 void bx_carbon_gui_c::snapshot_handler(void)
1657 PicHandle ScreenShot
;
1660 SetPortWindowPort(win
);
1662 ScreenShot
= OpenPicture(&win
->portRect
);
1664 CopyBits(&win
->portBits
, &win
->portBits
, &win
->portRect
, &win
->portRect
, srcCopy
, NULL
);
1670 HLock((Handle
)ScreenShot
);
1671 PutScrap(GetHandleSize((Handle
)ScreenShot
), 'PICT', *ScreenShot
);
1672 HUnlock((Handle
)ScreenShot
);
1674 KillPicture(ScreenShot
);
1680 // Hides the Mac mouse pointer
1686 SetPortWindowPort(win
);
1687 SetPt(&scrCenter
, 300, 240);
1688 LocalToGlobal(&scrCenter
);
1691 cursorVisible
= false;
1692 CheckMenuItem(GetMenuHandle(mBochs
), iCursor
, false);
1697 // Shows the Mac mouse pointer
1702 cursorVisible
= true;
1703 CheckMenuItem(GetMenuHandle(mBochs
), iCursor
, true);
1704 //CheckItem(GetMenuHandle(mBochs), iCursor, true);
1709 // Check the state of the emulation and use it to tell which tools are available or not.
1713 ScrapFlavorFlags theScrapFlags
;
1715 GetCurrentScrap(&theScrap
);
1717 // If keyboard mapping is on AND there is text on the clipboard enable pasting
1718 if (SIM
->get_param_bool(BXPN_KBD_USEMAPPING
)->get() &&
1719 (GetScrapFlavorFlags(theScrap
, kScrapFlavorTypeText
, &theScrapFlags
) == noErr
))
1721 EnableMenuItem(GetMenuRef(mEdit
), iPaste
);
1722 EnableControl(bx_tool_pixmap
[PASTE_TOOL_BUTTON
].control
);
1726 DisableMenuItem(GetMenuRef(mEdit
), iPaste
);
1727 DisableControl(bx_tool_pixmap
[PASTE_TOOL_BUTTON
].control
);
1730 // Currently copy and snapshot aren't available if we aren't in text mode
1731 if (screen_state
== GRAPHIC_MODE
) {
1732 DisableMenuItem(GetMenuRef(mEdit
), iCopy
);
1733 DisableMenuItem(GetMenuRef(mBochs
), iSnapshot
);
1734 DisableControl(bx_tool_pixmap
[COPY_TOOL_BUTTON
].control
);
1735 DisableControl(bx_tool_pixmap
[SNAPSHOT_TOOL_BUTTON
].control
);
1738 EnableMenuItem(GetMenuRef(mEdit
), iCopy
);
1739 EnableMenuItem(GetMenuRef(mBochs
), iSnapshot
);
1740 EnableControl(bx_tool_pixmap
[COPY_TOOL_BUTTON
].control
);
1741 EnableControl(bx_tool_pixmap
[SNAPSHOT_TOOL_BUTTON
].control
);
1744 // User control active if keys defined
1745 char *user_shortcut
;
1746 user_shortcut
= SIM
->get_param_string(BXPN_USER_SHORTCUT
)->getptr();
1747 if (user_shortcut
[0] && (strcmp(user_shortcut
, "none"))) {
1748 EnableControl(bx_tool_pixmap
[USER_TOOL_BUTTON
].control
);
1752 DisableControl(bx_tool_pixmap
[USER_TOOL_BUTTON
].control
);
1755 // Config panel only available if user has a terminal or equivalent
1756 if(isatty(STDIN_FILENO
))
1758 EnableControl(bx_tool_pixmap
[CONFIGURE_TOOL_BUTTON
].control
);
1762 DisableControl(bx_tool_pixmap
[CONFIGURE_TOOL_BUTTON
].control
);
1768 // Hides the Bochs toolbar
1772 HideWindow(toolwin
);
1776 MoveWindow(win
, gLeft
, gMinTop
, false);
1780 MoveWindow(hidden
, gLeft
, gMinTop
, false);
1783 CheckMenuItem(GetMenuHandle(mBochs
), iTool
, false);
1784 HiliteWindow(win
, true);
1789 // Shows the Bochs toolbar
1796 MoveWindow(win
, gLeft
, gMaxTop
, false);
1800 MoveWindow(hidden
, gLeft
, gMaxTop
, false);
1803 ShowWindow(toolwin
);
1804 // theGui->show_headerbar();
1805 CheckMenuItem(GetMenuHandle(mBochs
), iTool
, true);
1806 HiliteWindow(win
, true);
1811 // Hides the menubar (obviously)
1818 ShowWindow(backdrop
);
1824 menubarVisible
= false;
1825 CheckMenuItem(GetMenuHandle(mBochs
), iMenuBar
, false);
1830 // Makes the menubar visible again so other programs will display correctly.
1834 HideWindow(backdrop
);
1839 HiliteWindow(win
, true);
1843 menubarVisible
= true;
1844 CheckMenuItem(GetMenuHandle(mBochs
), iMenuBar
, true);
1849 // HideWindow(SouixWin);
1850 CheckMenuItem(GetMenuHandle(mBochs
), iConsole
, false);
1855 // ShowWindow(SouixWin);
1856 // SelectWindow(SouixWin);
1857 CheckMenuItem(GetMenuHandle(mBochs
), iConsole
, true);
1862 // Create a KCHR data structure to map Mac virtual key codes to Bochs key codes
1864 void CreateKeyMap(void)
1866 const unsigned char KCHRHeader
[258] = {
1871 const unsigned char KCHRTable
[130] = {
1884 BX_KEY_LEFT_BACKSLASH
,
1904 BX_KEY_RIGHT_BRACKET
,
1907 BX_KEY_LEFT_BRACKET
,
1913 BX_KEY_SINGLE_QUOTE
,
1928 0, // 0x36 (record button)
1929 0, // 0x37 (cmd key)
1930 0, // 0x38 (left shift)
1931 0, // 0x39 (caps lock)
1932 0, // 0x3A (left option/alt)
1933 0, // 0x3B (left ctrl)
1934 0, // 0x3C (right shift)
1935 0, // 0x3D (right option/alt)
1936 0, // 0x3E (right ctrl)
1937 0, // 0x3F (fn key -- laptops)
1939 BX_KEY_KP_DELETE
, // KP_PERIOD
1940 0, // 0x42 (move right/multiply)
1944 0, // 0x46 (move left/add)
1946 0, // 0x48 (move down/equals)
1951 0, // 0x4D (move up/divide)
1955 BX_KEY_EQUALS
, // 0x51 (kp equals)
1956 BX_KEY_KP_INSERT
, // 0x52 (kp 0)
1957 BX_KEY_KP_END
, // 0x53 (kp 1)
1958 BX_KEY_KP_DOWN
, // 0x54 (kp 2)
1959 BX_KEY_KP_PAGE_DOWN
, // 0x55 (kp 3)
1960 BX_KEY_KP_LEFT
, // 0x56 (kp 4)
1962 BX_KEY_KP_RIGHT
, // 0x58 (kp 6)
1963 BX_KEY_KP_HOME
, // 0x59 (kp 7)
1965 BX_KEY_KP_UP
, // 0x5B (kp 8)
1966 BX_KEY_KP_PAGE_UP
, // 0x5C (kp 9)
1979 BX_KEY_PRINT
, // 0x69 (print screen)
1981 BX_KEY_SCRL_LOCK
, // 0x6B (scroll lock)
1984 BX_KEY_MENU
, // 0x6E
1987 BX_KEY_PAUSE
, // 0x71 (pause)
2003 KCHR
= NewPtrClear(390);
2005 BX_PANIC(("mac: can't allocate memory for key map"));
2007 BlockMove(KCHRHeader
, KCHR
, sizeof(KCHRHeader
));
2008 BlockMove(KCHRTable
, Ptr(KCHR
+ sizeof(KCHRHeader
)), sizeof(KCHRTable
));
2013 // Create an array of PixMaps for the PC screen font
2015 void CreateVGAFont(unsigned char *vga_charmap
)
2018 unsigned char *fontData
, curPixel
;
2019 long row_bytes
, bytecount
;
2021 SetRect(&srcTextRect
, 0, 0, font_width
, font_height
);
2022 for (i
=0; i
<256; i
++)
2024 if(vgafont
[i
] != NULL
) free(vgafont
[i
]);
2025 vgafont
[i
] = CreateBitMap(font_width
, font_height
);
2026 row_bytes
= (*(vgafont
[i
])).rowBytes
;
2027 bytecount
= row_bytes
* font_height
;
2028 fontData
= (unsigned char *)NewPtrClear(bytecount
);
2030 for (x
=0; x
<font_height
; x
++)
2032 //curPixel = ~(bx_vgafont[i].data[x]);
2033 curPixel
= (vga_charmap
[(i
*32) + x
]);
2034 fontData
[x
*row_bytes
] = curPixel
;
2035 fontData
[x
*row_bytes
+ 1] = curPixel
<< 7;
2037 vgafont
[i
]->baseAddr
= Ptr(fontData
);
2042 // Allocate a new bitmap and fill in the fields with appropriate
2045 BitMap
*CreateBitMap(unsigned width
, unsigned height
)
2050 row_bytes
= ((width
+ 31) >> 5) << 2;
2051 bm
= (BitMap
*)calloc(1, sizeof(BitMap
));
2053 BX_PANIC(("mac: can't allocate memory for pixmap"));
2054 SetRect(&bm
->bounds
, 0, 0, width
, height
);
2055 bm
->rowBytes
= row_bytes
;
2056 // Quickdraw allocates a new color table by default, but we want to
2057 // use one we created earlier.
2063 // Allocate a new pixmap handle and fill in the fields with appropriate
2066 PixMapHandle CreatePixMap(unsigned left, unsigned top, unsigned width,
2067 unsigned height, unsigned depth, CTabHandle clut)
2072 row_bytes = (((long) depth * ((long) width) + 31) >> 5) << 2;
2075 BX_PANIC(("mac: can't allocate memory for pixmap"));
2076 (**pm).bounds.left = left;
2077 (**pm).bounds.top = top;
2078 (**pm).bounds.right = left+width;
2079 (**pm).bounds.bottom = top+height;
2080 (**pm).pixelSize = depth;
2081 (**pm).rowBytes = row_bytes | 0x8000;
2083 DisposeCTable((**pm).pmTable);
2084 (**pm).pmTable = clut;
2085 // Quickdraw allocates a new color table by default, but we want to
2086 // use one we created earlier.
2091 unsigned char reverse_bitorder(unsigned char b
)
2093 unsigned char ret
=0;
2095 for (unsigned i
=0; i
<8; i
++)
2097 ret
|= (b
& 0x01) << (7-i
);
2104 void bx_carbon_gui_c::mouse_enabled_changed_specific (bx_bool val
)
2108 void bx_carbon_gui_c::beep_on(float frequency
)
2111 BX_INFO(("Carbon Beep ON (frequency=%.2f)",frequency
));
2114 void bx_carbon_gui_c::beep_off()
2116 BX_INFO(("Carbon Beep OFF"));
2119 // we need to handle "ask" events so that PANICs are properly reported
2120 static BxEvent
* CarbonSiminterfaceCallback (void *theClass
, BxEvent
*event
)
2122 event
->retcode
= 0; // default return code
2124 if(event
->type
== BX_ASYNC_EVT_LOG_MSG
|| event
->type
== BX_SYNC_EVT_LOG_ASK
)
2126 DialogRef alertDialog
;
2128 CFStringRef exposition
;
2129 DialogItemIndex index
;
2130 AlertStdCFStringAlertParamRec alertParam
= {0};
2132 if(event
->u
.logmsg
.prefix
!= NULL
)
2134 title
= CFStringCreateWithCString(NULL
, event
->u
.logmsg
.prefix
, kCFStringEncodingASCII
);
2135 exposition
= CFStringCreateWithCString(NULL
, event
->u
.logmsg
.msg
, kCFStringEncodingASCII
);
2139 title
= CFStringCreateWithCString(NULL
, event
->u
.logmsg
.msg
, kCFStringEncodingASCII
);
2143 alertParam
.version
= kStdCFStringAlertVersionOne
;
2144 alertParam
.defaultText
= CFSTR("Continue");
2145 alertParam
.cancelText
= CFSTR("Quit");
2146 alertParam
.position
= kWindowDefaultPosition
;
2147 alertParam
.defaultButton
= kAlertStdAlertOKButton
;
2148 alertParam
.cancelButton
= kAlertStdAlertCancelButton
;
2150 CreateStandardAlert(
2153 exposition
, /* can be NULL */
2154 &alertParam
, /* can be NULL */
2159 NULL
, /* can be NULL */
2164 if(exposition
!= NULL
)
2166 CFRelease(exposition
);
2170 if(index
== kAlertStdAlertOKButton
)
2175 else if(index
== kAlertStdAlertCancelButton
)
2180 if(event
->u
.logmsg
.prefix
!= NULL
)
2182 BX_INFO(("Callback log: Prefix: %s", event
->u
.logmsg
.prefix
));
2184 BX_INFO(("Callback log: Message: %s", event
->u
.logmsg
.msg
));
2190 // Track down the message that exiting leaves...
2193 case BX_SYNC_EVT_TICK
:
2194 case BX_SYNC_EVT_LOG_ASK
:
2197 BX_INFO(("Callback tracing: Evt: %d (%s)", event
->type
,
2198 ((BX_EVT_IS_ASYNC(event
->type
))?"async":"sync")));
2201 if (old_callback
!= NULL
) {
2202 return (*old_callback
)(old_callback_arg
, event
);
2207 #endif /* if BX_WITH_CARBON */