2005-03-02 00:37:28 +03:00
|
|
|
/*
|
2008-01-23 02:25:15 +03:00
|
|
|
* QEMU Cocoa CG display driver
|
2007-09-17 01:08:06 +04:00
|
|
|
*
|
2008-01-23 02:25:15 +03:00
|
|
|
* Copyright (c) 2008 Mike Kronenberg
|
2007-09-17 01:08:06 +04:00
|
|
|
*
|
2005-03-02 00:37:28 +03:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
2005-03-03 01:22:43 +03:00
|
|
|
|
2005-03-02 00:37:28 +03:00
|
|
|
#import <Cocoa/Cocoa.h>
|
2011-05-29 21:42:51 +04:00
|
|
|
#include <crt_externs.h>
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2007-11-17 20:14:51 +03:00
|
|
|
#include "qemu-common.h"
|
2012-11-28 15:06:30 +04:00
|
|
|
#include "ui/console.h"
|
2013-12-04 17:08:04 +04:00
|
|
|
#include "ui/input.h"
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/sysemu.h"
|
2015-06-19 12:53:27 +03:00
|
|
|
#include "qmp-commands.h"
|
2015-06-19 12:53:27 +03:00
|
|
|
#include "sysemu/blockdev.h"
|
2005-03-03 01:22:43 +03:00
|
|
|
|
2009-12-13 02:45:40 +03:00
|
|
|
#ifndef MAC_OS_X_VERSION_10_5
|
|
|
|
#define MAC_OS_X_VERSION_10_5 1050
|
|
|
|
#endif
|
2013-04-22 14:29:49 +04:00
|
|
|
#ifndef MAC_OS_X_VERSION_10_6
|
|
|
|
#define MAC_OS_X_VERSION_10_6 1060
|
|
|
|
#endif
|
2015-05-19 11:11:18 +03:00
|
|
|
#ifndef MAC_OS_X_VERSION_10_10
|
|
|
|
#define MAC_OS_X_VERSION_10_10 101000
|
|
|
|
#endif
|
2009-12-13 02:45:40 +03:00
|
|
|
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
//#define DEBUG
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
#define COCOA_DEBUG(...) { (void) fprintf (stdout, __VA_ARGS__); }
|
2007-06-10 20:07:38 +04:00
|
|
|
#else
|
2008-01-23 02:25:15 +03:00
|
|
|
#define COCOA_DEBUG(...) ((void) 0)
|
2007-06-10 20:07:38 +04:00
|
|
|
#endif
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
#define cgrect(nsrect) (*(CGRect *)&(nsrect))
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
typedef struct {
|
|
|
|
int width;
|
|
|
|
int height;
|
|
|
|
int bitsPerComponent;
|
|
|
|
int bitsPerPixel;
|
|
|
|
} QEMUScreen;
|
|
|
|
|
|
|
|
NSWindow *normalWindow;
|
Update cocoa.m to match new DisplayState code (Samuel Benson)
Version 2 does as follows:
[1]: Corrects endianness on issues by using native BGR to RGB conversion
[2]: Uses DisplayState accessors for obtaining graphics context information,
which
[3]: Removes now unused variables, and
[4]: Allows reading of varying color modes (32bit/24/16), and converting to
native colorspace
[5]: Attempts to keep itself centered on screen (as opposed to bottom right,
which immediately goes off screen after bios load) on context changes
(window resizes)
Testing working on i386 (gentoo, Windows 2000) and PPC (debian) guests on PPC
and x86 Macs.
In regards to [4], Windows 2000 displays fine on quick tests, but on the lowest
setting I could test, 16bit color depth at 4bpp, colors are slightly off. I
used gentoo install-x86-minimal-2008.0 in framebuffer mode to test above
setting; the usual grey text is now blue, and Tux appears to be BGR shifted. I
do not know if previous code worked at such a low color setting.
Signed-off-by: Samuel Benson <qemu_ml@digitalescape.info>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6683 c046a42c-6fe2-441c-8c8c-71466251a162
2009-03-04 22:25:22 +03:00
|
|
|
static DisplayChangeListener *dcl;
|
2013-12-04 17:08:04 +04:00
|
|
|
static int last_buttons;
|
2008-01-23 02:25:15 +03:00
|
|
|
|
|
|
|
int gArgc;
|
|
|
|
char **gArgv;
|
2015-05-19 11:11:17 +03:00
|
|
|
bool stretch_video;
|
2015-06-19 12:53:27 +03:00
|
|
|
NSTextField *pauseLabel;
|
2015-06-19 12:53:27 +03:00
|
|
|
NSArray * supportedImageFileTypes;
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// keymap conversion
|
2005-10-30 21:24:49 +03:00
|
|
|
int keymap[] =
|
2005-03-02 00:37:28 +03:00
|
|
|
{
|
2005-10-30 21:24:49 +03:00
|
|
|
// SdlI macI macH SdlH 104xtH 104xtC sdl
|
|
|
|
30, // 0 0x00 0x1e A QZ_a
|
|
|
|
31, // 1 0x01 0x1f S QZ_s
|
|
|
|
32, // 2 0x02 0x20 D QZ_d
|
|
|
|
33, // 3 0x03 0x21 F QZ_f
|
|
|
|
35, // 4 0x04 0x23 H QZ_h
|
|
|
|
34, // 5 0x05 0x22 G QZ_g
|
|
|
|
44, // 6 0x06 0x2c Z QZ_z
|
|
|
|
45, // 7 0x07 0x2d X QZ_x
|
|
|
|
46, // 8 0x08 0x2e C QZ_c
|
|
|
|
47, // 9 0x09 0x2f V QZ_v
|
|
|
|
0, // 10 0x0A Undefined
|
|
|
|
48, // 11 0x0B 0x30 B QZ_b
|
|
|
|
16, // 12 0x0C 0x10 Q QZ_q
|
|
|
|
17, // 13 0x0D 0x11 W QZ_w
|
|
|
|
18, // 14 0x0E 0x12 E QZ_e
|
|
|
|
19, // 15 0x0F 0x13 R QZ_r
|
|
|
|
21, // 16 0x10 0x15 Y QZ_y
|
|
|
|
20, // 17 0x11 0x14 T QZ_t
|
|
|
|
2, // 18 0x12 0x02 1 QZ_1
|
|
|
|
3, // 19 0x13 0x03 2 QZ_2
|
|
|
|
4, // 20 0x14 0x04 3 QZ_3
|
|
|
|
5, // 21 0x15 0x05 4 QZ_4
|
|
|
|
7, // 22 0x16 0x07 6 QZ_6
|
|
|
|
6, // 23 0x17 0x06 5 QZ_5
|
|
|
|
13, // 24 0x18 0x0d = QZ_EQUALS
|
|
|
|
10, // 25 0x19 0x0a 9 QZ_9
|
|
|
|
8, // 26 0x1A 0x08 7 QZ_7
|
|
|
|
12, // 27 0x1B 0x0c - QZ_MINUS
|
|
|
|
9, // 28 0x1C 0x09 8 QZ_8
|
|
|
|
11, // 29 0x1D 0x0b 0 QZ_0
|
|
|
|
27, // 30 0x1E 0x1b ] QZ_RIGHTBRACKET
|
|
|
|
24, // 31 0x1F 0x18 O QZ_o
|
|
|
|
22, // 32 0x20 0x16 U QZ_u
|
|
|
|
26, // 33 0x21 0x1a [ QZ_LEFTBRACKET
|
|
|
|
23, // 34 0x22 0x17 I QZ_i
|
|
|
|
25, // 35 0x23 0x19 P QZ_p
|
|
|
|
28, // 36 0x24 0x1c ENTER QZ_RETURN
|
|
|
|
38, // 37 0x25 0x26 L QZ_l
|
|
|
|
36, // 38 0x26 0x24 J QZ_j
|
|
|
|
40, // 39 0x27 0x28 ' QZ_QUOTE
|
|
|
|
37, // 40 0x28 0x25 K QZ_k
|
|
|
|
39, // 41 0x29 0x27 ; QZ_SEMICOLON
|
|
|
|
43, // 42 0x2A 0x2b \ QZ_BACKSLASH
|
|
|
|
51, // 43 0x2B 0x33 , QZ_COMMA
|
|
|
|
53, // 44 0x2C 0x35 / QZ_SLASH
|
|
|
|
49, // 45 0x2D 0x31 N QZ_n
|
|
|
|
50, // 46 0x2E 0x32 M QZ_m
|
|
|
|
52, // 47 0x2F 0x34 . QZ_PERIOD
|
|
|
|
15, // 48 0x30 0x0f TAB QZ_TAB
|
|
|
|
57, // 49 0x31 0x39 SPACE QZ_SPACE
|
|
|
|
41, // 50 0x32 0x29 ` QZ_BACKQUOTE
|
|
|
|
14, // 51 0x33 0x0e BKSP QZ_BACKSPACE
|
|
|
|
0, // 52 0x34 Undefined
|
|
|
|
1, // 53 0x35 0x01 ESC QZ_ESCAPE
|
2013-12-09 02:59:02 +04:00
|
|
|
220, // 54 0x36 0xdc E0,5C R GUI QZ_RMETA
|
|
|
|
219, // 55 0x37 0xdb E0,5B L GUI QZ_LMETA
|
2005-10-30 21:24:49 +03:00
|
|
|
42, // 56 0x38 0x2a L SHFT QZ_LSHIFT
|
|
|
|
58, // 57 0x39 0x3a CAPS QZ_CAPSLOCK
|
|
|
|
56, // 58 0x3A 0x38 L ALT QZ_LALT
|
|
|
|
29, // 59 0x3B 0x1d L CTRL QZ_LCTRL
|
|
|
|
54, // 60 0x3C 0x36 R SHFT QZ_RSHIFT
|
|
|
|
184,// 61 0x3D 0xb8 E0,38 R ALT QZ_RALT
|
|
|
|
157,// 62 0x3E 0x9d E0,1D R CTRL QZ_RCTRL
|
|
|
|
0, // 63 0x3F Undefined
|
|
|
|
0, // 64 0x40 Undefined
|
|
|
|
0, // 65 0x41 Undefined
|
|
|
|
0, // 66 0x42 Undefined
|
|
|
|
55, // 67 0x43 0x37 KP * QZ_KP_MULTIPLY
|
|
|
|
0, // 68 0x44 Undefined
|
|
|
|
78, // 69 0x45 0x4e KP + QZ_KP_PLUS
|
|
|
|
0, // 70 0x46 Undefined
|
|
|
|
69, // 71 0x47 0x45 NUM QZ_NUMLOCK
|
|
|
|
0, // 72 0x48 Undefined
|
|
|
|
0, // 73 0x49 Undefined
|
|
|
|
0, // 74 0x4A Undefined
|
|
|
|
181,// 75 0x4B 0xb5 E0,35 KP / QZ_KP_DIVIDE
|
|
|
|
152,// 76 0x4C 0x9c E0,1C KP EN QZ_KP_ENTER
|
|
|
|
0, // 77 0x4D undefined
|
|
|
|
74, // 78 0x4E 0x4a KP - QZ_KP_MINUS
|
|
|
|
0, // 79 0x4F Undefined
|
|
|
|
0, // 80 0x50 Undefined
|
|
|
|
0, // 81 0x51 QZ_KP_EQUALS
|
|
|
|
82, // 82 0x52 0x52 KP 0 QZ_KP0
|
|
|
|
79, // 83 0x53 0x4f KP 1 QZ_KP1
|
|
|
|
80, // 84 0x54 0x50 KP 2 QZ_KP2
|
|
|
|
81, // 85 0x55 0x51 KP 3 QZ_KP3
|
|
|
|
75, // 86 0x56 0x4b KP 4 QZ_KP4
|
|
|
|
76, // 87 0x57 0x4c KP 5 QZ_KP5
|
|
|
|
77, // 88 0x58 0x4d KP 6 QZ_KP6
|
|
|
|
71, // 89 0x59 0x47 KP 7 QZ_KP7
|
|
|
|
0, // 90 0x5A Undefined
|
|
|
|
72, // 91 0x5B 0x48 KP 8 QZ_KP8
|
|
|
|
73, // 92 0x5C 0x49 KP 9 QZ_KP9
|
|
|
|
0, // 93 0x5D Undefined
|
|
|
|
0, // 94 0x5E Undefined
|
|
|
|
0, // 95 0x5F Undefined
|
|
|
|
63, // 96 0x60 0x3f F5 QZ_F5
|
|
|
|
64, // 97 0x61 0x40 F6 QZ_F6
|
|
|
|
65, // 98 0x62 0x41 F7 QZ_F7
|
|
|
|
61, // 99 0x63 0x3d F3 QZ_F3
|
|
|
|
66, // 100 0x64 0x42 F8 QZ_F8
|
|
|
|
67, // 101 0x65 0x43 F9 QZ_F9
|
|
|
|
0, // 102 0x66 Undefined
|
|
|
|
87, // 103 0x67 0x57 F11 QZ_F11
|
|
|
|
0, // 104 0x68 Undefined
|
2008-01-23 02:25:15 +03:00
|
|
|
183,// 105 0x69 0xb7 QZ_PRINT
|
2005-10-30 21:24:49 +03:00
|
|
|
0, // 106 0x6A Undefined
|
|
|
|
70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK
|
|
|
|
0, // 108 0x6C Undefined
|
|
|
|
68, // 109 0x6D 0x44 F10 QZ_F10
|
|
|
|
0, // 110 0x6E Undefined
|
|
|
|
88, // 111 0x6F 0x58 F12 QZ_F12
|
|
|
|
0, // 112 0x70 Undefined
|
|
|
|
110,// 113 0x71 0x0 QZ_PAUSE
|
|
|
|
210,// 114 0x72 0xd2 E0,52 INSERT QZ_INSERT
|
|
|
|
199,// 115 0x73 0xc7 E0,47 HOME QZ_HOME
|
|
|
|
201,// 116 0x74 0xc9 E0,49 PG UP QZ_PAGEUP
|
|
|
|
211,// 117 0x75 0xd3 E0,53 DELETE QZ_DELETE
|
|
|
|
62, // 118 0x76 0x3e F4 QZ_F4
|
|
|
|
207,// 119 0x77 0xcf E0,4f END QZ_END
|
|
|
|
60, // 120 0x78 0x3c F2 QZ_F2
|
|
|
|
209,// 121 0x79 0xd1 E0,51 PG DN QZ_PAGEDOWN
|
|
|
|
59, // 122 0x7A 0x3b F1 QZ_F1
|
|
|
|
203,// 123 0x7B 0xcb e0,4B L ARROW QZ_LEFT
|
|
|
|
205,// 124 0x7C 0xcd e0,4D R ARROW QZ_RIGHT
|
|
|
|
208,// 125 0x7D 0xd0 E0,50 D ARROW QZ_DOWN
|
|
|
|
200,// 126 0x7E 0xc8 E0,48 U ARROW QZ_UP
|
|
|
|
/* completed according to http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2013-12-09 02:59:03 +04:00
|
|
|
/* Additional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
|
2005-10-30 21:24:49 +03:00
|
|
|
/*
|
2007-09-17 12:09:54 +04:00
|
|
|
221 // 0xdd e0,5d APPS
|
|
|
|
// E0,2A,E0,37 PRNT SCRN
|
|
|
|
// E1,1D,45,E1,9D,C5 PAUSE
|
|
|
|
83 // 0x53 0x53 KP .
|
|
|
|
// ACPI Scan Codes
|
|
|
|
222 // 0xde E0, 5E Power
|
|
|
|
223 // 0xdf E0, 5F Sleep
|
|
|
|
227 // 0xe3 E0, 63 Wake
|
|
|
|
// Windows Multimedia Scan Codes
|
|
|
|
153 // 0x99 E0, 19 Next Track
|
|
|
|
144 // 0x90 E0, 10 Previous Track
|
|
|
|
164 // 0xa4 E0, 24 Stop
|
|
|
|
162 // 0xa2 E0, 22 Play/Pause
|
|
|
|
160 // 0xa0 E0, 20 Mute
|
|
|
|
176 // 0xb0 E0, 30 Volume Up
|
2007-09-17 01:08:06 +04:00
|
|
|
174 // 0xae E0, 2E Volume Down
|
2007-09-17 12:09:54 +04:00
|
|
|
237 // 0xed E0, 6D Media Select
|
|
|
|
236 // 0xec E0, 6C E-Mail
|
|
|
|
161 // 0xa1 E0, 21 Calculator
|
2007-09-17 01:08:06 +04:00
|
|
|
235 // 0xeb E0, 6B My Computer
|
2007-09-17 12:09:54 +04:00
|
|
|
229 // 0xe5 E0, 65 WWW Search
|
|
|
|
178 // 0xb2 E0, 32 WWW Home
|
|
|
|
234 // 0xea E0, 6A WWW Back
|
2007-09-17 01:08:06 +04:00
|
|
|
233 // 0xe9 E0, 69 WWW Forward
|
2007-09-17 12:09:54 +04:00
|
|
|
232 // 0xe8 E0, 68 WWW Stop
|
2007-09-17 01:08:06 +04:00
|
|
|
231 // 0xe7 E0, 67 WWW Refresh
|
2007-09-17 12:09:54 +04:00
|
|
|
230 // 0xe6 E0, 66 WWW Favorites
|
2005-10-30 21:24:49 +03:00
|
|
|
*/
|
2005-03-02 00:37:28 +03:00
|
|
|
};
|
|
|
|
|
2009-12-13 02:55:53 +03:00
|
|
|
static int cocoa_keycode_to_qemu(int keycode)
|
2005-03-02 00:37:28 +03:00
|
|
|
{
|
2013-12-07 17:48:05 +04:00
|
|
|
if (ARRAY_SIZE(keymap) <= keycode) {
|
2013-12-09 02:59:04 +04:00
|
|
|
fprintf(stderr, "(cocoa) warning unknown keycode 0x%x\n", keycode);
|
2005-03-02 00:37:28 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return keymap[keycode];
|
|
|
|
}
|
|
|
|
|
2015-06-19 12:53:27 +03:00
|
|
|
/* Displays an alert dialog box with the specified message */
|
|
|
|
static void QEMU_Alert(NSString *message)
|
|
|
|
{
|
|
|
|
NSAlert *alert;
|
|
|
|
alert = [NSAlert new];
|
|
|
|
[alert setMessageText: message];
|
|
|
|
[alert runModal];
|
|
|
|
}
|
2008-01-23 02:25:15 +03:00
|
|
|
|
2015-06-19 12:53:27 +03:00
|
|
|
/* Handles any errors that happen with a device transaction */
|
|
|
|
static void handleAnyDeviceErrors(Error * err)
|
|
|
|
{
|
|
|
|
if (err) {
|
|
|
|
QEMU_Alert([NSString stringWithCString: error_get_pretty(err)
|
|
|
|
encoding: NSASCIIStringEncoding]);
|
|
|
|
error_free(err);
|
|
|
|
}
|
|
|
|
}
|
2008-01-23 02:25:15 +03:00
|
|
|
|
2005-03-02 00:37:28 +03:00
|
|
|
/*
|
|
|
|
------------------------------------------------------
|
2008-01-23 02:25:15 +03:00
|
|
|
QemuCocoaView
|
2005-03-02 00:37:28 +03:00
|
|
|
------------------------------------------------------
|
|
|
|
*/
|
2008-01-23 02:25:15 +03:00
|
|
|
@interface QemuCocoaView : NSView
|
2005-03-02 00:37:28 +03:00
|
|
|
{
|
2008-01-23 02:25:15 +03:00
|
|
|
QEMUScreen screen;
|
|
|
|
NSWindow *fullScreenWindow;
|
|
|
|
float cx,cy,cw,ch,cdx,cdy;
|
|
|
|
CGDataProviderRef dataProviderRef;
|
|
|
|
int modifiers_state[256];
|
2013-12-09 02:59:03 +04:00
|
|
|
BOOL isMouseGrabbed;
|
2008-01-23 02:25:15 +03:00
|
|
|
BOOL isFullscreen;
|
|
|
|
BOOL isAbsoluteEnabled;
|
2014-06-23 13:35:24 +04:00
|
|
|
BOOL isMouseDeassociated;
|
2008-01-23 02:25:15 +03:00
|
|
|
}
|
2013-03-01 15:52:06 +04:00
|
|
|
- (void) switchSurface:(DisplaySurface *)surface;
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void) grabMouse;
|
|
|
|
- (void) ungrabMouse;
|
|
|
|
- (void) toggleFullScreen:(id)sender;
|
|
|
|
- (void) handleEvent:(NSEvent *)event;
|
|
|
|
- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
|
2014-06-23 13:35:24 +04:00
|
|
|
/* The state surrounding mouse grabbing is potentially confusing.
|
|
|
|
* isAbsoluteEnabled tracks qemu_input_is_absolute() [ie "is the emulated
|
|
|
|
* pointing device an absolute-position one?"], but is only updated on
|
|
|
|
* next refresh.
|
|
|
|
* isMouseGrabbed tracks whether GUI events are directed to the guest;
|
|
|
|
* it controls whether special keys like Cmd get sent to the guest,
|
|
|
|
* and whether we capture the mouse when in non-absolute mode.
|
|
|
|
* isMouseDeassociated tracks whether we've told MacOSX to disassociate
|
|
|
|
* the mouse and mouse cursor position by calling
|
|
|
|
* CGAssociateMouseAndMouseCursorPosition(FALSE)
|
|
|
|
* (which basically happens if we grab in non-absolute mode).
|
|
|
|
*/
|
2013-12-09 02:59:03 +04:00
|
|
|
- (BOOL) isMouseGrabbed;
|
2008-01-23 02:25:15 +03:00
|
|
|
- (BOOL) isAbsoluteEnabled;
|
2014-06-23 13:35:24 +04:00
|
|
|
- (BOOL) isMouseDeassociated;
|
2008-01-23 02:25:15 +03:00
|
|
|
- (float) cdx;
|
|
|
|
- (float) cdy;
|
|
|
|
- (QEMUScreen) gscreen;
|
2015-09-26 01:14:00 +03:00
|
|
|
- (void) raiseAllKeys;
|
2008-01-23 02:25:15 +03:00
|
|
|
@end
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2011-06-09 22:53:32 +04:00
|
|
|
QemuCocoaView *cocoaView;
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
@implementation QemuCocoaView
|
|
|
|
- (id)initWithFrame:(NSRect)frameRect
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaView: initWithFrame\n");
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
self = [super initWithFrame:frameRect];
|
|
|
|
if (self) {
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
screen.bitsPerComponent = 8;
|
|
|
|
screen.bitsPerPixel = 32;
|
|
|
|
screen.width = frameRect.size.width;
|
|
|
|
screen.height = frameRect.size.height;
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaView: dealloc\n");
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
if (dataProviderRef)
|
|
|
|
CGDataProviderRelease(dataProviderRef);
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
[super dealloc];
|
|
|
|
}
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2009-12-13 04:03:33 +03:00
|
|
|
- (BOOL) isOpaque
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2014-06-23 13:35:23 +04:00
|
|
|
- (BOOL) screenContainsPoint:(NSPoint) p
|
|
|
|
{
|
|
|
|
return (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height);
|
|
|
|
}
|
|
|
|
|
2014-06-23 13:35:25 +04:00
|
|
|
- (void) hideCursor
|
|
|
|
{
|
|
|
|
if (!cursor_hide) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
[NSCursor hide];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) unhideCursor
|
|
|
|
{
|
|
|
|
if (!cursor_hide) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
[NSCursor unhide];
|
|
|
|
}
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void) drawRect:(NSRect) rect
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaView: drawRect\n");
|
|
|
|
|
|
|
|
// get CoreGraphic context
|
|
|
|
CGContextRef viewContextRef = [[NSGraphicsContext currentContext] graphicsPort];
|
|
|
|
CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone);
|
|
|
|
CGContextSetShouldAntialias (viewContextRef, NO);
|
|
|
|
|
|
|
|
// draw screen bitmap directly to Core Graphics context
|
2013-12-24 06:51:47 +04:00
|
|
|
if (!dataProviderRef) {
|
|
|
|
// Draw request before any guest device has set up a framebuffer:
|
|
|
|
// just draw an opaque black rectangle
|
|
|
|
CGContextSetRGBFillColor(viewContextRef, 0, 0, 0, 1.0);
|
|
|
|
CGContextFillRect(viewContextRef, NSRectToCGRect(rect));
|
|
|
|
} else {
|
2008-01-23 02:25:15 +03:00
|
|
|
CGImageRef imageRef = CGImageCreate(
|
|
|
|
screen.width, //width
|
|
|
|
screen.height, //height
|
|
|
|
screen.bitsPerComponent, //bitsPerComponent
|
|
|
|
screen.bitsPerPixel, //bitsPerPixel
|
Update cocoa.m to match new DisplayState code (Samuel Benson)
Version 2 does as follows:
[1]: Corrects endianness on issues by using native BGR to RGB conversion
[2]: Uses DisplayState accessors for obtaining graphics context information,
which
[3]: Removes now unused variables, and
[4]: Allows reading of varying color modes (32bit/24/16), and converting to
native colorspace
[5]: Attempts to keep itself centered on screen (as opposed to bottom right,
which immediately goes off screen after bios load) on context changes
(window resizes)
Testing working on i386 (gentoo, Windows 2000) and PPC (debian) guests on PPC
and x86 Macs.
In regards to [4], Windows 2000 displays fine on quick tests, but on the lowest
setting I could test, 16bit color depth at 4bpp, colors are slightly off. I
used gentoo install-x86-minimal-2008.0 in framebuffer mode to test above
setting; the usual grey text is now blue, and Tux appears to be BGR shifted. I
do not know if previous code worked at such a low color setting.
Signed-off-by: Samuel Benson <qemu_ml@digitalescape.info>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6683 c046a42c-6fe2-441c-8c8c-71466251a162
2009-03-04 22:25:22 +03:00
|
|
|
(screen.width * (screen.bitsPerComponent/2)), //bytesPerRow
|
2009-12-13 02:58:21 +03:00
|
|
|
#ifdef __LITTLE_ENDIAN__
|
2008-01-23 02:25:15 +03:00
|
|
|
CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4
|
Update cocoa.m to match new DisplayState code (Samuel Benson)
Version 2 does as follows:
[1]: Corrects endianness on issues by using native BGR to RGB conversion
[2]: Uses DisplayState accessors for obtaining graphics context information,
which
[3]: Removes now unused variables, and
[4]: Allows reading of varying color modes (32bit/24/16), and converting to
native colorspace
[5]: Attempts to keep itself centered on screen (as opposed to bottom right,
which immediately goes off screen after bios load) on context changes
(window resizes)
Testing working on i386 (gentoo, Windows 2000) and PPC (debian) guests on PPC
and x86 Macs.
In regards to [4], Windows 2000 displays fine on quick tests, but on the lowest
setting I could test, 16bit color depth at 4bpp, colors are slightly off. I
used gentoo install-x86-minimal-2008.0 in framebuffer mode to test above
setting; the usual grey text is now blue, and Tux appears to be BGR shifted. I
do not know if previous code worked at such a low color setting.
Signed-off-by: Samuel Benson <qemu_ml@digitalescape.info>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6683 c046a42c-6fe2-441c-8c8c-71466251a162
2009-03-04 22:25:22 +03:00
|
|
|
kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
|
2008-01-23 02:25:15 +03:00
|
|
|
#else
|
|
|
|
CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc)
|
|
|
|
kCGImageAlphaNoneSkipFirst, //bitmapInfo
|
|
|
|
#endif
|
|
|
|
dataProviderRef, //provider
|
|
|
|
NULL, //decode
|
|
|
|
0, //interpolate
|
|
|
|
kCGRenderingIntentDefault //intent
|
|
|
|
);
|
2015-05-19 11:11:17 +03:00
|
|
|
// selective drawing code (draws only dirty rectangles) (OS X >= 10.4)
|
|
|
|
const NSRect *rectList;
|
|
|
|
NSInteger rectCount;
|
|
|
|
int i;
|
|
|
|
CGImageRef clipImageRef;
|
|
|
|
CGRect clipRect;
|
|
|
|
|
|
|
|
[self getRectsBeingDrawn:&rectList count:&rectCount];
|
|
|
|
for (i = 0; i < rectCount; i++) {
|
|
|
|
clipRect.origin.x = rectList[i].origin.x / cdx;
|
|
|
|
clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
|
|
|
|
clipRect.size.width = rectList[i].size.width / cdx;
|
|
|
|
clipRect.size.height = rectList[i].size.height / cdy;
|
|
|
|
clipImageRef = CGImageCreateWithImageInRect(
|
|
|
|
imageRef,
|
|
|
|
clipRect
|
|
|
|
);
|
|
|
|
CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipImageRef);
|
|
|
|
CGImageRelease (clipImageRef);
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
2008-01-23 02:25:15 +03:00
|
|
|
CGImageRelease (imageRef);
|
|
|
|
}
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void) setContentDimensions
|
2005-03-02 00:37:28 +03:00
|
|
|
{
|
2008-01-23 02:25:15 +03:00
|
|
|
COCOA_DEBUG("QemuCocoaView: setContentDimensions\n");
|
|
|
|
|
|
|
|
if (isFullscreen) {
|
|
|
|
cdx = [[NSScreen mainScreen] frame].size.width / (float)screen.width;
|
|
|
|
cdy = [[NSScreen mainScreen] frame].size.height / (float)screen.height;
|
2015-05-19 11:11:17 +03:00
|
|
|
|
|
|
|
/* stretches video, but keeps same aspect ratio */
|
|
|
|
if (stretch_video == true) {
|
|
|
|
/* use smallest stretch value - prevents clipping on sides */
|
|
|
|
if (MIN(cdx, cdy) == cdx) {
|
|
|
|
cdy = cdx;
|
|
|
|
} else {
|
|
|
|
cdx = cdy;
|
|
|
|
}
|
|
|
|
} else { /* No stretching */
|
|
|
|
cdx = cdy = 1;
|
|
|
|
}
|
2008-01-23 02:25:15 +03:00
|
|
|
cw = screen.width * cdx;
|
|
|
|
ch = screen.height * cdy;
|
|
|
|
cx = ([[NSScreen mainScreen] frame].size.width - cw) / 2.0;
|
|
|
|
cy = ([[NSScreen mainScreen] frame].size.height - ch) / 2.0;
|
|
|
|
} else {
|
|
|
|
cx = 0;
|
|
|
|
cy = 0;
|
|
|
|
cw = screen.width;
|
|
|
|
ch = screen.height;
|
|
|
|
cdx = 1.0;
|
|
|
|
cdy = 1.0;
|
|
|
|
}
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
|
|
|
|
2013-03-01 15:52:06 +04:00
|
|
|
- (void) switchSurface:(DisplaySurface *)surface
|
2005-03-02 00:37:28 +03:00
|
|
|
{
|
2013-03-01 15:52:06 +04:00
|
|
|
COCOA_DEBUG("QemuCocoaView: switchSurface\n");
|
2008-01-23 02:25:15 +03:00
|
|
|
|
2013-03-19 00:28:21 +04:00
|
|
|
int w = surface_width(surface);
|
|
|
|
int h = surface_height(surface);
|
2014-06-23 13:35:22 +04:00
|
|
|
/* cdx == 0 means this is our very first surface, in which case we need
|
|
|
|
* to recalculate the content dimensions even if it happens to be the size
|
|
|
|
* of the initial empty window.
|
|
|
|
*/
|
|
|
|
bool isResize = (w != screen.width || h != screen.height || cdx == 0.0);
|
2013-12-24 06:51:46 +04:00
|
|
|
|
|
|
|
int oldh = screen.height;
|
|
|
|
if (isResize) {
|
|
|
|
// Resize before we trigger the redraw, or we'll redraw at the wrong size
|
|
|
|
COCOA_DEBUG("switchSurface: new size %d x %d\n", w, h);
|
|
|
|
screen.width = w;
|
|
|
|
screen.height = h;
|
|
|
|
[self setContentDimensions];
|
|
|
|
[self setFrame:NSMakeRect(cx, cy, cw, ch)];
|
|
|
|
}
|
2013-03-19 00:28:21 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// update screenBuffer
|
|
|
|
if (dataProviderRef)
|
|
|
|
CGDataProviderRelease(dataProviderRef);
|
2007-09-17 12:09:54 +04:00
|
|
|
|
Update cocoa.m to match new DisplayState code (Samuel Benson)
Version 2 does as follows:
[1]: Corrects endianness on issues by using native BGR to RGB conversion
[2]: Uses DisplayState accessors for obtaining graphics context information,
which
[3]: Removes now unused variables, and
[4]: Allows reading of varying color modes (32bit/24/16), and converting to
native colorspace
[5]: Attempts to keep itself centered on screen (as opposed to bottom right,
which immediately goes off screen after bios load) on context changes
(window resizes)
Testing working on i386 (gentoo, Windows 2000) and PPC (debian) guests on PPC
and x86 Macs.
In regards to [4], Windows 2000 displays fine on quick tests, but on the lowest
setting I could test, 16bit color depth at 4bpp, colors are slightly off. I
used gentoo install-x86-minimal-2008.0 in framebuffer mode to test above
setting; the usual grey text is now blue, and Tux appears to be BGR shifted. I
do not know if previous code worked at such a low color setting.
Signed-off-by: Samuel Benson <qemu_ml@digitalescape.info>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6683 c046a42c-6fe2-441c-8c8c-71466251a162
2009-03-04 22:25:22 +03:00
|
|
|
//sync host window color space with guests
|
2013-12-24 15:54:12 +04:00
|
|
|
screen.bitsPerPixel = surface_bits_per_pixel(surface);
|
|
|
|
screen.bitsPerComponent = surface_bytes_per_pixel(surface) * 2;
|
Update cocoa.m to match new DisplayState code (Samuel Benson)
Version 2 does as follows:
[1]: Corrects endianness on issues by using native BGR to RGB conversion
[2]: Uses DisplayState accessors for obtaining graphics context information,
which
[3]: Removes now unused variables, and
[4]: Allows reading of varying color modes (32bit/24/16), and converting to
native colorspace
[5]: Attempts to keep itself centered on screen (as opposed to bottom right,
which immediately goes off screen after bios load) on context changes
(window resizes)
Testing working on i386 (gentoo, Windows 2000) and PPC (debian) guests on PPC
and x86 Macs.
In regards to [4], Windows 2000 displays fine on quick tests, but on the lowest
setting I could test, 16bit color depth at 4bpp, colors are slightly off. I
used gentoo install-x86-minimal-2008.0 in framebuffer mode to test above
setting; the usual grey text is now blue, and Tux appears to be BGR shifted. I
do not know if previous code worked at such a low color setting.
Signed-off-by: Samuel Benson <qemu_ml@digitalescape.info>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6683 c046a42c-6fe2-441c-8c8c-71466251a162
2009-03-04 22:25:22 +03:00
|
|
|
|
2013-03-01 15:52:06 +04:00
|
|
|
dataProviderRef = CGDataProviderCreateWithData(NULL, surface_data(surface), w * 4 * h, NULL);
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// update windows
|
|
|
|
if (isFullscreen) {
|
|
|
|
[[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]];
|
2013-12-24 06:51:46 +04:00
|
|
|
[normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + oldh, w, h + [normalWindow frame].size.height - oldh) display:NO animate:NO];
|
2008-01-23 02:25:15 +03:00
|
|
|
} else {
|
|
|
|
if (qemu_name)
|
|
|
|
[normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
|
2013-12-24 06:51:46 +04:00
|
|
|
[normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + oldh, w, h + [normalWindow frame].size.height - oldh) display:YES animate:NO];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isResize) {
|
|
|
|
[normalWindow center];
|
2008-01-23 02:25:15 +03:00
|
|
|
}
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void) toggleFullScreen:(id)sender
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n");
|
|
|
|
|
|
|
|
if (isFullscreen) { // switch from fullscreen to desktop
|
|
|
|
isFullscreen = FALSE;
|
|
|
|
[self ungrabMouse];
|
|
|
|
[self setContentDimensions];
|
|
|
|
if ([NSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { // test if "exitFullScreenModeWithOptions" is supported on host at runtime
|
|
|
|
[self exitFullScreenModeWithOptions:nil];
|
|
|
|
} else {
|
|
|
|
[fullScreenWindow close];
|
|
|
|
[normalWindow setContentView: self];
|
|
|
|
[normalWindow makeKeyAndOrderFront: self];
|
|
|
|
[NSMenu setMenuBarVisible:YES];
|
|
|
|
}
|
|
|
|
} else { // switch from desktop to fullscreen
|
|
|
|
isFullscreen = TRUE;
|
2015-05-19 11:11:17 +03:00
|
|
|
[normalWindow orderOut: nil]; /* Hide the window */
|
2008-01-23 02:25:15 +03:00
|
|
|
[self grabMouse];
|
|
|
|
[self setContentDimensions];
|
|
|
|
if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime
|
|
|
|
[self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
[NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
|
|
|
|
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting,
|
|
|
|
nil]];
|
|
|
|
} else {
|
|
|
|
[NSMenu setMenuBarVisible:NO];
|
|
|
|
fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
|
|
|
|
styleMask:NSBorderlessWindowMask
|
|
|
|
backing:NSBackingStoreBuffered
|
|
|
|
defer:NO];
|
2015-05-19 11:11:17 +03:00
|
|
|
[fullScreenWindow setAcceptsMouseMovedEvents: YES];
|
2008-01-23 02:25:15 +03:00
|
|
|
[fullScreenWindow setHasShadow:NO];
|
2015-05-19 11:11:17 +03:00
|
|
|
[fullScreenWindow setBackgroundColor: [NSColor blackColor]];
|
|
|
|
[self setFrame:NSMakeRect(cx, cy, cw, ch)];
|
|
|
|
[[fullScreenWindow contentView] addSubview: self];
|
2008-01-23 02:25:15 +03:00
|
|
|
[fullScreenWindow makeKeyAndOrderFront:self];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void) handleEvent:(NSEvent *)event
|
2007-09-17 12:09:54 +04:00
|
|
|
{
|
2008-01-23 02:25:15 +03:00
|
|
|
COCOA_DEBUG("QemuCocoaView: handleEvent\n");
|
|
|
|
|
|
|
|
int buttons = 0;
|
|
|
|
int keycode;
|
2013-12-04 17:08:04 +04:00
|
|
|
bool mouse_event = false;
|
2008-01-23 02:25:15 +03:00
|
|
|
NSPoint p = [event locationInWindow];
|
|
|
|
|
|
|
|
switch ([event type]) {
|
|
|
|
case NSFlagsChanged:
|
|
|
|
keycode = cocoa_keycode_to_qemu([event keyCode]);
|
2013-12-09 02:59:02 +04:00
|
|
|
|
2013-12-09 02:59:03 +04:00
|
|
|
if ((keycode == 219 || keycode == 220) && !isMouseGrabbed) {
|
2013-12-09 02:59:02 +04:00
|
|
|
/* Don't pass command key changes to guest unless mouse is grabbed */
|
|
|
|
keycode = 0;
|
|
|
|
}
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
if (keycode) {
|
|
|
|
if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup
|
2013-12-04 15:53:44 +04:00
|
|
|
qemu_input_event_send_key_number(dcl->con, keycode, true);
|
|
|
|
qemu_input_event_send_key_number(dcl->con, keycode, false);
|
2013-04-17 13:16:35 +04:00
|
|
|
} else if (qemu_console_is_graphic(NULL)) {
|
2008-01-23 02:25:15 +03:00
|
|
|
if (modifiers_state[keycode] == 0) { // keydown
|
2013-12-04 15:53:44 +04:00
|
|
|
qemu_input_event_send_key_number(dcl->con, keycode, true);
|
2008-01-23 02:25:15 +03:00
|
|
|
modifiers_state[keycode] = 1;
|
|
|
|
} else { // keyup
|
2013-12-04 15:53:44 +04:00
|
|
|
qemu_input_event_send_key_number(dcl->con, keycode, false);
|
2008-01-23 02:25:15 +03:00
|
|
|
modifiers_state[keycode] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// release Mouse grab when pressing ctrl+alt
|
2015-05-19 11:11:17 +03:00
|
|
|
if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
|
2008-01-23 02:25:15 +03:00
|
|
|
[self ungrabMouse];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NSKeyDown:
|
2013-12-09 02:59:02 +04:00
|
|
|
keycode = cocoa_keycode_to_qemu([event keyCode]);
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2013-12-09 02:59:02 +04:00
|
|
|
// forward command key combos to the host UI unless the mouse is grabbed
|
2013-12-09 02:59:03 +04:00
|
|
|
if (!isMouseGrabbed && ([event modifierFlags] & NSCommandKeyMask)) {
|
2008-01-23 02:25:15 +03:00
|
|
|
[NSApp sendEvent:event];
|
|
|
|
return;
|
|
|
|
}
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// default
|
|
|
|
|
|
|
|
// handle control + alt Key Combos (ctrl+alt is reserved for QEMU)
|
|
|
|
if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
|
|
|
|
switch (keycode) {
|
|
|
|
|
|
|
|
// enable graphic console
|
|
|
|
case 0x02 ... 0x0a: // '1' to '9' keys
|
|
|
|
console_select(keycode - 0x02);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle keys for graphic console
|
2013-04-17 13:16:35 +04:00
|
|
|
} else if (qemu_console_is_graphic(NULL)) {
|
2013-12-04 15:53:44 +04:00
|
|
|
qemu_input_event_send_key_number(dcl->con, keycode, true);
|
2008-01-23 02:25:15 +03:00
|
|
|
|
|
|
|
// handlekeys for Monitor
|
|
|
|
} else {
|
|
|
|
int keysym = 0;
|
|
|
|
switch([event keyCode]) {
|
|
|
|
case 115:
|
|
|
|
keysym = QEMU_KEY_HOME;
|
|
|
|
break;
|
|
|
|
case 117:
|
|
|
|
keysym = QEMU_KEY_DELETE;
|
|
|
|
break;
|
|
|
|
case 119:
|
|
|
|
keysym = QEMU_KEY_END;
|
|
|
|
break;
|
|
|
|
case 123:
|
|
|
|
keysym = QEMU_KEY_LEFT;
|
|
|
|
break;
|
|
|
|
case 124:
|
|
|
|
keysym = QEMU_KEY_RIGHT;
|
|
|
|
break;
|
|
|
|
case 125:
|
|
|
|
keysym = QEMU_KEY_DOWN;
|
|
|
|
break;
|
|
|
|
case 126:
|
|
|
|
keysym = QEMU_KEY_UP;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
NSString *ks = [event characters];
|
|
|
|
if ([ks length] > 0)
|
|
|
|
keysym = [ks characterAtIndex:0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (keysym)
|
|
|
|
kbd_put_keysym(keysym);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NSKeyUp:
|
|
|
|
keycode = cocoa_keycode_to_qemu([event keyCode]);
|
2013-12-09 02:59:02 +04:00
|
|
|
|
|
|
|
// don't pass the guest a spurious key-up if we treated this
|
|
|
|
// command-key combo as a host UI action
|
2013-12-09 02:59:03 +04:00
|
|
|
if (!isMouseGrabbed && ([event modifierFlags] & NSCommandKeyMask)) {
|
2013-12-09 02:59:02 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-17 13:16:35 +04:00
|
|
|
if (qemu_console_is_graphic(NULL)) {
|
2013-12-04 15:53:44 +04:00
|
|
|
qemu_input_event_send_key_number(dcl->con, keycode, false);
|
2008-01-23 02:25:15 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NSMouseMoved:
|
|
|
|
if (isAbsoluteEnabled) {
|
2014-06-23 13:35:23 +04:00
|
|
|
if (![self screenContainsPoint:p] || ![[self window] isKeyWindow]) {
|
2014-06-23 13:35:24 +04:00
|
|
|
if (isMouseGrabbed) {
|
|
|
|
[self ungrabMouse];
|
2008-01-23 02:25:15 +03:00
|
|
|
}
|
|
|
|
} else {
|
2014-06-23 13:35:24 +04:00
|
|
|
if (!isMouseGrabbed) {
|
|
|
|
[self grabMouse];
|
2008-01-23 02:25:15 +03:00
|
|
|
}
|
|
|
|
}
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
2013-12-04 17:08:04 +04:00
|
|
|
mouse_event = true;
|
2008-01-23 02:25:15 +03:00
|
|
|
break;
|
|
|
|
case NSLeftMouseDown:
|
|
|
|
if ([event modifierFlags] & NSCommandKeyMask) {
|
|
|
|
buttons |= MOUSE_EVENT_RBUTTON;
|
|
|
|
} else {
|
|
|
|
buttons |= MOUSE_EVENT_LBUTTON;
|
|
|
|
}
|
2013-12-04 17:08:04 +04:00
|
|
|
mouse_event = true;
|
2008-01-23 02:25:15 +03:00
|
|
|
break;
|
|
|
|
case NSRightMouseDown:
|
|
|
|
buttons |= MOUSE_EVENT_RBUTTON;
|
2013-12-04 17:08:04 +04:00
|
|
|
mouse_event = true;
|
2008-01-23 02:25:15 +03:00
|
|
|
break;
|
|
|
|
case NSOtherMouseDown:
|
|
|
|
buttons |= MOUSE_EVENT_MBUTTON;
|
2013-12-04 17:08:04 +04:00
|
|
|
mouse_event = true;
|
2008-01-23 02:25:15 +03:00
|
|
|
break;
|
|
|
|
case NSLeftMouseDragged:
|
|
|
|
if ([event modifierFlags] & NSCommandKeyMask) {
|
|
|
|
buttons |= MOUSE_EVENT_RBUTTON;
|
|
|
|
} else {
|
|
|
|
buttons |= MOUSE_EVENT_LBUTTON;
|
|
|
|
}
|
2013-12-04 17:08:04 +04:00
|
|
|
mouse_event = true;
|
2008-01-23 02:25:15 +03:00
|
|
|
break;
|
|
|
|
case NSRightMouseDragged:
|
|
|
|
buttons |= MOUSE_EVENT_RBUTTON;
|
2013-12-04 17:08:04 +04:00
|
|
|
mouse_event = true;
|
2008-01-23 02:25:15 +03:00
|
|
|
break;
|
|
|
|
case NSOtherMouseDragged:
|
|
|
|
buttons |= MOUSE_EVENT_MBUTTON;
|
2013-12-04 17:08:04 +04:00
|
|
|
mouse_event = true;
|
2008-01-23 02:25:15 +03:00
|
|
|
break;
|
|
|
|
case NSLeftMouseUp:
|
2014-06-23 13:35:24 +04:00
|
|
|
mouse_event = true;
|
|
|
|
if (!isMouseGrabbed && [self screenContainsPoint:p]) {
|
|
|
|
[self grabMouse];
|
2008-01-23 02:25:15 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NSRightMouseUp:
|
2013-12-04 17:08:04 +04:00
|
|
|
mouse_event = true;
|
2008-01-23 02:25:15 +03:00
|
|
|
break;
|
|
|
|
case NSOtherMouseUp:
|
2013-12-04 17:08:04 +04:00
|
|
|
mouse_event = true;
|
2008-01-23 02:25:15 +03:00
|
|
|
break;
|
|
|
|
case NSScrollWheel:
|
2014-06-23 13:35:24 +04:00
|
|
|
if (isMouseGrabbed) {
|
2013-12-04 17:08:04 +04:00
|
|
|
buttons |= ([event deltaY] < 0) ?
|
|
|
|
MOUSE_EVENT_WHEELUP : MOUSE_EVENT_WHEELDN;
|
2008-01-23 02:25:15 +03:00
|
|
|
}
|
2014-06-23 13:35:24 +04:00
|
|
|
mouse_event = true;
|
2008-01-23 02:25:15 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
[NSApp sendEvent:event];
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
2013-12-04 17:08:04 +04:00
|
|
|
|
|
|
|
if (mouse_event) {
|
|
|
|
if (last_buttons != buttons) {
|
|
|
|
static uint32_t bmap[INPUT_BUTTON_MAX] = {
|
|
|
|
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
|
|
|
|
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
|
|
|
|
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
|
|
|
|
[INPUT_BUTTON_WHEEL_UP] = MOUSE_EVENT_WHEELUP,
|
|
|
|
[INPUT_BUTTON_WHEEL_DOWN] = MOUSE_EVENT_WHEELDN,
|
|
|
|
};
|
|
|
|
qemu_input_update_buttons(dcl->con, bmap, last_buttons, buttons);
|
|
|
|
last_buttons = buttons;
|
|
|
|
}
|
2014-06-23 13:35:24 +04:00
|
|
|
if (isMouseGrabbed) {
|
|
|
|
if (isAbsoluteEnabled) {
|
|
|
|
/* Note that the origin for Cocoa mouse coords is bottom left, not top left.
|
|
|
|
* The check on screenContainsPoint is to avoid sending out of range values for
|
|
|
|
* clicks in the titlebar.
|
|
|
|
*/
|
|
|
|
if ([self screenContainsPoint:p]) {
|
|
|
|
qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, p.x, screen.width);
|
|
|
|
qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, screen.height - p.y, screen.height);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, (int)[event deltaX]);
|
|
|
|
qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, (int)[event deltaY]);
|
|
|
|
}
|
2013-12-04 17:08:04 +04:00
|
|
|
} else {
|
|
|
|
[NSApp sendEvent:event];
|
|
|
|
}
|
|
|
|
qemu_input_event_sync();
|
|
|
|
}
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void) grabMouse
|
2005-03-02 00:37:28 +03:00
|
|
|
{
|
2008-01-23 02:25:15 +03:00
|
|
|
COCOA_DEBUG("QemuCocoaView: grabMouse\n");
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
if (!isFullscreen) {
|
|
|
|
if (qemu_name)
|
|
|
|
[normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
|
|
|
|
else
|
|
|
|
[normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
|
|
|
|
}
|
2014-06-23 13:35:25 +04:00
|
|
|
[self hideCursor];
|
2014-06-23 13:35:24 +04:00
|
|
|
if (!isAbsoluteEnabled) {
|
|
|
|
isMouseDeassociated = TRUE;
|
|
|
|
CGAssociateMouseAndMouseCursorPosition(FALSE);
|
|
|
|
}
|
2013-12-09 02:59:03 +04:00
|
|
|
isMouseGrabbed = TRUE; // while isMouseGrabbed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void) ungrabMouse
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
if (!isFullscreen) {
|
|
|
|
if (qemu_name)
|
|
|
|
[normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
|
|
|
|
else
|
|
|
|
[normalWindow setTitle:@"QEMU"];
|
|
|
|
}
|
2014-06-23 13:35:25 +04:00
|
|
|
[self unhideCursor];
|
2014-06-23 13:35:24 +04:00
|
|
|
if (isMouseDeassociated) {
|
|
|
|
CGAssociateMouseAndMouseCursorPosition(TRUE);
|
|
|
|
isMouseDeassociated = FALSE;
|
|
|
|
}
|
2013-12-09 02:59:03 +04:00
|
|
|
isMouseGrabbed = FALSE;
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
|
2013-12-09 02:59:03 +04:00
|
|
|
- (BOOL) isMouseGrabbed {return isMouseGrabbed;}
|
2008-01-23 02:25:15 +03:00
|
|
|
- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
|
2014-06-23 13:35:24 +04:00
|
|
|
- (BOOL) isMouseDeassociated {return isMouseDeassociated;}
|
2008-01-23 02:25:15 +03:00
|
|
|
- (float) cdx {return cdx;}
|
|
|
|
- (float) cdy {return cdy;}
|
|
|
|
- (QEMUScreen) gscreen {return screen;}
|
2015-09-26 01:14:00 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Makes the target think all down keys are being released.
|
|
|
|
* This prevents a stuck key problem, since we will not see
|
|
|
|
* key up events for those keys after we have lost focus.
|
|
|
|
*/
|
|
|
|
- (void) raiseAllKeys
|
|
|
|
{
|
|
|
|
int index;
|
|
|
|
const int max_index = ARRAY_SIZE(modifiers_state);
|
|
|
|
|
|
|
|
for (index = 0; index < max_index; index++) {
|
|
|
|
if (modifiers_state[index]) {
|
|
|
|
modifiers_state[index] = 0;
|
|
|
|
qemu_input_event_send_key_number(dcl->con, index, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-03-02 00:37:28 +03:00
|
|
|
@end
|
|
|
|
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
|
2005-03-02 00:37:28 +03:00
|
|
|
/*
|
|
|
|
------------------------------------------------------
|
2008-01-23 02:25:15 +03:00
|
|
|
QemuCocoaAppController
|
2005-03-02 00:37:28 +03:00
|
|
|
------------------------------------------------------
|
|
|
|
*/
|
2008-01-23 02:25:15 +03:00
|
|
|
@interface QemuCocoaAppController : NSObject
|
2015-05-19 11:11:18 +03:00
|
|
|
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
|
2015-09-26 01:13:59 +03:00
|
|
|
<NSWindowDelegate, NSApplicationDelegate>
|
2015-05-19 11:11:18 +03:00
|
|
|
#endif
|
2005-03-02 00:37:28 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
|
2015-05-19 11:11:17 +03:00
|
|
|
- (void)doToggleFullScreen:(id)sender;
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void)toggleFullScreen:(id)sender;
|
|
|
|
- (void)showQEMUDoc:(id)sender;
|
|
|
|
- (void)showQEMUTec:(id)sender;
|
2015-05-19 11:11:17 +03:00
|
|
|
- (void)zoomToFit:(id) sender;
|
2015-05-19 11:11:18 +03:00
|
|
|
- (void)displayConsole:(id)sender;
|
2015-06-19 12:53:27 +03:00
|
|
|
- (void)pauseQEMU:(id)sender;
|
|
|
|
- (void)resumeQEMU:(id)sender;
|
|
|
|
- (void)displayPause;
|
|
|
|
- (void)removePause;
|
2015-06-19 12:53:27 +03:00
|
|
|
- (void)restartQEMU:(id)sender;
|
|
|
|
- (void)powerDownQEMU:(id)sender;
|
2015-06-19 12:53:27 +03:00
|
|
|
- (void)ejectDeviceMedia:(id)sender;
|
|
|
|
- (void)changeDeviceMedia:(id)sender;
|
2015-09-26 01:13:59 +03:00
|
|
|
- (BOOL)verifyQuit;
|
2005-03-02 00:37:28 +03:00
|
|
|
@end
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
@implementation QemuCocoaAppController
|
|
|
|
- (id) init
|
2005-03-02 00:37:28 +03:00
|
|
|
{
|
2008-01-23 02:25:15 +03:00
|
|
|
COCOA_DEBUG("QemuCocoaAppController: init\n");
|
2005-04-08 00:35:06 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
self = [super init];
|
|
|
|
if (self) {
|
2005-04-08 00:35:06 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// create a view and add it to the window
|
|
|
|
cocoaView = [[QemuCocoaView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0)];
|
|
|
|
if(!cocoaView) {
|
|
|
|
fprintf(stderr, "(cocoa) can't create a view\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// create a window
|
|
|
|
normalWindow = [[NSWindow alloc] initWithContentRect:[cocoaView frame]
|
|
|
|
styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
|
|
|
|
backing:NSBackingStoreBuffered defer:NO];
|
|
|
|
if(!normalWindow) {
|
|
|
|
fprintf(stderr, "(cocoa) can't create window\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
[normalWindow setAcceptsMouseMovedEvents:YES];
|
|
|
|
[normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]];
|
|
|
|
[normalWindow setContentView:cocoaView];
|
2015-05-19 11:11:18 +03:00
|
|
|
#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10)
|
2009-12-13 05:06:20 +03:00
|
|
|
[normalWindow useOptimizedDrawing:YES];
|
2015-05-19 11:11:18 +03:00
|
|
|
#endif
|
2008-01-23 02:25:15 +03:00
|
|
|
[normalWindow makeKeyAndOrderFront:self];
|
2013-12-24 15:54:12 +04:00
|
|
|
[normalWindow center];
|
2015-09-26 01:13:59 +03:00
|
|
|
[normalWindow setDelegate: self];
|
2015-05-19 11:11:17 +03:00
|
|
|
stretch_video = false;
|
2015-06-19 12:53:27 +03:00
|
|
|
|
|
|
|
/* Used for displaying pause on the screen */
|
|
|
|
pauseLabel = [NSTextField new];
|
|
|
|
[pauseLabel setBezeled:YES];
|
|
|
|
[pauseLabel setDrawsBackground:YES];
|
|
|
|
[pauseLabel setBackgroundColor: [NSColor whiteColor]];
|
|
|
|
[pauseLabel setEditable:NO];
|
|
|
|
[pauseLabel setSelectable:NO];
|
|
|
|
[pauseLabel setStringValue: @"Paused"];
|
|
|
|
[pauseLabel setFont: [NSFont fontWithName: @"Helvetica" size: 90]];
|
|
|
|
[pauseLabel setTextColor: [NSColor blackColor]];
|
|
|
|
[pauseLabel sizeToFit];
|
2015-06-19 12:53:27 +03:00
|
|
|
|
|
|
|
// set the supported image file types that can be opened
|
|
|
|
supportedImageFileTypes = [NSArray arrayWithObjects: @"img", @"iso", @"dmg",
|
|
|
|
@"qcow", @"qcow2", @"cloop", @"vmdk", nil];
|
2008-01-23 02:25:15 +03:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaAppController: dealloc\n");
|
|
|
|
|
|
|
|
if (cocoaView)
|
|
|
|
[cocoaView release];
|
|
|
|
[super dealloc];
|
|
|
|
}
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void)applicationDidFinishLaunching: (NSNotification *) note
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n");
|
2015-09-26 01:14:00 +03:00
|
|
|
// launch QEMU, with the global args
|
|
|
|
[self startEmulationWithArgc:gArgc argv:(char **)gArgv];
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
|
|
|
{
|
2008-01-23 02:25:15 +03:00
|
|
|
COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
|
|
|
|
|
2005-03-02 00:37:28 +03:00
|
|
|
qemu_system_shutdown_request();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2009-12-15 00:13:27 +03:00
|
|
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2015-09-26 01:13:59 +03:00
|
|
|
- (NSApplicationTerminateReply)applicationShouldTerminate:
|
|
|
|
(NSApplication *)sender
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaAppController: applicationShouldTerminate\n");
|
|
|
|
return [self verifyQuit];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called when the user clicks on a window's close button */
|
|
|
|
- (BOOL)windowShouldClose:(id)sender
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaAppController: windowShouldClose\n");
|
|
|
|
[NSApp terminate: sender];
|
|
|
|
/* If the user allows the application to quit then the call to
|
|
|
|
* NSApp terminate will never return. If we get here then the user
|
|
|
|
* cancelled the quit, so we should return NO to not permit the
|
|
|
|
* closing of this window.
|
|
|
|
*/
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2015-09-26 01:14:00 +03:00
|
|
|
/* Called when QEMU goes into the background */
|
|
|
|
- (void) applicationWillResignActive: (NSNotification *)aNotification
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaAppController: applicationWillResignActive\n");
|
|
|
|
[cocoaView raiseAllKeys];
|
|
|
|
}
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");
|
|
|
|
|
|
|
|
int status;
|
2011-05-29 21:42:51 +04:00
|
|
|
status = qemu_main(argc, argv, *_NSGetEnviron());
|
2008-01-23 02:25:15 +03:00
|
|
|
exit(status);
|
|
|
|
}
|
|
|
|
|
2015-05-19 11:11:17 +03:00
|
|
|
/* We abstract the method called by the Enter Fullscreen menu item
|
|
|
|
* because Mac OS 10.7 and higher disables it. This is because of the
|
|
|
|
* menu item's old selector's name toggleFullScreen:
|
|
|
|
*/
|
|
|
|
- (void) doToggleFullScreen:(id)sender
|
|
|
|
{
|
|
|
|
[self toggleFullScreen:(id)sender];
|
|
|
|
}
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void)toggleFullScreen:(id)sender
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");
|
|
|
|
|
|
|
|
[cocoaView toggleFullScreen:sender];
|
|
|
|
}
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
- (void)showQEMUDoc:(id)sender
|
2005-03-02 00:37:28 +03:00
|
|
|
{
|
2008-01-23 02:25:15 +03:00
|
|
|
COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
|
|
|
|
|
|
|
|
[[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
|
|
|
|
[[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)showQEMUTec:(id)sender
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
|
|
|
|
|
|
|
|
[[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
|
|
|
|
[[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
2015-05-19 11:11:17 +03:00
|
|
|
|
|
|
|
/* Stretches video to fit host monitor size */
|
|
|
|
- (void)zoomToFit:(id) sender
|
|
|
|
{
|
|
|
|
stretch_video = !stretch_video;
|
|
|
|
if (stretch_video == true) {
|
|
|
|
[sender setState: NSOnState];
|
|
|
|
} else {
|
|
|
|
[sender setState: NSOffState];
|
|
|
|
}
|
|
|
|
}
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2015-05-19 11:11:18 +03:00
|
|
|
/* Displays the console on the screen */
|
|
|
|
- (void)displayConsole:(id)sender
|
|
|
|
{
|
|
|
|
console_select([sender tag]);
|
|
|
|
}
|
2015-06-19 12:53:27 +03:00
|
|
|
|
|
|
|
/* Pause the guest */
|
|
|
|
- (void)pauseQEMU:(id)sender
|
|
|
|
{
|
|
|
|
qmp_stop(NULL);
|
|
|
|
[sender setEnabled: NO];
|
|
|
|
[[[sender menu] itemWithTitle: @"Resume"] setEnabled: YES];
|
|
|
|
[self displayPause];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Resume running the guest operating system */
|
|
|
|
- (void)resumeQEMU:(id) sender
|
|
|
|
{
|
|
|
|
qmp_cont(NULL);
|
|
|
|
[sender setEnabled: NO];
|
|
|
|
[[[sender menu] itemWithTitle: @"Pause"] setEnabled: YES];
|
|
|
|
[self removePause];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Displays the word pause on the screen */
|
|
|
|
- (void)displayPause
|
|
|
|
{
|
|
|
|
/* Coordinates have to be calculated each time because the window can change its size */
|
|
|
|
int xCoord, yCoord, width, height;
|
|
|
|
xCoord = ([normalWindow frame].size.width - [pauseLabel frame].size.width)/2;
|
|
|
|
yCoord = [normalWindow frame].size.height - [pauseLabel frame].size.height - ([pauseLabel frame].size.height * .5);
|
|
|
|
width = [pauseLabel frame].size.width;
|
|
|
|
height = [pauseLabel frame].size.height;
|
|
|
|
[pauseLabel setFrame: NSMakeRect(xCoord, yCoord, width, height)];
|
|
|
|
[cocoaView addSubview: pauseLabel];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Removes the word pause from the screen */
|
|
|
|
- (void)removePause
|
|
|
|
{
|
|
|
|
[pauseLabel removeFromSuperview];
|
|
|
|
}
|
|
|
|
|
2015-06-19 12:53:27 +03:00
|
|
|
/* Restarts QEMU */
|
|
|
|
- (void)restartQEMU:(id)sender
|
|
|
|
{
|
|
|
|
qmp_system_reset(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Powers down QEMU */
|
|
|
|
- (void)powerDownQEMU:(id)sender
|
|
|
|
{
|
|
|
|
qmp_system_powerdown(NULL);
|
|
|
|
}
|
|
|
|
|
2015-06-19 12:53:27 +03:00
|
|
|
/* Ejects the media.
|
|
|
|
* Uses sender's tag to figure out the device to eject.
|
|
|
|
*/
|
|
|
|
- (void)ejectDeviceMedia:(id)sender
|
|
|
|
{
|
|
|
|
NSString * drive;
|
|
|
|
drive = [sender representedObject];
|
|
|
|
if(drive == nil) {
|
|
|
|
NSBeep();
|
|
|
|
QEMU_Alert(@"Failed to find drive to eject!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Error *err = NULL;
|
|
|
|
qmp_eject([drive cStringUsingEncoding: NSASCIIStringEncoding], false, false, &err);
|
|
|
|
handleAnyDeviceErrors(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Displays a dialog box asking the user to select an image file to load.
|
|
|
|
* Uses sender's represented object value to figure out which drive to use.
|
|
|
|
*/
|
|
|
|
- (void)changeDeviceMedia:(id)sender
|
|
|
|
{
|
|
|
|
/* Find the drive name */
|
|
|
|
NSString * drive;
|
|
|
|
drive = [sender representedObject];
|
|
|
|
if(drive == nil) {
|
|
|
|
NSBeep();
|
|
|
|
QEMU_Alert(@"Could not find drive!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Display the file open dialog */
|
|
|
|
NSOpenPanel * openPanel;
|
|
|
|
openPanel = [NSOpenPanel openPanel];
|
|
|
|
[openPanel setCanChooseFiles: YES];
|
|
|
|
[openPanel setAllowsMultipleSelection: NO];
|
|
|
|
[openPanel setAllowedFileTypes: supportedImageFileTypes];
|
|
|
|
if([openPanel runModal] == NSFileHandlingPanelOKButton) {
|
|
|
|
NSString * file = [[[openPanel URLs] objectAtIndex: 0] path];
|
|
|
|
if(file == nil) {
|
|
|
|
NSBeep();
|
|
|
|
QEMU_Alert(@"Failed to convert URL to file path!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Error *err = NULL;
|
|
|
|
qmp_change_blockdev([drive cStringUsingEncoding: NSASCIIStringEncoding],
|
|
|
|
[file cStringUsingEncoding: NSASCIIStringEncoding],
|
|
|
|
"raw",
|
|
|
|
&err);
|
|
|
|
handleAnyDeviceErrors(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-26 01:13:59 +03:00
|
|
|
/* Verifies if the user really wants to quit */
|
|
|
|
- (BOOL)verifyQuit
|
|
|
|
{
|
|
|
|
NSAlert *alert = [NSAlert new];
|
|
|
|
[alert autorelease];
|
|
|
|
[alert setMessageText: @"Are you sure you want to quit QEMU?"];
|
|
|
|
[alert addButtonWithTitle: @"Cancel"];
|
|
|
|
[alert addButtonWithTitle: @"Quit"];
|
|
|
|
if([alert runModal] == NSAlertSecondButtonReturn) {
|
|
|
|
return YES;
|
|
|
|
} else {
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-19 11:11:18 +03:00
|
|
|
@end
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
|
|
|
|
int main (int argc, const char * argv[]) {
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
gArgc = argc;
|
|
|
|
gArgv = (char **)argv;
|
2009-12-13 04:11:44 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
/* In case we don't need to display a window, let's not do that */
|
|
|
|
for (i = 1; i < argc; i++) {
|
2011-03-15 16:18:22 +03:00
|
|
|
const char *opt = argv[i];
|
|
|
|
|
|
|
|
if (opt[0] == '-') {
|
|
|
|
/* Treat --foo the same as -foo. */
|
|
|
|
if (opt[1] == '-') {
|
|
|
|
opt++;
|
|
|
|
}
|
2011-05-30 02:22:49 +04:00
|
|
|
if (!strcmp(opt, "-h") || !strcmp(opt, "-help") ||
|
|
|
|
!strcmp(opt, "-vnc") ||
|
2011-03-15 16:18:22 +03:00
|
|
|
!strcmp(opt, "-nographic") ||
|
|
|
|
!strcmp(opt, "-version") ||
|
2012-05-28 05:18:31 +04:00
|
|
|
!strcmp(opt, "-curses") ||
|
2015-09-09 17:08:30 +03:00
|
|
|
!strcmp(opt, "-display") ||
|
2012-05-28 05:18:31 +04:00
|
|
|
!strcmp(opt, "-qtest")) {
|
2011-05-29 21:42:51 +04:00
|
|
|
return qemu_main(gArgc, gArgv, *_NSGetEnviron());
|
2011-03-15 16:18:22 +03:00
|
|
|
}
|
2009-12-13 04:11:44 +03:00
|
|
|
}
|
|
|
|
}
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2013-04-22 14:29:47 +04:00
|
|
|
// Pull this console process up to being a fully-fledged graphical
|
|
|
|
// app with a menubar and Dock icon
|
|
|
|
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
|
|
|
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
|
|
|
|
|
|
|
[NSApplication sharedApplication];
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// Add menus
|
|
|
|
NSMenu *menu;
|
|
|
|
NSMenuItem *menuItem;
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
[NSApp setMainMenu:[[NSMenu alloc] init]];
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// Application menu
|
|
|
|
menu = [[NSMenu alloc] initWithTitle:@""];
|
|
|
|
[menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU
|
|
|
|
[menu addItem:[NSMenuItem separatorItem]]; //Separator
|
|
|
|
[menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU
|
|
|
|
menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others
|
|
|
|
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
|
|
|
|
[menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All
|
|
|
|
[menu addItem:[NSMenuItem separatorItem]]; //Separator
|
|
|
|
[menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"];
|
|
|
|
menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""];
|
|
|
|
[menuItem setSubmenu:menu];
|
|
|
|
[[NSApp mainMenu] addItem:menuItem];
|
|
|
|
[NSApp performSelector:@selector(setAppleMenu:) withObject:menu]; // Workaround (this method is private since 10.4+)
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2015-06-19 12:53:27 +03:00
|
|
|
// Machine menu
|
|
|
|
menu = [[NSMenu alloc] initWithTitle: @"Machine"];
|
|
|
|
[menu setAutoenablesItems: NO];
|
|
|
|
[menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Pause" action: @selector(pauseQEMU:) keyEquivalent: @""] autorelease]];
|
|
|
|
menuItem = [[[NSMenuItem alloc] initWithTitle: @"Resume" action: @selector(resumeQEMU:) keyEquivalent: @""] autorelease];
|
|
|
|
[menu addItem: menuItem];
|
|
|
|
[menuItem setEnabled: NO];
|
2015-06-19 12:53:27 +03:00
|
|
|
[menu addItem: [NSMenuItem separatorItem]];
|
|
|
|
[menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Reset" action: @selector(restartQEMU:) keyEquivalent: @""] autorelease]];
|
|
|
|
[menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Power Down" action: @selector(powerDownQEMU:) keyEquivalent: @""] autorelease]];
|
2015-06-19 12:53:27 +03:00
|
|
|
menuItem = [[[NSMenuItem alloc] initWithTitle: @"Machine" action:nil keyEquivalent:@""] autorelease];
|
|
|
|
[menuItem setSubmenu:menu];
|
|
|
|
[[NSApp mainMenu] addItem:menuItem];
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// View menu
|
|
|
|
menu = [[NSMenu alloc] initWithTitle:@"View"];
|
2015-05-19 11:11:17 +03:00
|
|
|
[menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Enter Fullscreen" action:@selector(doToggleFullScreen:) keyEquivalent:@"f"] autorelease]]; // Fullscreen
|
|
|
|
[menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Zoom To Fit" action:@selector(zoomToFit:) keyEquivalent:@""] autorelease]];
|
2008-01-23 02:25:15 +03:00
|
|
|
menuItem = [[[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""] autorelease];
|
|
|
|
[menuItem setSubmenu:menu];
|
2005-03-02 00:37:28 +03:00
|
|
|
[[NSApp mainMenu] addItem:menuItem];
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// Window menu
|
|
|
|
menu = [[NSMenu alloc] initWithTitle:@"Window"];
|
|
|
|
[menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"] autorelease]]; // Miniaturize
|
|
|
|
menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
|
|
|
|
[menuItem setSubmenu:menu];
|
|
|
|
[[NSApp mainMenu] addItem:menuItem];
|
|
|
|
[NSApp setWindowsMenu:menu];
|
|
|
|
|
|
|
|
// Help menu
|
|
|
|
menu = [[NSMenu alloc] initWithTitle:@"Help"];
|
|
|
|
[menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
|
|
|
|
[menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
|
|
|
|
menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
|
|
|
|
[menuItem setSubmenu:menu];
|
|
|
|
[[NSApp mainMenu] addItem:menuItem];
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// Create an Application controller
|
|
|
|
QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
|
|
|
|
[NSApp setDelegate:appController];
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// Start the main event loop
|
|
|
|
[NSApp run];
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
[appController release];
|
|
|
|
[pool release];
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
return 0;
|
|
|
|
}
|
2007-09-17 12:09:54 +04:00
|
|
|
|
|
|
|
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
#pragma mark qemu
|
2012-11-13 17:51:41 +04:00
|
|
|
static void cocoa_update(DisplayChangeListener *dcl,
|
|
|
|
int x, int y, int w, int h)
|
2008-01-23 02:25:15 +03:00
|
|
|
{
|
2013-04-22 14:29:46 +04:00
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
COCOA_DEBUG("qemu_cocoa: cocoa_update\n");
|
|
|
|
|
|
|
|
NSRect rect;
|
|
|
|
if ([cocoaView cdx] == 1.0) {
|
|
|
|
rect = NSMakeRect(x, [cocoaView gscreen].height - y - h, w, h);
|
|
|
|
} else {
|
|
|
|
rect = NSMakeRect(
|
|
|
|
x * [cocoaView cdx],
|
|
|
|
([cocoaView gscreen].height - y - h) * [cocoaView cdy],
|
|
|
|
w * [cocoaView cdx],
|
|
|
|
h * [cocoaView cdy]);
|
|
|
|
}
|
2009-12-13 04:08:58 +03:00
|
|
|
[cocoaView setNeedsDisplayInRect:rect];
|
2013-04-22 14:29:46 +04:00
|
|
|
|
|
|
|
[pool release];
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
|
|
|
|
2013-02-28 18:03:04 +04:00
|
|
|
static void cocoa_switch(DisplayChangeListener *dcl,
|
|
|
|
DisplaySurface *surface)
|
2005-03-02 00:37:28 +03:00
|
|
|
{
|
2013-04-22 14:29:46 +04:00
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2013-04-22 14:29:46 +04:00
|
|
|
COCOA_DEBUG("qemu_cocoa: cocoa_switch\n");
|
2013-03-01 15:52:06 +04:00
|
|
|
[cocoaView switchSurface:surface];
|
2013-04-22 14:29:46 +04:00
|
|
|
[pool release];
|
2008-01-23 02:25:15 +03:00
|
|
|
}
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2013-03-01 16:03:04 +04:00
|
|
|
static void cocoa_refresh(DisplayChangeListener *dcl)
|
2008-01-23 02:25:15 +03:00
|
|
|
{
|
2013-04-22 14:29:46 +04:00
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2013-12-04 17:08:04 +04:00
|
|
|
if (qemu_input_is_absolute()) {
|
2008-01-23 02:25:15 +03:00
|
|
|
if (![cocoaView isAbsoluteEnabled]) {
|
2013-12-09 02:59:03 +04:00
|
|
|
if ([cocoaView isMouseGrabbed]) {
|
2008-01-23 02:25:15 +03:00
|
|
|
[cocoaView ungrabMouse];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[cocoaView setAbsoluteEnabled:YES];
|
|
|
|
}
|
2005-03-02 00:37:28 +03:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
NSDate *distantPast;
|
|
|
|
NSEvent *event;
|
|
|
|
distantPast = [NSDate distantPast];
|
|
|
|
do {
|
|
|
|
event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
|
|
|
|
inMode: NSDefaultRunLoopMode dequeue:YES];
|
|
|
|
if (event != nil) {
|
|
|
|
[cocoaView handleEvent:event];
|
|
|
|
}
|
|
|
|
} while(event != nil);
|
2013-04-17 13:16:35 +04:00
|
|
|
graphic_hw_update(NULL);
|
2013-04-22 14:29:46 +04:00
|
|
|
[pool release];
|
2008-01-23 02:25:15 +03:00
|
|
|
}
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
static void cocoa_cleanup(void)
|
|
|
|
{
|
|
|
|
COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n");
|
2011-08-21 22:42:08 +04:00
|
|
|
g_free(dcl);
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|
|
|
|
|
2012-11-13 17:51:41 +04:00
|
|
|
static const DisplayChangeListenerOps dcl_ops = {
|
|
|
|
.dpy_name = "cocoa",
|
2013-03-19 00:28:21 +04:00
|
|
|
.dpy_gfx_update = cocoa_update,
|
|
|
|
.dpy_gfx_switch = cocoa_switch,
|
|
|
|
.dpy_refresh = cocoa_refresh,
|
2012-11-13 17:51:41 +04:00
|
|
|
};
|
|
|
|
|
2015-05-19 11:11:18 +03:00
|
|
|
/* Returns a name for a given console */
|
|
|
|
static NSString * getConsoleName(QemuConsole * console)
|
|
|
|
{
|
|
|
|
return [NSString stringWithFormat: @"%s", qemu_console_get_label(console)];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add an entry to the View menu for each console */
|
|
|
|
static void add_console_menu_entries(void)
|
|
|
|
{
|
|
|
|
NSMenu *menu;
|
|
|
|
NSMenuItem *menuItem;
|
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
menu = [[[NSApp mainMenu] itemWithTitle:@"View"] submenu];
|
|
|
|
|
|
|
|
[menu addItem:[NSMenuItem separatorItem]];
|
|
|
|
|
|
|
|
while (qemu_console_lookup_by_index(index) != NULL) {
|
|
|
|
menuItem = [[[NSMenuItem alloc] initWithTitle: getConsoleName(qemu_console_lookup_by_index(index))
|
|
|
|
action: @selector(displayConsole:) keyEquivalent: @""] autorelease];
|
|
|
|
[menuItem setTag: index];
|
|
|
|
[menu addItem: menuItem];
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-19 12:53:27 +03:00
|
|
|
/* Make menu items for all removable devices.
|
|
|
|
* Each device is given an 'Eject' and 'Change' menu item.
|
|
|
|
*/
|
|
|
|
static void addRemovableDevicesMenuItems()
|
|
|
|
{
|
|
|
|
NSMenu *menu;
|
|
|
|
NSMenuItem *menuItem;
|
|
|
|
BlockInfoList *currentDevice, *pointerToFree;
|
|
|
|
NSString *deviceName;
|
|
|
|
|
|
|
|
currentDevice = qmp_query_block(NULL);
|
|
|
|
pointerToFree = currentDevice;
|
|
|
|
if(currentDevice == NULL) {
|
|
|
|
NSBeep();
|
|
|
|
QEMU_Alert(@"Failed to query for block devices!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
menu = [[[NSApp mainMenu] itemWithTitle:@"Machine"] submenu];
|
|
|
|
|
|
|
|
// Add a separator between related groups of menu items
|
|
|
|
[menu addItem:[NSMenuItem separatorItem]];
|
|
|
|
|
|
|
|
// Set the attributes to the "Removable Media" menu item
|
|
|
|
NSString *titleString = @"Removable Media";
|
|
|
|
NSMutableAttributedString *attString=[[NSMutableAttributedString alloc] initWithString:titleString];
|
|
|
|
NSColor *newColor = [NSColor blackColor];
|
|
|
|
NSFontManager *fontManager = [NSFontManager sharedFontManager];
|
|
|
|
NSFont *font = [fontManager fontWithFamily:@"Helvetica"
|
|
|
|
traits:NSBoldFontMask|NSItalicFontMask
|
|
|
|
weight:0
|
|
|
|
size:14];
|
|
|
|
[attString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, [titleString length])];
|
|
|
|
[attString addAttribute:NSForegroundColorAttributeName value:newColor range:NSMakeRange(0, [titleString length])];
|
|
|
|
[attString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt: 1] range:NSMakeRange(0, [titleString length])];
|
|
|
|
|
|
|
|
// Add the "Removable Media" menu item
|
|
|
|
menuItem = [NSMenuItem new];
|
|
|
|
[menuItem setAttributedTitle: attString];
|
|
|
|
[menuItem setEnabled: NO];
|
|
|
|
[menu addItem: menuItem];
|
|
|
|
|
|
|
|
/* Loop thru all the block devices in the emulator */
|
|
|
|
while (currentDevice) {
|
|
|
|
deviceName = [[NSString stringWithFormat: @"%s", currentDevice->value->device] retain];
|
|
|
|
|
|
|
|
if(currentDevice->value->removable) {
|
|
|
|
menuItem = [[NSMenuItem alloc] initWithTitle: [NSString stringWithFormat: @"Change %s...", currentDevice->value->device]
|
|
|
|
action: @selector(changeDeviceMedia:)
|
|
|
|
keyEquivalent: @""];
|
|
|
|
[menu addItem: menuItem];
|
|
|
|
[menuItem setRepresentedObject: deviceName];
|
|
|
|
[menuItem autorelease];
|
|
|
|
|
|
|
|
menuItem = [[NSMenuItem alloc] initWithTitle: [NSString stringWithFormat: @"Eject %s", currentDevice->value->device]
|
|
|
|
action: @selector(ejectDeviceMedia:)
|
|
|
|
keyEquivalent: @""];
|
|
|
|
[menu addItem: menuItem];
|
|
|
|
[menuItem setRepresentedObject: deviceName];
|
|
|
|
[menuItem autorelease];
|
|
|
|
}
|
|
|
|
currentDevice = currentDevice->next;
|
|
|
|
}
|
|
|
|
qapi_free_BlockInfoList(pointerToFree);
|
|
|
|
}
|
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
void cocoa_display_init(DisplayState *ds, int full_screen)
|
2005-03-02 00:37:28 +03:00
|
|
|
{
|
2008-01-23 02:25:15 +03:00
|
|
|
COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
|
|
|
|
|
2015-05-19 11:11:17 +03:00
|
|
|
/* if fullscreen mode is to be used */
|
|
|
|
if (full_screen == true) {
|
|
|
|
[NSApp activateIgnoringOtherApps: YES];
|
|
|
|
[(QemuCocoaAppController *)[[NSApplication sharedApplication] delegate] toggleFullScreen: nil];
|
|
|
|
}
|
|
|
|
|
2011-08-21 22:42:08 +04:00
|
|
|
dcl = g_malloc0(sizeof(DisplayChangeListener));
|
|
|
|
|
Update cocoa.m to match new DisplayState code (Samuel Benson)
Version 2 does as follows:
[1]: Corrects endianness on issues by using native BGR to RGB conversion
[2]: Uses DisplayState accessors for obtaining graphics context information,
which
[3]: Removes now unused variables, and
[4]: Allows reading of varying color modes (32bit/24/16), and converting to
native colorspace
[5]: Attempts to keep itself centered on screen (as opposed to bottom right,
which immediately goes off screen after bios load) on context changes
(window resizes)
Testing working on i386 (gentoo, Windows 2000) and PPC (debian) guests on PPC
and x86 Macs.
In regards to [4], Windows 2000 displays fine on quick tests, but on the lowest
setting I could test, 16bit color depth at 4bpp, colors are slightly off. I
used gentoo install-x86-minimal-2008.0 in framebuffer mode to test above
setting; the usual grey text is now blue, and Tux appears to be BGR shifted. I
do not know if previous code worked at such a low color setting.
Signed-off-by: Samuel Benson <qemu_ml@digitalescape.info>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6683 c046a42c-6fe2-441c-8c8c-71466251a162
2009-03-04 22:25:22 +03:00
|
|
|
// register vga output callbacks
|
2012-11-13 17:51:41 +04:00
|
|
|
dcl->ops = &dcl_ops;
|
2013-04-23 17:44:31 +04:00
|
|
|
register_displaychangelistener(dcl);
|
2006-05-23 01:25:04 +04:00
|
|
|
|
2008-01-23 02:25:15 +03:00
|
|
|
// register cleanup function
|
|
|
|
atexit(cocoa_cleanup);
|
2015-05-19 11:11:18 +03:00
|
|
|
|
|
|
|
/* At this point QEMU has created all the consoles, so we can add View
|
|
|
|
* menu entries for them.
|
|
|
|
*/
|
|
|
|
add_console_menu_entries();
|
2015-06-19 12:53:27 +03:00
|
|
|
|
|
|
|
/* Give all removable devices a menu item.
|
|
|
|
* Has to be called after QEMU has started to
|
|
|
|
* find out what removable devices it has.
|
|
|
|
*/
|
|
|
|
addRemovableDevicesMenuItems();
|
2005-03-02 00:37:28 +03:00
|
|
|
}
|