Previous 199869 Revisions Next

r41653 Sunday 8th November, 2015 at 12:43:04 UTC by Miodrag Milanović
renamed m -> mm (nw)
[src/osd/modules/debugger]debugosx.m debugosx.mm*
[src/osd/modules/debugger/osx]breakpointsview.m breakpointsview.mm* consoleview.m consoleview.mm* debugcommandhistory.m debugcommandhistory.mm* debugconsole.m debugconsole.mm* debugview.m debugview.mm* debugwindowhandler.m debugwindowhandler.mm* deviceinfoviewer.m deviceinfoviewer.mm* devicesviewer.m devicesviewer.mm* disassemblyview.m disassemblyview.mm* disassemblyviewer.m disassemblyviewer.mm* errorlogview.m errorlogview.mm* errorlogviewer.m errorlogviewer.mm* memoryview.m memoryview.mm* memoryviewer.m memoryviewer.mm* pointsviewer.m pointsviewer.mm* registersview.m registersview.mm* watchpointsview.m watchpointsview.mm*
[src/osd/sdl]SDLMain_tmpl.m SDLMain_tmpl.mm* aueffectutil.m aueffectutil.mm* osxutils.m osxutils.mm*

trunk/src/osd/modules/debugger/debugosx.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  debugosx.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9
10// TODO:
11//  * Automatic scrolling for console and log views
12//  * Keyboard shortcuts in error log and device windows
13//  * Don't accept keyboard input while the game is running
14//  * Interior focus rings - standard/exterior focus rings look really ugly here
15//  * Updates causing debug views' widths to change are sometimes obscured by the scroll views' opaque backgrounds
16//  * Scroll views with content narrower than clipping area are flaky under Tiger - nothing I can do about this
17
18
19// MAME headers
20#include "emu.h"
21#include "debugger.h"
22
23// MAMEOS headers
24#include "modules/lib/osdobj_common.h"
25#include "osx/debugosx.h"
26#include "osdsdl.h"
27#include "debug_module.h"
28
29#import "osx/debugconsole.h"
30#import "osx/debugwindowhandler.h"
31
32
33//============================================================
34//  MODULE SUPPORT
35//============================================================
36
37class debugger_osx : public osd_module, public debug_module
38{
39public:
40   debugger_osx()
41   : osd_module(OSD_DEBUG_PROVIDER, "osx"), debug_module(),
42     m_machine(NULL),
43     m_console(nil)
44   {
45   }
46
47   virtual ~debugger_osx()
48   {
49      if (m_console != nil)
50         [m_console release];
51   }
52
53   virtual int init(const osd_options &options);
54   virtual void exit();
55
56   virtual void init_debugger(running_machine &machine);
57   virtual void wait_for_debugger(device_t &device, bool firststop);
58   virtual void debugger_update();
59
60private:
61   running_machine *m_machine;
62   MAMEDebugConsole *m_console;
63};
64
65MODULE_DEFINITION(DEBUG_OSX, debugger_osx)
66
67//============================================================
68//  debugger_osx::init
69//============================================================
70
71int debugger_osx::init(const osd_options &options)
72{
73   return 0;
74}
75
76//============================================================
77//  debugger_osx::exit
78//============================================================
79
80void debugger_osx::exit()
81{
82   NSAutoreleasePool *const pool = [[NSAutoreleasePool alloc] init];
83   if (m_console)
84   {
85      NSDictionary *info = [NSDictionary dictionaryWithObject:[NSValue valueWithPointer:m_machine]
86                                          forKey:@"MAMEDebugMachine"];
87      [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification
88                                             object:m_console
89                                            userInfo:info];
90      [m_console release];
91      m_console = nil;
92      m_machine = NULL;
93   }
94   [pool release];
95}
96
97//============================================================
98//  debugger_osx::init_debugger
99//============================================================
100
101void debugger_osx::init_debugger(running_machine &machine)
102{
103   m_machine = &machine;
104}
105
106//============================================================
107//  debugger_osx::wait_for_debugger
108//============================================================
109
110void debugger_osx::wait_for_debugger(device_t &device, bool firststop)
111{
112   NSAutoreleasePool *const pool = [[NSAutoreleasePool alloc] init];
113
114   // create a console window
115   if (m_console == nil)
116      m_console = [[MAMEDebugConsole alloc] initWithMachine:*m_machine];
117
118   // make sure the debug windows are visible
119   if (firststop)
120   {
121      NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:&device],
122                                                      @"MAMEDebugDevice",
123                                                      [NSValue valueWithPointer:m_machine],
124                                                      @"MAMEDebugMachine",
125                                                      nil];
126      [[NSNotificationCenter defaultCenter] postNotificationName:MAMEShowDebuggerNotification
127                                             object:m_console
128                                            userInfo:info];
129   }
130
131   // get and process messages
132   NSEvent *ev = [NSApp nextEventMatchingMask:NSAnyEventMask
133                            untilDate:[NSDate distantFuture]
134                              inMode:NSDefaultRunLoopMode
135                              dequeue:YES];
136   if (ev != nil)
137      [NSApp sendEvent:ev];
138
139   [pool release];
140}
141
142
143//============================================================
144//  debugger_update
145//============================================================
146
147void debugger_osx::debugger_update()
148{
149}
trunk/src/osd/modules/debugger/debugosx.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  debugosx.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9
10// TODO:
11//  * Automatic scrolling for console and log views
12//  * Keyboard shortcuts in error log and device windows
13//  * Don't accept keyboard input while the game is running
14//  * Interior focus rings - standard/exterior focus rings look really ugly here
15//  * Updates causing debug views' widths to change are sometimes obscured by the scroll views' opaque backgrounds
16//  * Scroll views with content narrower than clipping area are flaky under Tiger - nothing I can do about this
17
18
19// MAME headers
20#include "emu.h"
21#include "debugger.h"
22
23// MAMEOS headers
24#include "modules/lib/osdobj_common.h"
25#include "osx/debugosx.h"
26#include "osdsdl.h"
27#include "debug_module.h"
28
29#import "osx/debugconsole.h"
30#import "osx/debugwindowhandler.h"
31
32
33//============================================================
34//  MODULE SUPPORT
35//============================================================
36
37class debugger_osx : public osd_module, public debug_module
38{
39public:
40   debugger_osx()
41   : osd_module(OSD_DEBUG_PROVIDER, "osx"), debug_module(),
42     m_machine(NULL),
43     m_console(nil)
44   {
45   }
46
47   virtual ~debugger_osx()
48   {
49      if (m_console != nil)
50         [m_console release];
51   }
52
53   virtual int init(const osd_options &options);
54   virtual void exit();
55
56   virtual void init_debugger(running_machine &machine);
57   virtual void wait_for_debugger(device_t &device, bool firststop);
58   virtual void debugger_update();
59
60private:
61   running_machine *m_machine;
62   MAMEDebugConsole *m_console;
63};
64
65MODULE_DEFINITION(DEBUG_OSX, debugger_osx)
66
67//============================================================
68//  debugger_osx::init
69//============================================================
70
71int debugger_osx::init(const osd_options &options)
72{
73   return 0;
74}
75
76//============================================================
77//  debugger_osx::exit
78//============================================================
79
80void debugger_osx::exit()
81{
82   NSAutoreleasePool *const pool = [[NSAutoreleasePool alloc] init];
83   if (m_console)
84   {
85      NSDictionary *info = [NSDictionary dictionaryWithObject:[NSValue valueWithPointer:m_machine]
86                                          forKey:@"MAMEDebugMachine"];
87      [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification
88                                             object:m_console
89                                            userInfo:info];
90      [m_console release];
91      m_console = nil;
92      m_machine = NULL;
93   }
94   [pool release];
95}
96
97//============================================================
98//  debugger_osx::init_debugger
99//============================================================
100
101void debugger_osx::init_debugger(running_machine &machine)
102{
103   m_machine = &machine;
104}
105
106//============================================================
107//  debugger_osx::wait_for_debugger
108//============================================================
109
110void debugger_osx::wait_for_debugger(device_t &device, bool firststop)
111{
112   NSAutoreleasePool *const pool = [[NSAutoreleasePool alloc] init];
113
114   // create a console window
115   if (m_console == nil)
116      m_console = [[MAMEDebugConsole alloc] initWithMachine:*m_machine];
117
118   // make sure the debug windows are visible
119   if (firststop)
120   {
121      NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:&device],
122                                                      @"MAMEDebugDevice",
123                                                      [NSValue valueWithPointer:m_machine],
124                                                      @"MAMEDebugMachine",
125                                                      nil];
126      [[NSNotificationCenter defaultCenter] postNotificationName:MAMEShowDebuggerNotification
127                                             object:m_console
128                                            userInfo:info];
129   }
130
131   // get and process messages
132   NSEvent *ev = [NSApp nextEventMatchingMask:NSAnyEventMask
133                            untilDate:[NSDate distantFuture]
134                              inMode:NSDefaultRunLoopMode
135                              dequeue:YES];
136   if (ev != nil)
137      [NSApp sendEvent:ev];
138
139   [pool release];
140}
141
142
143//============================================================
144//  debugger_update
145//============================================================
146
147void debugger_osx::debugger_update()
148{
149}
trunk/src/osd/modules/debugger/osx/breakpointsview.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  breakpointsview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "breakpointsview.h"
10
11#include "debug/debugvw.h"
12
13
14@implementation MAMEBreakpointsView
15
16- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
17   if (!(self = [super initWithFrame:f type:DVT_BREAK_POINTS machine:m wholeLineScroll:YES]))
18      return nil;
19   return self;
20}
21
22
23- (void)dealloc {
24   [super dealloc];
25}
26
27@end
trunk/src/osd/modules/debugger/osx/breakpointsview.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  breakpointsview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "breakpointsview.h"
10
11#include "debug/debugvw.h"
12
13
14@implementation MAMEBreakpointsView
15
16- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
17   if (!(self = [super initWithFrame:f type:DVT_BREAK_POINTS machine:m wholeLineScroll:YES]))
18      return nil;
19   return self;
20}
21
22
23- (void)dealloc {
24   [super dealloc];
25}
26
27@end
trunk/src/osd/modules/debugger/osx/consoleview.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  consoleview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "consoleview.h"
10
11#include "debug/debugvw.h"
12
13
14@implementation MAMEConsoleView
15
16- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
17   if (!(self = [super initWithFrame:f type:DVT_CONSOLE machine:m wholeLineScroll:NO]))
18      return nil;
19   return self;
20}
21
22
23- (void)dealloc {
24   [super dealloc];
25}
26
27@end
trunk/src/osd/modules/debugger/osx/consoleview.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  consoleview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "consoleview.h"
10
11#include "debug/debugvw.h"
12
13
14@implementation MAMEConsoleView
15
16- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
17   if (!(self = [super initWithFrame:f type:DVT_CONSOLE machine:m wholeLineScroll:NO]))
18      return nil;
19   return self;
20}
21
22
23- (void)dealloc {
24   [super dealloc];
25}
26
27@end
trunk/src/osd/modules/debugger/osx/debugcommandhistory.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  debugcommandhistory.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9//============================================================
10//  MAMEDebugView class
11//============================================================
12
13#import "debugcommandhistory.h"
14
15
16@implementation MAMEDebugCommandHistory
17
18+ (NSInteger)defaultLength {
19   return 100;
20}
21
22
23- (id)init {
24   if (!(self = [super init]))
25      return nil;
26   length = [[self class] defaultLength];
27   position = -1;
28   current = nil;
29   history = [[NSMutableArray alloc] initWithCapacity:length];
30   return self;
31}
32
33
34- (void)dealloc {
35   if (current != nil)
36      [current release];
37   if (history != nil)
38      [history release];
39   [super dealloc];
40}
41
42
43- (NSInteger)length {
44   return length;
45}
46
47
48- (void)setLength:(NSInteger)l {
49   length = l;
50   if ([history count] > length)
51      [history removeObjectsInRange:NSMakeRange(length, [history count] - length)];
52}
53
54
55- (void)add:(NSString *)entry {
56   if (([history count] == 0) || ![[history objectAtIndex:0] isEqualToString:entry]) {
57      [history insertObject:entry atIndex:0];
58      while ([history count] > length)
59         [history removeLastObject];
60   }
61   position = 0;
62}
63
64
65- (NSString *)previous:(NSString *)cur {
66   if ((position + 1) < [history count]) {
67      if (position < 0) {
68         [current autorelease];
69         current = [cur copy];
70      }
71      return [history objectAtIndex:++position];
72   } else {
73      return nil;
74   }
75}
76
77
78- (NSString *)next:(NSString *)cur {
79   if (position > 0) {
80      return [history objectAtIndex:--position];
81   } else if ((position == 0) && (current != nil) && ![current isEqualToString:[history objectAtIndex:0]]) {
82      position--;
83      return [[current retain] autorelease];
84   } else {
85      return nil;
86   }
87}
88
89
90- (void)edit {
91   if (position == 0)
92      position--;
93}
94
95- (void)reset {
96   position = -1;
97   if (current != nil) {
98      [current release];
99      current = nil;
100   }
101}
102
103
104- (void)clear {
105   position = -1;
106   if (current != nil) {
107      [current release];
108      current = nil;
109   }
110   [history removeAllObjects];
111}
112
113@end
trunk/src/osd/modules/debugger/osx/debugcommandhistory.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  debugcommandhistory.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9//============================================================
10//  MAMEDebugView class
11//============================================================
12
13#import "debugcommandhistory.h"
14
15
16@implementation MAMEDebugCommandHistory
17
18+ (NSInteger)defaultLength {
19   return 100;
20}
21
22
23- (id)init {
24   if (!(self = [super init]))
25      return nil;
26   length = [[self class] defaultLength];
27   position = -1;
28   current = nil;
29   history = [[NSMutableArray alloc] initWithCapacity:length];
30   return self;
31}
32
33
34- (void)dealloc {
35   if (current != nil)
36      [current release];
37   if (history != nil)
38      [history release];
39   [super dealloc];
40}
41
42
43- (NSInteger)length {
44   return length;
45}
46
47
48- (void)setLength:(NSInteger)l {
49   length = l;
50   if ([history count] > length)
51      [history removeObjectsInRange:NSMakeRange(length, [history count] - length)];
52}
53
54
55- (void)add:(NSString *)entry {
56   if (([history count] == 0) || ![[history objectAtIndex:0] isEqualToString:entry]) {
57      [history insertObject:entry atIndex:0];
58      while ([history count] > length)
59         [history removeLastObject];
60   }
61   position = 0;
62}
63
64
65- (NSString *)previous:(NSString *)cur {
66   if ((position + 1) < [history count]) {
67      if (position < 0) {
68         [current autorelease];
69         current = [cur copy];
70      }
71      return [history objectAtIndex:++position];
72   } else {
73      return nil;
74   }
75}
76
77
78- (NSString *)next:(NSString *)cur {
79   if (position > 0) {
80      return [history objectAtIndex:--position];
81   } else if ((position == 0) && (current != nil) && ![current isEqualToString:[history objectAtIndex:0]]) {
82      position--;
83      return [[current retain] autorelease];
84   } else {
85      return nil;
86   }
87}
88
89
90- (void)edit {
91   if (position == 0)
92      position--;
93}
94
95- (void)reset {
96   position = -1;
97   if (current != nil) {
98      [current release];
99      current = nil;
100   }
101}
102
103
104- (void)clear {
105   position = -1;
106   if (current != nil) {
107      [current release];
108      current = nil;
109   }
110   [history removeAllObjects];
111}
112
113@end
trunk/src/osd/modules/debugger/osx/debugconsole.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  debugconsole.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "debugconsole.h"
10
11#import "debugcommandhistory.h"
12#import "consoleview.h"
13#import "debugview.h"
14#import "deviceinfoviewer.h"
15#import "devicesviewer.h"
16#import "disassemblyview.h"
17#import "disassemblyviewer.h"
18#import "errorlogviewer.h"
19#import "memoryviewer.h"
20#import "pointsviewer.h"
21#import "registersview.h"
22
23#include "debug/debugcon.h"
24#include "debug/debugcpu.h"
25
26
27@implementation MAMEDebugConsole
28
29- (id)initWithMachine:(running_machine &)m {
30   NSSplitView      *regSplit, *dasmSplit;
31   NSScrollView   *regScroll, *dasmScroll, *consoleScroll;
32   NSView         *consoleContainer;
33   NSPopUpButton   *actionButton;
34   NSRect         rct;
35
36   // initialise superclass
37   if (!(self = [super initWithMachine:m title:@"Debug"]))
38      return nil;
39   history = [[MAMEDebugCommandHistory alloc] init];
40   auxiliaryWindows = [[NSMutableArray alloc] init];
41   NSFont *const defaultFont = [[MAMEDebugView class] defaultFontForMachine:m];
42
43   // create the register view
44   regView = [[MAMERegistersView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine];
45   regScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
46   [regScroll setHasHorizontalScroller:YES];
47   [regScroll setHasVerticalScroller:YES];
48   [regScroll setAutohidesScrollers:YES];
49   [regScroll setBorderType:NSBezelBorder];
50   [regScroll setDocumentView:regView];
51   [regView release];
52
53   // create the disassembly view
54   dasmView = [[MAMEDisassemblyView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine];
55   [dasmView setExpression:@"curpc"];
56   dasmScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
57   [dasmScroll setHasHorizontalScroller:YES];
58   [dasmScroll setHasVerticalScroller:YES];
59   [dasmScroll setAutohidesScrollers:YES];
60   [dasmScroll setBorderType:NSBezelBorder];
61   [dasmScroll setDocumentView:dasmView];
62   [dasmView release];
63
64   // create the console view
65   consoleView = [[MAMEConsoleView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine];
66   consoleScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
67   [consoleScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
68   [consoleScroll setHasHorizontalScroller:YES];
69   [consoleScroll setHasVerticalScroller:YES];
70   [consoleScroll setAutohidesScrollers:YES];
71   [consoleScroll setBorderType:NSBezelBorder];
72   [consoleScroll setDocumentView:consoleView];
73   [consoleView release];
74
75   // create the command field
76   commandField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
77   [commandField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)];
78   [commandField setFont:defaultFont];
79   [commandField setFocusRingType:NSFocusRingTypeNone];
80   [commandField setTarget:self];
81   [commandField setAction:@selector(doCommand:)];
82   [commandField setDelegate:self];
83   [commandField sizeToFit];
84   rct = [commandField frame];
85   [commandField setFrame:NSMakeRect(rct.size.height, 0, 100 - rct.size.height, rct.size.height)];
86
87   // create the action pull-down button
88   actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, 0, rct.size.height, rct.size.height)];
89   [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMaxYMargin)];
90   [actionButton setFont:[NSFont systemFontOfSize:[defaultFont pointSize]]];
91   [dasmView insertActionItemsInMenu:[actionButton menu] atIndex:1];
92
93   // create the container for the console and command input field
94   consoleContainer = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
95   [consoleScroll setFrame:NSMakeRect(0,
96                              rct.size.height,
97                              100,
98                              [consoleContainer bounds].size.height - rct.size.height)];
99   [consoleContainer addSubview:consoleScroll];
100   [consoleContainer addSubview:commandField];
101   [consoleContainer addSubview:actionButton];
102   [consoleScroll release];
103   [commandField release];
104   [actionButton release];
105
106   // create the split between the disassembly and the console
107   dasmSplit = [[NSSplitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
108   [dasmSplit setDelegate:self];
109   [dasmSplit setVertical:NO];
110   [dasmSplit addSubview:dasmScroll];
111   [dasmSplit addSubview:consoleContainer];
112   [dasmScroll release];
113   [consoleContainer release];
114
115   // create the split between the registers and the console
116   regSplit = [[NSSplitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
117   [regSplit setDelegate:self];
118   [regSplit setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
119   [regSplit setVertical:YES];
120   [regSplit addSubview:regScroll];
121   [regSplit addSubview:dasmSplit];
122   [regScroll release];
123   [dasmSplit release];
124
125   // put the split views in the window and get them into a half-reasonable state
126   [window setContentView:regSplit];
127   [regSplit release];
128   [regSplit adjustSubviews];
129   [dasmSplit adjustSubviews];
130
131   // keyboard focus should start on the command field
132   [window makeFirstResponder:commandField];
133
134   // calculate the optimal size for everything
135   NSRect const   available = [[NSScreen mainScreen] visibleFrame];
136   NSSize const   regCurrent = [regScroll frame].size;
137   NSSize const   regSize = [NSScrollView frameSizeForContentSize:[regView maximumFrameSize]
138                                   hasHorizontalScroller:YES
139                                    hasVerticalScroller:YES
140                                           borderType:[regScroll borderType]];
141   NSSize const   dasmCurrent = [dasmScroll frame].size;
142   NSSize const   dasmSize = [NSScrollView frameSizeForContentSize:[dasmView maximumFrameSize]
143                                   hasHorizontalScroller:YES
144                                    hasVerticalScroller:YES
145                                           borderType:[dasmScroll borderType]];
146   NSSize const   consoleCurrent = [consoleContainer frame].size;
147   NSSize         consoleSize = [NSScrollView frameSizeForContentSize:[consoleView maximumFrameSize]
148                                      hasHorizontalScroller:YES
149                                       hasVerticalScroller:YES
150                                              borderType:[consoleScroll borderType]];
151   NSRect         windowFrame = [window frame];
152   NSSize         adjustment;
153
154   consoleSize.width += consoleCurrent.width - [consoleScroll frame].size.width;
155   consoleSize.height += consoleCurrent.height - [consoleScroll frame].size.height;
156   adjustment.width = regSize.width - regCurrent.width;
157   adjustment.height = regSize.height - regCurrent.height;
158   adjustment.width += MAX(dasmSize.width - dasmCurrent.width, consoleSize.width - consoleCurrent.width);
159
160   windowFrame.size.width += adjustment.width;
161   windowFrame.size.height += adjustment.height; // not used - better to go for fixed height
162   windowFrame.size.height = MIN(512.0, available.size.height);
163   windowFrame.size.width = MIN(windowFrame.size.width, available.size.width);
164   windowFrame.origin.x = available.origin.x + available.size.width - windowFrame.size.width;
165   windowFrame.origin.y = available.origin.y;
166   [window setFrame:windowFrame display:YES];
167
168   NSRect lhsFrame = [regScroll frame];
169   NSRect rhsFrame = [dasmSplit frame];
170   adjustment.width = MIN(regSize.width, ([regSplit frame].size.width - [regSplit dividerThickness]) / 2);
171   rhsFrame.origin.x -= lhsFrame.size.width - adjustment.width;
172   rhsFrame.size.width += lhsFrame.size.width - adjustment.width;
173   lhsFrame.size.width = adjustment.width;
174   [regScroll setFrame:lhsFrame];
175   [dasmSplit setFrame:rhsFrame];
176
177   // select the current processor
178   [self setCPU:machine->firstcpu];
179
180   [[NSNotificationCenter defaultCenter] addObserver:self
181                                  selector:@selector(auxiliaryWindowWillClose:)
182                                     name:MAMEAuxiliaryDebugWindowWillCloseNotification
183                                    object:nil];
184
185   // don't forget the return value
186   return self;
187}
188
189
190- (void)dealloc {
191   [[NSNotificationCenter defaultCenter] removeObserver:self];
192
193   if (history != nil)
194      [history release];
195   if (auxiliaryWindows != nil)
196      [auxiliaryWindows release];
197
198   [super dealloc];
199}
200
201
202- (void)setCPU:(device_t *)device {
203   [regView selectSubviewForDevice:device];
204   [dasmView selectSubviewForDevice:device];
205   [window setTitle:[NSString stringWithFormat:@"Debug: %s - %s '%s'",
206                                    device->machine().system().name,
207                                    device->name(),
208                                    device->tag()]];
209}
210
211
212- (IBAction)doCommand:(id)sender {
213   NSString *command = [sender stringValue];
214   if ([command length] == 0)
215   {
216      debug_cpu_get_visible_cpu(*machine)->debug()->single_step();
217      [history reset];
218   }
219   else
220   {
221      debug_console_execute_command(*machine, [command UTF8String], 1);
222      [history add:command];
223      [history edit];
224   }
225   [sender setStringValue:@""];
226}
227
228
229- (IBAction)debugToggleBreakpoint:(id)sender {
230   device_t &device = [dasmView source]->device();
231   if ([dasmView cursorVisible] && (debug_cpu_get_visible_cpu(*machine) == &device))
232   {
233      offs_t const address = [dasmView selectedAddress];
234      device_debug::breakpoint *bp = [[self class] findBreakpointAtAddress:address
235                                                   forDevice:device];
236
237      // if it doesn't exist, add a new one
238      NSString *command;
239      if (bp == NULL)
240         command = [NSString stringWithFormat:@"bpset 0x%lX", (unsigned long)address];
241      else
242         command = [NSString stringWithFormat:@"bpclear 0x%X", (unsigned)bp->index()];
243      debug_console_execute_command(*machine, [command UTF8String], 1);
244   }
245}
246
247
248- (IBAction)debugToggleBreakpointEnable:(id)sender {
249   device_t &device = [dasmView source]->device();
250   if ([dasmView cursorVisible] && (debug_cpu_get_visible_cpu(*machine) == &device))
251   {
252      device_debug::breakpoint *bp = [[self class] findBreakpointAtAddress:[dasmView selectedAddress]
253                                                   forDevice:device];
254      if (bp != NULL)
255      {
256         NSString *command;
257         if (bp->enabled())
258            command = [NSString stringWithFormat:@"bpdisable 0x%X", (unsigned)bp->index()];
259         else
260            command = [NSString stringWithFormat:@"bpenable 0x%X", (unsigned)bp->index()];
261         debug_console_execute_command(*machine, [command UTF8String], 1);
262      }
263   }
264}
265
266
267- (IBAction)debugRunToCursor:(id)sender {
268   device_t &device = [dasmView source]->device();
269   if ([dasmView cursorVisible] && (debug_cpu_get_visible_cpu(*machine) == &device))
270   {
271      NSString *command = [NSString stringWithFormat:@"go 0x%lX", (unsigned long)[dasmView selectedAddress]];
272      debug_console_execute_command(*machine, [command UTF8String], 1);
273   }
274}
275
276
277- (IBAction)debugNewMemoryWindow:(id)sender {
278   MAMEMemoryViewer *win = [[MAMEMemoryViewer alloc] initWithMachine:*machine console:self];
279   [auxiliaryWindows addObject:win];
280   [win release];
281   [win activate];
282}
283
284
285- (IBAction)debugNewDisassemblyWindow:(id)sender {
286   MAMEDisassemblyViewer *win = [[MAMEDisassemblyViewer alloc] initWithMachine:*machine console:self];
287   [auxiliaryWindows addObject:win];
288   [win release];
289   [win activate];
290}
291
292
293- (IBAction)debugNewErrorLogWindow:(id)sender {
294   MAMEErrorLogViewer *win = [[MAMEErrorLogViewer alloc] initWithMachine:*machine console:self];
295   [auxiliaryWindows addObject:win];
296   [win release];
297   [win activate];
298}
299
300
301- (IBAction)debugNewPointsWindow:(id)sender{
302   MAMEPointsViewer *win = [[MAMEPointsViewer alloc] initWithMachine:*machine console:self];
303   [auxiliaryWindows addObject:win];
304   [win release];
305   [win activate];
306}
307
308
309- (IBAction)debugNewDevicesWindow:(id)sender {
310   MAMEDevicesViewer *win = [[MAMEDevicesViewer alloc] initWithMachine:*machine console:self];
311   [auxiliaryWindows addObject:win];
312   [win release];
313   [win activate];
314}
315
316
317- (void)debugNewMemoryWindowForSpace:(address_space *)space device:(device_t *)device expression:(NSString *)expression {
318   MAMEMemoryViewer *win = [[MAMEMemoryViewer alloc] initWithMachine:*machine console:self];
319   [auxiliaryWindows addObject:win];
320   [win release];
321   if ([win selectSubviewForSpace:space])
322   {
323      if (expression != nil)
324         [win setExpression:expression];
325   }
326   else
327   {
328      [win selectSubviewForDevice:device];
329   }
330   [win activate];
331}
332
333
334- (void)debugNewDisassemblyWindowForSpace:(address_space *)space device:(device_t *)device expression:(NSString *)expression {
335   MAMEDisassemblyViewer *win = [[MAMEDisassemblyViewer alloc] initWithMachine:*machine console:self];
336   [auxiliaryWindows addObject:win];
337   [win release];
338   if ([win selectSubviewForSpace:space])
339   {
340      if (expression != nil)
341         [win setExpression:expression];
342   }
343   else
344   {
345      [win selectSubviewForDevice:device];
346   }
347   [win activate];
348}
349
350
351- (void)debugNewInfoWindowForDevice:(device_t &)device {
352   MAMEDeviceInfoViewer *win = [[MAMEDeviceInfoViewer alloc] initWithDevice:device
353                                                    machine:*machine
354                                                    console:self];
355   [auxiliaryWindows addObject:win];
356   [win release];
357   [win activate];
358}
359
360
361- (void)showDebugger:(NSNotification *)notification {
362   device_t *device = (device_t * )[[[notification userInfo] objectForKey:@"MAMEDebugDevice"] pointerValue];
363   if (&device->machine() == machine)
364   {
365      [self setCPU:device];
366      [window makeKeyAndOrderFront:self];
367   }
368}
369
370
371- (void)auxiliaryWindowWillClose:(NSNotification *)notification {
372   [auxiliaryWindows removeObjectIdenticalTo:[notification object]];
373}
374
375
376- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor {
377   if (control == commandField)
378      [history edit];
379
380   return YES;
381}
382
383
384- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command {
385   if (control == commandField) {
386      if (command == @selector(cancelOperation:)) {
387         [commandField setStringValue:@""];
388         [history reset];
389         return YES;
390      } else if (command == @selector(moveUp:)) {
391         NSString *hist = [history previous:[commandField stringValue]];
392         if (hist != nil) {
393            [commandField setStringValue:hist];
394            [commandField selectText:self];
395            [(NSText *)[window firstResponder] setSelectedRange:NSMakeRange([hist length], 0)];
396         }
397         return YES;
398      } else if (command == @selector(moveDown:)) {
399         NSString *hist = [history next:[commandField stringValue]];
400         if (hist != nil) {
401            [commandField setStringValue:hist];
402            [commandField selectText:self];
403            [(NSText *)[window firstResponder] setSelectedRange:NSMakeRange([hist length], 0)];
404         }
405         return YES;
406      }
407    }
408   return NO;
409}
410
411
412- (void)windowWillClose:(NSNotification *)notification {
413   if ([notification object] == window)
414   {
415      NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:machine],
416                                                      @"MAMEDebugMachine",
417                                                      nil];
418      [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification
419                                             object:self
420                                            userInfo:info];
421      debug_cpu_get_visible_cpu(*machine)->debug()->go();
422   }
423}
424
425
426- (CGFloat)splitView:(NSSplitView *)sender constrainMinCoordinate:(CGFloat)min ofSubviewAt:(NSInteger)offs {
427   return (min < 100) ? 100 : min;
428}
429
430
431- (CGFloat)splitView:(NSSplitView *)sender constrainMaxCoordinate:(CGFloat)max ofSubviewAt:(NSInteger)offs {
432   NSSize   sz = [sender bounds].size;
433   CGFloat   allowed = ([sender isVertical] ? sz.width : sz.height) - 100 - [sender dividerThickness];
434   return (max > allowed) ? allowed : max;
435}
436
437
438- (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview {
439   // allow registers or disassembly to be collapsed, but not console
440   return [[sender subviews] indexOfObjectIdenticalTo:subview] == 0;
441}
442
443
444- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize {
445   // This can only deal with a single split, but that's all we use, anyway
446   NSRect first, second;
447   [sender adjustSubviews];
448   first = [[[sender subviews] objectAtIndex:0] frame];
449   second = [[[sender subviews] objectAtIndex:1] frame];
450   if ([sender isVertical]) {
451      if (first.size.width < 100) {
452         CGFloat diff = 100 - first.size.width;
453         first.size.width = 100;
454         second.origin.x += diff;
455         second.size.width -= diff;
456      } else if (second.size.width < 100) {
457         CGFloat diff = 100 - second.size.width;
458         second.size.width = 100;
459         second.origin.x -= diff;
460         first.size.width -= diff;
461      }
462   } else {
463      if (first.size.height < 100) {
464         CGFloat diff = 100 - first.size.height;
465         first.size.height = 100;
466         second.origin.y += diff;
467         second.size.height -= diff;
468      } else if (second.size.height < 100) {
469         CGFloat diff = 100 - second.size.height;
470         second.size.height = 100;
471         second.origin.y -= diff;
472         first.size.height -= diff;
473      }
474   }
475   [[[sender subviews] objectAtIndex:0] setFrame:first];
476   [[[sender subviews] objectAtIndex:1] setFrame:second];
477}
478
479
480- (BOOL)validateMenuItem:(NSMenuItem *)item {
481   SEL const action = [item action];
482   BOOL const inContextMenu = ([item menu] == [dasmView menu]);
483   BOOL const haveCursor = [dasmView cursorVisible];
484   BOOL const isCurrent = (debug_cpu_get_visible_cpu(*machine) == &[dasmView source]->device());
485
486   device_debug::breakpoint *breakpoint = NULL;
487   if (haveCursor)
488   {
489      breakpoint = [[self class] findBreakpointAtAddress:[dasmView selectedAddress]
490                                     forDevice:[dasmView source]->device()];
491   }
492
493   if (action == @selector(debugToggleBreakpoint:))
494   {
495      if (haveCursor)
496      {
497         if (breakpoint != NULL)
498         {
499            if (inContextMenu)
500               [item setTitle:@"Clear Breakpoint"];
501            else
502               [item setTitle:@"Clear Breakpoint at Cursor"];
503         }
504         else
505         {
506            if (inContextMenu)
507               [item setTitle:@"Set Breakpoint"];
508            else
509               [item setTitle:@"Set Breakpoint at Cursor"];
510         }
511      }
512      else
513      {
514         if (inContextMenu)
515            [item setTitle:@"Toggle Breakpoint"];
516         else
517            [item setTitle:@"Toggle Breakpoint at Cursor"];
518      }
519      return haveCursor && isCurrent;
520   }
521   else if (action == @selector(debugToggleBreakpointEnable:))
522   {
523      if ((breakpoint != NULL) && !breakpoint->enabled())
524      {
525         if (inContextMenu)
526            [item setTitle:@"Enable Breakpoint"];
527         else
528            [item setTitle:@"Enable Breakpoint at Cursor"];
529      }
530      else
531      {
532         if (inContextMenu)
533            [item setTitle:@"Disable Breakpoint"];
534         else
535            [item setTitle:@"Disable Breakpoint at Cursor"];
536      }
537      return (breakpoint != NULL) && isCurrent;
538   }
539   else if (action == @selector(debugRunToCursor:))
540   {
541      return isCurrent;
542   }
543   else
544   {
545      return YES;
546   }
547}
548
549@end
trunk/src/osd/modules/debugger/osx/debugconsole.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  debugconsole.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "debugconsole.h"
10
11#import "debugcommandhistory.h"
12#import "consoleview.h"
13#import "debugview.h"
14#import "deviceinfoviewer.h"
15#import "devicesviewer.h"
16#import "disassemblyview.h"
17#import "disassemblyviewer.h"
18#import "errorlogviewer.h"
19#import "memoryviewer.h"
20#import "pointsviewer.h"
21#import "registersview.h"
22
23#include "debug/debugcon.h"
24#include "debug/debugcpu.h"
25
26
27@implementation MAMEDebugConsole
28
29- (id)initWithMachine:(running_machine &)m {
30   NSSplitView      *regSplit, *dasmSplit;
31   NSScrollView   *regScroll, *dasmScroll, *consoleScroll;
32   NSView         *consoleContainer;
33   NSPopUpButton   *actionButton;
34   NSRect         rct;
35
36   // initialise superclass
37   if (!(self = [super initWithMachine:m title:@"Debug"]))
38      return nil;
39   history = [[MAMEDebugCommandHistory alloc] init];
40   auxiliaryWindows = [[NSMutableArray alloc] init];
41   NSFont *const defaultFont = [[MAMEDebugView class] defaultFontForMachine:m];
42
43   // create the register view
44   regView = [[MAMERegistersView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine];
45   regScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
46   [regScroll setHasHorizontalScroller:YES];
47   [regScroll setHasVerticalScroller:YES];
48   [regScroll setAutohidesScrollers:YES];
49   [regScroll setBorderType:NSBezelBorder];
50   [regScroll setDocumentView:regView];
51   [regView release];
52
53   // create the disassembly view
54   dasmView = [[MAMEDisassemblyView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine];
55   [dasmView setExpression:@"curpc"];
56   dasmScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
57   [dasmScroll setHasHorizontalScroller:YES];
58   [dasmScroll setHasVerticalScroller:YES];
59   [dasmScroll setAutohidesScrollers:YES];
60   [dasmScroll setBorderType:NSBezelBorder];
61   [dasmScroll setDocumentView:dasmView];
62   [dasmView release];
63
64   // create the console view
65   consoleView = [[MAMEConsoleView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine];
66   consoleScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
67   [consoleScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
68   [consoleScroll setHasHorizontalScroller:YES];
69   [consoleScroll setHasVerticalScroller:YES];
70   [consoleScroll setAutohidesScrollers:YES];
71   [consoleScroll setBorderType:NSBezelBorder];
72   [consoleScroll setDocumentView:consoleView];
73   [consoleView release];
74
75   // create the command field
76   commandField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
77   [commandField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)];
78   [commandField setFont:defaultFont];
79   [commandField setFocusRingType:NSFocusRingTypeNone];
80   [commandField setTarget:self];
81   [commandField setAction:@selector(doCommand:)];
82   [commandField setDelegate:self];
83   [commandField sizeToFit];
84   rct = [commandField frame];
85   [commandField setFrame:NSMakeRect(rct.size.height, 0, 100 - rct.size.height, rct.size.height)];
86
87   // create the action pull-down button
88   actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, 0, rct.size.height, rct.size.height)];
89   [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMaxYMargin)];
90   [actionButton setFont:[NSFont systemFontOfSize:[defaultFont pointSize]]];
91   [dasmView insertActionItemsInMenu:[actionButton menu] atIndex:1];
92
93   // create the container for the console and command input field
94   consoleContainer = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
95   [consoleScroll setFrame:NSMakeRect(0,
96                              rct.size.height,
97                              100,
98                              [consoleContainer bounds].size.height - rct.size.height)];
99   [consoleContainer addSubview:consoleScroll];
100   [consoleContainer addSubview:commandField];
101   [consoleContainer addSubview:actionButton];
102   [consoleScroll release];
103   [commandField release];
104   [actionButton release];
105
106   // create the split between the disassembly and the console
107   dasmSplit = [[NSSplitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
108   [dasmSplit setDelegate:self];
109   [dasmSplit setVertical:NO];
110   [dasmSplit addSubview:dasmScroll];
111   [dasmSplit addSubview:consoleContainer];
112   [dasmScroll release];
113   [consoleContainer release];
114
115   // create the split between the registers and the console
116   regSplit = [[NSSplitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
117   [regSplit setDelegate:self];
118   [regSplit setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
119   [regSplit setVertical:YES];
120   [regSplit addSubview:regScroll];
121   [regSplit addSubview:dasmSplit];
122   [regScroll release];
123   [dasmSplit release];
124
125   // put the split views in the window and get them into a half-reasonable state
126   [window setContentView:regSplit];
127   [regSplit release];
128   [regSplit adjustSubviews];
129   [dasmSplit adjustSubviews];
130
131   // keyboard focus should start on the command field
132   [window makeFirstResponder:commandField];
133
134   // calculate the optimal size for everything
135   NSRect const   available = [[NSScreen mainScreen] visibleFrame];
136   NSSize const   regCurrent = [regScroll frame].size;
137   NSSize const   regSize = [NSScrollView frameSizeForContentSize:[regView maximumFrameSize]
138                                   hasHorizontalScroller:YES
139                                    hasVerticalScroller:YES
140                                           borderType:[regScroll borderType]];
141   NSSize const   dasmCurrent = [dasmScroll frame].size;
142   NSSize const   dasmSize = [NSScrollView frameSizeForContentSize:[dasmView maximumFrameSize]
143                                   hasHorizontalScroller:YES
144                                    hasVerticalScroller:YES
145                                           borderType:[dasmScroll borderType]];
146   NSSize const   consoleCurrent = [consoleContainer frame].size;
147   NSSize         consoleSize = [NSScrollView frameSizeForContentSize:[consoleView maximumFrameSize]
148                                      hasHorizontalScroller:YES
149                                       hasVerticalScroller:YES
150                                              borderType:[consoleScroll borderType]];
151   NSRect         windowFrame = [window frame];
152   NSSize         adjustment;
153
154   consoleSize.width += consoleCurrent.width - [consoleScroll frame].size.width;
155   consoleSize.height += consoleCurrent.height - [consoleScroll frame].size.height;
156   adjustment.width = regSize.width - regCurrent.width;
157   adjustment.height = regSize.height - regCurrent.height;
158   adjustment.width += MAX(dasmSize.width - dasmCurrent.width, consoleSize.width - consoleCurrent.width);
159
160   windowFrame.size.width += adjustment.width;
161   windowFrame.size.height += adjustment.height; // not used - better to go for fixed height
162   windowFrame.size.height = MIN(512.0, available.size.height);
163   windowFrame.size.width = MIN(windowFrame.size.width, available.size.width);
164   windowFrame.origin.x = available.origin.x + available.size.width - windowFrame.size.width;
165   windowFrame.origin.y = available.origin.y;
166   [window setFrame:windowFrame display:YES];
167
168   NSRect lhsFrame = [regScroll frame];
169   NSRect rhsFrame = [dasmSplit frame];
170   adjustment.width = MIN(regSize.width, ([regSplit frame].size.width - [regSplit dividerThickness]) / 2);
171   rhsFrame.origin.x -= lhsFrame.size.width - adjustment.width;
172   rhsFrame.size.width += lhsFrame.size.width - adjustment.width;
173   lhsFrame.size.width = adjustment.width;
174   [regScroll setFrame:lhsFrame];
175   [dasmSplit setFrame:rhsFrame];
176
177   // select the current processor
178   [self setCPU:machine->firstcpu];
179
180   [[NSNotificationCenter defaultCenter] addObserver:self
181                                  selector:@selector(auxiliaryWindowWillClose:)
182                                     name:MAMEAuxiliaryDebugWindowWillCloseNotification
183                                    object:nil];
184
185   // don't forget the return value
186   return self;
187}
188
189
190- (void)dealloc {
191   [[NSNotificationCenter defaultCenter] removeObserver:self];
192
193   if (history != nil)
194      [history release];
195   if (auxiliaryWindows != nil)
196      [auxiliaryWindows release];
197
198   [super dealloc];
199}
200
201
202- (void)setCPU:(device_t *)device {
203   [regView selectSubviewForDevice:device];
204   [dasmView selectSubviewForDevice:device];
205   [window setTitle:[NSString stringWithFormat:@"Debug: %s - %s '%s'",
206                                    device->machine().system().name,
207                                    device->name(),
208                                    device->tag()]];
209}
210
211
212- (IBAction)doCommand:(id)sender {
213   NSString *command = [sender stringValue];
214   if ([command length] == 0)
215   {
216      debug_cpu_get_visible_cpu(*machine)->debug()->single_step();
217      [history reset];
218   }
219   else
220   {
221      debug_console_execute_command(*machine, [command UTF8String], 1);
222      [history add:command];
223      [history edit];
224   }
225   [sender setStringValue:@""];
226}
227
228
229- (IBAction)debugToggleBreakpoint:(id)sender {
230   device_t &device = [dasmView source]->device();
231   if ([dasmView cursorVisible] && (debug_cpu_get_visible_cpu(*machine) == &device))
232   {
233      offs_t const address = [dasmView selectedAddress];
234      device_debug::breakpoint *bp = [[self class] findBreakpointAtAddress:address
235                                                   forDevice:device];
236
237      // if it doesn't exist, add a new one
238      NSString *command;
239      if (bp == NULL)
240         command = [NSString stringWithFormat:@"bpset 0x%lX", (unsigned long)address];
241      else
242         command = [NSString stringWithFormat:@"bpclear 0x%X", (unsigned)bp->index()];
243      debug_console_execute_command(*machine, [command UTF8String], 1);
244   }
245}
246
247
248- (IBAction)debugToggleBreakpointEnable:(id)sender {
249   device_t &device = [dasmView source]->device();
250   if ([dasmView cursorVisible] && (debug_cpu_get_visible_cpu(*machine) == &device))
251   {
252      device_debug::breakpoint *bp = [[self class] findBreakpointAtAddress:[dasmView selectedAddress]
253                                                   forDevice:device];
254      if (bp != NULL)
255      {
256         NSString *command;
257         if (bp->enabled())
258            command = [NSString stringWithFormat:@"bpdisable 0x%X", (unsigned)bp->index()];
259         else
260            command = [NSString stringWithFormat:@"bpenable 0x%X", (unsigned)bp->index()];
261         debug_console_execute_command(*machine, [command UTF8String], 1);
262      }
263   }
264}
265
266
267- (IBAction)debugRunToCursor:(id)sender {
268   device_t &device = [dasmView source]->device();
269   if ([dasmView cursorVisible] && (debug_cpu_get_visible_cpu(*machine) == &device))
270   {
271      NSString *command = [NSString stringWithFormat:@"go 0x%lX", (unsigned long)[dasmView selectedAddress]];
272      debug_console_execute_command(*machine, [command UTF8String], 1);
273   }
274}
275
276
277- (IBAction)debugNewMemoryWindow:(id)sender {
278   MAMEMemoryViewer *win = [[MAMEMemoryViewer alloc] initWithMachine:*machine console:self];
279   [auxiliaryWindows addObject:win];
280   [win release];
281   [win activate];
282}
283
284
285- (IBAction)debugNewDisassemblyWindow:(id)sender {
286   MAMEDisassemblyViewer *win = [[MAMEDisassemblyViewer alloc] initWithMachine:*machine console:self];
287   [auxiliaryWindows addObject:win];
288   [win release];
289   [win activate];
290}
291
292
293- (IBAction)debugNewErrorLogWindow:(id)sender {
294   MAMEErrorLogViewer *win = [[MAMEErrorLogViewer alloc] initWithMachine:*machine console:self];
295   [auxiliaryWindows addObject:win];
296   [win release];
297   [win activate];
298}
299
300
301- (IBAction)debugNewPointsWindow:(id)sender{
302   MAMEPointsViewer *win = [[MAMEPointsViewer alloc] initWithMachine:*machine console:self];
303   [auxiliaryWindows addObject:win];
304   [win release];
305   [win activate];
306}
307
308
309- (IBAction)debugNewDevicesWindow:(id)sender {
310   MAMEDevicesViewer *win = [[MAMEDevicesViewer alloc] initWithMachine:*machine console:self];
311   [auxiliaryWindows addObject:win];
312   [win release];
313   [win activate];
314}
315
316
317- (void)debugNewMemoryWindowForSpace:(address_space *)space device:(device_t *)device expression:(NSString *)expression {
318   MAMEMemoryViewer *win = [[MAMEMemoryViewer alloc] initWithMachine:*machine console:self];
319   [auxiliaryWindows addObject:win];
320   [win release];
321   if ([win selectSubviewForSpace:space])
322   {
323      if (expression != nil)
324         [win setExpression:expression];
325   }
326   else
327   {
328      [win selectSubviewForDevice:device];
329   }
330   [win activate];
331}
332
333
334- (void)debugNewDisassemblyWindowForSpace:(address_space *)space device:(device_t *)device expression:(NSString *)expression {
335   MAMEDisassemblyViewer *win = [[MAMEDisassemblyViewer alloc] initWithMachine:*machine console:self];
336   [auxiliaryWindows addObject:win];
337   [win release];
338   if ([win selectSubviewForSpace:space])
339   {
340      if (expression != nil)
341         [win setExpression:expression];
342   }
343   else
344   {
345      [win selectSubviewForDevice:device];
346   }
347   [win activate];
348}
349
350
351- (void)debugNewInfoWindowForDevice:(device_t &)device {
352   MAMEDeviceInfoViewer *win = [[MAMEDeviceInfoViewer alloc] initWithDevice:device
353                                                    machine:*machine
354                                                    console:self];
355   [auxiliaryWindows addObject:win];
356   [win release];
357   [win activate];
358}
359
360
361- (void)showDebugger:(NSNotification *)notification {
362   device_t *device = (device_t * )[[[notification userInfo] objectForKey:@"MAMEDebugDevice"] pointerValue];
363   if (&device->machine() == machine)
364   {
365      [self setCPU:device];
366      [window makeKeyAndOrderFront:self];
367   }
368}
369
370
371- (void)auxiliaryWindowWillClose:(NSNotification *)notification {
372   [auxiliaryWindows removeObjectIdenticalTo:[notification object]];
373}
374
375
376- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor {
377   if (control == commandField)
378      [history edit];
379
380   return YES;
381}
382
383
384- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command {
385   if (control == commandField) {
386      if (command == @selector(cancelOperation:)) {
387         [commandField setStringValue:@""];
388         [history reset];
389         return YES;
390      } else if (command == @selector(moveUp:)) {
391         NSString *hist = [history previous:[commandField stringValue]];
392         if (hist != nil) {
393            [commandField setStringValue:hist];
394            [commandField selectText:self];
395            [(NSText *)[window firstResponder] setSelectedRange:NSMakeRange([hist length], 0)];
396         }
397         return YES;
398      } else if (command == @selector(moveDown:)) {
399         NSString *hist = [history next:[commandField stringValue]];
400         if (hist != nil) {
401            [commandField setStringValue:hist];
402            [commandField selectText:self];
403            [(NSText *)[window firstResponder] setSelectedRange:NSMakeRange([hist length], 0)];
404         }
405         return YES;
406      }
407    }
408   return NO;
409}
410
411
412- (void)windowWillClose:(NSNotification *)notification {
413   if ([notification object] == window)
414   {
415      NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:machine],
416                                                      @"MAMEDebugMachine",
417                                                      nil];
418      [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification
419                                             object:self
420                                            userInfo:info];
421      debug_cpu_get_visible_cpu(*machine)->debug()->go();
422   }
423}
424
425
426- (CGFloat)splitView:(NSSplitView *)sender constrainMinCoordinate:(CGFloat)min ofSubviewAt:(NSInteger)offs {
427   return (min < 100) ? 100 : min;
428}
429
430
431- (CGFloat)splitView:(NSSplitView *)sender constrainMaxCoordinate:(CGFloat)max ofSubviewAt:(NSInteger)offs {
432   NSSize   sz = [sender bounds].size;
433   CGFloat   allowed = ([sender isVertical] ? sz.width : sz.height) - 100 - [sender dividerThickness];
434   return (max > allowed) ? allowed : max;
435}
436
437
438- (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview {
439   // allow registers or disassembly to be collapsed, but not console
440   return [[sender subviews] indexOfObjectIdenticalTo:subview] == 0;
441}
442
443
444- (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize {
445   // This can only deal with a single split, but that's all we use, anyway
446   NSRect first, second;
447   [sender adjustSubviews];
448   first = [[[sender subviews] objectAtIndex:0] frame];
449   second = [[[sender subviews] objectAtIndex:1] frame];
450   if ([sender isVertical]) {
451      if (first.size.width < 100) {
452         CGFloat diff = 100 - first.size.width;
453         first.size.width = 100;
454         second.origin.x += diff;
455         second.size.width -= diff;
456      } else if (second.size.width < 100) {
457         CGFloat diff = 100 - second.size.width;
458         second.size.width = 100;
459         second.origin.x -= diff;
460         first.size.width -= diff;
461      }
462   } else {
463      if (first.size.height < 100) {
464         CGFloat diff = 100 - first.size.height;
465         first.size.height = 100;
466         second.origin.y += diff;
467         second.size.height -= diff;
468      } else if (second.size.height < 100) {
469         CGFloat diff = 100 - second.size.height;
470         second.size.height = 100;
471         second.origin.y -= diff;
472         first.size.height -= diff;
473      }
474   }
475   [[[sender subviews] objectAtIndex:0] setFrame:first];
476   [[[sender subviews] objectAtIndex:1] setFrame:second];
477}
478
479
480- (BOOL)validateMenuItem:(NSMenuItem *)item {
481   SEL const action = [item action];
482   BOOL const inContextMenu = ([item menu] == [dasmView menu]);
483   BOOL const haveCursor = [dasmView cursorVisible];
484   BOOL const isCurrent = (debug_cpu_get_visible_cpu(*machine) == &[dasmView source]->device());
485
486   device_debug::breakpoint *breakpoint = NULL;
487   if (haveCursor)
488   {
489      breakpoint = [[self class] findBreakpointAtAddress:[dasmView selectedAddress]
490                                     forDevice:[dasmView source]->device()];
491   }
492
493   if (action == @selector(debugToggleBreakpoint:))
494   {
495      if (haveCursor)
496      {
497         if (breakpoint != NULL)
498         {
499            if (inContextMenu)
500               [item setTitle:@"Clear Breakpoint"];
501            else
502               [item setTitle:@"Clear Breakpoint at Cursor"];
503         }
504         else
505         {
506            if (inContextMenu)
507               [item setTitle:@"Set Breakpoint"];
508            else
509               [item setTitle:@"Set Breakpoint at Cursor"];
510         }
511      }
512      else
513      {
514         if (inContextMenu)
515            [item setTitle:@"Toggle Breakpoint"];
516         else
517            [item setTitle:@"Toggle Breakpoint at Cursor"];
518      }
519      return haveCursor && isCurrent;
520   }
521   else if (action == @selector(debugToggleBreakpointEnable:))
522   {
523      if ((breakpoint != NULL) && !breakpoint->enabled())
524      {
525         if (inContextMenu)
526            [item setTitle:@"Enable Breakpoint"];
527         else
528            [item setTitle:@"Enable Breakpoint at Cursor"];
529      }
530      else
531      {
532         if (inContextMenu)
533            [item setTitle:@"Disable Breakpoint"];
534         else
535            [item setTitle:@"Disable Breakpoint at Cursor"];
536      }
537      return (breakpoint != NULL) && isCurrent;
538   }
539   else if (action == @selector(debugRunToCursor:))
540   {
541      return isCurrent;
542   }
543   else
544   {
545      return YES;
546   }
547}
548
549@end
trunk/src/osd/modules/debugger/osx/debugview.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  debugview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "debugview.h"
10
11#include "debug/debugcpu.h"
12
13#include "modules/lib/osdobj_common.h"
14
15#include <string.h>
16
17
18static NSColor *DefaultForeground;
19static NSColor *ChangedForeground;
20static NSColor *InvalidForeground;
21static NSColor *CommentForeground;
22static NSColor *DisabledChangedForeground;
23static NSColor *DisabledInvalidForeground;
24static NSColor *DisabledCommentForeground;
25
26static NSColor *DefaultBackground;
27static NSColor *VisitedBackground;
28static NSColor *AncillaryBackground;
29static NSColor *SelectedBackground;
30static NSColor *CurrentBackground;
31static NSColor *SelectedCurrentBackground;
32static NSColor *InactiveSelectedBackground;
33static NSColor *InactiveSelectedCurrentBackground;
34
35static NSCharacterSet *NonWhiteCharacters;
36
37
38static void debugwin_view_update(debug_view &view, void *osdprivate)
39{
40   NSAutoreleasePool *const pool = [[NSAutoreleasePool alloc] init];
41   [(MAMEDebugView *)osdprivate update];
42   [pool release];
43}
44
45
46@implementation MAMEDebugView
47
48+ (void)initialize {
49   DefaultForeground = [[NSColor colorWithCalibratedWhite:0.0 alpha:1.0] retain];
50   ChangedForeground = [[NSColor colorWithCalibratedRed:0.875 green:0.0 blue:0.0 alpha:1.0] retain];
51   InvalidForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:1.0 alpha:1.0] retain];
52   CommentForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.375 blue:0.0 alpha:1.0] retain];
53   DisabledChangedForeground = [[NSColor colorWithCalibratedRed:0.5 green:0.125 blue:0.125 alpha:1.0] retain];
54   DisabledInvalidForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.5 alpha:1.0] retain];
55   DisabledCommentForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.25 blue:0.0 alpha:1.0] retain];
56
57   DefaultBackground = [[NSColor colorWithCalibratedWhite:1.0 alpha:1.0] retain];
58   VisitedBackground = [[NSColor colorWithCalibratedRed:0.75 green:1.0 blue:0.75 alpha:1.0] retain];
59   AncillaryBackground = [[NSColor colorWithCalibratedWhite:0.75 alpha:1.0] retain];
60   SelectedBackground = [[NSColor colorWithCalibratedRed:0.75 green:0.875 blue:1.0 alpha:1.0] retain];
61   CurrentBackground = [[NSColor colorWithCalibratedRed:1.0 green:0.75 blue:0.75 alpha:1.0] retain];
62   SelectedCurrentBackground = [[NSColor colorWithCalibratedRed:0.875 green:0.625 blue:0.875 alpha:1.0] retain];
63   InactiveSelectedBackground = [[NSColor colorWithCalibratedWhite:0.875 alpha:1.0] retain];
64   InactiveSelectedCurrentBackground = [[NSColor colorWithCalibratedRed:0.875 green:0.5 blue:0.625 alpha:1.0] retain];
65
66   NonWhiteCharacters = [[NSCharacterSet whitespaceAndNewlineCharacterSet] invertedSet];
67}
68
69
70- (NSColor *)foregroundForAttribute:(UINT8)attrib {
71   if (attrib & DCA_COMMENT)
72      return (attrib & DCA_DISABLED) ? DisabledCommentForeground : CommentForeground;
73   else if (attrib & DCA_INVALID)
74      return (attrib & DCA_DISABLED) ? DisabledInvalidForeground : InvalidForeground;
75   else if (attrib & DCA_CHANGED)
76      return (attrib & DCA_DISABLED) ? DisabledChangedForeground : ChangedForeground;
77   else
78      return DefaultForeground;
79}
80
81
82- (NSColor *)backgroundForAttribute:(UINT8)attrib {
83   BOOL const active = [[self window] isKeyWindow] && ([[self window] firstResponder] == self);
84   if ((attrib & DCA_SELECTED) && (attrib & DCA_CURRENT))
85      return active ? SelectedCurrentBackground : InactiveSelectedCurrentBackground;
86   else if (attrib & DCA_CURRENT)
87      return CurrentBackground;
88   else if (attrib & DCA_SELECTED)
89      return active ? SelectedBackground : InactiveSelectedBackground;
90   else if (attrib & DCA_ANCILLARY)
91      return AncillaryBackground;
92   else if (attrib & DCA_VISITED)
93      return VisitedBackground;
94   else
95      return DefaultBackground;
96}
97
98
99- (debug_view_xy)convertLocation:(NSPoint)location {
100   debug_view_xy position;
101
102   position.y = lround(floor(location.y / fontHeight));
103   if (position.y < 0)
104      position.y = 0;
105   else if (position.y >= totalHeight)
106      position.y = totalHeight - 1;
107
108   debug_view_xy const origin = view->visible_position();
109   debug_view_xy const size = view->visible_size();
110   debug_view_char const *data = view->viewdata();
111   if (!data || (position.y < origin.y) || (position.y >= origin.y + size.y))
112   {
113      // y coordinate outside visible area, x will be a guess
114      position.x = lround(floor((location.x - [textContainer lineFragmentPadding]) / fontWidth));
115   }
116   else
117   {
118      data += ((position.y - view->visible_position().y) * view->visible_size().x);
119      int         attr = -1;
120      NSUInteger   start = 0, length = 0;
121      for (UINT32 col = origin.x; col < origin.x + size.x; col++)
122      {
123         [[text mutableString] appendFormat:@"%c", data[col - origin.x].byte];
124         if ((start < length) && (attr != data[col - origin.x].attrib))
125         {
126            NSRange const run = NSMakeRange(start, length - start);
127            [text addAttribute:NSFontAttributeName
128                      value:font
129                      range:NSMakeRange(0, length)];
130            [text addAttribute:NSForegroundColorAttributeName
131                      value:[self foregroundForAttribute:attr]
132                      range:run];
133            start = length;
134         }
135         attr = data[col - origin.x].attrib;
136         length = [text length];
137      }
138      if (start < length)
139      {
140         NSRange const run = NSMakeRange(start, length - start);
141         [text addAttribute:NSFontAttributeName
142                   value:font
143                   range:NSMakeRange(0, length)];
144         [text addAttribute:NSForegroundColorAttributeName
145                   value:[self foregroundForAttribute:attr]
146                   range:run];
147      }
148      CGFloat fraction;
149      NSUInteger const glyph = [layoutManager glyphIndexForPoint:NSMakePoint(location.x, fontHeight / 2)
150                                       inTextContainer:textContainer
151                           fractionOfDistanceThroughGlyph:&fraction];
152      position.x = [layoutManager characterIndexForGlyphAtIndex:glyph]; // FIXME: assumes 1:1 character mapping
153      [text deleteCharactersInRange:NSMakeRange(0, length)];
154   }
155   if (position.x < 0)
156      position.x = 0;
157   else if (position.x >= totalWidth)
158      position.x = totalWidth - 1;
159
160   return position;
161}
162
163
164- (void)convertBounds:(NSRect)b toFirstAffectedLine:(INT32 *)f count:(INT32 *)c {
165   *f = lround(floor(b.origin.y / fontHeight));
166   *c = lround(ceil((b.origin.y + b.size.height) / fontHeight)) - *f;
167}
168
169
170- (void)recomputeVisible {
171   // this gets all the lines that are at least partially visible
172   debug_view_xy origin(0, 0), size(totalWidth, totalHeight);
173   [self convertBounds:[self visibleRect] toFirstAffectedLine:&origin.y count:&size.y];
174   size.y = MIN(size.y, totalHeight - origin.y);
175
176   // tell the underlying view how much real estate is available
177   view->set_visible_size(size);
178   view->set_visible_position(origin);
179   originTop = origin.y;
180}
181
182
183- (void)typeCharacterAndScrollToCursor:(char)ch {
184   debug_view_xy const oldPos = view->cursor_position();
185   view->process_char(ch);
186   if (view->cursor_supported() && view->cursor_visible())
187   {
188      debug_view_xy const newPos = view->cursor_position();
189      if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y))
190      {
191         // FIXME - use proper font metrics
192         [self scrollRectToVisible:NSMakeRect((newPos.x * fontWidth) + [textContainer lineFragmentPadding],
193                                     newPos.y * fontHeight,
194                                     fontWidth,
195                                     fontHeight)];
196      }
197   }
198}
199
200
201- (void)adjustSizeAndRecomputeVisible {
202   NSSize const clip = [[[self enclosingScrollView] contentView] bounds].size;
203   NSSize content = NSMakeSize((fontWidth * totalWidth) + (2 * [textContainer lineFragmentPadding]),
204                        fontHeight * totalHeight);
205   if (wholeLineScroll)
206      content.height += (fontHeight * 2) - 1;
207   [self setFrameSize:NSMakeSize(ceil(MAX(clip.width, content.width)),
208                          ceil(MAX(clip.height, content.height)))];
209   [self recomputeVisible];
210}
211
212
213+ (NSFont *)defaultFontForMachine:(running_machine &)m {
214   osd_options const &options = downcast<osd_options const &>(m.options());
215   char const *const face = options.debugger_font();
216   float const size = options.debugger_font_size();
217
218   NSFont *const result = (('\0' != *face) && (0 != strcmp(OSDOPTVAL_AUTO, face)))
219                   ? [NSFont fontWithName:[NSString stringWithUTF8String:face] size:MAX(0, size)]
220                   : nil;
221
222   return (nil != result) ? result : [NSFont userFixedPitchFontOfSize:MAX(0, size)];
223}
224
225
226- (id)initWithFrame:(NSRect)f type:(debug_view_type)t machine:(running_machine &)m wholeLineScroll:(BOOL)w {
227   if (!(self = [super initWithFrame:f]))
228      return nil;
229   type = t;
230   machine = &m;
231   view = machine->debug_view().alloc_view((debug_view_type)type, debugwin_view_update, self);
232   if (view == nil) {
233      [self release];
234      return nil;
235   }
236   wholeLineScroll = w;
237   debug_view_xy const size = view->total_size();
238   totalWidth = size.x;
239   totalHeight = size.y;
240   originTop = 0;
241
242   text = [[NSTextStorage alloc] init];
243   textContainer = [[NSTextContainer alloc] init];
244   layoutManager = [[NSLayoutManager alloc] init];
245   [layoutManager addTextContainer:textContainer];
246   [textContainer release];
247   [text addLayoutManager:layoutManager];
248   [layoutManager release];
249
250   [self setFont:[[self class] defaultFontForMachine:m]];
251
252   NSMenu *contextMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Context"];
253   [self addContextMenuItemsToMenu:contextMenu];
254   [self setMenu:contextMenu];
255   [contextMenu release];
256
257   return self;
258}
259
260
261- (void)dealloc {
262   [[NSNotificationCenter defaultCenter] removeObserver:self];
263   if (view != NULL) machine->debug_view().free_view(*view);
264   if (font != nil) [font release];
265   if (text != nil) [text release];
266   [super dealloc];
267}
268
269
270- (void)update {
271   // resize our frame if the total size has changed
272   debug_view_xy const newSize = view->total_size();
273   BOOL const resized = (newSize.x != totalWidth) || (newSize.y != totalHeight);
274   if (resized)
275   {
276      NSScrollView *const scroller = [self enclosingScrollView];
277      if (scroller)
278      {
279         NSSize const clip = [[scroller contentView] bounds].size;
280         NSSize content = NSMakeSize((fontWidth * newSize.x) + (2 * [textContainer lineFragmentPadding]),
281                              fontHeight * newSize.y);
282         if (wholeLineScroll)
283            content.height += (fontHeight * 2) - 1;
284         [self setFrameSize:NSMakeSize(ceil(MAX(clip.width, content.width)),
285                                ceil(MAX(clip.height, content.height)))];
286      }
287      totalWidth = newSize.x;
288      totalHeight = newSize.y;
289   }
290
291   // scroll the view if we're being told to
292   debug_view_xy const newOrigin = view->visible_position();
293   if (newOrigin.y != originTop)
294   {
295      NSRect const visible = [self visibleRect];
296      NSPoint scroll = NSMakePoint(visible.origin.x, newOrigin.y * fontHeight);
297      [self scrollPoint:scroll];
298      originTop = newOrigin.y;
299   }
300
301   // mark as dirty
302   [self setNeedsDisplay:YES];
303}
304
305
306- (NSSize)maximumFrameSize {
307   debug_view_xy const max = view->total_size();
308   return NSMakeSize(ceil((max.x * fontWidth) + (2 * [textContainer lineFragmentPadding])),
309                 ceil((max.y + (wholeLineScroll ? 1 : 0)) * fontHeight));
310}
311
312
313- (NSFont *)font {
314   return [[font retain] autorelease];
315}
316
317
318- (void)setFont:(NSFont *)f {
319   [font autorelease];
320   font = [f retain];
321   fontWidth = [font maximumAdvancement].width;
322   fontHeight = ceil([font ascender] - [font descender]);
323   fontAscent = [font ascender];
324   [[self enclosingScrollView] setLineScroll:fontHeight];
325   totalWidth = totalHeight = 0;
326   [self update];
327}
328
329
330- (BOOL)cursorSupported {
331   return view->cursor_supported();
332}
333
334
335- (BOOL)cursorVisible {
336   return view->cursor_visible();
337}
338
339
340- (debug_view_xy)cursorPosition {
341   return view->cursor_position();
342}
343
344
345- (IBAction)copyVisible:(id)sender {
346   debug_view_xy const size = view->visible_size();
347   debug_view_char const *data = view->viewdata();
348   if (!data)
349   {
350      NSBeep();
351      return;
352   }
353
354   for (UINT32 row = 0; row < size.y; row++, data += size.x)
355   {
356      // add content for the line and set colours
357      int         attr = -1;
358      NSUInteger   start = [text length], length = start;
359      for (UINT32 col = 0; col < size.x; col++)
360      {
361         [[text mutableString] appendFormat:@"%c", data[col].byte];
362         if ((start < length) && (attr != (data[col].attrib & ~DCA_SELECTED)))
363         {
364            NSRange const run = NSMakeRange(start, length - start);
365            [text addAttribute:NSForegroundColorAttributeName
366                      value:[self foregroundForAttribute:attr]
367                      range:run];
368            [text addAttribute:NSBackgroundColorAttributeName
369                      value:[self backgroundForAttribute:attr]
370                      range:run];
371            start = length;
372         }
373         attr = data[col].attrib & ~DCA_SELECTED;
374         length = [text length];
375      }
376
377      // clean up trailing whitespace
378      NSRange trim = [[text string] rangeOfCharacterFromSet:NonWhiteCharacters
379                                         options:NSBackwardsSearch
380                                          range:NSMakeRange(start, length - start)];
381      if (trim.location != NSNotFound)
382         trim = [[text string] rangeOfComposedCharacterSequenceAtIndex:(trim.location + trim.length - 1)];
383      else if (start > 0)
384         trim = [[text string] rangeOfComposedCharacterSequenceAtIndex:(start - 1)];
385      else
386         trim = NSMakeRange(start, 0);
387      trim.location += trim.length;
388      trim.length = length - trim.location;
389      [text deleteCharactersInRange:trim];
390
391      // add the line ending and set colours
392      [[text mutableString] appendString:@"\n"];
393      NSRange const run = NSMakeRange(start, [text length] - start);
394      [text addAttribute:NSForegroundColorAttributeName
395                value:[self foregroundForAttribute:attr]
396                range:run];
397      [text addAttribute:NSBackgroundColorAttributeName
398                value:[self backgroundForAttribute:attr]
399                range:run];
400   }
401
402   // set the font and send it to the pasteboard
403   NSRange const run = NSMakeRange(0, [text length]);
404   [text addAttribute:NSFontAttributeName value:font range:run];
405   NSPasteboard *const board = [NSPasteboard generalPasteboard];
406   [board declareTypes:[NSArray arrayWithObject:NSRTFPboardType] owner:nil];
407   [board setData:[text RTFFromRange:run documentAttributes:[NSDictionary dictionary]] forType:NSRTFPboardType];
408   [text deleteCharactersInRange:run];
409}
410
411
412- (IBAction)paste:(id)sender {
413   NSPasteboard *const board = [NSPasteboard generalPasteboard];
414   NSString *const avail = [board availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]];
415   if (avail == nil)
416   {
417      NSBeep();
418      return;
419   }
420
421   NSData *const data = [[board stringForType:avail] dataUsingEncoding:NSASCIIStringEncoding
422                                       allowLossyConversion:YES];
423   char const *const bytes = (char const *)[data bytes];
424   debug_view_xy const oldPos = view->cursor_position();
425   for (NSUInteger i = 0, l = [data length]; i < l; i++)
426      view->process_char(bytes[i]);
427   if (view->cursor_supported() && view->cursor_visible())
428   {
429      debug_view_xy const newPos = view->cursor_position();
430      if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y))
431      {
432         // FIXME - use proper font metrics
433         [self scrollRectToVisible:NSMakeRect((newPos.x * fontWidth) + [textContainer lineFragmentPadding],
434                                     newPos.y * fontHeight,
435                                     fontWidth,
436                                     fontHeight)];
437      }
438   }
439}
440
441
442- (void)viewBoundsDidChange:(NSNotification *)notification {
443   NSView *const changed = [notification object];
444   if (changed == [[self enclosingScrollView] contentView])
445      [self adjustSizeAndRecomputeVisible];
446}
447
448
449- (void)viewFrameDidChange:(NSNotification *)notification {
450   NSView *const changed = [notification object];
451   if (changed == [[self enclosingScrollView] contentView])
452      [self adjustSizeAndRecomputeVisible];
453}
454
455
456- (void)windowDidBecomeKey:(NSNotification *)notification {
457   NSWindow *const win = [notification object];
458   if ((win == [self window]) && ([win firstResponder] == self) && view->cursor_supported())
459      [self setNeedsDisplay:YES];
460}
461
462
463- (void)windowDidResignKey:(NSNotification *)notification {
464   NSWindow *const win = [notification object];
465   if ((win == [self window]) && ([win firstResponder] == self) && view->cursor_supported())
466      [self setNeedsDisplay:YES];
467}
468
469
470- (void)addContextMenuItemsToMenu:(NSMenu *)menu {
471   NSMenuItem   *item;
472
473   item = [menu addItemWithTitle:@"Copy Visible"
474                     action:@selector(copyVisible:)
475               keyEquivalent:@""];
476   [item setTarget:self];
477
478   item = [menu addItemWithTitle:@"Paste"
479                     action:@selector(paste:)
480               keyEquivalent:@""];
481   [item setTarget:self];
482}
483
484
485- (BOOL)acceptsFirstResponder {
486   return view->cursor_supported();
487}
488
489
490- (BOOL)becomeFirstResponder {
491   if (view->cursor_supported())
492   {
493      debug_view_xy pos;
494      view->set_cursor_visible(true);
495      pos = view->cursor_position();
496      [self scrollRectToVisible:NSMakeRect((pos.x * fontWidth) + [textContainer lineFragmentPadding],
497                                  pos.y * fontHeight,
498                                  fontWidth,
499                                  fontHeight)]; // FIXME: metrics
500      [self setNeedsDisplay:YES];
501      return [super becomeFirstResponder];
502   }
503   else
504   {
505      return NO;
506   }
507}
508
509
510- (BOOL)resignFirstResponder {
511   if (view->cursor_supported())
512      [self setNeedsDisplay:YES];
513   return [super resignFirstResponder];
514}
515
516
517- (void)viewDidMoveToSuperview {
518   [super viewDidMoveToSuperview];
519
520   [[NSNotificationCenter defaultCenter] removeObserver:self
521                                       name:NSViewBoundsDidChangeNotification
522                                      object:nil];
523   [[NSNotificationCenter defaultCenter] removeObserver:self
524                                       name:NSViewFrameDidChangeNotification
525                                      object:nil];
526
527   NSScrollView *const scroller = [self enclosingScrollView];
528   if (scroller != nil)
529   {
530      [scroller setLineScroll:fontHeight];
531      [[scroller contentView] setPostsBoundsChangedNotifications:YES];
532      [[scroller contentView] setPostsFrameChangedNotifications:YES];
533      [[NSNotificationCenter defaultCenter] addObserver:self
534                                     selector:@selector(viewBoundsDidChange:)
535                                        name:NSViewBoundsDidChangeNotification
536                                       object:[scroller contentView]];
537      [[NSNotificationCenter defaultCenter] addObserver:self
538                                     selector:@selector(viewFrameDidChange:)
539                                        name:NSViewFrameDidChangeNotification
540                                       object:[scroller contentView]];
541      [self adjustSizeAndRecomputeVisible];
542   }
543}
544
545
546- (void)viewDidMoveToWindow {
547   [super viewDidMoveToWindow];
548
549   [[NSNotificationCenter defaultCenter] removeObserver:self
550                                       name:NSWindowDidBecomeKeyNotification
551                                      object:nil];
552   [[NSNotificationCenter defaultCenter] removeObserver:self
553                                       name:NSWindowDidResignKeyNotification
554                                      object:nil];
555
556   if ([self window] != nil)
557   {
558      [[NSNotificationCenter defaultCenter] addObserver:self
559                                     selector:@selector(windowDidBecomeKey:)
560                                        name:NSWindowDidBecomeKeyNotification
561                                       object:[self window]];
562      [[NSNotificationCenter defaultCenter] addObserver:self
563                                     selector:@selector(windowDidResignKey:)
564                                        name:NSWindowDidResignKeyNotification
565                                       object:[self window]];
566      [self setNeedsDisplay:YES];
567   }
568}
569
570
571- (BOOL)isFlipped {
572   return YES;
573}
574
575
576- (BOOL)isOpaque {
577   return YES;
578}
579
580
581- (NSRect)adjustScroll:(NSRect)proposedVisibleRect {
582   if (wholeLineScroll)
583   {
584      CGFloat const clamp = [self bounds].size.height - fontHeight - proposedVisibleRect.size.height;
585      proposedVisibleRect.origin.y = MIN(proposedVisibleRect.origin.y, MAX(clamp, 0));
586      proposedVisibleRect.origin.y -= fmod(proposedVisibleRect.origin.y, fontHeight);
587   }
588   return proposedVisibleRect;
589}
590
591
592- (void)drawRect:(NSRect)dirtyRect {
593   // work out what's available
594   [self recomputeVisible];
595   debug_view_xy const origin = view->visible_position();
596   debug_view_xy const size = view->visible_size();
597
598   // work out how much we need to draw
599   INT32 row, clip;
600   [self convertBounds:dirtyRect toFirstAffectedLine:&row count:&clip];
601   clip += row;
602   row = MAX(row, origin.y);
603   clip = MIN(clip, origin.y + size.y);
604
605   // this gets the text for the whole visible area
606   debug_view_char const *data = view->viewdata();
607   if (!data)
608      return;
609
610   // clear any space above the available content
611   data += ((row - origin.y) * size.x);
612   if (dirtyRect.origin.y < (row * fontHeight))
613   {
614      [DefaultBackground set];
615      [NSBezierPath fillRect:NSMakeRect(0,
616                                dirtyRect.origin.y,
617                                [self bounds].size.width,
618                                (row * fontHeight) - dirtyRect.origin.y)];
619   }
620
621   // render entire lines to get character alignment right
622   for ( ; row < clip; row++, data += size.x)
623   {
624      int         attr = -1;
625      NSUInteger   start = 0, length = 0;
626      for (UINT32 col = origin.x; col < origin.x + size.x; col++)
627      {
628         [[text mutableString] appendFormat:@"%c", data[col - origin.x].byte];
629         if ((start < length) && (attr != data[col - origin.x].attrib))
630         {
631            NSRange const run = NSMakeRange(start, length - start);
632            [text addAttribute:NSFontAttributeName
633                      value:font
634                      range:NSMakeRange(0, length)];
635            [text addAttribute:NSForegroundColorAttributeName
636                      value:[self foregroundForAttribute:attr]
637                      range:run];
638            NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run
639                                              actualCharacterRange:NULL];
640            NSRect box = [layoutManager boundingRectForGlyphRange:glyphs
641                                         inTextContainer:textContainer];
642            if (start == 0)
643            {
644               box.size.width += box.origin.x;
645               box.origin.x = 0;
646            }
647            [[self backgroundForAttribute:attr] set];
648            [NSBezierPath fillRect:NSMakeRect(box.origin.x,
649                                      row * fontHeight,
650                                      box.size.width,
651                                      fontHeight)];
652            start = length;
653         }
654         attr = data[col - origin.x].attrib;
655         length = [text length];
656      }
657      NSRange const run = NSMakeRange(start, length - start);
658      [text addAttribute:NSFontAttributeName
659                value:font
660                range:NSMakeRange(0, length)];
661      [text addAttribute:NSForegroundColorAttributeName
662                value:[self foregroundForAttribute:attr]
663                range:run];
664      NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run
665                                        actualCharacterRange:NULL];
666      NSRect box = [layoutManager boundingRectForGlyphRange:glyphs
667                                   inTextContainer:textContainer];
668      if (start == 0)
669         box.origin.x = 0;
670      box.size.width = MAX([self bounds].size.width - box.origin.x, 0);
671      [[self backgroundForAttribute:attr] set];
672      [NSBezierPath fillRect:NSMakeRect(box.origin.x,
673                                row * fontHeight,
674                                box.size.width,
675                                fontHeight)];
676      [layoutManager drawGlyphsForGlyphRange:[layoutManager glyphRangeForTextContainer:textContainer]
677                              atPoint:NSMakePoint(0, row * fontHeight)];
678      [text deleteCharactersInRange:NSMakeRange(0, length)];
679   }
680
681   // clear any space below the available content
682   if ((dirtyRect.origin.y + dirtyRect.size.height) > (row * fontHeight))
683   {
684      [DefaultBackground set];
685      [NSBezierPath fillRect:NSMakeRect(0,
686                                row * fontHeight,
687                                [self bounds].size.width,
688                                (dirtyRect.origin.y + dirtyRect.size.height) - (row * fontHeight))];
689   }
690}
691
692
693- (void)mouseDown:(NSEvent *)event {
694   NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil];
695   NSUInteger const modifiers = [event modifierFlags];
696   view->process_click(((modifiers & NSCommandKeyMask) && [[self window] isMainWindow]) ? DCK_RIGHT_CLICK
697                 : (modifiers & NSAlternateKeyMask) ? DCK_MIDDLE_CLICK
698                 : DCK_LEFT_CLICK,
699                  [self convertLocation:location]);
700}
701
702
703- (void)mouseDragged:(NSEvent *)event {
704   [self autoscroll:event];
705   NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil];
706   NSUInteger const modifiers = [event modifierFlags];
707   if (view->cursor_supported()
708    && !(modifiers & NSAlternateKeyMask)
709    && (!(modifiers & NSCommandKeyMask) || ![[self window] isMainWindow]))
710   {
711      view->set_cursor_position([self convertLocation:location]);
712      view->set_cursor_visible(true);
713      [self setNeedsDisplay:YES];
714   }
715}
716
717
718- (void)rightMouseDown:(NSEvent *)event {
719   NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil];
720   if (view->cursor_supported())
721   {
722      view->set_cursor_position([self convertLocation:location]);
723      view->set_cursor_visible(true);
724      [self setNeedsDisplay:YES];
725   }
726   [super rightMouseDown:event];
727}
728
729
730- (void)keyDown:(NSEvent *)event {
731   NSUInteger   modifiers = [event modifierFlags];
732   NSString   *str = [event charactersIgnoringModifiers];
733
734   if ([str length] == 1)
735   {
736      if (modifiers & NSNumericPadKeyMask)
737      {
738         switch ([str characterAtIndex:0])
739         {
740         case NSUpArrowFunctionKey:
741            if (modifiers & NSCommandKeyMask)
742               view->process_char(DCH_CTRLHOME);
743            else
744               view->process_char(DCH_UP);
745            return;
746         case NSDownArrowFunctionKey:
747            if (modifiers & NSCommandKeyMask)
748               view->process_char(DCH_CTRLEND);
749            else
750               view->process_char(DCH_DOWN);
751            return;
752         case NSLeftArrowFunctionKey:
753            if (modifiers & NSCommandKeyMask)
754               [self typeCharacterAndScrollToCursor:DCH_HOME];
755            else if (modifiers & NSAlternateKeyMask)
756               [self typeCharacterAndScrollToCursor:DCH_CTRLLEFT];
757            else
758               [self typeCharacterAndScrollToCursor:DCH_LEFT];
759            return;
760         case NSRightArrowFunctionKey:
761            if (modifiers & NSCommandKeyMask)
762               [self typeCharacterAndScrollToCursor:DCH_END];
763            else if (modifiers & NSAlternateKeyMask)
764               [self typeCharacterAndScrollToCursor:DCH_CTRLRIGHT];
765            else
766               [self typeCharacterAndScrollToCursor:DCH_RIGHT];
767            return;
768         default:
769            [self interpretKeyEvents:[NSArray arrayWithObject:event]];
770            return;
771         }
772      }
773      else if (modifiers & NSFunctionKeyMask)
774      {
775         switch ([str characterAtIndex:0])
776         {
777            case NSPageUpFunctionKey:
778               if (modifiers & NSAlternateKeyMask)
779               {
780                  view->process_char(DCH_PUP);
781                  return;
782               }
783            case NSPageDownFunctionKey:
784               if (modifiers & NSAlternateKeyMask)
785               {
786                  view->process_char(DCH_PDOWN);
787                  return;
788               }
789            default:
790               ;
791         }
792         [super keyDown:event];
793         return;
794      }
795   }
796   [self interpretKeyEvents:[NSArray arrayWithObject:event]];
797}
798
799
800- (void)insertTab:(id)sender {
801   if ([[self window] firstResponder] == self)
802      [[self window] selectNextKeyView:self];
803}
804
805
806- (void)insertBacktab:(id)sender {
807   if ([[self window] firstResponder] == self)
808      [[self window] selectPreviousKeyView:self];
809}
810
811
812- (void)insertNewline:(id)sender {
813   debug_cpu_get_visible_cpu(*machine)->debug()->single_step();
814}
815
816
817- (void)insertText:(id)string {
818   NSUInteger   len;
819   NSRange      found;
820   if ([string isKindOfClass:[NSAttributedString class]])
821      string = [string string];
822   for (len = [string length], found = NSMakeRange(0, 0);
823       found.location < len;
824       found.location += found.length) {
825      found = [string rangeOfComposedCharacterSequenceAtIndex:found.location];
826      if (found.length == 1) {
827         unichar ch = [string characterAtIndex:found.location];
828         if ((ch >= 32) && (ch < 127))
829            [self typeCharacterAndScrollToCursor:ch];
830      }
831   }
832}
833
834
835- (BOOL)validateMenuItem:(NSMenuItem *)item {
836   SEL   action = [item action];
837
838   if (action == @selector(paste:))
839   {
840      NSPasteboard *const board = [NSPasteboard generalPasteboard];
841      return [board availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]] != nil;
842   }
843   else
844   {
845      return YES;
846   }
847}
848
849@end
trunk/src/osd/modules/debugger/osx/debugview.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  debugview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "debugview.h"
10
11#include "debug/debugcpu.h"
12
13#include "modules/lib/osdobj_common.h"
14
15#include <string.h>
16
17
18static NSColor *DefaultForeground;
19static NSColor *ChangedForeground;
20static NSColor *InvalidForeground;
21static NSColor *CommentForeground;
22static NSColor *DisabledChangedForeground;
23static NSColor *DisabledInvalidForeground;
24static NSColor *DisabledCommentForeground;
25
26static NSColor *DefaultBackground;
27static NSColor *VisitedBackground;
28static NSColor *AncillaryBackground;
29static NSColor *SelectedBackground;
30static NSColor *CurrentBackground;
31static NSColor *SelectedCurrentBackground;
32static NSColor *InactiveSelectedBackground;
33static NSColor *InactiveSelectedCurrentBackground;
34
35static NSCharacterSet *NonWhiteCharacters;
36
37
38static void debugwin_view_update(debug_view &view, void *osdprivate)
39{
40   NSAutoreleasePool *const pool = [[NSAutoreleasePool alloc] init];
41   [(MAMEDebugView *)osdprivate update];
42   [pool release];
43}
44
45
46@implementation MAMEDebugView
47
48+ (void)initialize {
49   DefaultForeground = [[NSColor colorWithCalibratedWhite:0.0 alpha:1.0] retain];
50   ChangedForeground = [[NSColor colorWithCalibratedRed:0.875 green:0.0 blue:0.0 alpha:1.0] retain];
51   InvalidForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:1.0 alpha:1.0] retain];
52   CommentForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.375 blue:0.0 alpha:1.0] retain];
53   DisabledChangedForeground = [[NSColor colorWithCalibratedRed:0.5 green:0.125 blue:0.125 alpha:1.0] retain];
54   DisabledInvalidForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.5 alpha:1.0] retain];
55   DisabledCommentForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.25 blue:0.0 alpha:1.0] retain];
56
57   DefaultBackground = [[NSColor colorWithCalibratedWhite:1.0 alpha:1.0] retain];
58   VisitedBackground = [[NSColor colorWithCalibratedRed:0.75 green:1.0 blue:0.75 alpha:1.0] retain];
59   AncillaryBackground = [[NSColor colorWithCalibratedWhite:0.75 alpha:1.0] retain];
60   SelectedBackground = [[NSColor colorWithCalibratedRed:0.75 green:0.875 blue:1.0 alpha:1.0] retain];
61   CurrentBackground = [[NSColor colorWithCalibratedRed:1.0 green:0.75 blue:0.75 alpha:1.0] retain];
62   SelectedCurrentBackground = [[NSColor colorWithCalibratedRed:0.875 green:0.625 blue:0.875 alpha:1.0] retain];
63   InactiveSelectedBackground = [[NSColor colorWithCalibratedWhite:0.875 alpha:1.0] retain];
64   InactiveSelectedCurrentBackground = [[NSColor colorWithCalibratedRed:0.875 green:0.5 blue:0.625 alpha:1.0] retain];
65
66   NonWhiteCharacters = [[NSCharacterSet whitespaceAndNewlineCharacterSet] invertedSet];
67}
68
69
70- (NSColor *)foregroundForAttribute:(UINT8)attrib {
71   if (attrib & DCA_COMMENT)
72      return (attrib & DCA_DISABLED) ? DisabledCommentForeground : CommentForeground;
73   else if (attrib & DCA_INVALID)
74      return (attrib & DCA_DISABLED) ? DisabledInvalidForeground : InvalidForeground;
75   else if (attrib & DCA_CHANGED)
76      return (attrib & DCA_DISABLED) ? DisabledChangedForeground : ChangedForeground;
77   else
78      return DefaultForeground;
79}
80
81
82- (NSColor *)backgroundForAttribute:(UINT8)attrib {
83   BOOL const active = [[self window] isKeyWindow] && ([[self window] firstResponder] == self);
84   if ((attrib & DCA_SELECTED) && (attrib & DCA_CURRENT))
85      return active ? SelectedCurrentBackground : InactiveSelectedCurrentBackground;
86   else if (attrib & DCA_CURRENT)
87      return CurrentBackground;
88   else if (attrib & DCA_SELECTED)
89      return active ? SelectedBackground : InactiveSelectedBackground;
90   else if (attrib & DCA_ANCILLARY)
91      return AncillaryBackground;
92   else if (attrib & DCA_VISITED)
93      return VisitedBackground;
94   else
95      return DefaultBackground;
96}
97
98
99- (debug_view_xy)convertLocation:(NSPoint)location {
100   debug_view_xy position;
101
102   position.y = lround(floor(location.y / fontHeight));
103   if (position.y < 0)
104      position.y = 0;
105   else if (position.y >= totalHeight)
106      position.y = totalHeight - 1;
107
108   debug_view_xy const origin = view->visible_position();
109   debug_view_xy const size = view->visible_size();
110   debug_view_char const *data = view->viewdata();
111   if (!data || (position.y < origin.y) || (position.y >= origin.y + size.y))
112   {
113      // y coordinate outside visible area, x will be a guess
114      position.x = lround(floor((location.x - [textContainer lineFragmentPadding]) / fontWidth));
115   }
116   else
117   {
118      data += ((position.y - view->visible_position().y) * view->visible_size().x);
119      int         attr = -1;
120      NSUInteger   start = 0, length = 0;
121      for (UINT32 col = origin.x; col < origin.x + size.x; col++)
122      {
123         [[text mutableString] appendFormat:@"%c", data[col - origin.x].byte];
124         if ((start < length) && (attr != data[col - origin.x].attrib))
125         {
126            NSRange const run = NSMakeRange(start, length - start);
127            [text addAttribute:NSFontAttributeName
128                      value:font
129                      range:NSMakeRange(0, length)];
130            [text addAttribute:NSForegroundColorAttributeName
131                      value:[self foregroundForAttribute:attr]
132                      range:run];
133            start = length;
134         }
135         attr = data[col - origin.x].attrib;
136         length = [text length];
137      }
138      if (start < length)
139      {
140         NSRange const run = NSMakeRange(start, length - start);
141         [text addAttribute:NSFontAttributeName
142                   value:font
143                   range:NSMakeRange(0, length)];
144         [text addAttribute:NSForegroundColorAttributeName
145                   value:[self foregroundForAttribute:attr]
146                   range:run];
147      }
148      CGFloat fraction;
149      NSUInteger const glyph = [layoutManager glyphIndexForPoint:NSMakePoint(location.x, fontHeight / 2)
150                                       inTextContainer:textContainer
151                           fractionOfDistanceThroughGlyph:&fraction];
152      position.x = [layoutManager characterIndexForGlyphAtIndex:glyph]; // FIXME: assumes 1:1 character mapping
153      [text deleteCharactersInRange:NSMakeRange(0, length)];
154   }
155   if (position.x < 0)
156      position.x = 0;
157   else if (position.x >= totalWidth)
158      position.x = totalWidth - 1;
159
160   return position;
161}
162
163
164- (void)convertBounds:(NSRect)b toFirstAffectedLine:(INT32 *)f count:(INT32 *)c {
165   *f = lround(floor(b.origin.y / fontHeight));
166   *c = lround(ceil((b.origin.y + b.size.height) / fontHeight)) - *f;
167}
168
169
170- (void)recomputeVisible {
171   // this gets all the lines that are at least partially visible
172   debug_view_xy origin(0, 0), size(totalWidth, totalHeight);
173   [self convertBounds:[self visibleRect] toFirstAffectedLine:&origin.y count:&size.y];
174   size.y = MIN(size.y, totalHeight - origin.y);
175
176   // tell the underlying view how much real estate is available
177   view->set_visible_size(size);
178   view->set_visible_position(origin);
179   originTop = origin.y;
180}
181
182
183- (void)typeCharacterAndScrollToCursor:(char)ch {
184   debug_view_xy const oldPos = view->cursor_position();
185   view->process_char(ch);
186   if (view->cursor_supported() && view->cursor_visible())
187   {
188      debug_view_xy const newPos = view->cursor_position();
189      if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y))
190      {
191         // FIXME - use proper font metrics
192         [self scrollRectToVisible:NSMakeRect((newPos.x * fontWidth) + [textContainer lineFragmentPadding],
193                                     newPos.y * fontHeight,
194                                     fontWidth,
195                                     fontHeight)];
196      }
197   }
198}
199
200
201- (void)adjustSizeAndRecomputeVisible {
202   NSSize const clip = [[[self enclosingScrollView] contentView] bounds].size;
203   NSSize content = NSMakeSize((fontWidth * totalWidth) + (2 * [textContainer lineFragmentPadding]),
204                        fontHeight * totalHeight);
205   if (wholeLineScroll)
206      content.height += (fontHeight * 2) - 1;
207   [self setFrameSize:NSMakeSize(ceil(MAX(clip.width, content.width)),
208                          ceil(MAX(clip.height, content.height)))];
209   [self recomputeVisible];
210}
211
212
213+ (NSFont *)defaultFontForMachine:(running_machine &)m {
214   osd_options const &options = downcast<osd_options const &>(m.options());
215   char const *const face = options.debugger_font();
216   float const size = options.debugger_font_size();
217
218   NSFont *const result = (('\0' != *face) && (0 != strcmp(OSDOPTVAL_AUTO, face)))
219                   ? [NSFont fontWithName:[NSString stringWithUTF8String:face] size:MAX(0, size)]
220                   : nil;
221
222   return (nil != result) ? result : [NSFont userFixedPitchFontOfSize:MAX(0, size)];
223}
224
225
226- (id)initWithFrame:(NSRect)f type:(debug_view_type)t machine:(running_machine &)m wholeLineScroll:(BOOL)w {
227   if (!(self = [super initWithFrame:f]))
228      return nil;
229   type = t;
230   machine = &m;
231   view = machine->debug_view().alloc_view((debug_view_type)type, debugwin_view_update, self);
232   if (view == nil) {
233      [self release];
234      return nil;
235   }
236   wholeLineScroll = w;
237   debug_view_xy const size = view->total_size();
238   totalWidth = size.x;
239   totalHeight = size.y;
240   originTop = 0;
241
242   text = [[NSTextStorage alloc] init];
243   textContainer = [[NSTextContainer alloc] init];
244   layoutManager = [[NSLayoutManager alloc] init];
245   [layoutManager addTextContainer:textContainer];
246   [textContainer release];
247   [text addLayoutManager:layoutManager];
248   [layoutManager release];
249
250   [self setFont:[[self class] defaultFontForMachine:m]];
251
252   NSMenu *contextMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Context"];
253   [self addContextMenuItemsToMenu:contextMenu];
254   [self setMenu:contextMenu];
255   [contextMenu release];
256
257   return self;
258}
259
260
261- (void)dealloc {
262   [[NSNotificationCenter defaultCenter] removeObserver:self];
263   if (view != NULL) machine->debug_view().free_view(*view);
264   if (font != nil) [font release];
265   if (text != nil) [text release];
266   [super dealloc];
267}
268
269
270- (void)update {
271   // resize our frame if the total size has changed
272   debug_view_xy const newSize = view->total_size();
273   BOOL const resized = (newSize.x != totalWidth) || (newSize.y != totalHeight);
274   if (resized)
275   {
276      NSScrollView *const scroller = [self enclosingScrollView];
277      if (scroller)
278      {
279         NSSize const clip = [[scroller contentView] bounds].size;
280         NSSize content = NSMakeSize((fontWidth * newSize.x) + (2 * [textContainer lineFragmentPadding]),
281                              fontHeight * newSize.y);
282         if (wholeLineScroll)
283            content.height += (fontHeight * 2) - 1;
284         [self setFrameSize:NSMakeSize(ceil(MAX(clip.width, content.width)),
285                                ceil(MAX(clip.height, content.height)))];
286      }
287      totalWidth = newSize.x;
288      totalHeight = newSize.y;
289   }
290
291   // scroll the view if we're being told to
292   debug_view_xy const newOrigin = view->visible_position();
293   if (newOrigin.y != originTop)
294   {
295      NSRect const visible = [self visibleRect];
296      NSPoint scroll = NSMakePoint(visible.origin.x, newOrigin.y * fontHeight);
297      [self scrollPoint:scroll];
298      originTop = newOrigin.y;
299   }
300
301   // mark as dirty
302   [self setNeedsDisplay:YES];
303}
304
305
306- (NSSize)maximumFrameSize {
307   debug_view_xy const max = view->total_size();
308   return NSMakeSize(ceil((max.x * fontWidth) + (2 * [textContainer lineFragmentPadding])),
309                 ceil((max.y + (wholeLineScroll ? 1 : 0)) * fontHeight));
310}
311
312
313- (NSFont *)font {
314   return [[font retain] autorelease];
315}
316
317
318- (void)setFont:(NSFont *)f {
319   [font autorelease];
320   font = [f retain];
321   fontWidth = [font maximumAdvancement].width;
322   fontHeight = ceil([font ascender] - [font descender]);
323   fontAscent = [font ascender];
324   [[self enclosingScrollView] setLineScroll:fontHeight];
325   totalWidth = totalHeight = 0;
326   [self update];
327}
328
329
330- (BOOL)cursorSupported {
331   return view->cursor_supported();
332}
333
334
335- (BOOL)cursorVisible {
336   return view->cursor_visible();
337}
338
339
340- (debug_view_xy)cursorPosition {
341   return view->cursor_position();
342}
343
344
345- (IBAction)copyVisible:(id)sender {
346   debug_view_xy const size = view->visible_size();
347   debug_view_char const *data = view->viewdata();
348   if (!data)
349   {
350      NSBeep();
351      return;
352   }
353
354   for (UINT32 row = 0; row < size.y; row++, data += size.x)
355   {
356      // add content for the line and set colours
357      int         attr = -1;
358      NSUInteger   start = [text length], length = start;
359      for (UINT32 col = 0; col < size.x; col++)
360      {
361         [[text mutableString] appendFormat:@"%c", data[col].byte];
362         if ((start < length) && (attr != (data[col].attrib & ~DCA_SELECTED)))
363         {
364            NSRange const run = NSMakeRange(start, length - start);
365            [text addAttribute:NSForegroundColorAttributeName
366                      value:[self foregroundForAttribute:attr]
367                      range:run];
368            [text addAttribute:NSBackgroundColorAttributeName
369                      value:[self backgroundForAttribute:attr]
370                      range:run];
371            start = length;
372         }
373         attr = data[col].attrib & ~DCA_SELECTED;
374         length = [text length];
375      }
376
377      // clean up trailing whitespace
378      NSRange trim = [[text string] rangeOfCharacterFromSet:NonWhiteCharacters
379                                         options:NSBackwardsSearch
380                                          range:NSMakeRange(start, length - start)];
381      if (trim.location != NSNotFound)
382         trim = [[text string] rangeOfComposedCharacterSequenceAtIndex:(trim.location + trim.length - 1)];
383      else if (start > 0)
384         trim = [[text string] rangeOfComposedCharacterSequenceAtIndex:(start - 1)];
385      else
386         trim = NSMakeRange(start, 0);
387      trim.location += trim.length;
388      trim.length = length - trim.location;
389      [text deleteCharactersInRange:trim];
390
391      // add the line ending and set colours
392      [[text mutableString] appendString:@"\n"];
393      NSRange const run = NSMakeRange(start, [text length] - start);
394      [text addAttribute:NSForegroundColorAttributeName
395                value:[self foregroundForAttribute:attr]
396                range:run];
397      [text addAttribute:NSBackgroundColorAttributeName
398                value:[self backgroundForAttribute:attr]
399                range:run];
400   }
401
402   // set the font and send it to the pasteboard
403   NSRange const run = NSMakeRange(0, [text length]);
404   [text addAttribute:NSFontAttributeName value:font range:run];
405   NSPasteboard *const board = [NSPasteboard generalPasteboard];
406   [board declareTypes:[NSArray arrayWithObject:NSRTFPboardType] owner:nil];
407   [board setData:[text RTFFromRange:run documentAttributes:[NSDictionary dictionary]] forType:NSRTFPboardType];
408   [text deleteCharactersInRange:run];
409}
410
411
412- (IBAction)paste:(id)sender {
413   NSPasteboard *const board = [NSPasteboard generalPasteboard];
414   NSString *const avail = [board availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]];
415   if (avail == nil)
416   {
417      NSBeep();
418      return;
419   }
420
421   NSData *const data = [[board stringForType:avail] dataUsingEncoding:NSASCIIStringEncoding
422                                       allowLossyConversion:YES];
423   char const *const bytes = (char const *)[data bytes];
424   debug_view_xy const oldPos = view->cursor_position();
425   for (NSUInteger i = 0, l = [data length]; i < l; i++)
426      view->process_char(bytes[i]);
427   if (view->cursor_supported() && view->cursor_visible())
428   {
429      debug_view_xy const newPos = view->cursor_position();
430      if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y))
431      {
432         // FIXME - use proper font metrics
433         [self scrollRectToVisible:NSMakeRect((newPos.x * fontWidth) + [textContainer lineFragmentPadding],
434                                     newPos.y * fontHeight,
435                                     fontWidth,
436                                     fontHeight)];
437      }
438   }
439}
440
441
442- (void)viewBoundsDidChange:(NSNotification *)notification {
443   NSView *const changed = [notification object];
444   if (changed == [[self enclosingScrollView] contentView])
445      [self adjustSizeAndRecomputeVisible];
446}
447
448
449- (void)viewFrameDidChange:(NSNotification *)notification {
450   NSView *const changed = [notification object];
451   if (changed == [[self enclosingScrollView] contentView])
452      [self adjustSizeAndRecomputeVisible];
453}
454
455
456- (void)windowDidBecomeKey:(NSNotification *)notification {
457   NSWindow *const win = [notification object];
458   if ((win == [self window]) && ([win firstResponder] == self) && view->cursor_supported())
459      [self setNeedsDisplay:YES];
460}
461
462
463- (void)windowDidResignKey:(NSNotification *)notification {
464   NSWindow *const win = [notification object];
465   if ((win == [self window]) && ([win firstResponder] == self) && view->cursor_supported())
466      [self setNeedsDisplay:YES];
467}
468
469
470- (void)addContextMenuItemsToMenu:(NSMenu *)menu {
471   NSMenuItem   *item;
472
473   item = [menu addItemWithTitle:@"Copy Visible"
474                     action:@selector(copyVisible:)
475               keyEquivalent:@""];
476   [item setTarget:self];
477
478   item = [menu addItemWithTitle:@"Paste"
479                     action:@selector(paste:)
480               keyEquivalent:@""];
481   [item setTarget:self];
482}
483
484
485- (BOOL)acceptsFirstResponder {
486   return view->cursor_supported();
487}
488
489
490- (BOOL)becomeFirstResponder {
491   if (view->cursor_supported())
492   {
493      debug_view_xy pos;
494      view->set_cursor_visible(true);
495      pos = view->cursor_position();
496      [self scrollRectToVisible:NSMakeRect((pos.x * fontWidth) + [textContainer lineFragmentPadding],
497                                  pos.y * fontHeight,
498                                  fontWidth,
499                                  fontHeight)]; // FIXME: metrics
500      [self setNeedsDisplay:YES];
501      return [super becomeFirstResponder];
502   }
503   else
504   {
505      return NO;
506   }
507}
508
509
510- (BOOL)resignFirstResponder {
511   if (view->cursor_supported())
512      [self setNeedsDisplay:YES];
513   return [super resignFirstResponder];
514}
515
516
517- (void)viewDidMoveToSuperview {
518   [super viewDidMoveToSuperview];
519
520   [[NSNotificationCenter defaultCenter] removeObserver:self
521                                       name:NSViewBoundsDidChangeNotification
522                                      object:nil];
523   [[NSNotificationCenter defaultCenter] removeObserver:self
524                                       name:NSViewFrameDidChangeNotification
525                                      object:nil];
526
527   NSScrollView *const scroller = [self enclosingScrollView];
528   if (scroller != nil)
529   {
530      [scroller setLineScroll:fontHeight];
531      [[scroller contentView] setPostsBoundsChangedNotifications:YES];
532      [[scroller contentView] setPostsFrameChangedNotifications:YES];
533      [[NSNotificationCenter defaultCenter] addObserver:self
534                                     selector:@selector(viewBoundsDidChange:)
535                                        name:NSViewBoundsDidChangeNotification
536                                       object:[scroller contentView]];
537      [[NSNotificationCenter defaultCenter] addObserver:self
538                                     selector:@selector(viewFrameDidChange:)
539                                        name:NSViewFrameDidChangeNotification
540                                       object:[scroller contentView]];
541      [self adjustSizeAndRecomputeVisible];
542   }
543}
544
545
546- (void)viewDidMoveToWindow {
547   [super viewDidMoveToWindow];
548
549   [[NSNotificationCenter defaultCenter] removeObserver:self
550                                       name:NSWindowDidBecomeKeyNotification
551                                      object:nil];
552   [[NSNotificationCenter defaultCenter] removeObserver:self
553                                       name:NSWindowDidResignKeyNotification
554                                      object:nil];
555
556   if ([self window] != nil)
557   {
558      [[NSNotificationCenter defaultCenter] addObserver:self
559                                     selector:@selector(windowDidBecomeKey:)
560                                        name:NSWindowDidBecomeKeyNotification
561                                       object:[self window]];
562      [[NSNotificationCenter defaultCenter] addObserver:self
563                                     selector:@selector(windowDidResignKey:)
564                                        name:NSWindowDidResignKeyNotification
565                                       object:[self window]];
566      [self setNeedsDisplay:YES];
567   }
568}
569
570
571- (BOOL)isFlipped {
572   return YES;
573}
574
575
576- (BOOL)isOpaque {
577   return YES;
578}
579
580
581- (NSRect)adjustScroll:(NSRect)proposedVisibleRect {
582   if (wholeLineScroll)
583   {
584      CGFloat const clamp = [self bounds].size.height - fontHeight - proposedVisibleRect.size.height;
585      proposedVisibleRect.origin.y = MIN(proposedVisibleRect.origin.y, MAX(clamp, 0));
586      proposedVisibleRect.origin.y -= fmod(proposedVisibleRect.origin.y, fontHeight);
587   }
588   return proposedVisibleRect;
589}
590
591
592- (void)drawRect:(NSRect)dirtyRect {
593   // work out what's available
594   [self recomputeVisible];
595   debug_view_xy const origin = view->visible_position();
596   debug_view_xy const size = view->visible_size();
597
598   // work out how much we need to draw
599   INT32 row, clip;
600   [self convertBounds:dirtyRect toFirstAffectedLine:&row count:&clip];
601   clip += row;
602   row = MAX(row, origin.y);
603   clip = MIN(clip, origin.y + size.y);
604
605   // this gets the text for the whole visible area
606   debug_view_char const *data = view->viewdata();
607   if (!data)
608      return;
609
610   // clear any space above the available content
611   data += ((row - origin.y) * size.x);
612   if (dirtyRect.origin.y < (row * fontHeight))
613   {
614      [DefaultBackground set];
615      [NSBezierPath fillRect:NSMakeRect(0,
616                                dirtyRect.origin.y,
617                                [self bounds].size.width,
618                                (row * fontHeight) - dirtyRect.origin.y)];
619   }
620
621   // render entire lines to get character alignment right
622   for ( ; row < clip; row++, data += size.x)
623   {
624      int         attr = -1;
625      NSUInteger   start = 0, length = 0;
626      for (UINT32 col = origin.x; col < origin.x + size.x; col++)
627      {
628         [[text mutableString] appendFormat:@"%c", data[col - origin.x].byte];
629         if ((start < length) && (attr != data[col - origin.x].attrib))
630         {
631            NSRange const run = NSMakeRange(start, length - start);
632            [text addAttribute:NSFontAttributeName
633                      value:font
634                      range:NSMakeRange(0, length)];
635            [text addAttribute:NSForegroundColorAttributeName
636                      value:[self foregroundForAttribute:attr]
637                      range:run];
638            NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run
639                                              actualCharacterRange:NULL];
640            NSRect box = [layoutManager boundingRectForGlyphRange:glyphs
641                                         inTextContainer:textContainer];
642            if (start == 0)
643            {
644               box.size.width += box.origin.x;
645               box.origin.x = 0;
646            }
647            [[self backgroundForAttribute:attr] set];
648            [NSBezierPath fillRect:NSMakeRect(box.origin.x,
649                                      row * fontHeight,
650                                      box.size.width,
651                                      fontHeight)];
652            start = length;
653         }
654         attr = data[col - origin.x].attrib;
655         length = [text length];
656      }
657      NSRange const run = NSMakeRange(start, length - start);
658      [text addAttribute:NSFontAttributeName
659                value:font
660                range:NSMakeRange(0, length)];
661      [text addAttribute:NSForegroundColorAttributeName
662                value:[self foregroundForAttribute:attr]
663                range:run];
664      NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run
665                                        actualCharacterRange:NULL];
666      NSRect box = [layoutManager boundingRectForGlyphRange:glyphs
667                                   inTextContainer:textContainer];
668      if (start == 0)
669         box.origin.x = 0;
670      box.size.width = MAX([self bounds].size.width - box.origin.x, 0);
671      [[self backgroundForAttribute:attr] set];
672      [NSBezierPath fillRect:NSMakeRect(box.origin.x,
673                                row * fontHeight,
674                                box.size.width,
675                                fontHeight)];
676      [layoutManager drawGlyphsForGlyphRange:[layoutManager glyphRangeForTextContainer:textContainer]
677                              atPoint:NSMakePoint(0, row * fontHeight)];
678      [text deleteCharactersInRange:NSMakeRange(0, length)];
679   }
680
681   // clear any space below the available content
682   if ((dirtyRect.origin.y + dirtyRect.size.height) > (row * fontHeight))
683   {
684      [DefaultBackground set];
685      [NSBezierPath fillRect:NSMakeRect(0,
686                                row * fontHeight,
687                                [self bounds].size.width,
688                                (dirtyRect.origin.y + dirtyRect.size.height) - (row * fontHeight))];
689   }
690}
691
692
693- (void)mouseDown:(NSEvent *)event {
694   NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil];
695   NSUInteger const modifiers = [event modifierFlags];
696   view->process_click(((modifiers & NSCommandKeyMask) && [[self window] isMainWindow]) ? DCK_RIGHT_CLICK
697                 : (modifiers & NSAlternateKeyMask) ? DCK_MIDDLE_CLICK
698                 : DCK_LEFT_CLICK,
699                  [self convertLocation:location]);
700}
701
702
703- (void)mouseDragged:(NSEvent *)event {
704   [self autoscroll:event];
705   NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil];
706   NSUInteger const modifiers = [event modifierFlags];
707   if (view->cursor_supported()
708    && !(modifiers & NSAlternateKeyMask)
709    && (!(modifiers & NSCommandKeyMask) || ![[self window] isMainWindow]))
710   {
711      view->set_cursor_position([self convertLocation:location]);
712      view->set_cursor_visible(true);
713      [self setNeedsDisplay:YES];
714   }
715}
716
717
718- (void)rightMouseDown:(NSEvent *)event {
719   NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil];
720   if (view->cursor_supported())
721   {
722      view->set_cursor_position([self convertLocation:location]);
723      view->set_cursor_visible(true);
724      [self setNeedsDisplay:YES];
725   }
726   [super rightMouseDown:event];
727}
728
729
730- (void)keyDown:(NSEvent *)event {
731   NSUInteger   modifiers = [event modifierFlags];
732   NSString   *str = [event charactersIgnoringModifiers];
733
734   if ([str length] == 1)
735   {
736      if (modifiers & NSNumericPadKeyMask)
737      {
738         switch ([str characterAtIndex:0])
739         {
740         case NSUpArrowFunctionKey:
741            if (modifiers & NSCommandKeyMask)
742               view->process_char(DCH_CTRLHOME);
743            else
744               view->process_char(DCH_UP);
745            return;
746         case NSDownArrowFunctionKey:
747            if (modifiers & NSCommandKeyMask)
748               view->process_char(DCH_CTRLEND);
749            else
750               view->process_char(DCH_DOWN);
751            return;
752         case NSLeftArrowFunctionKey:
753            if (modifiers & NSCommandKeyMask)
754               [self typeCharacterAndScrollToCursor:DCH_HOME];
755            else if (modifiers & NSAlternateKeyMask)
756               [self typeCharacterAndScrollToCursor:DCH_CTRLLEFT];
757            else
758               [self typeCharacterAndScrollToCursor:DCH_LEFT];
759            return;
760         case NSRightArrowFunctionKey:
761            if (modifiers & NSCommandKeyMask)
762               [self typeCharacterAndScrollToCursor:DCH_END];
763            else if (modifiers & NSAlternateKeyMask)
764               [self typeCharacterAndScrollToCursor:DCH_CTRLRIGHT];
765            else
766               [self typeCharacterAndScrollToCursor:DCH_RIGHT];
767            return;
768         default:
769            [self interpretKeyEvents:[NSArray arrayWithObject:event]];
770            return;
771         }
772      }
773      else if (modifiers & NSFunctionKeyMask)
774      {
775         switch ([str characterAtIndex:0])
776         {
777            case NSPageUpFunctionKey:
778               if (modifiers & NSAlternateKeyMask)
779               {
780                  view->process_char(DCH_PUP);
781                  return;
782               }
783            case NSPageDownFunctionKey:
784               if (modifiers & NSAlternateKeyMask)
785               {
786                  view->process_char(DCH_PDOWN);
787                  return;
788               }
789            default:
790               ;
791         }
792         [super keyDown:event];
793         return;
794      }
795   }
796   [self interpretKeyEvents:[NSArray arrayWithObject:event]];
797}
798
799
800- (void)insertTab:(id)sender {
801   if ([[self window] firstResponder] == self)
802      [[self window] selectNextKeyView:self];
803}
804
805
806- (void)insertBacktab:(id)sender {
807   if ([[self window] firstResponder] == self)
808      [[self window] selectPreviousKeyView:self];
809}
810
811
812- (void)insertNewline:(id)sender {
813   debug_cpu_get_visible_cpu(*machine)->debug()->single_step();
814}
815
816
817- (void)insertText:(id)string {
818   NSUInteger   len;
819   NSRange      found;
820   if ([string isKindOfClass:[NSAttributedString class]])
821      string = [string string];
822   for (len = [string length], found = NSMakeRange(0, 0);
823       found.location < len;
824       found.location += found.length) {
825      found = [string rangeOfComposedCharacterSequenceAtIndex:found.location];
826      if (found.length == 1) {
827         unichar ch = [string characterAtIndex:found.location];
828         if ((ch >= 32) && (ch < 127))
829            [self typeCharacterAndScrollToCursor:ch];
830      }
831   }
832}
833
834
835- (BOOL)validateMenuItem:(NSMenuItem *)item {
836   SEL   action = [item action];
837
838   if (action == @selector(paste:))
839   {
840      NSPasteboard *const board = [NSPasteboard generalPasteboard];
841      return [board availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]] != nil;
842   }
843   else
844   {
845      return YES;
846   }
847}
848
849@end
trunk/src/osd/modules/debugger/osx/debugwindowhandler.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  debugwindowhandler.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "debugwindowhandler.h"
10
11#import "debugconsole.h"
12#import "debugcommandhistory.h"
13#import "debugview.h"
14
15
16//============================================================
17//  NOTIFICATIONS
18//============================================================
19
20NSString *const MAMEHideDebuggerNotification = @"MAMEHideDebuggerNotification";
21NSString *const MAMEShowDebuggerNotification = @"MAMEShowDebuggerNotification";
22NSString *const MAMEAuxiliaryDebugWindowWillCloseNotification = @"MAMEAuxiliaryDebugWindowWillCloseNotification";
23
24
25//============================================================
26//  MAMEDebugWindowHandler class
27//============================================================
28
29@implementation MAMEDebugWindowHandler
30
31+ (void)addCommonActionItems:(NSMenu *)menu {
32   NSMenuItem *runParentItem = [menu addItemWithTitle:@"Run"
33                                    action:@selector(debugRun:)
34                               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF5FunctionKey]];
35   NSMenu *runMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Run"];
36   [runParentItem setSubmenu:runMenu];
37   [runMenu release];
38   [runParentItem setKeyEquivalentModifierMask:0];
39   [[runMenu addItemWithTitle:@"and Hide Debugger"
40                  action:@selector(debugRunAndHide:)
41             keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF12FunctionKey]]
42    setKeyEquivalentModifierMask:0];
43   [[runMenu addItemWithTitle:@"to Next CPU"
44                  action:@selector(debugRunToNextCPU:)
45             keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF6FunctionKey]]
46    setKeyEquivalentModifierMask:0];
47   [[runMenu addItemWithTitle:@"until Next Interrupt on Current CPU"
48                  action:@selector(debugRunToNextInterrupt:)
49             keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF7FunctionKey]]
50    setKeyEquivalentModifierMask:0];
51   [[runMenu addItemWithTitle:@"until Next VBLANK"
52                  action:@selector(debugRunToNextVBLANK:)
53             keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF8FunctionKey]]
54    setKeyEquivalentModifierMask:0];
55
56   NSMenuItem *stepParentItem = [menu addItemWithTitle:@"Step" action:NULL keyEquivalent:@""];
57   NSMenu *stepMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Step"];
58   [stepParentItem setSubmenu:stepMenu];
59   [stepMenu release];
60   [[stepMenu addItemWithTitle:@"Into"
61                   action:@selector(debugStepInto:)
62              keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF11FunctionKey]]
63    setKeyEquivalentModifierMask:0];
64   [[stepMenu addItemWithTitle:@"Over"
65                   action:@selector(debugStepOver:)
66              keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]]
67    setKeyEquivalentModifierMask:0];
68   [[stepMenu addItemWithTitle:@"Out"
69                   action:@selector(debugStepOut:)
70              keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]]
71    setKeyEquivalentModifierMask:NSShiftKeyMask];
72
73   NSMenuItem *resetParentItem = [menu addItemWithTitle:@"Reset" action:NULL keyEquivalent:@""];
74   NSMenu *resetMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Reset"];
75   [resetParentItem setSubmenu:resetMenu];
76   [resetMenu release];
77   [[resetMenu addItemWithTitle:@"Soft"
78                    action:@selector(debugSoftReset:)
79               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]]
80    setKeyEquivalentModifierMask:0];
81   [[resetMenu addItemWithTitle:@"Hard"
82                    action:@selector(debugHardReset:)
83               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]]
84    setKeyEquivalentModifierMask:NSShiftKeyMask];
85
86   [menu addItem:[NSMenuItem separatorItem]];
87
88   NSMenuItem *newParentItem = [menu addItemWithTitle:@"New" action:NULL keyEquivalent:@""];
89   NSMenu *newMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"New"];
90   [newParentItem setSubmenu:newMenu];
91   [newMenu release];
92   [newMenu addItemWithTitle:@"Memory Window"
93                  action:@selector(debugNewMemoryWindow:)
94            keyEquivalent:@"d"];
95   [newMenu addItemWithTitle:@"Disassembly Window"
96                  action:@selector(debugNewDisassemblyWindow:)
97            keyEquivalent:@"a"];
98   [newMenu addItemWithTitle:@"Error Log Window"
99                  action:@selector(debugNewErrorLogWindow:)
100            keyEquivalent:@"l"];
101   [newMenu addItemWithTitle:@"(Break|Watch)points Window"
102                  action:@selector(debugNewPointsWindow:)
103            keyEquivalent:@"b"];
104   [newMenu addItemWithTitle:@"Devices Window"
105                  action:@selector(debugNewDevicesWindow:)
106            keyEquivalent:@"D"];
107
108   [menu addItem:[NSMenuItem separatorItem]];
109
110   [menu addItemWithTitle:@"Close Window" action:@selector(performClose:) keyEquivalent:@"w"];
111   [menu addItemWithTitle:@"Quit" action:@selector(debugExit:) keyEquivalent:@"q"];
112}
113
114
115+ (NSPopUpButton *)newActionButtonWithFrame:(NSRect)frame {
116   NSPopUpButton *actionButton = [[NSPopUpButton alloc] initWithFrame:frame pullsDown:YES];
117   [actionButton setTitle:@""];
118   [actionButton addItemWithTitle:@""];
119   [actionButton setBezelStyle:NSShadowlessSquareBezelStyle];
120   [actionButton setFocusRingType:NSFocusRingTypeNone];
121   [[actionButton cell] setArrowPosition:NSPopUpArrowAtCenter];
122   [[self class] addCommonActionItems:[actionButton menu]];
123   return actionButton;
124}
125
126
127+ (device_debug::breakpoint *)findBreakpointAtAddress:(offs_t)address forDevice:(device_t &)device {
128   device_debug *const cpuinfo = device.debug();
129   device_debug::breakpoint *bp = cpuinfo->breakpoint_first();
130   while ((bp != NULL) && (address != bp->address())) bp = bp->next();
131   return bp;
132}
133
134
135- (id)initWithMachine:(running_machine &)m title:(NSString *)t {
136   if (!(self = [super init]))
137      return nil;
138
139   window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 320, 240)
140                               styleMask:(NSTitledWindowMask |
141                                       NSClosableWindowMask |
142                                       NSMiniaturizableWindowMask |
143                                       NSResizableWindowMask)
144                                 backing:NSBackingStoreBuffered
145                                  defer:YES];
146   [window setReleasedWhenClosed:NO];
147   [window setDelegate:self];
148   [window setTitle:t];
149   [window setContentMinSize:NSMakeSize(320, 240)];
150
151   [[NSNotificationCenter defaultCenter] addObserver:self
152                                  selector:@selector(showDebugger:)
153                                     name:MAMEShowDebuggerNotification
154                                    object:nil];
155   [[NSNotificationCenter defaultCenter] addObserver:self
156                                  selector:@selector(hideDebugger:)
157                                     name:MAMEHideDebuggerNotification
158                                    object:nil];
159
160   machine = &m;
161
162   return self;
163}
164
165
166- (void)dealloc {
167   [[NSNotificationCenter defaultCenter] removeObserver:self];
168
169   if (window != nil)
170   {
171      [window orderOut:self];
172      [window release];
173   }
174
175   [super dealloc];
176}
177
178
179- (void)activate {
180   [window makeKeyAndOrderFront:self];
181}
182
183
184- (IBAction)debugRun:(id)sender {
185   debug_cpu_get_visible_cpu(*machine)->debug()->go();
186}
187
188
189- (IBAction)debugRunAndHide:(id)sender {
190   [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification object:self];
191   debug_cpu_get_visible_cpu(*machine)->debug()->go();
192}
193
194
195- (IBAction)debugRunToNextCPU:(id)sender {
196   debug_cpu_get_visible_cpu(*machine)->debug()->go_next_device();
197}
198
199
200- (IBAction)debugRunToNextInterrupt:(id)sender {
201   debug_cpu_get_visible_cpu(*machine)->debug()->go_interrupt();
202}
203
204
205- (IBAction)debugRunToNextVBLANK:(id)sender {
206   debug_cpu_get_visible_cpu(*machine)->debug()->go_vblank();
207}
208
209
210- (IBAction)debugStepInto:(id)sender {
211   debug_cpu_get_visible_cpu(*machine)->debug()->single_step();
212}
213
214
215- (IBAction)debugStepOver:(id)sender {
216   debug_cpu_get_visible_cpu(*machine)->debug()->single_step_over();
217}
218
219
220- (IBAction)debugStepOut:(id)sender {
221   debug_cpu_get_visible_cpu(*machine)->debug()->single_step_out();
222}
223
224
225- (IBAction)debugSoftReset:(id)sender {
226   machine->schedule_soft_reset();
227   debug_cpu_get_visible_cpu(*machine)->debug()->go();
228}
229
230
231- (IBAction)debugHardReset:(id)sender {
232   machine->schedule_hard_reset();
233}
234
235
236- (IBAction)debugExit:(id)sender {
237   machine->schedule_exit();
238}
239
240
241- (void)showDebugger:(NSNotification *)notification {
242   running_machine *m = (running_machine *)[[[notification userInfo] objectForKey:@"MAMEDebugMachine"] pointerValue];
243   if (m == machine)
244   {
245      if (![window isVisible] && ![window isMiniaturized])
246         [window orderFront:self];
247   }
248}
249
250
251- (void)hideDebugger:(NSNotification *)notification {
252   running_machine *m = (running_machine *)[[[notification userInfo] objectForKey:@"MAMEDebugMachine"] pointerValue];
253   if (m == machine)
254      [window orderOut:self];
255}
256
257@end
258
259
260//============================================================
261//  MAMEAuxiliaryDebugWindowHandler class
262//============================================================
263
264@implementation MAMEAuxiliaryDebugWindowHandler
265
266+ (void)cascadeWindow:(NSWindow *)window {
267   static NSPoint lastPosition = { 0, 0 };
268   if (NSEqualPoints(lastPosition, NSZeroPoint)) {
269      NSRect available = [[NSScreen mainScreen] visibleFrame];
270      lastPosition = NSMakePoint(available.origin.x + 12, available.origin.y + available.size.height - 8);
271   }
272   lastPosition = [window cascadeTopLeftFromPoint:lastPosition];
273}
274
275
276- (id)initWithMachine:(running_machine &)m title:(NSString *)t console:(MAMEDebugConsole *)c {
277   if (!(self = [super initWithMachine:m title:t]))
278      return nil;
279   console = c;
280   return self;
281}
282
283
284- (void)dealloc {
285   [super dealloc];
286}
287
288
289- (IBAction)debugNewMemoryWindow:(id)sender {
290   [console debugNewMemoryWindow:sender];
291}
292
293
294- (IBAction)debugNewDisassemblyWindow:(id)sender {
295   [console debugNewDisassemblyWindow:sender];
296}
297
298
299- (IBAction)debugNewErrorLogWindow:(id)sender {
300   [console debugNewErrorLogWindow:sender];
301}
302
303
304- (IBAction)debugNewPointsWindow:(id)sender {
305   [console debugNewPointsWindow:sender];
306}
307
308
309- (IBAction)debugNewDevicesWindow:(id)sender {
310   [console debugNewDevicesWindow:sender];
311}
312
313
314- (void)windowWillClose:(NSNotification *)notification {
315   [[NSNotificationCenter defaultCenter] postNotificationName:MAMEAuxiliaryDebugWindowWillCloseNotification
316                                          object:self];
317}
318
319- (void)cascadeWindowWithDesiredSize:(NSSize)desired forView:(NSView *)view {
320   // convert desired size to an adjustment and apply it to the current window frame
321   NSSize const current = [view frame].size;
322   desired.width -= current.width;
323   desired.height -= current.height;
324   NSRect windowFrame = [window frame];
325   windowFrame.size.width += desired.width;
326   windowFrame.size.height += desired.height;
327
328   // limit the size to the minimum size
329   NSSize const minimum = [window minSize];
330   windowFrame.size.width = MAX(windowFrame.size.width, minimum.width);
331   windowFrame.size.height = MAX(windowFrame.size.height, minimum.height);
332
333   // limit the size to the main screen size
334   NSRect const available = [[NSScreen mainScreen] visibleFrame];
335   windowFrame.size.width = MIN(windowFrame.size.width, available.size.width);
336   windowFrame.size.height = MIN(windowFrame.size.height, available.size.height);
337
338   // arbitrary additional height limit
339   windowFrame.size.height = MIN(windowFrame.size.height, 320);
340
341   // place it in the bottom right corner and apply
342   windowFrame.origin.x = available.origin.x + available.size.width - windowFrame.size.width;
343   windowFrame.origin.y = available.origin.y;
344   [window setFrame:windowFrame display:YES];
345   [[self class] cascadeWindow:window];
346}
347
348@end
349
350
351//============================================================
352//  MAMEExpreesionAuxiliaryDebugWindowHandler class
353//============================================================
354
355@implementation MAMEExpressionAuxiliaryDebugWindowHandler
356
357- (id)initWithMachine:(running_machine &)m title:(NSString *)t console:(MAMEDebugConsole *)c {
358   if (!(self = [super initWithMachine:m title:t console:c]))
359      return nil;
360   history = [[MAMEDebugCommandHistory alloc] init];
361   return self;
362}
363
364
365- (void)dealloc {
366   if (history != nil)
367      [history release];
368   [super dealloc];
369}
370
371
372- (id <MAMEDebugViewExpressionSupport>)documentView {
373   return nil;
374}
375
376
377- (NSString *)expression {
378   return [[self documentView] expression];
379}
380
381- (void)setExpression:(NSString *)expression {
382   [history add:expression];
383   [[self documentView] setExpression:expression];
384   [expressionField setStringValue:expression];
385   [expressionField selectText:self];
386}
387
388
389- (IBAction)doExpression:(id)sender {
390   NSString *expr = [sender stringValue];
391   if ([expr length] > 0) {
392      [history add:expr];
393      [[self documentView] setExpression:expr];
394   } else {
395      [sender setStringValue:[[self documentView] expression]];
396      [history reset];
397   }
398   [sender selectText:self];
399}
400
401
402- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor
403{
404   if (control == expressionField)
405      [history edit];
406
407   return YES;
408}
409
410
411- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command {
412   if (control == expressionField) {
413      if (command == @selector(cancelOperation:)) {
414         [history reset];
415         [expressionField setStringValue:[[self documentView] expression]];
416         [expressionField selectText:self];
417         return YES;
418      } else if (command == @selector(moveUp:)) {
419         NSString *hist = [history previous:[expressionField stringValue]];
420         if (hist != nil) {
421            [expressionField setStringValue:hist];
422            [expressionField selectText:self];
423         }
424         return YES;
425      } else if (command == @selector(moveDown:)) {
426         NSString *hist = [history next:[expressionField stringValue]];
427         if (hist != nil) {
428            [expressionField setStringValue:hist];
429            [expressionField selectText:self];
430         }
431         return YES;
432      }
433    }
434   return NO;
435}
436
437@end
trunk/src/osd/modules/debugger/osx/debugwindowhandler.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  debugwindowhandler.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "debugwindowhandler.h"
10
11#import "debugconsole.h"
12#import "debugcommandhistory.h"
13#import "debugview.h"
14
15
16//============================================================
17//  NOTIFICATIONS
18//============================================================
19
20NSString *const MAMEHideDebuggerNotification = @"MAMEHideDebuggerNotification";
21NSString *const MAMEShowDebuggerNotification = @"MAMEShowDebuggerNotification";
22NSString *const MAMEAuxiliaryDebugWindowWillCloseNotification = @"MAMEAuxiliaryDebugWindowWillCloseNotification";
23
24
25//============================================================
26//  MAMEDebugWindowHandler class
27//============================================================
28
29@implementation MAMEDebugWindowHandler
30
31+ (void)addCommonActionItems:(NSMenu *)menu {
32   NSMenuItem *runParentItem = [menu addItemWithTitle:@"Run"
33                                    action:@selector(debugRun:)
34                               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF5FunctionKey]];
35   NSMenu *runMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Run"];
36   [runParentItem setSubmenu:runMenu];
37   [runMenu release];
38   [runParentItem setKeyEquivalentModifierMask:0];
39   [[runMenu addItemWithTitle:@"and Hide Debugger"
40                  action:@selector(debugRunAndHide:)
41             keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF12FunctionKey]]
42    setKeyEquivalentModifierMask:0];
43   [[runMenu addItemWithTitle:@"to Next CPU"
44                  action:@selector(debugRunToNextCPU:)
45             keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF6FunctionKey]]
46    setKeyEquivalentModifierMask:0];
47   [[runMenu addItemWithTitle:@"until Next Interrupt on Current CPU"
48                  action:@selector(debugRunToNextInterrupt:)
49             keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF7FunctionKey]]
50    setKeyEquivalentModifierMask:0];
51   [[runMenu addItemWithTitle:@"until Next VBLANK"
52                  action:@selector(debugRunToNextVBLANK:)
53             keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF8FunctionKey]]
54    setKeyEquivalentModifierMask:0];
55
56   NSMenuItem *stepParentItem = [menu addItemWithTitle:@"Step" action:NULL keyEquivalent:@""];
57   NSMenu *stepMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Step"];
58   [stepParentItem setSubmenu:stepMenu];
59   [stepMenu release];
60   [[stepMenu addItemWithTitle:@"Into"
61                   action:@selector(debugStepInto:)
62              keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF11FunctionKey]]
63    setKeyEquivalentModifierMask:0];
64   [[stepMenu addItemWithTitle:@"Over"
65                   action:@selector(debugStepOver:)
66              keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]]
67    setKeyEquivalentModifierMask:0];
68   [[stepMenu addItemWithTitle:@"Out"
69                   action:@selector(debugStepOut:)
70              keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]]
71    setKeyEquivalentModifierMask:NSShiftKeyMask];
72
73   NSMenuItem *resetParentItem = [menu addItemWithTitle:@"Reset" action:NULL keyEquivalent:@""];
74   NSMenu *resetMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Reset"];
75   [resetParentItem setSubmenu:resetMenu];
76   [resetMenu release];
77   [[resetMenu addItemWithTitle:@"Soft"
78                    action:@selector(debugSoftReset:)
79               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]]
80    setKeyEquivalentModifierMask:0];
81   [[resetMenu addItemWithTitle:@"Hard"
82                    action:@selector(debugHardReset:)
83               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]]
84    setKeyEquivalentModifierMask:NSShiftKeyMask];
85
86   [menu addItem:[NSMenuItem separatorItem]];
87
88   NSMenuItem *newParentItem = [menu addItemWithTitle:@"New" action:NULL keyEquivalent:@""];
89   NSMenu *newMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"New"];
90   [newParentItem setSubmenu:newMenu];
91   [newMenu release];
92   [newMenu addItemWithTitle:@"Memory Window"
93                  action:@selector(debugNewMemoryWindow:)
94            keyEquivalent:@"d"];
95   [newMenu addItemWithTitle:@"Disassembly Window"
96                  action:@selector(debugNewDisassemblyWindow:)
97            keyEquivalent:@"a"];
98   [newMenu addItemWithTitle:@"Error Log Window"
99                  action:@selector(debugNewErrorLogWindow:)
100            keyEquivalent:@"l"];
101   [newMenu addItemWithTitle:@"(Break|Watch)points Window"
102                  action:@selector(debugNewPointsWindow:)
103            keyEquivalent:@"b"];
104   [newMenu addItemWithTitle:@"Devices Window"
105                  action:@selector(debugNewDevicesWindow:)
106            keyEquivalent:@"D"];
107
108   [menu addItem:[NSMenuItem separatorItem]];
109
110   [menu addItemWithTitle:@"Close Window" action:@selector(performClose:) keyEquivalent:@"w"];
111   [menu addItemWithTitle:@"Quit" action:@selector(debugExit:) keyEquivalent:@"q"];
112}
113
114
115+ (NSPopUpButton *)newActionButtonWithFrame:(NSRect)frame {
116   NSPopUpButton *actionButton = [[NSPopUpButton alloc] initWithFrame:frame pullsDown:YES];
117   [actionButton setTitle:@""];
118   [actionButton addItemWithTitle:@""];
119   [actionButton setBezelStyle:NSShadowlessSquareBezelStyle];
120   [actionButton setFocusRingType:NSFocusRingTypeNone];
121   [[actionButton cell] setArrowPosition:NSPopUpArrowAtCenter];
122   [[self class] addCommonActionItems:[actionButton menu]];
123   return actionButton;
124}
125
126
127+ (device_debug::breakpoint *)findBreakpointAtAddress:(offs_t)address forDevice:(device_t &)device {
128   device_debug *const cpuinfo = device.debug();
129   device_debug::breakpoint *bp = cpuinfo->breakpoint_first();
130   while ((bp != NULL) && (address != bp->address())) bp = bp->next();
131   return bp;
132}
133
134
135- (id)initWithMachine:(running_machine &)m title:(NSString *)t {
136   if (!(self = [super init]))
137      return nil;
138
139   window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 320, 240)
140                               styleMask:(NSTitledWindowMask |
141                                       NSClosableWindowMask |
142                                       NSMiniaturizableWindowMask |
143                                       NSResizableWindowMask)
144                                 backing:NSBackingStoreBuffered
145                                  defer:YES];
146   [window setReleasedWhenClosed:NO];
147   [window setDelegate:self];
148   [window setTitle:t];
149   [window setContentMinSize:NSMakeSize(320, 240)];
150
151   [[NSNotificationCenter defaultCenter] addObserver:self
152                                  selector:@selector(showDebugger:)
153                                     name:MAMEShowDebuggerNotification
154                                    object:nil];
155   [[NSNotificationCenter defaultCenter] addObserver:self
156                                  selector:@selector(hideDebugger:)
157                                     name:MAMEHideDebuggerNotification
158                                    object:nil];
159
160   machine = &m;
161
162   return self;
163}
164
165
166- (void)dealloc {
167   [[NSNotificationCenter defaultCenter] removeObserver:self];
168
169   if (window != nil)
170   {
171      [window orderOut:self];
172      [window release];
173   }
174
175   [super dealloc];
176}
177
178
179- (void)activate {
180   [window makeKeyAndOrderFront:self];
181}
182
183
184- (IBAction)debugRun:(id)sender {
185   debug_cpu_get_visible_cpu(*machine)->debug()->go();
186}
187
188
189- (IBAction)debugRunAndHide:(id)sender {
190   [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification object:self];
191   debug_cpu_get_visible_cpu(*machine)->debug()->go();
192}
193
194
195- (IBAction)debugRunToNextCPU:(id)sender {
196   debug_cpu_get_visible_cpu(*machine)->debug()->go_next_device();
197}
198
199
200- (IBAction)debugRunToNextInterrupt:(id)sender {
201   debug_cpu_get_visible_cpu(*machine)->debug()->go_interrupt();
202}
203
204
205- (IBAction)debugRunToNextVBLANK:(id)sender {
206   debug_cpu_get_visible_cpu(*machine)->debug()->go_vblank();
207}
208
209
210- (IBAction)debugStepInto:(id)sender {
211   debug_cpu_get_visible_cpu(*machine)->debug()->single_step();
212}
213
214
215- (IBAction)debugStepOver:(id)sender {
216   debug_cpu_get_visible_cpu(*machine)->debug()->single_step_over();
217}
218
219
220- (IBAction)debugStepOut:(id)sender {
221   debug_cpu_get_visible_cpu(*machine)->debug()->single_step_out();
222}
223
224
225- (IBAction)debugSoftReset:(id)sender {
226   machine->schedule_soft_reset();
227   debug_cpu_get_visible_cpu(*machine)->debug()->go();
228}
229
230
231- (IBAction)debugHardReset:(id)sender {
232   machine->schedule_hard_reset();
233}
234
235
236- (IBAction)debugExit:(id)sender {
237   machine->schedule_exit();
238}
239
240
241- (void)showDebugger:(NSNotification *)notification {
242   running_machine *m = (running_machine *)[[[notification userInfo] objectForKey:@"MAMEDebugMachine"] pointerValue];
243   if (m == machine)
244   {
245      if (![window isVisible] && ![window isMiniaturized])
246         [window orderFront:self];
247   }
248}
249
250
251- (void)hideDebugger:(NSNotification *)notification {
252   running_machine *m = (running_machine *)[[[notification userInfo] objectForKey:@"MAMEDebugMachine"] pointerValue];
253   if (m == machine)
254      [window orderOut:self];
255}
256
257@end
258
259
260//============================================================
261//  MAMEAuxiliaryDebugWindowHandler class
262//============================================================
263
264@implementation MAMEAuxiliaryDebugWindowHandler
265
266+ (void)cascadeWindow:(NSWindow *)window {
267   static NSPoint lastPosition = { 0, 0 };
268   if (NSEqualPoints(lastPosition, NSZeroPoint)) {
269      NSRect available = [[NSScreen mainScreen] visibleFrame];
270      lastPosition = NSMakePoint(available.origin.x + 12, available.origin.y + available.size.height - 8);
271   }
272   lastPosition = [window cascadeTopLeftFromPoint:lastPosition];
273}
274
275
276- (id)initWithMachine:(running_machine &)m title:(NSString *)t console:(MAMEDebugConsole *)c {
277   if (!(self = [super initWithMachine:m title:t]))
278      return nil;
279   console = c;
280   return self;
281}
282
283
284- (void)dealloc {
285   [super dealloc];
286}
287
288
289- (IBAction)debugNewMemoryWindow:(id)sender {
290   [console debugNewMemoryWindow:sender];
291}
292
293
294- (IBAction)debugNewDisassemblyWindow:(id)sender {
295   [console debugNewDisassemblyWindow:sender];
296}
297
298
299- (IBAction)debugNewErrorLogWindow:(id)sender {
300   [console debugNewErrorLogWindow:sender];
301}
302
303
304- (IBAction)debugNewPointsWindow:(id)sender {
305   [console debugNewPointsWindow:sender];
306}
307
308
309- (IBAction)debugNewDevicesWindow:(id)sender {
310   [console debugNewDevicesWindow:sender];
311}
312
313
314- (void)windowWillClose:(NSNotification *)notification {
315   [[NSNotificationCenter defaultCenter] postNotificationName:MAMEAuxiliaryDebugWindowWillCloseNotification
316                                          object:self];
317}
318
319- (void)cascadeWindowWithDesiredSize:(NSSize)desired forView:(NSView *)view {
320   // convert desired size to an adjustment and apply it to the current window frame
321   NSSize const current = [view frame].size;
322   desired.width -= current.width;
323   desired.height -= current.height;
324   NSRect windowFrame = [window frame];
325   windowFrame.size.width += desired.width;
326   windowFrame.size.height += desired.height;
327
328   // limit the size to the minimum size
329   NSSize const minimum = [window minSize];
330   windowFrame.size.width = MAX(windowFrame.size.width, minimum.width);
331   windowFrame.size.height = MAX(windowFrame.size.height, minimum.height);
332
333   // limit the size to the main screen size
334   NSRect const available = [[NSScreen mainScreen] visibleFrame];
335   windowFrame.size.width = MIN(windowFrame.size.width, available.size.width);
336   windowFrame.size.height = MIN(windowFrame.size.height, available.size.height);
337
338   // arbitrary additional height limit
339   windowFrame.size.height = MIN(windowFrame.size.height, 320);
340
341   // place it in the bottom right corner and apply
342   windowFrame.origin.x = available.origin.x + available.size.width - windowFrame.size.width;
343   windowFrame.origin.y = available.origin.y;
344   [window setFrame:windowFrame display:YES];
345   [[self class] cascadeWindow:window];
346}
347
348@end
349
350
351//============================================================
352//  MAMEExpreesionAuxiliaryDebugWindowHandler class
353//============================================================
354
355@implementation MAMEExpressionAuxiliaryDebugWindowHandler
356
357- (id)initWithMachine:(running_machine &)m title:(NSString *)t console:(MAMEDebugConsole *)c {
358   if (!(self = [super initWithMachine:m title:t console:c]))
359      return nil;
360   history = [[MAMEDebugCommandHistory alloc] init];
361   return self;
362}
363
364
365- (void)dealloc {
366   if (history != nil)
367      [history release];
368   [super dealloc];
369}
370
371
372- (id <MAMEDebugViewExpressionSupport>)documentView {
373   return nil;
374}
375
376
377- (NSString *)expression {
378   return [[self documentView] expression];
379}
380
381- (void)setExpression:(NSString *)expression {
382   [history add:expression];
383   [[self documentView] setExpression:expression];
384   [expressionField setStringValue:expression];
385   [expressionField selectText:self];
386}
387
388
389- (IBAction)doExpression:(id)sender {
390   NSString *expr = [sender stringValue];
391   if ([expr length] > 0) {
392      [history add:expr];
393      [[self documentView] setExpression:expr];
394   } else {
395      [sender setStringValue:[[self documentView] expression]];
396      [history reset];
397   }
398   [sender selectText:self];
399}
400
401
402- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor
403{
404   if (control == expressionField)
405      [history edit];
406
407   return YES;
408}
409
410
411- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command {
412   if (control == expressionField) {
413      if (command == @selector(cancelOperation:)) {
414         [history reset];
415         [expressionField setStringValue:[[self documentView] expression]];
416         [expressionField selectText:self];
417         return YES;
418      } else if (command == @selector(moveUp:)) {
419         NSString *hist = [history previous:[expressionField stringValue]];
420         if (hist != nil) {
421            [expressionField setStringValue:hist];
422            [expressionField selectText:self];
423         }
424         return YES;
425      } else if (command == @selector(moveDown:)) {
426         NSString *hist = [history next:[expressionField stringValue]];
427         if (hist != nil) {
428            [expressionField setStringValue:hist];
429            [expressionField selectText:self];
430         }
431         return YES;
432      }
433    }
434   return NO;
435}
436
437@end
trunk/src/osd/modules/debugger/osx/deviceinfoviewer.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  deviceinfoviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "deviceinfoviewer.h"
10
11
12@interface MAMEDeviceInfoView : NSView
13{
14   CGFloat   minWidth;
15}
16
17- (id)initWithFrame:(NSRect)frame;
18
19- (void)setMinWidth:(CGFloat)aWidth;
20
21@end
22
23
24@implementation MAMEDeviceInfoView
25
26- (id)initWithFrame:(NSRect)frame {
27   if (!(self = [super initWithFrame:frame]))
28      return nil;
29   minWidth = 0;
30   return self;
31}
32
33- (void)setMinWidth:(CGFloat)aWidth {
34   minWidth = aWidth;
35}
36
37- (BOOL)isFlipped {
38   return YES;
39}
40
41- (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize {
42   NSSize const newBoundsSize = [[self superview] bounds].size;
43   [self setFrameSize:NSMakeSize(MAX(newBoundsSize.width, minWidth), [self frame].size.height)];
44}
45
46@end
47
48
49@implementation MAMEDeviceInfoViewer
50
51- (NSTextField *)makeLabel:(NSString *)text {
52   NSTextField *const result = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 14)];
53   [result setAutoresizingMask:(NSViewMaxYMargin | NSViewMaxXMargin)];
54   [[result cell] setControlSize:NSSmallControlSize];
55   [result setEditable:NO];
56   [result setSelectable:NO];
57   [result setBezeled:NO];
58   [result setBordered:NO];
59   [result setDrawsBackground:NO];
60   [result setAlignment:NSRightTextAlignment];
61   [result setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
62   [result setStringValue:text];
63   [result sizeToFit];
64   return result;
65}
66
67
68- (NSTextField *)makeField:(NSString *)text {
69   NSTextField *const result = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 14)];
70   [result setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)];
71   [[result cell] setControlSize:NSSmallControlSize];
72   [result setEditable:NO];
73   [result setSelectable:YES];
74   [result setBezeled:NO];
75   [result setBordered:NO];
76   [result setDrawsBackground:NO];
77   [result setAlignment:NSLeftTextAlignment];
78   [result setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
79   [result setStringValue:text];
80   [result sizeToFit];
81   return result;
82}
83
84
85- (NSBox *)makeBox:(NSString *)t toFit:(NSView *)v {
86   NSBox *const result = [[NSBox alloc] initWithFrame:NSMakeRect(0, 0, [v frame].size.width - 34, 32)];
87   [result setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)];
88   [result setTitle:t];
89   [result setBoxType:NSBoxPrimary];
90   [result setBorderType:NSLineBorder];
91   [result setContentViewMargins:NSMakeSize(0, 0)];
92   [result setAutoresizesSubviews:YES];
93   return result;
94}
95
96
97- (void)addLabel:(NSString *)l withWidth:(CGFloat)w andField:(NSString *)f toView:(NSView *)v {
98   NSTextField *const label = [self makeLabel:l];
99   NSTextField *const field = [self makeField:f];
100   CGFloat const height = MAX([label frame].size.height, [field frame].size.height);
101   NSSize space = [v bounds].size;
102   space.width = MAX(space.width, [field frame].size.width + w + 52);
103   space.height += height + 8;
104   [label setFrame:NSMakeRect(25, space.height - height - 20, w, height)];
105   [field setFrame:NSMakeRect(w + 27, space.height - height - 20, space.width - w - 52, height)];
106   [v setFrameSize:space];
107   [v addSubview:label];
108   [v addSubview:field];
109   [label release];
110   [field release];
111}
112
113
114- (void)addField:(NSString *)f toBox:(NSBox *)b {
115   NSTextField *const field = [self makeField:f];
116   [field setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
117   NSSize space = [b frame].size;
118   space.width = MAX(space.width, [field frame].size.width + 32);
119   space.height += [field frame].size.height + 8;
120   [field setFrame:NSMakeRect(15, 14, space.width - 32, [field frame].size.height)];
121   [b setFrameSize:space];
122   [[b contentView] addSubview:field];
123   [field release];
124}
125
126
127- (void)addBox:(NSBox *)b toView:(NSView *)v {
128   NSSize space = [v frame].size;
129   space.width = MAX(space.width, [b frame].size.width + 34);
130   space.height += [b frame].size.height + 4;
131   [b setFrameOrigin:NSMakePoint(17, space.height - [b frame].size.height - 16)];
132   [v setFrameSize:space];
133   [v addSubview:b];
134}
135
136
137- (id)initWithDevice:(device_t &)d machine:(running_machine &)m console:(MAMEDebugConsole *)c {
138   MAMEDeviceInfoView   *contentView;
139   NSScrollView      *contentScroll;
140
141   if (!(self = [super initWithMachine:m
142                          title:[NSString stringWithFormat:@"Device %s", d.tag()]
143                        console:c]))
144   {
145      return nil;
146   }
147   device = &d;
148
149   // Create a view to hold everything
150   contentView = [[MAMEDeviceInfoView alloc] initWithFrame:NSMakeRect(0, 0, 320, 32)];
151   [contentView setAutoresizesSubviews:YES];
152
153   // add the stuff that's always present
154   [self addLabel:@"Tag:"
155       withWidth:100
156        andField:[NSString stringWithUTF8String:device->tag()]
157         toView:contentView];
158   [self addLabel:@"Name:"
159       withWidth:100
160        andField:[NSString stringWithUTF8String:device->name()]
161         toView:contentView];
162   [self addLabel:@"Shortname:"
163       withWidth:100
164        andField:[NSString stringWithUTF8String:device->shortname()]
165         toView:contentView];
166
167   // add interfaces if present
168   device_interface *interface = device->first_interface();
169   if (interface != NULL)
170   {
171      NSBox *const interfacesBox = [self makeBox:@"Interfaces" toFit:contentView];
172      while (interface != NULL)
173      {
174         [self addField:[NSString stringWithUTF8String:interface->interface_type()]
175                toBox:interfacesBox];
176         interface = interface->interface_next();
177      }
178      [self addBox:interfacesBox toView:contentView];
179      [interfacesBox release];
180   }
181
182   // add memory maps if present
183   device_memory_interface *memory;
184   if (device->interface(memory))
185   {
186      NSBox *memoryBox = nil;
187      for (address_spacenum i = AS_0; i < ADDRESS_SPACES; i++)
188      {
189         if (memory->has_space(i))
190         {
191            if (memoryBox == nil)
192               memoryBox = [self makeBox:@"Memory maps" toFit:contentView];
193            [self addField:[NSString stringWithUTF8String:memory->space_config(i)->name()]
194                   toBox:memoryBox];
195         }
196      }
197      if (memoryBox != nil)
198      {
199         [self addBox:memoryBox toView:contentView];
200         [memoryBox release];
201      }
202   }
203
204   // lock minimum content size
205   [contentView setMinWidth:[contentView frame].size.width];
206   [contentView setAutoresizingMask:NSViewWidthSizable];
207
208   // create a scroll view for holding everything
209   NSSize desired = [NSScrollView frameSizeForContentSize:[contentView frame].size
210                            hasHorizontalScroller:YES
211                              hasVerticalScroller:YES
212                                    borderType:NSNoBorder];
213   [window setContentSize:desired];
214   contentScroll = [[NSScrollView alloc] initWithFrame:[[window contentView] bounds]];
215   [contentScroll setDrawsBackground:NO];
216   [contentScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
217   [contentScroll setHasHorizontalScroller:YES];
218   [contentScroll setHasVerticalScroller:YES];
219   [contentScroll setAutohidesScrollers:YES];
220   [contentScroll setBorderType:NSNoBorder];
221   [contentScroll setDocumentView:contentView];
222   [contentView release];
223   [[window contentView] addSubview:contentScroll];
224   [contentScroll release];
225
226   // calculate the optimal size for everything
227   [self cascadeWindowWithDesiredSize:[contentScroll frame].size forView:contentScroll];
228
229   // don't forget the result
230   return self;
231}
232
233@end
trunk/src/osd/modules/debugger/osx/deviceinfoviewer.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  deviceinfoviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "deviceinfoviewer.h"
10
11
12@interface MAMEDeviceInfoView : NSView
13{
14   CGFloat   minWidth;
15}
16
17- (id)initWithFrame:(NSRect)frame;
18
19- (void)setMinWidth:(CGFloat)aWidth;
20
21@end
22
23
24@implementation MAMEDeviceInfoView
25
26- (id)initWithFrame:(NSRect)frame {
27   if (!(self = [super initWithFrame:frame]))
28      return nil;
29   minWidth = 0;
30   return self;
31}
32
33- (void)setMinWidth:(CGFloat)aWidth {
34   minWidth = aWidth;
35}
36
37- (BOOL)isFlipped {
38   return YES;
39}
40
41- (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize {
42   NSSize const newBoundsSize = [[self superview] bounds].size;
43   [self setFrameSize:NSMakeSize(MAX(newBoundsSize.width, minWidth), [self frame].size.height)];
44}
45
46@end
47
48
49@implementation MAMEDeviceInfoViewer
50
51- (NSTextField *)makeLabel:(NSString *)text {
52   NSTextField *const result = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 14)];
53   [result setAutoresizingMask:(NSViewMaxYMargin | NSViewMaxXMargin)];
54   [[result cell] setControlSize:NSSmallControlSize];
55   [result setEditable:NO];
56   [result setSelectable:NO];
57   [result setBezeled:NO];
58   [result setBordered:NO];
59   [result setDrawsBackground:NO];
60   [result setAlignment:NSRightTextAlignment];
61   [result setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
62   [result setStringValue:text];
63   [result sizeToFit];
64   return result;
65}
66
67
68- (NSTextField *)makeField:(NSString *)text {
69   NSTextField *const result = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 14)];
70   [result setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)];
71   [[result cell] setControlSize:NSSmallControlSize];
72   [result setEditable:NO];
73   [result setSelectable:YES];
74   [result setBezeled:NO];
75   [result setBordered:NO];
76   [result setDrawsBackground:NO];
77   [result setAlignment:NSLeftTextAlignment];
78   [result setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
79   [result setStringValue:text];
80   [result sizeToFit];
81   return result;
82}
83
84
85- (NSBox *)makeBox:(NSString *)t toFit:(NSView *)v {
86   NSBox *const result = [[NSBox alloc] initWithFrame:NSMakeRect(0, 0, [v frame].size.width - 34, 32)];
87   [result setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)];
88   [result setTitle:t];
89   [result setBoxType:NSBoxPrimary];
90   [result setBorderType:NSLineBorder];
91   [result setContentViewMargins:NSMakeSize(0, 0)];
92   [result setAutoresizesSubviews:YES];
93   return result;
94}
95
96
97- (void)addLabel:(NSString *)l withWidth:(CGFloat)w andField:(NSString *)f toView:(NSView *)v {
98   NSTextField *const label = [self makeLabel:l];
99   NSTextField *const field = [self makeField:f];
100   CGFloat const height = MAX([label frame].size.height, [field frame].size.height);
101   NSSize space = [v bounds].size;
102   space.width = MAX(space.width, [field frame].size.width + w + 52);
103   space.height += height + 8;
104   [label setFrame:NSMakeRect(25, space.height - height - 20, w, height)];
105   [field setFrame:NSMakeRect(w + 27, space.height - height - 20, space.width - w - 52, height)];
106   [v setFrameSize:space];
107   [v addSubview:label];
108   [v addSubview:field];
109   [label release];
110   [field release];
111}
112
113
114- (void)addField:(NSString *)f toBox:(NSBox *)b {
115   NSTextField *const field = [self makeField:f];
116   [field setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
117   NSSize space = [b frame].size;
118   space.width = MAX(space.width, [field frame].size.width + 32);
119   space.height += [field frame].size.height + 8;
120   [field setFrame:NSMakeRect(15, 14, space.width - 32, [field frame].size.height)];
121   [b setFrameSize:space];
122   [[b contentView] addSubview:field];
123   [field release];
124}
125
126
127- (void)addBox:(NSBox *)b toView:(NSView *)v {
128   NSSize space = [v frame].size;
129   space.width = MAX(space.width, [b frame].size.width + 34);
130   space.height += [b frame].size.height + 4;
131   [b setFrameOrigin:NSMakePoint(17, space.height - [b frame].size.height - 16)];
132   [v setFrameSize:space];
133   [v addSubview:b];
134}
135
136
137- (id)initWithDevice:(device_t &)d machine:(running_machine &)m console:(MAMEDebugConsole *)c {
138   MAMEDeviceInfoView   *contentView;
139   NSScrollView      *contentScroll;
140
141   if (!(self = [super initWithMachine:m
142                          title:[NSString stringWithFormat:@"Device %s", d.tag()]
143                        console:c]))
144   {
145      return nil;
146   }
147   device = &d;
148
149   // Create a view to hold everything
150   contentView = [[MAMEDeviceInfoView alloc] initWithFrame:NSMakeRect(0, 0, 320, 32)];
151   [contentView setAutoresizesSubviews:YES];
152
153   // add the stuff that's always present
154   [self addLabel:@"Tag:"
155       withWidth:100
156        andField:[NSString stringWithUTF8String:device->tag()]
157         toView:contentView];
158   [self addLabel:@"Name:"
159       withWidth:100
160        andField:[NSString stringWithUTF8String:device->name()]
161         toView:contentView];
162   [self addLabel:@"Shortname:"
163       withWidth:100
164        andField:[NSString stringWithUTF8String:device->shortname()]
165         toView:contentView];
166
167   // add interfaces if present
168   device_interface *interface = device->first_interface();
169   if (interface != NULL)
170   {
171      NSBox *const interfacesBox = [self makeBox:@"Interfaces" toFit:contentView];
172      while (interface != NULL)
173      {
174         [self addField:[NSString stringWithUTF8String:interface->interface_type()]
175                toBox:interfacesBox];
176         interface = interface->interface_next();
177      }
178      [self addBox:interfacesBox toView:contentView];
179      [interfacesBox release];
180   }
181
182   // add memory maps if present
183   device_memory_interface *memory;
184   if (device->interface(memory))
185   {
186      NSBox *memoryBox = nil;
187      for (address_spacenum i = AS_0; i < ADDRESS_SPACES; i++)
188      {
189         if (memory->has_space(i))
190         {
191            if (memoryBox == nil)
192               memoryBox = [self makeBox:@"Memory maps" toFit:contentView];
193            [self addField:[NSString stringWithUTF8String:memory->space_config(i)->name()]
194                   toBox:memoryBox];
195         }
196      }
197      if (memoryBox != nil)
198      {
199         [self addBox:memoryBox toView:contentView];
200         [memoryBox release];
201      }
202   }
203
204   // lock minimum content size
205   [contentView setMinWidth:[contentView frame].size.width];
206   [contentView setAutoresizingMask:NSViewWidthSizable];
207
208   // create a scroll view for holding everything
209   NSSize desired = [NSScrollView frameSizeForContentSize:[contentView frame].size
210                            hasHorizontalScroller:YES
211                              hasVerticalScroller:YES
212                                    borderType:NSNoBorder];
213   [window setContentSize:desired];
214   contentScroll = [[NSScrollView alloc] initWithFrame:[[window contentView] bounds]];
215   [contentScroll setDrawsBackground:NO];
216   [contentScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
217   [contentScroll setHasHorizontalScroller:YES];
218   [contentScroll setHasVerticalScroller:YES];
219   [contentScroll setAutohidesScrollers:YES];
220   [contentScroll setBorderType:NSNoBorder];
221   [contentScroll setDocumentView:contentView];
222   [contentView release];
223   [[window contentView] addSubview:contentScroll];
224   [contentScroll release];
225
226   // calculate the optimal size for everything
227   [self cascadeWindowWithDesiredSize:[contentScroll frame].size forView:contentScroll];
228
229   // don't forget the result
230   return self;
231}
232
233@end
trunk/src/osd/modules/debugger/osx/devicesviewer.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  devicesviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "devicesviewer.h"
10
11#import "debugconsole.h"
12
13
14@interface MAMEDeviceWrapper : NSObject
15{
16   running_machine   *machine;
17   device_t      *device;
18   NSArray         *children;
19}
20
21- (id)initWithMachine:(running_machine &)m device:(device_t &)d;
22
23- (running_machine &)machine;
24- (device_t &)device;
25- (NSString *)tag;
26- (NSString *)name;
27- (NSUInteger)children;
28- (MAMEDeviceWrapper *)childAtIndex:(NSUInteger)index;
29
30@end
31
32
33@implementation MAMEDeviceWrapper
34
35- (void)wrapChildren {
36   NSMutableArray *const tmp = [[NSMutableArray alloc] init];
37   for (device_t *child = device->first_subdevice(); child != NULL; child = child->next())
38   {
39      MAMEDeviceWrapper *const wrap = [[MAMEDeviceWrapper alloc] initWithMachine:*machine
40                                                         device:*child];
41      [tmp addObject:wrap];
42      [wrap release];
43   }
44   children = [[NSArray alloc] initWithArray:tmp];
45   [tmp release];
46}
47
48
49- (id)initWithMachine:(running_machine &)m device:(device_t &)d {
50   if (!(self = [super init]))
51      return nil;
52   machine = &m;
53   device = &d;
54   children = nil;
55   return self;
56}
57
58
59- (void)dealloc {
60   if (children != nil)
61      [children release];
62   [super dealloc];
63}
64
65
66- (running_machine &)machine {
67   return *machine;
68}
69
70
71- (device_t &)device {
72   return *device;
73}
74
75
76- (NSString *)tag {
77   return (device == &machine->root_device()) ? @"<root>"
78                                    : [NSString stringWithUTF8String:device->basetag()];
79}
80
81
82- (NSString *)name {
83   return [NSString stringWithUTF8String:device->name()];
84}
85
86
87- (NSUInteger)children {
88   if (children == nil)
89      [self wrapChildren];
90   return [children count];
91}
92
93
94- (MAMEDeviceWrapper *)childAtIndex:(NSUInteger)index {
95   if (children == nil)
96      [self wrapChildren];
97   return (index < [children count]) ? [children objectAtIndex:index] : nil;
98}
99
100@end
101
102
103@implementation MAMEDevicesViewer
104
105- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
106   NSScrollView   *devicesScroll;
107   NSTableColumn   *tagColumn, *nameColumn;
108
109   if (!(self = [super initWithMachine:m title:@"All Devices" console:c]))
110      return nil;
111   root = [[MAMEDeviceWrapper alloc] initWithMachine:m device:m.root_device()];
112
113   // create the devices view
114   devicesView = [[NSOutlineView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
115   [devicesView setUsesAlternatingRowBackgroundColors:YES];
116   [devicesView setAllowsColumnReordering:YES];
117   [devicesView setAllowsColumnResizing:YES];
118   [devicesView setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle];
119   [devicesView setAllowsEmptySelection:YES];
120   [devicesView setAllowsMultipleSelection:NO];
121   [devicesView setAllowsColumnSelection:NO];
122   tagColumn = [[NSTableColumn alloc] initWithIdentifier:@"tag"];
123   [[tagColumn headerCell] setStringValue:@"Tag"];
124   [tagColumn setEditable:NO];
125   [tagColumn setMinWidth:100];
126   [tagColumn setWidth:120];
127   [tagColumn setResizingMask:(NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask)];
128   [devicesView addTableColumn:tagColumn];
129   [tagColumn release];
130   nameColumn = [[NSTableColumn alloc] initWithIdentifier:@"name"];
131   [[nameColumn headerCell] setStringValue:@"Name"];
132   [nameColumn setEditable:NO];
133   [nameColumn setMinWidth:100];
134   [nameColumn setMinWidth:360];
135   [nameColumn setResizingMask:(NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask)];
136   [devicesView addTableColumn:nameColumn];
137   [nameColumn release];
138   [devicesView setOutlineTableColumn:tagColumn];
139   [devicesView setAutoresizesOutlineColumn:YES];
140   [devicesView setDoubleAction:@selector(showDeviceDetail:)];
141   [devicesView setDataSource:self];
142   devicesScroll = [[NSScrollView alloc] initWithFrame:[[window contentView] bounds]];
143   [devicesScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
144   [devicesScroll setHasHorizontalScroller:YES];
145   [devicesScroll setHasVerticalScroller:YES];
146   [devicesScroll setAutohidesScrollers:YES];
147   [devicesScroll setBorderType:NSNoBorder];
148   [devicesScroll setDocumentView:devicesView];
149   [devicesView release];
150   [[window contentView] addSubview:devicesScroll];
151   [devicesScroll release];
152
153   // set default state
154   [devicesView expandItem:root expandChildren:YES];
155   [window makeFirstResponder:devicesView];
156   [window setTitle:@"All Devices"];
157
158   // calculate the optimal size for everything
159   NSSize const desired = [NSScrollView frameSizeForContentSize:NSMakeSize(480, 320)
160                                 hasHorizontalScroller:YES
161                                  hasVerticalScroller:YES
162                                         borderType:[devicesScroll borderType]];
163   [self cascadeWindowWithDesiredSize:desired forView:devicesScroll];
164
165   // don't forget the result
166   return self;
167}
168
169
170- (void)dealloc {
171   if (root != nil)
172      [root release];
173   [super dealloc];
174}
175
176
177- (IBAction)showDeviceDetail:(id)sender {
178   [console debugNewInfoWindowForDevice:[(MAMEDeviceWrapper *)[sender itemAtRow:[sender clickedRow]] device]];
179}
180
181
182- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
183   return [(MAMEDeviceWrapper *)item children] > 0;
184}
185
186
187- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
188   if (item != nil)
189      return [(MAMEDeviceWrapper *)item children];
190   else
191      return 1;
192}
193
194
195- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
196   if (item != nil)
197      return [(MAMEDeviceWrapper *)item childAtIndex:index];
198   else if (index == 0)
199      return root;
200   else
201      return nil;
202}
203
204
205- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
206   if ([[tableColumn identifier] isEqualToString:@"tag"])
207      return [(MAMEDeviceWrapper *)item tag];
208   else if ([[tableColumn identifier] isEqualToString:@"name"])
209      return [(MAMEDeviceWrapper *)item name];
210   else
211      return nil;
212}
213
214@end
trunk/src/osd/modules/debugger/osx/devicesviewer.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  devicesviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "devicesviewer.h"
10
11#import "debugconsole.h"
12
13
14@interface MAMEDeviceWrapper : NSObject
15{
16   running_machine   *machine;
17   device_t      *device;
18   NSArray         *children;
19}
20
21- (id)initWithMachine:(running_machine &)m device:(device_t &)d;
22
23- (running_machine &)machine;
24- (device_t &)device;
25- (NSString *)tag;
26- (NSString *)name;
27- (NSUInteger)children;
28- (MAMEDeviceWrapper *)childAtIndex:(NSUInteger)index;
29
30@end
31
32
33@implementation MAMEDeviceWrapper
34
35- (void)wrapChildren {
36   NSMutableArray *const tmp = [[NSMutableArray alloc] init];
37   for (device_t *child = device->first_subdevice(); child != NULL; child = child->next())
38   {
39      MAMEDeviceWrapper *const wrap = [[MAMEDeviceWrapper alloc] initWithMachine:*machine
40                                                         device:*child];
41      [tmp addObject:wrap];
42      [wrap release];
43   }
44   children = [[NSArray alloc] initWithArray:tmp];
45   [tmp release];
46}
47
48
49- (id)initWithMachine:(running_machine &)m device:(device_t &)d {
50   if (!(self = [super init]))
51      return nil;
52   machine = &m;
53   device = &d;
54   children = nil;
55   return self;
56}
57
58
59- (void)dealloc {
60   if (children != nil)
61      [children release];
62   [super dealloc];
63}
64
65
66- (running_machine &)machine {
67   return *machine;
68}
69
70
71- (device_t &)device {
72   return *device;
73}
74
75
76- (NSString *)tag {
77   return (device == &machine->root_device()) ? @"<root>"
78                                    : [NSString stringWithUTF8String:device->basetag()];
79}
80
81
82- (NSString *)name {
83   return [NSString stringWithUTF8String:device->name()];
84}
85
86
87- (NSUInteger)children {
88   if (children == nil)
89      [self wrapChildren];
90   return [children count];
91}
92
93
94- (MAMEDeviceWrapper *)childAtIndex:(NSUInteger)index {
95   if (children == nil)
96      [self wrapChildren];
97   return (index < [children count]) ? [children objectAtIndex:index] : nil;
98}
99
100@end
101
102
103@implementation MAMEDevicesViewer
104
105- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
106   NSScrollView   *devicesScroll;
107   NSTableColumn   *tagColumn, *nameColumn;
108
109   if (!(self = [super initWithMachine:m title:@"All Devices" console:c]))
110      return nil;
111   root = [[MAMEDeviceWrapper alloc] initWithMachine:m device:m.root_device()];
112
113   // create the devices view
114   devicesView = [[NSOutlineView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
115   [devicesView setUsesAlternatingRowBackgroundColors:YES];
116   [devicesView setAllowsColumnReordering:YES];
117   [devicesView setAllowsColumnResizing:YES];
118   [devicesView setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle];
119   [devicesView setAllowsEmptySelection:YES];
120   [devicesView setAllowsMultipleSelection:NO];
121   [devicesView setAllowsColumnSelection:NO];
122   tagColumn = [[NSTableColumn alloc] initWithIdentifier:@"tag"];
123   [[tagColumn headerCell] setStringValue:@"Tag"];
124   [tagColumn setEditable:NO];
125   [tagColumn setMinWidth:100];
126   [tagColumn setWidth:120];
127   [tagColumn setResizingMask:(NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask)];
128   [devicesView addTableColumn:tagColumn];
129   [tagColumn release];
130   nameColumn = [[NSTableColumn alloc] initWithIdentifier:@"name"];
131   [[nameColumn headerCell] setStringValue:@"Name"];
132   [nameColumn setEditable:NO];
133   [nameColumn setMinWidth:100];
134   [nameColumn setMinWidth:360];
135   [nameColumn setResizingMask:(NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask)];
136   [devicesView addTableColumn:nameColumn];
137   [nameColumn release];
138   [devicesView setOutlineTableColumn:tagColumn];
139   [devicesView setAutoresizesOutlineColumn:YES];
140   [devicesView setDoubleAction:@selector(showDeviceDetail:)];
141   [devicesView setDataSource:self];
142   devicesScroll = [[NSScrollView alloc] initWithFrame:[[window contentView] bounds]];
143   [devicesScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
144   [devicesScroll setHasHorizontalScroller:YES];
145   [devicesScroll setHasVerticalScroller:YES];
146   [devicesScroll setAutohidesScrollers:YES];
147   [devicesScroll setBorderType:NSNoBorder];
148   [devicesScroll setDocumentView:devicesView];
149   [devicesView release];
150   [[window contentView] addSubview:devicesScroll];
151   [devicesScroll release];
152
153   // set default state
154   [devicesView expandItem:root expandChildren:YES];
155   [window makeFirstResponder:devicesView];
156   [window setTitle:@"All Devices"];
157
158   // calculate the optimal size for everything
159   NSSize const desired = [NSScrollView frameSizeForContentSize:NSMakeSize(480, 320)
160                                 hasHorizontalScroller:YES
161                                  hasVerticalScroller:YES
162                                         borderType:[devicesScroll borderType]];
163   [self cascadeWindowWithDesiredSize:desired forView:devicesScroll];
164
165   // don't forget the result
166   return self;
167}
168
169
170- (void)dealloc {
171   if (root != nil)
172      [root release];
173   [super dealloc];
174}
175
176
177- (IBAction)showDeviceDetail:(id)sender {
178   [console debugNewInfoWindowForDevice:[(MAMEDeviceWrapper *)[sender itemAtRow:[sender clickedRow]] device]];
179}
180
181
182- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
183   return [(MAMEDeviceWrapper *)item children] > 0;
184}
185
186
187- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
188   if (item != nil)
189      return [(MAMEDeviceWrapper *)item children];
190   else
191      return 1;
192}
193
194
195- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
196   if (item != nil)
197      return [(MAMEDeviceWrapper *)item childAtIndex:index];
198   else if (index == 0)
199      return root;
200   else
201      return nil;
202}
203
204
205- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
206   if ([[tableColumn identifier] isEqualToString:@"tag"])
207      return [(MAMEDeviceWrapper *)item tag];
208   else if ([[tableColumn identifier] isEqualToString:@"name"])
209      return [(MAMEDeviceWrapper *)item name];
210   else
211      return nil;
212}
213
214@end
trunk/src/osd/modules/debugger/osx/disassemblyview.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  disassemblyview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "disassemblyview.h"
10
11#include "debug/debugvw.h"
12
13
14@implementation MAMEDisassemblyView
15
16- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
17   if (!(self = [super initWithFrame:f type:DVT_DISASSEMBLY machine:m wholeLineScroll:NO]))
18      return nil;
19   return self;
20}
21
22
23- (void)dealloc {
24   [super dealloc];
25}
26
27
28- (BOOL)validateMenuItem:(NSMenuItem *)item {
29   SEL const action = [item action];
30
31   if (action == @selector(showRightColumn:))
32   {
33      [item setState:((downcast<debug_view_disasm *>(view)->right_column() == [item tag]) ? NSOnState : NSOffState)];
34      return YES;
35   }
36   else
37   {
38      return [super validateMenuItem:item];
39   }
40}
41
42
43- (NSSize)maximumFrameSize {
44   debug_view_xy         max(0, 0);
45   debug_view_source const   *source = view->source();
46   for (debug_view_source const *source = view->first_source(); source != NULL; source = source->next())
47   {
48      view->set_source(*source);
49      debug_view_xy const current = view->total_size();
50      max.x = MAX(max.x, current.x);
51      max.y = MAX(max.y, current.y);
52   }
53   view->set_source(*source);
54   return NSMakeSize(ceil((max.x * fontWidth) + (2 * [textContainer lineFragmentPadding])),
55                 ceil(max.y * fontHeight));
56}
57
58
59- (void)addContextMenuItemsToMenu:(NSMenu *)menu {
60   NSMenuItem   *item;
61
62   [super addContextMenuItemsToMenu:menu];
63
64   if ([menu numberOfItems] > 0)
65      [menu addItem:[NSMenuItem separatorItem]];
66
67   item = [menu addItemWithTitle:@"Toggle Breakpoint"
68                     action:@selector(debugToggleBreakpoint:)
69               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]];
70   [item setKeyEquivalentModifierMask:0];
71
72   item = [menu addItemWithTitle:@"Disable Breakpoint"
73                     action:@selector(debugToggleBreakpointEnable:)
74               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]];
75   [item setKeyEquivalentModifierMask:NSShiftKeyMask];
76
77   [menu addItem:[NSMenuItem separatorItem]];
78
79   item = [menu addItemWithTitle:@"Run to Cursor"
80                     action:@selector(debugRunToCursor:)
81               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey]];
82   [item setKeyEquivalentModifierMask:0];
83
84   [menu addItem:[NSMenuItem separatorItem]];
85
86   item = [menu addItemWithTitle:@"Raw Opcodes"
87                     action:@selector(showRightColumn:)
88               keyEquivalent:@"r"];
89   [item setTarget:self];
90   [item setTag:DASM_RIGHTCOL_RAW];
91
92   item = [menu addItemWithTitle:@"Encrypted Opcodes"
93                     action:@selector(showRightColumn:)
94               keyEquivalent:@"e"];
95   [item setTarget:self];
96   [item setTag:DASM_RIGHTCOL_ENCRYPTED];
97
98   item = [menu addItemWithTitle:@"Comments"
99                     action:@selector(showRightColumn:)
100               keyEquivalent:@"n"];
101   [item setTarget:self];
102   [item setTag:DASM_RIGHTCOL_COMMENTS];
103}
104
105
106- (NSString *)selectedSubviewName {
107   const debug_view_source *source = view->source();
108   if (source != NULL)
109      return [NSString stringWithUTF8String:source->name()];
110   else
111      return @"";
112}
113
114
115- (int)selectedSubviewIndex {
116   const debug_view_source *source = view->source();
117   if (source != NULL)
118      return view->source_list().indexof(*source);
119   else
120      return -1;
121}
122
123
124- (void)selectSubviewAtIndex:(int)index {
125   const int   selected = view->source_list().indexof(*view->source());
126   if (selected != index) {
127      view->set_source(*view->source_list().find(index));
128      if ([[self window] firstResponder] != self)
129         view->set_cursor_visible(false);
130   }
131}
132
133
134- (BOOL)selectSubviewForDevice:(device_t *)device {
135   debug_view_source const *const source = view->source_for_device(device);
136   if (source != NULL)
137   {
138      if (view->source() != source)
139      {
140         view->set_source(*source);
141         if ([[self window] firstResponder] != self)
142            view->set_cursor_visible(false);
143      }
144      return YES;
145   }
146   else
147   {
148      return NO;
149   }
150}
151
152
153- (BOOL)selectSubviewForSpace:(address_space *)space {
154   if (space == NULL) return NO;
155   debug_view_disasm_source const *source = downcast<debug_view_disasm_source const *>(view->first_source());
156   while ((source != NULL) && (&source->space() != space))
157      source = downcast<debug_view_disasm_source *>(source->next());
158   if (source != NULL)
159   {
160      if (view->source() != source)
161      {
162         view->set_source(*source);
163         if ([[self window] firstResponder] != self)
164            view->set_cursor_visible(false);
165      }
166      return YES;
167   }
168   else
169   {
170      return NO;
171   }
172}
173
174
175- (NSString *)expression {
176   return [NSString stringWithUTF8String:downcast<debug_view_disasm *>(view)->expression()];
177}
178
179
180- (void)setExpression:(NSString *)exp {
181   downcast<debug_view_disasm *>(view)->set_expression([exp UTF8String]);
182}
183
184
185- (debug_view_disasm_source const *)source {
186   return downcast<debug_view_disasm_source const *>(view->source());
187}
188
189
190- (offs_t)selectedAddress {
191   return downcast<debug_view_disasm *>(view)->selected_address();
192}
193
194
195- (IBAction)showRightColumn:(id)sender {
196   downcast<debug_view_disasm *>(view)->set_right_column((disasm_right_column) [sender tag]);
197}
198
199
200- (void)insertActionItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index {
201   NSMenuItem *breakItem = [menu insertItemWithTitle:@"Toggle Breakpoint at Cursor"
202                                    action:@selector(debugToggleBreakpoint:)
203                              keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]
204                                   atIndex:index++];
205   [breakItem setKeyEquivalentModifierMask:0];
206
207   NSMenuItem *disableItem = [menu insertItemWithTitle:@"Disable Breakpoint at Cursor"
208                                     action:@selector(debugToggleBreakpointEnable:)
209                                keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]
210                                    atIndex:index++];
211   [disableItem setKeyEquivalentModifierMask:NSShiftKeyMask];
212
213   NSMenu      *runMenu = [[menu itemWithTitle:@"Run"] submenu];
214   NSMenuItem   *runItem;
215   if (runMenu != nil) {
216      runItem = [runMenu addItemWithTitle:@"to Cursor"
217                            action:@selector(debugRunToCursor:)
218                       keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey]];
219   } else {
220      runItem = [menu insertItemWithTitle:@"Run to Cursor"
221                            action:@selector(debugRunToCursor:)
222                       keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey]
223                           atIndex:index++];
224   }
225   [runItem setKeyEquivalentModifierMask:0];
226
227   [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
228
229   NSMenuItem *rawItem = [menu insertItemWithTitle:@"Show Raw Opcodes"
230                                  action:@selector(showRightColumn:)
231                             keyEquivalent:@"r"
232                                 atIndex:index++];
233   [rawItem setTarget:self];
234   [rawItem setTag:DASM_RIGHTCOL_RAW];
235
236   NSMenuItem *encItem = [menu insertItemWithTitle:@"Show Encrypted Opcodes"
237                                  action:@selector(showRightColumn:)
238                             keyEquivalent:@"e"
239                                 atIndex:index++];
240   [encItem setTarget:self];
241   [encItem setTag:DASM_RIGHTCOL_ENCRYPTED];
242
243   NSMenuItem *commentsItem = [menu insertItemWithTitle:@"Show Comments"
244                                      action:@selector(showRightColumn:)
245                                 keyEquivalent:@"n"
246                                     atIndex:index++];
247   [commentsItem setTarget:self];
248   [commentsItem setTag:DASM_RIGHTCOL_COMMENTS];
249
250   if (index < [menu numberOfItems])
251      [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
252}
253
254
255- (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index {
256   for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next())
257   {
258      [[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()]
259                     action:NULL
260                keyEquivalent:@""
261                     atIndex:index++] setTag:view->source_list().indexof(*source)];
262   }
263   if (index < [menu numberOfItems])
264      [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
265}
266
267@end
trunk/src/osd/modules/debugger/osx/disassemblyview.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  disassemblyview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "disassemblyview.h"
10
11#include "debug/debugvw.h"
12
13
14@implementation MAMEDisassemblyView
15
16- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
17   if (!(self = [super initWithFrame:f type:DVT_DISASSEMBLY machine:m wholeLineScroll:NO]))
18      return nil;
19   return self;
20}
21
22
23- (void)dealloc {
24   [super dealloc];
25}
26
27
28- (BOOL)validateMenuItem:(NSMenuItem *)item {
29   SEL const action = [item action];
30
31   if (action == @selector(showRightColumn:))
32   {
33      [item setState:((downcast<debug_view_disasm *>(view)->right_column() == [item tag]) ? NSOnState : NSOffState)];
34      return YES;
35   }
36   else
37   {
38      return [super validateMenuItem:item];
39   }
40}
41
42
43- (NSSize)maximumFrameSize {
44   debug_view_xy         max(0, 0);
45   debug_view_source const   *source = view->source();
46   for (debug_view_source const *source = view->first_source(); source != NULL; source = source->next())
47   {
48      view->set_source(*source);
49      debug_view_xy const current = view->total_size();
50      max.x = MAX(max.x, current.x);
51      max.y = MAX(max.y, current.y);
52   }
53   view->set_source(*source);
54   return NSMakeSize(ceil((max.x * fontWidth) + (2 * [textContainer lineFragmentPadding])),
55                 ceil(max.y * fontHeight));
56}
57
58
59- (void)addContextMenuItemsToMenu:(NSMenu *)menu {
60   NSMenuItem   *item;
61
62   [super addContextMenuItemsToMenu:menu];
63
64   if ([menu numberOfItems] > 0)
65      [menu addItem:[NSMenuItem separatorItem]];
66
67   item = [menu addItemWithTitle:@"Toggle Breakpoint"
68                     action:@selector(debugToggleBreakpoint:)
69               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]];
70   [item setKeyEquivalentModifierMask:0];
71
72   item = [menu addItemWithTitle:@"Disable Breakpoint"
73                     action:@selector(debugToggleBreakpointEnable:)
74               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]];
75   [item setKeyEquivalentModifierMask:NSShiftKeyMask];
76
77   [menu addItem:[NSMenuItem separatorItem]];
78
79   item = [menu addItemWithTitle:@"Run to Cursor"
80                     action:@selector(debugRunToCursor:)
81               keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey]];
82   [item setKeyEquivalentModifierMask:0];
83
84   [menu addItem:[NSMenuItem separatorItem]];
85
86   item = [menu addItemWithTitle:@"Raw Opcodes"
87                     action:@selector(showRightColumn:)
88               keyEquivalent:@"r"];
89   [item setTarget:self];
90   [item setTag:DASM_RIGHTCOL_RAW];
91
92   item = [menu addItemWithTitle:@"Encrypted Opcodes"
93                     action:@selector(showRightColumn:)
94               keyEquivalent:@"e"];
95   [item setTarget:self];
96   [item setTag:DASM_RIGHTCOL_ENCRYPTED];
97
98   item = [menu addItemWithTitle:@"Comments"
99                     action:@selector(showRightColumn:)
100               keyEquivalent:@"n"];
101   [item setTarget:self];
102   [item setTag:DASM_RIGHTCOL_COMMENTS];
103}
104
105
106- (NSString *)selectedSubviewName {
107   const debug_view_source *source = view->source();
108   if (source != NULL)
109      return [NSString stringWithUTF8String:source->name()];
110   else
111      return @"";
112}
113
114
115- (int)selectedSubviewIndex {
116   const debug_view_source *source = view->source();
117   if (source != NULL)
118      return view->source_list().indexof(*source);
119   else
120      return -1;
121}
122
123
124- (void)selectSubviewAtIndex:(int)index {
125   const int   selected = view->source_list().indexof(*view->source());
126   if (selected != index) {
127      view->set_source(*view->source_list().find(index));
128      if ([[self window] firstResponder] != self)
129         view->set_cursor_visible(false);
130   }
131}
132
133
134- (BOOL)selectSubviewForDevice:(device_t *)device {
135   debug_view_source const *const source = view->source_for_device(device);
136   if (source != NULL)
137   {
138      if (view->source() != source)
139      {
140         view->set_source(*source);
141         if ([[self window] firstResponder] != self)
142            view->set_cursor_visible(false);
143      }
144      return YES;
145   }
146   else
147   {
148      return NO;
149   }
150}
151
152
153- (BOOL)selectSubviewForSpace:(address_space *)space {
154   if (space == NULL) return NO;
155   debug_view_disasm_source const *source = downcast<debug_view_disasm_source const *>(view->first_source());
156   while ((source != NULL) && (&source->space() != space))
157      source = downcast<debug_view_disasm_source *>(source->next());
158   if (source != NULL)
159   {
160      if (view->source() != source)
161      {
162         view->set_source(*source);
163         if ([[self window] firstResponder] != self)
164            view->set_cursor_visible(false);
165      }
166      return YES;
167   }
168   else
169   {
170      return NO;
171   }
172}
173
174
175- (NSString *)expression {
176   return [NSString stringWithUTF8String:downcast<debug_view_disasm *>(view)->expression()];
177}
178
179
180- (void)setExpression:(NSString *)exp {
181   downcast<debug_view_disasm *>(view)->set_expression([exp UTF8String]);
182}
183
184
185- (debug_view_disasm_source const *)source {
186   return downcast<debug_view_disasm_source const *>(view->source());
187}
188
189
190- (offs_t)selectedAddress {
191   return downcast<debug_view_disasm *>(view)->selected_address();
192}
193
194
195- (IBAction)showRightColumn:(id)sender {
196   downcast<debug_view_disasm *>(view)->set_right_column((disasm_right_column) [sender tag]);
197}
198
199
200- (void)insertActionItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index {
201   NSMenuItem *breakItem = [menu insertItemWithTitle:@"Toggle Breakpoint at Cursor"
202                                    action:@selector(debugToggleBreakpoint:)
203                              keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]
204                                   atIndex:index++];
205   [breakItem setKeyEquivalentModifierMask:0];
206
207   NSMenuItem *disableItem = [menu insertItemWithTitle:@"Disable Breakpoint at Cursor"
208                                     action:@selector(debugToggleBreakpointEnable:)
209                                keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]
210                                    atIndex:index++];
211   [disableItem setKeyEquivalentModifierMask:NSShiftKeyMask];
212
213   NSMenu      *runMenu = [[menu itemWithTitle:@"Run"] submenu];
214   NSMenuItem   *runItem;
215   if (runMenu != nil) {
216      runItem = [runMenu addItemWithTitle:@"to Cursor"
217                            action:@selector(debugRunToCursor:)
218                       keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey]];
219   } else {
220      runItem = [menu insertItemWithTitle:@"Run to Cursor"
221                            action:@selector(debugRunToCursor:)
222                       keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey]
223                           atIndex:index++];
224   }
225   [runItem setKeyEquivalentModifierMask:0];
226
227   [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
228
229   NSMenuItem *rawItem = [menu insertItemWithTitle:@"Show Raw Opcodes"
230                                  action:@selector(showRightColumn:)
231                             keyEquivalent:@"r"
232                                 atIndex:index++];
233   [rawItem setTarget:self];
234   [rawItem setTag:DASM_RIGHTCOL_RAW];
235
236   NSMenuItem *encItem = [menu insertItemWithTitle:@"Show Encrypted Opcodes"
237                                  action:@selector(showRightColumn:)
238                             keyEquivalent:@"e"
239                                 atIndex:index++];
240   [encItem setTarget:self];
241   [encItem setTag:DASM_RIGHTCOL_ENCRYPTED];
242
243   NSMenuItem *commentsItem = [menu insertItemWithTitle:@"Show Comments"
244                                      action:@selector(showRightColumn:)
245                                 keyEquivalent:@"n"
246                                     atIndex:index++];
247   [commentsItem setTarget:self];
248   [commentsItem setTag:DASM_RIGHTCOL_COMMENTS];
249
250   if (index < [menu numberOfItems])
251      [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
252}
253
254
255- (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index {
256   for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next())
257   {
258      [[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()]
259                     action:NULL
260                keyEquivalent:@""
261                     atIndex:index++] setTag:view->source_list().indexof(*source)];
262   }
263   if (index < [menu numberOfItems])
264      [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
265}
266
267@end
trunk/src/osd/modules/debugger/osx/disassemblyviewer.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  disassemblyviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "disassemblyviewer.h"
10
11#import "debugconsole.h"
12#import "debugview.h"
13#import "disassemblyview.h"
14
15#include "debugger.h"
16#include "debug/debugcon.h"
17#include "debug/debugcpu.h"
18
19
20@implementation MAMEDisassemblyViewer
21
22- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
23   NSScrollView   *dasmScroll;
24   NSView         *expressionContainer;
25   NSPopUpButton   *actionButton;
26   NSRect         expressionFrame;
27
28   if (!(self = [super initWithMachine:m title:@"Disassembly" console:c]))
29      return nil;
30   NSRect const contentBounds = [[window contentView] bounds];
31   NSFont *const defaultFont = [[MAMEDebugView class] defaultFontForMachine:m];
32
33   // create the expression field
34   expressionField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
35   [expressionField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxXMargin | NSViewMinYMargin)];
36   [expressionField setFont:defaultFont];
37   [expressionField setFocusRingType:NSFocusRingTypeNone];
38   [expressionField setTarget:self];
39   [expressionField setAction:@selector(doExpression:)];
40   [expressionField setDelegate:self];
41   [expressionField sizeToFit];
42
43   // create the subview popup
44   subviewButton = [[NSPopUpButton alloc] initWithFrame:NSOffsetRect(expressionFrame,
45                                                     expressionFrame.size.width,
46                                                     0)];
47   [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)];
48   [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle];
49   [subviewButton setFocusRingType:NSFocusRingTypeNone];
50   [subviewButton setFont:defaultFont];
51   [subviewButton setTarget:self];
52   [subviewButton setAction:@selector(changeSubview:)];
53   [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom];
54   [subviewButton sizeToFit];
55
56   // adjust sizes to make it fit nicely
57   expressionFrame = [expressionField frame];
58   expressionFrame.size.height = MAX(expressionFrame.size.height, [subviewButton frame].size.height);
59   expressionFrame.size.width = (contentBounds.size.width - expressionFrame.size.height) / 2;
60   [expressionField setFrame:expressionFrame];
61   expressionFrame.origin.x = expressionFrame.size.width;
62   expressionFrame.size.width = contentBounds.size.width - expressionFrame.size.height - expressionFrame.origin.x;
63   [subviewButton setFrame:expressionFrame];
64
65   // create a container for the expression field and subview popup
66   expressionFrame = NSMakeRect(expressionFrame.size.height,
67                         contentBounds.size.height - expressionFrame.size.height,
68                         contentBounds.size.width - expressionFrame.size.height,
69                         expressionFrame.size.height);
70   expressionContainer = [[NSView alloc] initWithFrame:expressionFrame];
71   [expressionContainer setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
72   [expressionContainer addSubview:expressionField];
73   [expressionField release];
74   [expressionContainer addSubview:subviewButton];
75   [subviewButton release];
76   [[window contentView] addSubview:expressionContainer];
77   [expressionContainer release];
78
79   // create the disassembly view
80   dasmView = [[MAMEDisassemblyView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine];
81   [dasmView insertSubviewItemsInMenu:[subviewButton menu] atIndex:0];
82   dasmScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,
83                                                0,
84                                                contentBounds.size.width,
85                                                expressionFrame.origin.y)];
86   [dasmScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
87   [dasmScroll setHasHorizontalScroller:YES];
88   [dasmScroll setHasVerticalScroller:YES];
89   [dasmScroll setAutohidesScrollers:YES];
90   [dasmScroll setBorderType:NSNoBorder];
91   [dasmScroll setDocumentView:dasmView];
92   [dasmView release];
93   [[window contentView] addSubview:dasmScroll];
94   [dasmScroll release];
95
96   // create the action popup
97   actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0,
98                                                    expressionFrame.origin.y,
99                                                    expressionFrame.size.height,
100                                                    expressionFrame.size.height)];
101   [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
102   [actionButton setFont:[NSFont systemFontOfSize:[defaultFont pointSize]]];
103   [dasmView insertActionItemsInMenu:[actionButton menu] atIndex:1];
104   [[window contentView] addSubview:actionButton];
105   [actionButton release];
106
107   // set default state
108   [dasmView selectSubviewForDevice:debug_cpu_get_visible_cpu(*machine)];
109   [dasmView setExpression:@"curpc"];
110   [expressionField setStringValue:@"curpc"];
111   [expressionField selectText:self];
112   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]];
113   [window makeFirstResponder:expressionField];
114   [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]];
115
116   // calculate the optimal size for everything
117   NSSize const desired = [NSScrollView frameSizeForContentSize:[dasmView maximumFrameSize]
118                                 hasHorizontalScroller:YES
119                                  hasVerticalScroller:YES
120                                         borderType:[dasmScroll borderType]];
121   [self cascadeWindowWithDesiredSize:desired forView:dasmScroll];
122
123   // don't forget the result
124   return self;
125}
126
127
128- (void)dealloc {
129   [super dealloc];
130}
131
132
133- (id <MAMEDebugViewExpressionSupport>)documentView {
134   return dasmView;
135}
136
137
138- (IBAction)debugNewMemoryWindow:(id)sender {
139   debug_view_disasm_source const *source = [dasmView source];
140   [console debugNewMemoryWindowForSpace:&source->space()
141                           device:&source->device()
142                        expression:nil];
143}
144
145
146- (IBAction)debugNewDisassemblyWindow:(id)sender {
147   debug_view_disasm_source const *source = [dasmView source];
148   [console debugNewDisassemblyWindowForSpace:&source->space()
149                              device:&source->device()
150                           expression:[dasmView expression]];
151}
152
153
154- (BOOL)selectSubviewForDevice:(device_t *)device {
155   BOOL const result = [dasmView selectSubviewForDevice:device];
156   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]];
157   [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]];
158   return result;
159}
160
161
162- (BOOL)selectSubviewForSpace:(address_space *)space {
163   BOOL const result = [dasmView selectSubviewForSpace:space];
164   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]];
165   [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]];
166   return result;
167}
168
169
170- (IBAction)debugToggleBreakpoint:(id)sender {
171   if ([dasmView cursorVisible])
172   {
173      device_t &device = [dasmView source]->device();
174      offs_t const address = [dasmView selectedAddress];
175      device_debug::breakpoint *bp = [[self class] findBreakpointAtAddress:address forDevice:device];
176
177      // if it doesn't exist, add a new one
178      if (bp == NULL)
179      {
180         UINT32 const bpnum = device.debug()->breakpoint_set(address, NULL, NULL);
181         debug_console_printf(*machine, "Breakpoint %X set\n", bpnum);
182      }
183      else
184      {
185         int const bpnum = bp->index();
186         device.debug()->breakpoint_clear(bpnum);
187         debug_console_printf(*machine, "Breakpoint %X cleared\n", (UINT32)bpnum);
188      }
189
190      // fail to do this and the display doesn't update
191      machine->debug_view().update_all();
192      debugger_refresh_display(*machine);
193   }
194}
195
196
197- (IBAction)debugToggleBreakpointEnable:(id)sender {
198   if ([dasmView cursorVisible])
199   {
200      device_t &device = [dasmView source]->device();
201      offs_t const address = [dasmView selectedAddress];
202      device_debug::breakpoint *bp = [[self class] findBreakpointAtAddress:address forDevice:device];
203      if (bp != NULL)
204      {
205         device.debug()->breakpoint_enable(bp->index(), !bp->enabled());
206         debug_console_printf(*machine,
207                         "Breakpoint %X %s\n",
208                         (UINT32)bp->index(),
209                         bp->enabled() ? "enabled" : "disabled");
210         machine->debug_view().update_all();
211         debugger_refresh_display(*machine);
212      }
213   }
214}
215
216
217- (IBAction)debugRunToCursor:(id)sender {
218   if ([dasmView cursorVisible])
219      [dasmView source]->device().debug()->go([dasmView selectedAddress]);
220}
221
222
223- (IBAction)changeSubview:(id)sender {
224   [dasmView selectSubviewAtIndex:[[sender selectedItem] tag]];
225   [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]];
226}
227
228
229- (BOOL)validateMenuItem:(NSMenuItem *)item {
230   SEL const action = [item action];
231   BOOL const inContextMenu = ([item menu] == [dasmView menu]);
232   BOOL const haveCursor = [dasmView cursorVisible];
233
234   device_debug::breakpoint *breakpoint = NULL;
235   if (haveCursor)
236   {
237      breakpoint = [[self class] findBreakpointAtAddress:[dasmView selectedAddress]
238                                     forDevice:[dasmView source]->device()];
239   }
240
241   if (action == @selector(debugToggleBreakpoint:))
242   {
243      if (haveCursor)
244      {
245         if (breakpoint != NULL)
246         {
247            if (inContextMenu)
248               [item setTitle:@"Clear Breakpoint"];
249            else
250               [item setTitle:@"Clear Breakpoint at Cursor"];
251         }
252         else
253         {
254            if (inContextMenu)
255               [item setTitle:@"Set Breakpoint"];
256            else
257               [item setTitle:@"Set Breakpoint at Cursor"];
258         }
259      }
260      else
261      {
262         if (inContextMenu)
263            [item setTitle:@"Toggle Breakpoint"];
264         else
265            [item setTitle:@"Toggle Breakpoint at Cursor"];
266      }
267      return haveCursor;
268   }
269   else if (action == @selector(debugToggleBreakpointEnable:))
270   {
271      if ((breakpoint != NULL) && !breakpoint->enabled())
272      {
273         if (inContextMenu)
274            [item setTitle:@"Enable Breakpoint"];
275         else
276            [item setTitle:@"Enable Breakpoint at Cursor"];
277      }
278      else
279      {
280         if (inContextMenu)
281            [item setTitle:@"Disable Breakpoint"];
282         else
283            [item setTitle:@"Disable Breakpoint at Cursor"];
284      }
285      return breakpoint != NULL;
286   }
287   else
288   {
289      return YES;
290   }
291}
292
293@end
trunk/src/osd/modules/debugger/osx/disassemblyviewer.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  disassemblyviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "disassemblyviewer.h"
10
11#import "debugconsole.h"
12#import "debugview.h"
13#import "disassemblyview.h"
14
15#include "debugger.h"
16#include "debug/debugcon.h"
17#include "debug/debugcpu.h"
18
19
20@implementation MAMEDisassemblyViewer
21
22- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
23   NSScrollView   *dasmScroll;
24   NSView         *expressionContainer;
25   NSPopUpButton   *actionButton;
26   NSRect         expressionFrame;
27
28   if (!(self = [super initWithMachine:m title:@"Disassembly" console:c]))
29      return nil;
30   NSRect const contentBounds = [[window contentView] bounds];
31   NSFont *const defaultFont = [[MAMEDebugView class] defaultFontForMachine:m];
32
33   // create the expression field
34   expressionField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
35   [expressionField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxXMargin | NSViewMinYMargin)];
36   [expressionField setFont:defaultFont];
37   [expressionField setFocusRingType:NSFocusRingTypeNone];
38   [expressionField setTarget:self];
39   [expressionField setAction:@selector(doExpression:)];
40   [expressionField setDelegate:self];
41   [expressionField sizeToFit];
42
43   // create the subview popup
44   subviewButton = [[NSPopUpButton alloc] initWithFrame:NSOffsetRect(expressionFrame,
45                                                     expressionFrame.size.width,
46                                                     0)];
47   [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)];
48   [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle];
49   [subviewButton setFocusRingType:NSFocusRingTypeNone];
50   [subviewButton setFont:defaultFont];
51   [subviewButton setTarget:self];
52   [subviewButton setAction:@selector(changeSubview:)];
53   [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom];
54   [subviewButton sizeToFit];
55
56   // adjust sizes to make it fit nicely
57   expressionFrame = [expressionField frame];
58   expressionFrame.size.height = MAX(expressionFrame.size.height, [subviewButton frame].size.height);
59   expressionFrame.size.width = (contentBounds.size.width - expressionFrame.size.height) / 2;
60   [expressionField setFrame:expressionFrame];
61   expressionFrame.origin.x = expressionFrame.size.width;
62   expressionFrame.size.width = contentBounds.size.width - expressionFrame.size.height - expressionFrame.origin.x;
63   [subviewButton setFrame:expressionFrame];
64
65   // create a container for the expression field and subview popup
66   expressionFrame = NSMakeRect(expressionFrame.size.height,
67                         contentBounds.size.height - expressionFrame.size.height,
68                         contentBounds.size.width - expressionFrame.size.height,
69                         expressionFrame.size.height);
70   expressionContainer = [[NSView alloc] initWithFrame:expressionFrame];
71   [expressionContainer setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
72   [expressionContainer addSubview:expressionField];
73   [expressionField release];
74   [expressionContainer addSubview:subviewButton];
75   [subviewButton release];
76   [[window contentView] addSubview:expressionContainer];
77   [expressionContainer release];
78
79   // create the disassembly view
80   dasmView = [[MAMEDisassemblyView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine];
81   [dasmView insertSubviewItemsInMenu:[subviewButton menu] atIndex:0];
82   dasmScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,
83                                                0,
84                                                contentBounds.size.width,
85                                                expressionFrame.origin.y)];
86   [dasmScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
87   [dasmScroll setHasHorizontalScroller:YES];
88   [dasmScroll setHasVerticalScroller:YES];
89   [dasmScroll setAutohidesScrollers:YES];
90   [dasmScroll setBorderType:NSNoBorder];
91   [dasmScroll setDocumentView:dasmView];
92   [dasmView release];
93   [[window contentView] addSubview:dasmScroll];
94   [dasmScroll release];
95
96   // create the action popup
97   actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0,
98                                                    expressionFrame.origin.y,
99                                                    expressionFrame.size.height,
100                                                    expressionFrame.size.height)];
101   [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
102   [actionButton setFont:[NSFont systemFontOfSize:[defaultFont pointSize]]];
103   [dasmView insertActionItemsInMenu:[actionButton menu] atIndex:1];
104   [[window contentView] addSubview:actionButton];
105   [actionButton release];
106
107   // set default state
108   [dasmView selectSubviewForDevice:debug_cpu_get_visible_cpu(*machine)];
109   [dasmView setExpression:@"curpc"];
110   [expressionField setStringValue:@"curpc"];
111   [expressionField selectText:self];
112   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]];
113   [window makeFirstResponder:expressionField];
114   [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]];
115
116   // calculate the optimal size for everything
117   NSSize const desired = [NSScrollView frameSizeForContentSize:[dasmView maximumFrameSize]
118                                 hasHorizontalScroller:YES
119                                  hasVerticalScroller:YES
120                                         borderType:[dasmScroll borderType]];
121   [self cascadeWindowWithDesiredSize:desired forView:dasmScroll];
122
123   // don't forget the result
124   return self;
125}
126
127
128- (void)dealloc {
129   [super dealloc];
130}
131
132
133- (id <MAMEDebugViewExpressionSupport>)documentView {
134   return dasmView;
135}
136
137
138- (IBAction)debugNewMemoryWindow:(id)sender {
139   debug_view_disasm_source const *source = [dasmView source];
140   [console debugNewMemoryWindowForSpace:&source->space()
141                           device:&source->device()
142                        expression:nil];
143}
144
145
146- (IBAction)debugNewDisassemblyWindow:(id)sender {
147   debug_view_disasm_source const *source = [dasmView source];
148   [console debugNewDisassemblyWindowForSpace:&source->space()
149                              device:&source->device()
150                           expression:[dasmView expression]];
151}
152
153
154- (BOOL)selectSubviewForDevice:(device_t *)device {
155   BOOL const result = [dasmView selectSubviewForDevice:device];
156   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]];
157   [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]];
158   return result;
159}
160
161
162- (BOOL)selectSubviewForSpace:(address_space *)space {
163   BOOL const result = [dasmView selectSubviewForSpace:space];
164   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]];
165   [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]];
166   return result;
167}
168
169
170- (IBAction)debugToggleBreakpoint:(id)sender {
171   if ([dasmView cursorVisible])
172   {
173      device_t &device = [dasmView source]->device();
174      offs_t const address = [dasmView selectedAddress];
175      device_debug::breakpoint *bp = [[self class] findBreakpointAtAddress:address forDevice:device];
176
177      // if it doesn't exist, add a new one
178      if (bp == NULL)
179      {
180         UINT32 const bpnum = device.debug()->breakpoint_set(address, NULL, NULL);
181         debug_console_printf(*machine, "Breakpoint %X set\n", bpnum);
182      }
183      else
184      {
185         int const bpnum = bp->index();
186         device.debug()->breakpoint_clear(bpnum);
187         debug_console_printf(*machine, "Breakpoint %X cleared\n", (UINT32)bpnum);
188      }
189
190      // fail to do this and the display doesn't update
191      machine->debug_view().update_all();
192      debugger_refresh_display(*machine);
193   }
194}
195
196
197- (IBAction)debugToggleBreakpointEnable:(id)sender {
198   if ([dasmView cursorVisible])
199   {
200      device_t &device = [dasmView source]->device();
201      offs_t const address = [dasmView selectedAddress];
202      device_debug::breakpoint *bp = [[self class] findBreakpointAtAddress:address forDevice:device];
203      if (bp != NULL)
204      {
205         device.debug()->breakpoint_enable(bp->index(), !bp->enabled());
206         debug_console_printf(*machine,
207                         "Breakpoint %X %s\n",
208                         (UINT32)bp->index(),
209                         bp->enabled() ? "enabled" : "disabled");
210         machine->debug_view().update_all();
211         debugger_refresh_display(*machine);
212      }
213   }
214}
215
216
217- (IBAction)debugRunToCursor:(id)sender {
218   if ([dasmView cursorVisible])
219      [dasmView source]->device().debug()->go([dasmView selectedAddress]);
220}
221
222
223- (IBAction)changeSubview:(id)sender {
224   [dasmView selectSubviewAtIndex:[[sender selectedItem] tag]];
225   [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]];
226}
227
228
229- (BOOL)validateMenuItem:(NSMenuItem *)item {
230   SEL const action = [item action];
231   BOOL const inContextMenu = ([item menu] == [dasmView menu]);
232   BOOL const haveCursor = [dasmView cursorVisible];
233
234   device_debug::breakpoint *breakpoint = NULL;
235   if (haveCursor)
236   {
237      breakpoint = [[self class] findBreakpointAtAddress:[dasmView selectedAddress]
238                                     forDevice:[dasmView source]->device()];
239   }
240
241   if (action == @selector(debugToggleBreakpoint:))
242   {
243      if (haveCursor)
244      {
245         if (breakpoint != NULL)
246         {
247            if (inContextMenu)
248               [item setTitle:@"Clear Breakpoint"];
249            else
250               [item setTitle:@"Clear Breakpoint at Cursor"];
251         }
252         else
253         {
254            if (inContextMenu)
255               [item setTitle:@"Set Breakpoint"];
256            else
257               [item setTitle:@"Set Breakpoint at Cursor"];
258         }
259      }
260      else
261      {
262         if (inContextMenu)
263            [item setTitle:@"Toggle Breakpoint"];
264         else
265            [item setTitle:@"Toggle Breakpoint at Cursor"];
266      }
267      return haveCursor;
268   }
269   else if (action == @selector(debugToggleBreakpointEnable:))
270   {
271      if ((breakpoint != NULL) && !breakpoint->enabled())
272      {
273         if (inContextMenu)
274            [item setTitle:@"Enable Breakpoint"];
275         else
276            [item setTitle:@"Enable Breakpoint at Cursor"];
277      }
278      else
279      {
280         if (inContextMenu)
281            [item setTitle:@"Disable Breakpoint"];
282         else
283            [item setTitle:@"Disable Breakpoint at Cursor"];
284      }
285      return breakpoint != NULL;
286   }
287   else
288   {
289      return YES;
290   }
291}
292
293@end
trunk/src/osd/modules/debugger/osx/errorlogview.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  errorlogview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "errorlogview.h"
10
11#include "debug/debugvw.h"
12
13
14@implementation MAMEErrorLogView
15
16- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
17   if (!(self = [super initWithFrame:f type:DVT_LOG machine:m wholeLineScroll:NO]))
18      return nil;
19   return self;
20}
21
22
23- (void)dealloc {
24   [super dealloc];
25}
26
27@end
trunk/src/osd/modules/debugger/osx/errorlogview.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  errorlogview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "errorlogview.h"
10
11#include "debug/debugvw.h"
12
13
14@implementation MAMEErrorLogView
15
16- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
17   if (!(self = [super initWithFrame:f type:DVT_LOG machine:m wholeLineScroll:NO]))
18      return nil;
19   return self;
20}
21
22
23- (void)dealloc {
24   [super dealloc];
25}
26
27@end
trunk/src/osd/modules/debugger/osx/errorlogviewer.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  errorlogviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "errorlogviewer.h"
10
11#import "errorlogview.h"
12
13
14@implementation MAMEErrorLogViewer
15
16- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
17   NSScrollView   *logScroll;
18   NSString      *title;
19
20   title = [NSString stringWithFormat:@"Error Log: %@ [%@]",
21                              [NSString stringWithUTF8String:m.system().description],
22                              [NSString stringWithUTF8String:m.system().name]];
23   if (!(self = [super initWithMachine:m title:title console:c]))
24      return nil;
25
26   // create the error log view
27   logView = [[MAMEErrorLogView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine];
28   logScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
29   [logScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
30   [logScroll setHasHorizontalScroller:YES];
31   [logScroll setHasVerticalScroller:YES];
32   [logScroll setAutohidesScrollers:YES];
33   [logScroll setBorderType:NSNoBorder];
34   [logScroll setDocumentView:logView];
35   [logView release];
36   [window setContentView:logScroll];
37   [logScroll release];
38
39   // calculate the optimal size for everything
40   {
41      NSSize   desired = [NSScrollView frameSizeForContentSize:[logView maximumFrameSize]
42                                hasHorizontalScroller:YES
43                                 hasVerticalScroller:YES
44                                        borderType:[logScroll borderType]];
45
46      // this thing starts with no content, so its prefered height may be very small
47      desired.height = MAX(desired.height, 240);
48      [self cascadeWindowWithDesiredSize:desired forView:logScroll];
49   }
50
51   // don't forget the result
52   return self;
53}
54
55
56- (void)dealloc {
57   [super dealloc];
58}
59
60@end
trunk/src/osd/modules/debugger/osx/errorlogviewer.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  errorlogviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "errorlogviewer.h"
10
11#import "errorlogview.h"
12
13
14@implementation MAMEErrorLogViewer
15
16- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
17   NSScrollView   *logScroll;
18   NSString      *title;
19
20   title = [NSString stringWithFormat:@"Error Log: %@ [%@]",
21                              [NSString stringWithUTF8String:m.system().description],
22                              [NSString stringWithUTF8String:m.system().name]];
23   if (!(self = [super initWithMachine:m title:title console:c]))
24      return nil;
25
26   // create the error log view
27   logView = [[MAMEErrorLogView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine];
28   logScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
29   [logScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
30   [logScroll setHasHorizontalScroller:YES];
31   [logScroll setHasVerticalScroller:YES];
32   [logScroll setAutohidesScrollers:YES];
33   [logScroll setBorderType:NSNoBorder];
34   [logScroll setDocumentView:logView];
35   [logView release];
36   [window setContentView:logScroll];
37   [logScroll release];
38
39   // calculate the optimal size for everything
40   {
41      NSSize   desired = [NSScrollView frameSizeForContentSize:[logView maximumFrameSize]
42                                hasHorizontalScroller:YES
43                                 hasVerticalScroller:YES
44                                        borderType:[logScroll borderType]];
45
46      // this thing starts with no content, so its prefered height may be very small
47      desired.height = MAX(desired.height, 240);
48      [self cascadeWindowWithDesiredSize:desired forView:logScroll];
49   }
50
51   // don't forget the result
52   return self;
53}
54
55
56- (void)dealloc {
57   [super dealloc];
58}
59
60@end
trunk/src/osd/modules/debugger/osx/memoryview.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  memoryview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "memoryview.h"
10
11#include "debug/debugcpu.h"
12#include "debug/debugvw.h"
13
14
15@implementation MAMEMemoryView
16
17- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
18   if (!(self = [super initWithFrame:f type:DVT_MEMORY machine:m wholeLineScroll:NO]))
19      return nil;
20   return self;
21}
22
23
24- (void)dealloc {
25   [super dealloc];
26}
27
28
29- (BOOL)validateMenuItem:(NSMenuItem *)item {
30   SEL               action = [item action];
31   NSInteger         tag = [item tag];
32   debug_view_memory   *memview = downcast<debug_view_memory *>(view);
33
34   if (action == @selector(showChunkSize:))
35   {
36      [item setState:((tag == memview->bytes_per_chunk()) ? NSOnState : NSOffState)];
37      return YES;
38   }
39   else if (action == @selector(showPhysicalAddresses:))
40   {
41      [item setState:((tag == memview->physical()) ? NSOnState : NSOffState)];
42      return YES;
43   }
44   else if (action == @selector(showReverseView:))
45   {
46      [item setState:((tag == memview->reverse()) ? NSOnState : NSOffState)];
47      return YES;
48   }
49   else if (action == @selector(showReverseViewToggle:))
50   {
51      [item setState:(memview->reverse() ? NSOnState : NSOffState)];
52      return YES;
53   }
54   else if (action == @selector(changeBytesPerLine:))
55   {
56      return (memview->chunks_per_row() + [item tag]) > 0;
57   }
58   else
59   {
60      return [super validateMenuItem:item];
61   }
62}
63
64
65- (NSSize)maximumFrameSize {
66   debug_view_xy         max(0, 0);
67   debug_view_source const   *source = view->source();
68   for (debug_view_source const *source = view->first_source(); source != NULL; source = source->next())
69   {
70      view->set_source(*source);
71      debug_view_xy const current = view->total_size();
72      max.x = MAX(max.x, current.x);
73      max.y = MAX(max.y, current.y);
74   }
75   view->set_source(*source);
76   return NSMakeSize(ceil((max.x * fontWidth) + (2 * [textContainer lineFragmentPadding])),
77                 ceil(max.y * fontHeight));
78}
79
80
81- (void)addContextMenuItemsToMenu:(NSMenu *)menu {
82   [super addContextMenuItemsToMenu:menu];
83   if ([menu numberOfItems] > 0)
84      [menu addItem:[NSMenuItem separatorItem]];
85   [self insertActionItemsInMenu:menu atIndex:[menu numberOfItems]];
86}
87
88
89- (NSString *)selectedSubviewName {
90   debug_view_source const *source = view->source();
91   if (source != NULL)
92      return [NSString stringWithUTF8String:source->name()];
93   else
94      return @"";
95}
96
97
98- (int)selectedSubviewIndex {
99   debug_view_source const *source = view->source();
100   if (source != NULL)
101      return view->source_list().indexof(*source);
102   else
103      return -1;
104}
105
106
107- (void)selectSubviewAtIndex:(int)index {
108   int const   selected = view->source_list().indexof(*view->source());
109   if (selected != index) {
110      view->set_source(*view->source_list().find(index));
111      if ([[self window] firstResponder] != self)
112         view->set_cursor_visible(false);
113   }
114}
115
116
117- (BOOL)selectSubviewForDevice:(device_t *)device {
118   debug_view_source const *const source = view->source_for_device(device);
119   if (source != NULL)
120   {
121      if (view->source() != source)
122      {
123         view->set_source(*source);
124         if ([[self window] firstResponder] != self)
125            view->set_cursor_visible(false);
126      }
127      return YES;
128   }
129   else
130   {
131      return NO;
132   }
133}
134
135
136- (BOOL)selectSubviewForSpace:(address_space *)space {
137   if (space == NULL) return NO;
138   debug_view_memory_source const *source = downcast<debug_view_memory_source const *>(view->first_source());
139   while ((source != NULL) && (source->space() != space))
140      source = downcast<debug_view_memory_source *>(source->next());
141   if (source != NULL)
142   {
143      if (view->source() != source)
144      {
145         view->set_source(*source);
146         if ([[self window] firstResponder] != self)
147            view->set_cursor_visible(false);
148      }
149      return YES;
150   }
151   else
152   {
153      return NO;
154   }
155}
156
157
158- (NSString *)expression {
159   return [NSString stringWithUTF8String:downcast<debug_view_memory *>(view)->expression()];
160}
161
162
163- (void)setExpression:(NSString *)exp {
164   downcast<debug_view_memory *>(view)->set_expression([exp UTF8String]);
165}
166
167
168- (debug_view_memory_source const *)source {
169   return downcast<debug_view_memory_source const *>(view->source());
170}
171
172
173- (IBAction)showChunkSize:(id)sender {
174   downcast<debug_view_memory *>(view)->set_bytes_per_chunk([sender tag]);
175}
176
177
178- (IBAction)showPhysicalAddresses:(id)sender {
179   downcast<debug_view_memory *>(view)->set_physical([sender tag]);
180}
181
182
183- (IBAction)showReverseView:(id)sender {
184   downcast<debug_view_memory *>(view)->set_reverse([sender tag]);
185}
186
187
188- (IBAction)showReverseViewToggle:(id)sender {
189   downcast<debug_view_memory *>(view)->set_reverse(!downcast<debug_view_memory *>(view)->reverse());
190}
191
192
193- (IBAction)changeBytesPerLine:(id)sender {
194   debug_view_memory *const memView = downcast<debug_view_memory *>(view);
195   memView->set_chunks_per_row(memView->chunks_per_row() + [sender tag]);
196}
197
198
199- (void)insertActionItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index {
200   NSInteger tag;
201   for (tag = 1; tag <= 8; tag <<= 1) {
202      NSString   *title = [NSString stringWithFormat:@"%ld-byte Chunks", (long)tag];
203      NSMenuItem   *chunkItem = [menu insertItemWithTitle:title
204                                       action:@selector(showChunkSize:)
205                                  keyEquivalent:[NSString stringWithFormat:@"%ld", (long)tag]
206                                       atIndex:index++];
207      [chunkItem setTarget:self];
208      [chunkItem setTag:tag];
209   }
210
211   [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
212
213   NSMenuItem *logicalItem = [menu insertItemWithTitle:@"Logical Addresses"
214                                     action:@selector(showPhysicalAddresses:)
215                                keyEquivalent:@"v"
216                                    atIndex:index++];
217   [logicalItem setTarget:self];
218   [logicalItem setTag:FALSE];
219
220   NSMenuItem *physicalItem = [menu insertItemWithTitle:@"Physical Addresses"
221                                      action:@selector(showPhysicalAddresses:)
222                                 keyEquivalent:@"y"
223                                     atIndex:index++];
224   [physicalItem setTarget:self];
225   [physicalItem setTag:TRUE];
226
227   [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
228
229   NSMenuItem *reverseItem = [menu insertItemWithTitle:@"Reverse View"
230                                     action:@selector(showReverseViewToggle:)
231                                keyEquivalent:@"r"
232                                    atIndex:index++];
233   [reverseItem setTarget:self];
234
235   [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
236
237   NSMenuItem *increaseItem = [menu insertItemWithTitle:@"Increase Bytes Per Line"
238                                      action:@selector(changeBytesPerLine:)
239                                 keyEquivalent:@"p"
240                                     atIndex:index++];
241   [increaseItem setTarget:self];
242   [increaseItem setTag:1];
243
244   NSMenuItem *decreaseItem = [menu insertItemWithTitle:@"Decrease Bytes Per Line"
245                                      action:@selector(changeBytesPerLine:)
246                                 keyEquivalent:@"o"
247                                     atIndex:index++];
248   [decreaseItem setTarget:self];
249   [decreaseItem setTag:-1];
250
251   if (index < [menu numberOfItems])
252      [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
253}
254
255
256- (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index {
257   for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next())
258   {
259      [[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()]
260                     action:NULL
261                keyEquivalent:@""
262                     atIndex:index++] setTag:view->source_list().indexof(*source)];
263   }
264   if (index < [menu numberOfItems])
265      [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
266}
267
268@end
trunk/src/osd/modules/debugger/osx/memoryview.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  memoryview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "memoryview.h"
10
11#include "debug/debugcpu.h"
12#include "debug/debugvw.h"
13
14
15@implementation MAMEMemoryView
16
17- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
18   if (!(self = [super initWithFrame:f type:DVT_MEMORY machine:m wholeLineScroll:NO]))
19      return nil;
20   return self;
21}
22
23
24- (void)dealloc {
25   [super dealloc];
26}
27
28
29- (BOOL)validateMenuItem:(NSMenuItem *)item {
30   SEL               action = [item action];
31   NSInteger         tag = [item tag];
32   debug_view_memory   *memview = downcast<debug_view_memory *>(view);
33
34   if (action == @selector(showChunkSize:))
35   {
36      [item setState:((tag == memview->bytes_per_chunk()) ? NSOnState : NSOffState)];
37      return YES;
38   }
39   else if (action == @selector(showPhysicalAddresses:))
40   {
41      [item setState:((tag == memview->physical()) ? NSOnState : NSOffState)];
42      return YES;
43   }
44   else if (action == @selector(showReverseView:))
45   {
46      [item setState:((tag == memview->reverse()) ? NSOnState : NSOffState)];
47      return YES;
48   }
49   else if (action == @selector(showReverseViewToggle:))
50   {
51      [item setState:(memview->reverse() ? NSOnState : NSOffState)];
52      return YES;
53   }
54   else if (action == @selector(changeBytesPerLine:))
55   {
56      return (memview->chunks_per_row() + [item tag]) > 0;
57   }
58   else
59   {
60      return [super validateMenuItem:item];
61   }
62}
63
64
65- (NSSize)maximumFrameSize {
66   debug_view_xy         max(0, 0);
67   debug_view_source const   *source = view->source();
68   for (debug_view_source const *source = view->first_source(); source != NULL; source = source->next())
69   {
70      view->set_source(*source);
71      debug_view_xy const current = view->total_size();
72      max.x = MAX(max.x, current.x);
73      max.y = MAX(max.y, current.y);
74   }
75   view->set_source(*source);
76   return NSMakeSize(ceil((max.x * fontWidth) + (2 * [textContainer lineFragmentPadding])),
77                 ceil(max.y * fontHeight));
78}
79
80
81- (void)addContextMenuItemsToMenu:(NSMenu *)menu {
82   [super addContextMenuItemsToMenu:menu];
83   if ([menu numberOfItems] > 0)
84      [menu addItem:[NSMenuItem separatorItem]];
85   [self insertActionItemsInMenu:menu atIndex:[menu numberOfItems]];
86}
87
88
89- (NSString *)selectedSubviewName {
90   debug_view_source const *source = view->source();
91   if (source != NULL)
92      return [NSString stringWithUTF8String:source->name()];
93   else
94      return @"";
95}
96
97
98- (int)selectedSubviewIndex {
99   debug_view_source const *source = view->source();
100   if (source != NULL)
101      return view->source_list().indexof(*source);
102   else
103      return -1;
104}
105
106
107- (void)selectSubviewAtIndex:(int)index {
108   int const   selected = view->source_list().indexof(*view->source());
109   if (selected != index) {
110      view->set_source(*view->source_list().find(index));
111      if ([[self window] firstResponder] != self)
112         view->set_cursor_visible(false);
113   }
114}
115
116
117- (BOOL)selectSubviewForDevice:(device_t *)device {
118   debug_view_source const *const source = view->source_for_device(device);
119   if (source != NULL)
120   {
121      if (view->source() != source)
122      {
123         view->set_source(*source);
124         if ([[self window] firstResponder] != self)
125            view->set_cursor_visible(false);
126      }
127      return YES;
128   }
129   else
130   {
131      return NO;
132   }
133}
134
135
136- (BOOL)selectSubviewForSpace:(address_space *)space {
137   if (space == NULL) return NO;
138   debug_view_memory_source const *source = downcast<debug_view_memory_source const *>(view->first_source());
139   while ((source != NULL) && (source->space() != space))
140      source = downcast<debug_view_memory_source *>(source->next());
141   if (source != NULL)
142   {
143      if (view->source() != source)
144      {
145         view->set_source(*source);
146         if ([[self window] firstResponder] != self)
147            view->set_cursor_visible(false);
148      }
149      return YES;
150   }
151   else
152   {
153      return NO;
154   }
155}
156
157
158- (NSString *)expression {
159   return [NSString stringWithUTF8String:downcast<debug_view_memory *>(view)->expression()];
160}
161
162
163- (void)setExpression:(NSString *)exp {
164   downcast<debug_view_memory *>(view)->set_expression([exp UTF8String]);
165}
166
167
168- (debug_view_memory_source const *)source {
169   return downcast<debug_view_memory_source const *>(view->source());
170}
171
172
173- (IBAction)showChunkSize:(id)sender {
174   downcast<debug_view_memory *>(view)->set_bytes_per_chunk([sender tag]);
175}
176
177
178- (IBAction)showPhysicalAddresses:(id)sender {
179   downcast<debug_view_memory *>(view)->set_physical([sender tag]);
180}
181
182
183- (IBAction)showReverseView:(id)sender {
184   downcast<debug_view_memory *>(view)->set_reverse([sender tag]);
185}
186
187
188- (IBAction)showReverseViewToggle:(id)sender {
189   downcast<debug_view_memory *>(view)->set_reverse(!downcast<debug_view_memory *>(view)->reverse());
190}
191
192
193- (IBAction)changeBytesPerLine:(id)sender {
194   debug_view_memory *const memView = downcast<debug_view_memory *>(view);
195   memView->set_chunks_per_row(memView->chunks_per_row() + [sender tag]);
196}
197
198
199- (void)insertActionItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index {
200   NSInteger tag;
201   for (tag = 1; tag <= 8; tag <<= 1) {
202      NSString   *title = [NSString stringWithFormat:@"%ld-byte Chunks", (long)tag];
203      NSMenuItem   *chunkItem = [menu insertItemWithTitle:title
204                                       action:@selector(showChunkSize:)
205                                  keyEquivalent:[NSString stringWithFormat:@"%ld", (long)tag]
206                                       atIndex:index++];
207      [chunkItem setTarget:self];
208      [chunkItem setTag:tag];
209   }
210
211   [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
212
213   NSMenuItem *logicalItem = [menu insertItemWithTitle:@"Logical Addresses"
214                                     action:@selector(showPhysicalAddresses:)
215                                keyEquivalent:@"v"
216                                    atIndex:index++];
217   [logicalItem setTarget:self];
218   [logicalItem setTag:FALSE];
219
220   NSMenuItem *physicalItem = [menu insertItemWithTitle:@"Physical Addresses"
221                                      action:@selector(showPhysicalAddresses:)
222                                 keyEquivalent:@"y"
223                                     atIndex:index++];
224   [physicalItem setTarget:self];
225   [physicalItem setTag:TRUE];
226
227   [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
228
229   NSMenuItem *reverseItem = [menu insertItemWithTitle:@"Reverse View"
230                                     action:@selector(showReverseViewToggle:)
231                                keyEquivalent:@"r"
232                                    atIndex:index++];
233   [reverseItem setTarget:self];
234
235   [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
236
237   NSMenuItem *increaseItem = [menu insertItemWithTitle:@"Increase Bytes Per Line"
238                                      action:@selector(changeBytesPerLine:)
239                                 keyEquivalent:@"p"
240                                     atIndex:index++];
241   [increaseItem setTarget:self];
242   [increaseItem setTag:1];
243
244   NSMenuItem *decreaseItem = [menu insertItemWithTitle:@"Decrease Bytes Per Line"
245                                      action:@selector(changeBytesPerLine:)
246                                 keyEquivalent:@"o"
247                                     atIndex:index++];
248   [decreaseItem setTarget:self];
249   [decreaseItem setTag:-1];
250
251   if (index < [menu numberOfItems])
252      [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
253}
254
255
256- (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index {
257   for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next())
258   {
259      [[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()]
260                     action:NULL
261                keyEquivalent:@""
262                     atIndex:index++] setTag:view->source_list().indexof(*source)];
263   }
264   if (index < [menu numberOfItems])
265      [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
266}
267
268@end
trunk/src/osd/modules/debugger/osx/memoryviewer.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  memoryviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "memoryviewer.h"
10
11#import "debugconsole.h"
12#import "debugview.h"
13#import "memoryview.h"
14
15#include "debug/debugcpu.h"
16#include "debug/dvmemory.h"
17
18
19@implementation MAMEMemoryViewer
20
21- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
22   NSScrollView   *memoryScroll;
23   NSView         *expressionContainer;
24   NSPopUpButton   *actionButton;
25   NSRect         expressionFrame;
26
27   if (!(self = [super initWithMachine:m title:@"Memory" console:c]))
28      return nil;
29   NSRect const contentBounds = [[window contentView] bounds];
30   NSFont *const defaultFont = [[MAMEDebugView class] defaultFontForMachine:m];
31
32   // create the expression field
33   expressionField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
34   [expressionField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxXMargin | NSViewMinYMargin)];
35   [expressionField setFont:defaultFont];
36   [expressionField setFocusRingType:NSFocusRingTypeNone];
37   [expressionField setTarget:self];
38   [expressionField setAction:@selector(doExpression:)];
39   [expressionField setDelegate:self];
40   [expressionField sizeToFit];
41
42   // create the subview popup
43   subviewButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
44   [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)];
45   [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle];
46   [subviewButton setFocusRingType:NSFocusRingTypeNone];
47   [subviewButton setFont:defaultFont];
48   [subviewButton setTarget:self];
49   [subviewButton setAction:@selector(changeSubview:)];
50   [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom];
51   [subviewButton sizeToFit];
52
53   // adjust sizes to make it fit nicely
54   expressionFrame = [expressionField frame];
55   expressionFrame.size.height = MAX(expressionFrame.size.height, [subviewButton frame].size.height);
56   expressionFrame.size.width = (contentBounds.size.width - expressionFrame.size.height) / 2;
57   [expressionField setFrame:expressionFrame];
58   expressionFrame.origin.x = expressionFrame.size.width;
59   expressionFrame.size.width = contentBounds.size.width - expressionFrame.size.height - expressionFrame.origin.x;
60   [subviewButton setFrame:expressionFrame];
61
62   // create a container for the expression field and subview popup
63   expressionFrame = NSMakeRect(expressionFrame.size.height,
64                         contentBounds.size.height - expressionFrame.size.height,
65                         contentBounds.size.width - expressionFrame.size.height,
66                         expressionFrame.size.height);
67   expressionContainer = [[NSView alloc] initWithFrame:expressionFrame];
68   [expressionContainer setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
69   [expressionContainer addSubview:expressionField];
70   [expressionField release];
71   [expressionContainer addSubview:subviewButton];
72   [subviewButton release];
73   [[window contentView] addSubview:expressionContainer];
74   [expressionContainer release];
75
76   // create the memory view
77   memoryView = [[MAMEMemoryView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)
78                                    machine:*machine];
79   [memoryView insertSubviewItemsInMenu:[subviewButton menu] atIndex:0];
80   memoryScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,
81                                                  0,
82                                                  contentBounds.size.width,
83                                                  expressionFrame.origin.y)];
84   [memoryScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
85   [memoryScroll setHasHorizontalScroller:YES];
86   [memoryScroll setHasVerticalScroller:YES];
87   [memoryScroll setAutohidesScrollers:YES];
88   [memoryScroll setBorderType:NSNoBorder];
89   [memoryScroll setDocumentView:memoryView];
90   [memoryView release];
91   [[window contentView] addSubview:memoryScroll];
92   [memoryScroll release];
93
94   // create the action popup
95   actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0,
96                                                    expressionFrame.origin.y,
97                                                    expressionFrame.size.height,
98                                                    expressionFrame.size.height)];
99   [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
100   [actionButton setFont:[NSFont systemFontOfSize:[defaultFont pointSize]]];
101   [memoryView insertActionItemsInMenu:[actionButton menu] atIndex:1];
102   [[window contentView] addSubview:actionButton];
103   [actionButton release];
104
105   // set default state
106   [memoryView selectSubviewForDevice:debug_cpu_get_visible_cpu(*machine)];
107   [memoryView setExpression:@"0"];
108   [expressionField setStringValue:@"0"];
109   [expressionField selectText:self];
110   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]];
111   [window makeFirstResponder:expressionField];
112   [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]];
113
114   // calculate the optimal size for everything
115   NSSize const desired = [NSScrollView frameSizeForContentSize:[memoryView maximumFrameSize]
116                                 hasHorizontalScroller:YES
117                                  hasVerticalScroller:YES
118                                         borderType:[memoryScroll borderType]];
119   [self cascadeWindowWithDesiredSize:desired forView:memoryScroll];
120
121   // don't forget the result
122   return self;
123}
124
125
126- (void)dealloc {
127   [super dealloc];
128}
129
130
131- (id <MAMEDebugViewExpressionSupport>)documentView {
132   return memoryView;
133}
134
135
136- (IBAction)debugNewMemoryWindow:(id)sender {
137   debug_view_memory_source const *source = [memoryView source];
138   [console debugNewMemoryWindowForSpace:source->space()
139                           device:source->device()
140                        expression:[memoryView expression]];
141}
142
143
144- (IBAction)debugNewDisassemblyWindow:(id)sender {
145   debug_view_memory_source const *source = [memoryView source];
146   [console debugNewDisassemblyWindowForSpace:source->space()
147                              device:source->device()
148                           expression:[memoryView expression]];
149}
150
151
152- (BOOL)selectSubviewForDevice:(device_t *)device {
153   BOOL const result = [memoryView selectSubviewForDevice:device];
154   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]];
155   [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]];
156   return result;
157}
158
159
160- (BOOL)selectSubviewForSpace:(address_space *)space {
161   BOOL const result = [memoryView selectSubviewForSpace:space];
162   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]];
163   [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]];
164   return result;
165}
166
167
168- (IBAction)changeSubview:(id)sender {
169   [memoryView selectSubviewAtIndex:[[sender selectedItem] tag]];
170   [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]];
171}
172
173@end
trunk/src/osd/modules/debugger/osx/memoryviewer.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  memoryviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "memoryviewer.h"
10
11#import "debugconsole.h"
12#import "debugview.h"
13#import "memoryview.h"
14
15#include "debug/debugcpu.h"
16#include "debug/dvmemory.h"
17
18
19@implementation MAMEMemoryViewer
20
21- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
22   NSScrollView   *memoryScroll;
23   NSView         *expressionContainer;
24   NSPopUpButton   *actionButton;
25   NSRect         expressionFrame;
26
27   if (!(self = [super initWithMachine:m title:@"Memory" console:c]))
28      return nil;
29   NSRect const contentBounds = [[window contentView] bounds];
30   NSFont *const defaultFont = [[MAMEDebugView class] defaultFontForMachine:m];
31
32   // create the expression field
33   expressionField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
34   [expressionField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxXMargin | NSViewMinYMargin)];
35   [expressionField setFont:defaultFont];
36   [expressionField setFocusRingType:NSFocusRingTypeNone];
37   [expressionField setTarget:self];
38   [expressionField setAction:@selector(doExpression:)];
39   [expressionField setDelegate:self];
40   [expressionField sizeToFit];
41
42   // create the subview popup
43   subviewButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
44   [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)];
45   [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle];
46   [subviewButton setFocusRingType:NSFocusRingTypeNone];
47   [subviewButton setFont:defaultFont];
48   [subviewButton setTarget:self];
49   [subviewButton setAction:@selector(changeSubview:)];
50   [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom];
51   [subviewButton sizeToFit];
52
53   // adjust sizes to make it fit nicely
54   expressionFrame = [expressionField frame];
55   expressionFrame.size.height = MAX(expressionFrame.size.height, [subviewButton frame].size.height);
56   expressionFrame.size.width = (contentBounds.size.width - expressionFrame.size.height) / 2;
57   [expressionField setFrame:expressionFrame];
58   expressionFrame.origin.x = expressionFrame.size.width;
59   expressionFrame.size.width = contentBounds.size.width - expressionFrame.size.height - expressionFrame.origin.x;
60   [subviewButton setFrame:expressionFrame];
61
62   // create a container for the expression field and subview popup
63   expressionFrame = NSMakeRect(expressionFrame.size.height,
64                         contentBounds.size.height - expressionFrame.size.height,
65                         contentBounds.size.width - expressionFrame.size.height,
66                         expressionFrame.size.height);
67   expressionContainer = [[NSView alloc] initWithFrame:expressionFrame];
68   [expressionContainer setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
69   [expressionContainer addSubview:expressionField];
70   [expressionField release];
71   [expressionContainer addSubview:subviewButton];
72   [subviewButton release];
73   [[window contentView] addSubview:expressionContainer];
74   [expressionContainer release];
75
76   // create the memory view
77   memoryView = [[MAMEMemoryView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)
78                                    machine:*machine];
79   [memoryView insertSubviewItemsInMenu:[subviewButton menu] atIndex:0];
80   memoryScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,
81                                                  0,
82                                                  contentBounds.size.width,
83                                                  expressionFrame.origin.y)];
84   [memoryScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
85   [memoryScroll setHasHorizontalScroller:YES];
86   [memoryScroll setHasVerticalScroller:YES];
87   [memoryScroll setAutohidesScrollers:YES];
88   [memoryScroll setBorderType:NSNoBorder];
89   [memoryScroll setDocumentView:memoryView];
90   [memoryView release];
91   [[window contentView] addSubview:memoryScroll];
92   [memoryScroll release];
93
94   // create the action popup
95   actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0,
96                                                    expressionFrame.origin.y,
97                                                    expressionFrame.size.height,
98                                                    expressionFrame.size.height)];
99   [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
100   [actionButton setFont:[NSFont systemFontOfSize:[defaultFont pointSize]]];
101   [memoryView insertActionItemsInMenu:[actionButton menu] atIndex:1];
102   [[window contentView] addSubview:actionButton];
103   [actionButton release];
104
105   // set default state
106   [memoryView selectSubviewForDevice:debug_cpu_get_visible_cpu(*machine)];
107   [memoryView setExpression:@"0"];
108   [expressionField setStringValue:@"0"];
109   [expressionField selectText:self];
110   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]];
111   [window makeFirstResponder:expressionField];
112   [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]];
113
114   // calculate the optimal size for everything
115   NSSize const desired = [NSScrollView frameSizeForContentSize:[memoryView maximumFrameSize]
116                                 hasHorizontalScroller:YES
117                                  hasVerticalScroller:YES
118                                         borderType:[memoryScroll borderType]];
119   [self cascadeWindowWithDesiredSize:desired forView:memoryScroll];
120
121   // don't forget the result
122   return self;
123}
124
125
126- (void)dealloc {
127   [super dealloc];
128}
129
130
131- (id <MAMEDebugViewExpressionSupport>)documentView {
132   return memoryView;
133}
134
135
136- (IBAction)debugNewMemoryWindow:(id)sender {
137   debug_view_memory_source const *source = [memoryView source];
138   [console debugNewMemoryWindowForSpace:source->space()
139                           device:source->device()
140                        expression:[memoryView expression]];
141}
142
143
144- (IBAction)debugNewDisassemblyWindow:(id)sender {
145   debug_view_memory_source const *source = [memoryView source];
146   [console debugNewDisassemblyWindowForSpace:source->space()
147                              device:source->device()
148                           expression:[memoryView expression]];
149}
150
151
152- (BOOL)selectSubviewForDevice:(device_t *)device {
153   BOOL const result = [memoryView selectSubviewForDevice:device];
154   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]];
155   [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]];
156   return result;
157}
158
159
160- (BOOL)selectSubviewForSpace:(address_space *)space {
161   BOOL const result = [memoryView selectSubviewForSpace:space];
162   [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]];
163   [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]];
164   return result;
165}
166
167
168- (IBAction)changeSubview:(id)sender {
169   [memoryView selectSubviewAtIndex:[[sender selectedItem] tag]];
170   [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]];
171}
172
173@end
trunk/src/osd/modules/debugger/osx/pointsviewer.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  pointsviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "pointsviewer.h"
10
11#import "breakpointsview.h"
12#import "watchpointsview.h"
13
14
15@implementation MAMEPointsViewer
16
17- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
18   MAMEDebugView   *breakView, *watchView;
19   NSScrollView   *breakScroll, *watchScroll;
20   NSTabViewItem   *breakTab, *watchTab;
21   NSPopUpButton   *actionButton, *subviewButton;
22   NSRect         subviewFrame;
23
24   if (!(self = [super initWithMachine:m title:@"(Break|Watch)points" console:c]))
25      return nil;
26   NSRect const contentBounds = [[window contentView] bounds];
27   NSFont *const defaultFont = [[MAMEDebugView class] defaultFontForMachine:m];
28
29   // create the subview popup
30   subviewButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
31   [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
32   [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle];
33   [subviewButton setFocusRingType:NSFocusRingTypeNone];
34   [subviewButton setFont:defaultFont];
35   [subviewButton setTarget:self];
36   [subviewButton setAction:@selector(changeSubview:)];
37   [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom];
38   [[[subviewButton menu] addItemWithTitle:@"All Breakpoints"
39                            action:NULL
40                       keyEquivalent:@""] setTag:0];
41   [[[subviewButton menu] addItemWithTitle:@"All Watchpoints"
42                            action:NULL
43                       keyEquivalent:@""] setTag:1];
44   [subviewButton sizeToFit];
45   subviewFrame = [subviewButton frame];
46   subviewFrame.origin.x = subviewFrame.size.height;
47   subviewFrame.origin.y = contentBounds.size.height - subviewFrame.size.height;
48   subviewFrame.size.width = contentBounds.size.width - subviewFrame.size.height;
49   [subviewButton setFrame:subviewFrame];
50   [[window contentView] addSubview:subviewButton];
51   [subviewButton release];
52
53   // create the action popup
54   actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0,
55                                                    subviewFrame.origin.y,
56                                                    subviewFrame.size.height,
57                                                    subviewFrame.size.height)];
58   [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
59   [actionButton setFont:[NSFont systemFontOfSize:[defaultFont pointSize]]];
60   [[window contentView] addSubview:actionButton];
61   [actionButton release];
62
63   // create the breakpoints view
64   breakView = [[MAMEBreakpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)
65                                       machine:*machine];
66   breakScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,
67                                                 0,
68                                                 contentBounds.size.width,
69                                                 contentBounds.size.height - subviewFrame.size.height)];
70   [breakScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
71   [breakScroll setHasHorizontalScroller:YES];
72   [breakScroll setHasVerticalScroller:YES];
73   [breakScroll setAutohidesScrollers:YES];
74   [breakScroll setBorderType:NSNoBorder];
75   [breakScroll setDocumentView:breakView];
76   [breakView release];
77   breakTab = [[NSTabViewItem alloc] initWithIdentifier:@""];
78   [breakTab setView:breakScroll];
79   [breakScroll release];
80
81   // create the breakpoints view
82   watchView = [[MAMEWatchpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)
83                                       machine:*machine];
84   watchScroll = [[NSScrollView alloc] initWithFrame:[breakScroll frame]];
85   [watchScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
86   [watchScroll setHasHorizontalScroller:YES];
87   [watchScroll setHasVerticalScroller:YES];
88   [watchScroll setAutohidesScrollers:YES];
89   [watchScroll setBorderType:NSNoBorder];
90   [watchScroll setDocumentView:watchView];
91   [watchView release];
92   watchTab = [[NSTabViewItem alloc] initWithIdentifier:@""];
93   [watchTab setView:watchScroll];
94   [watchScroll release];
95
96   // create a tabless tabview for the two subviews
97   tabs = [[NSTabView alloc] initWithFrame:[breakScroll frame]];
98   [tabs setTabViewType:NSNoTabsNoBorder];
99   [tabs setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
100   [tabs addTabViewItem:breakTab];
101   [breakTab release];
102   [tabs addTabViewItem:watchTab];
103   [watchTab release];
104   [[window contentView] addSubview:tabs];
105   [tabs release];
106
107   // set default state
108   [subviewButton selectItemAtIndex:0];
109   [tabs selectFirstTabViewItem:self];
110   [window makeFirstResponder:subviewButton];
111   [window setTitle:[[subviewButton selectedItem] title]];
112
113   // calculate the optimal size for everything
114   NSSize const breakDesired = [NSScrollView frameSizeForContentSize:[breakView maximumFrameSize]
115                                    hasHorizontalScroller:YES
116                                      hasVerticalScroller:YES
117                                             borderType:[breakScroll borderType]];
118   NSSize const watchDesired = [NSScrollView frameSizeForContentSize:[watchView maximumFrameSize]
119                                    hasHorizontalScroller:YES
120                                      hasVerticalScroller:YES
121                                             borderType:[watchScroll borderType]];
122   NSSize const desired = NSMakeSize(MAX(breakDesired.width, watchDesired.width),
123                             MAX(breakDesired.height, watchDesired.height));
124   [self cascadeWindowWithDesiredSize:desired forView:tabs];
125
126   // don't forget the result
127   return self;
128}
129
130
131- (void)dealloc {
132   [super dealloc];
133}
134
135
136- (IBAction)changeSubview:(id)sender {
137   [tabs selectTabViewItemAtIndex:[[sender selectedItem] tag]];
138   [window setTitle:[[sender selectedItem] title]];
139}
140
141@end
trunk/src/osd/modules/debugger/osx/pointsviewer.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  pointsviewer.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "pointsviewer.h"
10
11#import "breakpointsview.h"
12#import "watchpointsview.h"
13
14
15@implementation MAMEPointsViewer
16
17- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
18   MAMEDebugView   *breakView, *watchView;
19   NSScrollView   *breakScroll, *watchScroll;
20   NSTabViewItem   *breakTab, *watchTab;
21   NSPopUpButton   *actionButton, *subviewButton;
22   NSRect         subviewFrame;
23
24   if (!(self = [super initWithMachine:m title:@"(Break|Watch)points" console:c]))
25      return nil;
26   NSRect const contentBounds = [[window contentView] bounds];
27   NSFont *const defaultFont = [[MAMEDebugView class] defaultFontForMachine:m];
28
29   // create the subview popup
30   subviewButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
31   [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
32   [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle];
33   [subviewButton setFocusRingType:NSFocusRingTypeNone];
34   [subviewButton setFont:defaultFont];
35   [subviewButton setTarget:self];
36   [subviewButton setAction:@selector(changeSubview:)];
37   [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom];
38   [[[subviewButton menu] addItemWithTitle:@"All Breakpoints"
39                            action:NULL
40                       keyEquivalent:@""] setTag:0];
41   [[[subviewButton menu] addItemWithTitle:@"All Watchpoints"
42                            action:NULL
43                       keyEquivalent:@""] setTag:1];
44   [subviewButton sizeToFit];
45   subviewFrame = [subviewButton frame];
46   subviewFrame.origin.x = subviewFrame.size.height;
47   subviewFrame.origin.y = contentBounds.size.height - subviewFrame.size.height;
48   subviewFrame.size.width = contentBounds.size.width - subviewFrame.size.height;
49   [subviewButton setFrame:subviewFrame];
50   [[window contentView] addSubview:subviewButton];
51   [subviewButton release];
52
53   // create the action popup
54   actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0,
55                                                    subviewFrame.origin.y,
56                                                    subviewFrame.size.height,
57                                                    subviewFrame.size.height)];
58   [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
59   [actionButton setFont:[NSFont systemFontOfSize:[defaultFont pointSize]]];
60   [[window contentView] addSubview:actionButton];
61   [actionButton release];
62
63   // create the breakpoints view
64   breakView = [[MAMEBreakpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)
65                                       machine:*machine];
66   breakScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,
67                                                 0,
68                                                 contentBounds.size.width,
69                                                 contentBounds.size.height - subviewFrame.size.height)];
70   [breakScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
71   [breakScroll setHasHorizontalScroller:YES];
72   [breakScroll setHasVerticalScroller:YES];
73   [breakScroll setAutohidesScrollers:YES];
74   [breakScroll setBorderType:NSNoBorder];
75   [breakScroll setDocumentView:breakView];
76   [breakView release];
77   breakTab = [[NSTabViewItem alloc] initWithIdentifier:@""];
78   [breakTab setView:breakScroll];
79   [breakScroll release];
80
81   // create the breakpoints view
82   watchView = [[MAMEWatchpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)
83                                       machine:*machine];
84   watchScroll = [[NSScrollView alloc] initWithFrame:[breakScroll frame]];
85   [watchScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
86   [watchScroll setHasHorizontalScroller:YES];
87   [watchScroll setHasVerticalScroller:YES];
88   [watchScroll setAutohidesScrollers:YES];
89   [watchScroll setBorderType:NSNoBorder];
90   [watchScroll setDocumentView:watchView];
91   [watchView release];
92   watchTab = [[NSTabViewItem alloc] initWithIdentifier:@""];
93   [watchTab setView:watchScroll];
94   [watchScroll release];
95
96   // create a tabless tabview for the two subviews
97   tabs = [[NSTabView alloc] initWithFrame:[breakScroll frame]];
98   [tabs setTabViewType:NSNoTabsNoBorder];
99   [tabs setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
100   [tabs addTabViewItem:breakTab];
101   [breakTab release];
102   [tabs addTabViewItem:watchTab];
103   [watchTab release];
104   [[window contentView] addSubview:tabs];
105   [tabs release];
106
107   // set default state
108   [subviewButton selectItemAtIndex:0];
109   [tabs selectFirstTabViewItem:self];
110   [window makeFirstResponder:subviewButton];
111   [window setTitle:[[subviewButton selectedItem] title]];
112
113   // calculate the optimal size for everything
114   NSSize const breakDesired = [NSScrollView frameSizeForContentSize:[breakView maximumFrameSize]
115                                    hasHorizontalScroller:YES
116                                      hasVerticalScroller:YES
117                                             borderType:[breakScroll borderType]];
118   NSSize const watchDesired = [NSScrollView frameSizeForContentSize:[watchView maximumFrameSize]
119                                    hasHorizontalScroller:YES
120                                      hasVerticalScroller:YES
121                                             borderType:[watchScroll borderType]];
122   NSSize const desired = NSMakeSize(MAX(breakDesired.width, watchDesired.width),
123                             MAX(breakDesired.height, watchDesired.height));
124   [self cascadeWindowWithDesiredSize:desired forView:tabs];
125
126   // don't forget the result
127   return self;
128}
129
130
131- (void)dealloc {
132   [super dealloc];
133}
134
135
136- (IBAction)changeSubview:(id)sender {
137   [tabs selectTabViewItemAtIndex:[[sender selectedItem] tag]];
138   [window setTitle:[[sender selectedItem] title]];
139}
140
141@end
trunk/src/osd/modules/debugger/osx/registersview.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  registersview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "registersview.h"
10
11#include "debug/debugcpu.h"
12#include "debug/debugvw.h"
13
14
15@implementation MAMERegistersView
16
17- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
18   if (!(self = [super initWithFrame:f type:DVT_STATE machine:m wholeLineScroll:NO]))
19      return nil;
20   return self;
21}
22
23
24- (void)dealloc {
25   [super dealloc];
26}
27
28
29- (NSSize)maximumFrameSize {
30   debug_view_xy         max;
31   device_t            *curcpu = debug_cpu_get_visible_cpu(*machine);
32   const debug_view_source   *source = view->source_for_device(curcpu);
33
34   max.x = max.y = 0;
35   for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next())
36   {
37      debug_view_xy   current;
38      view->set_source(*source);
39      current = view->total_size();
40      if (current.x > max.x)
41         max.x = current.x;
42      if (current.y > max.y)
43         max.y = current.y;
44   }
45   view->set_source(*source);
46   return NSMakeSize(max.x * fontWidth, max.y * fontHeight);
47}
48
49
50- (NSString *)selectedSubviewName {
51   return @"";
52}
53
54
55- (int)selectedSubviewIndex {
56   return -1;
57}
58
59
60- (void)selectSubviewAtIndex:(int)index {
61}
62
63
64- (void)selectSubviewForDevice:(device_t *)device {
65   view->set_source(*view->source_for_device(device));
66}
67
68@end
trunk/src/osd/modules/debugger/osx/registersview.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  registersview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "registersview.h"
10
11#include "debug/debugcpu.h"
12#include "debug/debugvw.h"
13
14
15@implementation MAMERegistersView
16
17- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
18   if (!(self = [super initWithFrame:f type:DVT_STATE machine:m wholeLineScroll:NO]))
19      return nil;
20   return self;
21}
22
23
24- (void)dealloc {
25   [super dealloc];
26}
27
28
29- (NSSize)maximumFrameSize {
30   debug_view_xy         max;
31   device_t            *curcpu = debug_cpu_get_visible_cpu(*machine);
32   const debug_view_source   *source = view->source_for_device(curcpu);
33
34   max.x = max.y = 0;
35   for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next())
36   {
37      debug_view_xy   current;
38      view->set_source(*source);
39      current = view->total_size();
40      if (current.x > max.x)
41         max.x = current.x;
42      if (current.y > max.y)
43         max.y = current.y;
44   }
45   view->set_source(*source);
46   return NSMakeSize(max.x * fontWidth, max.y * fontHeight);
47}
48
49
50- (NSString *)selectedSubviewName {
51   return @"";
52}
53
54
55- (int)selectedSubviewIndex {
56   return -1;
57}
58
59
60- (void)selectSubviewAtIndex:(int)index {
61}
62
63
64- (void)selectSubviewForDevice:(device_t *)device {
65   view->set_source(*view->source_for_device(device));
66}
67
68@end
trunk/src/osd/modules/debugger/osx/watchpointsview.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  watchpointsview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "watchpointsview.h"
10
11#include "debug/debugvw.h"
12
13
14@implementation MAMEWatchpointsView
15
16- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
17   if (!(self = [super initWithFrame:f type:DVT_WATCH_POINTS machine:m wholeLineScroll:YES]))
18      return nil;
19   return self;
20}
21
22
23- (void)dealloc {
24   [super dealloc];
25}
26
27@end
trunk/src/osd/modules/debugger/osx/watchpointsview.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  watchpointsview.m - MacOS X Cocoa debug window handling
6//
7//============================================================
8
9#import "watchpointsview.h"
10
11#include "debug/debugvw.h"
12
13
14@implementation MAMEWatchpointsView
15
16- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
17   if (!(self = [super initWithFrame:f type:DVT_WATCH_POINTS machine:m wholeLineScroll:YES]))
18      return nil;
19   return self;
20}
21
22
23- (void)dealloc {
24   [super dealloc];
25}
26
27@end
trunk/src/osd/sdl/SDLMain_tmpl.m
r250164r250165
1// license:Zlib|LGPL-2.1+
2// copyright-holders:http://libsdl.org/
3/*   SDLMain.m - main entry point for our Cocoa-ized SDL app
4       Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
5       Non-NIB-Code & other changes: Max Horn <max@quendi.de>
6
7    Feel free to customize this file to suit your needs
8*/
9
10#import "sdlinc.h"
11#import "SDLMain_tmpl.h"
12#import <sys/param.h> /* for MAXPATHLEN */
13#import <unistd.h>
14
15/* For some reason, Apple removed setAppleMenu from the headers in 10.4,
16 but the method still is there and works. To avoid warnings, we declare
17 it ourselves here. */
18@interface NSApplication(SDL_Missing_Methods)
19- (void)setAppleMenu:(NSMenu *)menu;
20@end
21
22/* Use this flag to determine whether we use SDLMain.nib or not */
23#define      SDL_USE_NIB_FILE   0
24
25/* Use this flag to determine whether we use CPS (docking) or not */
26#define      SDL_USE_CPS      0
27#ifdef SDL_USE_CPS
28/* Portions of CPS.h */
29typedef struct CPSProcessSerNum
30{
31   UInt32      lo;
32   UInt32      hi;
33} CPSProcessSerNum;
34
35extern "C" OSErr   CPSGetCurrentProcess( CPSProcessSerNum *psn);
36extern "C" OSErr    CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
37extern "C" OSErr   CPSSetFrontProcess( CPSProcessSerNum *psn);
38
39#endif /* SDL_USE_CPS */
40
41static int    gArgc;
42static char  **gArgv;
43static BOOL   gFinderLaunch;
44static BOOL   gCalledAppMainline = FALSE;
45
46static NSString *getApplicationName(void)
47{
48    NSDictionary *dict;
49    NSString *appName = 0;
50
51    /* Determine the application name */
52    dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
53    if (dict)
54        appName = [dict objectForKey: @"CFBundleName"];
55   
56    if (![appName length])
57        appName = [[NSProcessInfo processInfo] processName];
58
59    return appName;
60}
61
62#if SDL_USE_NIB_FILE
63/* A helper category for NSString */
64@interface NSString (ReplaceSubString)
65- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
66@end
67#endif
68
69@interface SDLApplication : NSApplication
70@end
71
72@implementation SDLApplication
73/* Invoked from the Quit menu item */
74- (void)terminate:(id)sender
75{
76    /* Post a SDL_QUIT event */
77    SDL_Event event;
78    event.type = SDL_QUIT;
79    SDL_PushEvent(&event);
80}
81@end
82
83/* The main class of the application, the application's delegate */
84@implementation SDLMain
85
86/* Set the working directory to the .app's parent directory */
87- (void) setupWorkingDirectory:(BOOL)shouldChdir
88{
89    if (shouldChdir)
90    {
91        char parentdir[MAXPATHLEN];
92      CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
93      CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
94      if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) {
95           assert ( chdir (parentdir) == 0 );   /* chdir to the binary app's parent */
96      }
97      CFRelease(url);
98      CFRelease(url2);
99   }
100
101}
102
103#if SDL_USE_NIB_FILE
104
105/* Fix menu to contain the real app name instead of "SDL App" */
106- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
107{
108    NSRange aRange;
109    NSEnumerator *enumerator;
110    NSMenuItem *menuItem;
111
112    aRange = [[aMenu title] rangeOfString:@"SDL App"];
113    if (aRange.length != 0)
114        [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
115
116    enumerator = [[aMenu itemArray] objectEnumerator];
117    while ((menuItem = [enumerator nextObject]))
118    {
119        aRange = [[menuItem title] rangeOfString:@"SDL App"];
120        if (aRange.length != 0)
121            [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
122        if ([menuItem hasSubmenu])
123            [self fixMenu:[menuItem submenu] withAppName:appName];
124    }
125    [ aMenu sizeToFit ];
126}
127
128#else
129
130static void setApplicationMenu(void)
131{
132    /* warning: this code is very odd */
133    NSMenu *appleMenu;
134    NSMenuItem *menuItem;
135    NSString *title;
136    NSString *appName;
137   
138    appName = getApplicationName();
139    appleMenu = [[NSMenu alloc] initWithTitle:@""];
140   
141    /* Add menu items */
142    title = [@"About " stringByAppendingString:appName];
143    [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
144
145    [appleMenu addItem:[NSMenuItem separatorItem]];
146
147    title = [@"Hide " stringByAppendingString:appName];
148    [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
149
150    menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
151    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
152
153    [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
154
155    [appleMenu addItem:[NSMenuItem separatorItem]];
156
157    title = [@"Quit " stringByAppendingString:appName];
158    [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
159
160   
161    /* Put menu into the menubar */
162    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
163    [menuItem setSubmenu:appleMenu];
164    [[NSApp mainMenu] addItem:menuItem];
165
166    /* Tell the application object that this is now the application menu */
167    [NSApp setAppleMenu:appleMenu];
168
169    /* Finally give up our references to the objects */
170    [appleMenu release];
171    [menuItem release];
172}
173
174/* Create a window menu */
175static void setupWindowMenu(void)
176{
177    NSMenu      *windowMenu;
178    NSMenuItem  *windowMenuItem;
179    NSMenuItem  *menuItem;
180
181    windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
182   
183    /* "Minimize" item */
184    menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
185    [windowMenu addItem:menuItem];
186    [menuItem release];
187   
188    /* Put menu into the menubar */
189    windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
190    [windowMenuItem setSubmenu:windowMenu];
191    [[NSApp mainMenu] addItem:windowMenuItem];
192   
193    /* Tell the application object that this is now the window menu */
194    [NSApp setWindowsMenu:windowMenu];
195
196    /* Finally give up our references to the objects */
197    [windowMenu release];
198    [windowMenuItem release];
199}
200
201/* Replacement for NSApplicationMain */
202static void CustomApplicationMain (int argc, char **argv)
203{
204    NSAutoreleasePool   *pool = [[NSAutoreleasePool alloc] init];
205    SDLMain            *sdlMain;
206
207    /* Ensure the application object is initialised */
208    [SDLApplication sharedApplication];
209   
210#ifdef SDL_USE_CPS
211    {
212        CPSProcessSerNum PSN;
213        /* Tell the dock about us */
214        if (!CPSGetCurrentProcess(&PSN))
215            if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
216                if (!CPSSetFrontProcess(&PSN))
217                    [SDLApplication sharedApplication];
218    }
219#endif /* SDL_USE_CPS */
220
221    /* Set up the menubar */
222    [NSApp setMainMenu:[[NSMenu alloc] init]];
223    setApplicationMenu();
224    setupWindowMenu();
225
226    /* Create SDLMain and make it the app delegate */
227    sdlMain = [[SDLMain alloc] init];
228    [NSApp setDelegate:sdlMain];
229   
230    /* Start the main event loop */
231    [NSApp run];
232   
233    [sdlMain release];
234    [pool release];
235}
236
237#endif
238
239
240/*
241 * Catch document open requests...this lets us notice files when the app
242 *  was launched by double-clicking a document, or when a document was
243 *  dragged/dropped on the app's icon. You need to have a
244 *  CFBundleDocumentsType section in your Info.plist to get this message,
245 *  apparently.
246 *
247 * Files are added to gArgv, so to the app, they'll look like command line
248 *  arguments. Previously, apps launched from the finder had nothing but
249 *  an argv[0].
250 *
251 * This message may be received multiple times to open several docs on launch.
252 *
253 * This message is ignored once the app's mainline has been called.
254 */
255- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
256{
257    const char *temparg;
258    size_t arglen;
259    char *arg;
260    char **newargv;
261
262    if (!gFinderLaunch)  /* MacOS is passing command line args. */
263        return FALSE;
264
265    if (gCalledAppMainline)  /* app has started, ignore this document. */
266        return FALSE;
267
268    temparg = [filename UTF8String];
269    arglen = SDL_strlen(temparg) + 1;
270    arg = (char *) SDL_malloc(arglen);
271    if (arg == NULL)
272        return FALSE;
273
274    newargv = (char **) SDL_realloc(gArgv, sizeof (char *) * (gArgc + 2));
275    if (newargv == NULL)
276    {
277        SDL_free(arg);
278        return FALSE;
279    }
280    gArgv = newargv;
281
282    SDL_strlcpy(arg, temparg, arglen);
283    gArgv[gArgc++] = arg;
284    gArgv[gArgc] = NULL;
285    return TRUE;
286}
287
288
289/* Called when the internal event loop has just started running */
290- (void) applicationDidFinishLaunching: (NSNotification *) note
291{
292    int status;
293
294    /* Set the working directory to the .app's parent directory */
295    [self setupWorkingDirectory:gFinderLaunch];
296
297#if SDL_USE_NIB_FILE
298    /* Set the main menu to contain the real app name instead of "SDL App" */
299    [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
300#endif
301
302    /* Hand off to main application code */
303    gCalledAppMainline = TRUE;
304    status = SDL_main (gArgc, gArgv);
305
306    /* We're done, thank you for playing */
307    exit(status);
308}
309@end
310
311
312@implementation NSString (ReplaceSubString)
313
314- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
315{
316    unsigned int bufferSize;
317    unsigned int selfLen = [self length];
318    unsigned int aStringLen = [aString length];
319    unichar *buffer;
320    NSRange localRange;
321    NSString *result;
322
323    bufferSize = selfLen + aStringLen - aRange.length;
324    buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
325   
326    /* Get first part into buffer */
327    localRange.location = 0;
328    localRange.length = aRange.location;
329    [self getCharacters:buffer range:localRange];
330   
331    /* Get middle part into buffer */
332    localRange.location = 0;
333    localRange.length = aStringLen;
334    [aString getCharacters:(buffer+aRange.location) range:localRange];
335     
336    /* Get last part into buffer */
337    localRange.location = aRange.location + aRange.length;
338    localRange.length = selfLen - localRange.location;
339    [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
340   
341    /* Build output string */
342    result = [NSString stringWithCharacters:buffer length:bufferSize];
343   
344    NSDeallocateMemoryPages(buffer, bufferSize);
345   
346    return result;
347}
348
349@end
350
351
352
353#ifdef main
354#  undef main
355#endif
356
357
358/* Main entry point to executable - should *not* be SDL_main! */
359int main (int argc, char **argv)
360{
361    /* Copy the arguments into a global variable */
362    /* This is passed if we are launched by double-clicking */
363    if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
364        gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
365        gArgv[0] = argv[0];
366        gArgv[1] = NULL;
367        gArgc = 1;
368        gFinderLaunch = YES;
369    } else {
370        int i;
371        gArgc = argc;
372        gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
373        for (i = 0; i <= argc; i++)
374            gArgv[i] = argv[i];
375        gFinderLaunch = NO;
376    }
377
378#if SDL_USE_NIB_FILE
379    [SDLApplication poseAsClass:[NSApplication class]];
380    NSApplicationMain (argc, argv);
381#else
382    CustomApplicationMain (argc, argv);
383#endif
384    return 0;
385}
386
trunk/src/osd/sdl/SDLMain_tmpl.mm
r0r250165
1// license:Zlib|LGPL-2.1+
2// copyright-holders:http://libsdl.org/
3/*   SDLMain.m - main entry point for our Cocoa-ized SDL app
4       Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
5       Non-NIB-Code & other changes: Max Horn <max@quendi.de>
6
7    Feel free to customize this file to suit your needs
8*/
9
10#import "sdlinc.h"
11#import "SDLMain_tmpl.h"
12#import <sys/param.h> /* for MAXPATHLEN */
13#import <unistd.h>
14
15/* For some reason, Apple removed setAppleMenu from the headers in 10.4,
16 but the method still is there and works. To avoid warnings, we declare
17 it ourselves here. */
18@interface NSApplication(SDL_Missing_Methods)
19- (void)setAppleMenu:(NSMenu *)menu;
20@end
21
22/* Use this flag to determine whether we use SDLMain.nib or not */
23#define      SDL_USE_NIB_FILE   0
24
25/* Use this flag to determine whether we use CPS (docking) or not */
26#define      SDL_USE_CPS      0
27#ifdef SDL_USE_CPS
28/* Portions of CPS.h */
29typedef struct CPSProcessSerNum
30{
31   UInt32      lo;
32   UInt32      hi;
33} CPSProcessSerNum;
34
35extern "C" OSErr   CPSGetCurrentProcess( CPSProcessSerNum *psn);
36extern "C" OSErr    CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
37extern "C" OSErr   CPSSetFrontProcess( CPSProcessSerNum *psn);
38
39#endif /* SDL_USE_CPS */
40
41static int    gArgc;
42static char  **gArgv;
43static BOOL   gFinderLaunch;
44static BOOL   gCalledAppMainline = FALSE;
45
46static NSString *getApplicationName(void)
47{
48    NSDictionary *dict;
49    NSString *appName = 0;
50
51    /* Determine the application name */
52    dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
53    if (dict)
54        appName = [dict objectForKey: @"CFBundleName"];
55   
56    if (![appName length])
57        appName = [[NSProcessInfo processInfo] processName];
58
59    return appName;
60}
61
62#if SDL_USE_NIB_FILE
63/* A helper category for NSString */
64@interface NSString (ReplaceSubString)
65- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
66@end
67#endif
68
69@interface SDLApplication : NSApplication
70@end
71
72@implementation SDLApplication
73/* Invoked from the Quit menu item */
74- (void)terminate:(id)sender
75{
76    /* Post a SDL_QUIT event */
77    SDL_Event event;
78    event.type = SDL_QUIT;
79    SDL_PushEvent(&event);
80}
81@end
82
83/* The main class of the application, the application's delegate */
84@implementation SDLMain
85
86/* Set the working directory to the .app's parent directory */
87- (void) setupWorkingDirectory:(BOOL)shouldChdir
88{
89    if (shouldChdir)
90    {
91        char parentdir[MAXPATHLEN];
92      CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
93      CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
94      if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) {
95           assert ( chdir (parentdir) == 0 );   /* chdir to the binary app's parent */
96      }
97      CFRelease(url);
98      CFRelease(url2);
99   }
100
101}
102
103#if SDL_USE_NIB_FILE
104
105/* Fix menu to contain the real app name instead of "SDL App" */
106- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
107{
108    NSRange aRange;
109    NSEnumerator *enumerator;
110    NSMenuItem *menuItem;
111
112    aRange = [[aMenu title] rangeOfString:@"SDL App"];
113    if (aRange.length != 0)
114        [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
115
116    enumerator = [[aMenu itemArray] objectEnumerator];
117    while ((menuItem = [enumerator nextObject]))
118    {
119        aRange = [[menuItem title] rangeOfString:@"SDL App"];
120        if (aRange.length != 0)
121            [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
122        if ([menuItem hasSubmenu])
123            [self fixMenu:[menuItem submenu] withAppName:appName];
124    }
125    [ aMenu sizeToFit ];
126}
127
128#else
129
130static void setApplicationMenu(void)
131{
132    /* warning: this code is very odd */
133    NSMenu *appleMenu;
134    NSMenuItem *menuItem;
135    NSString *title;
136    NSString *appName;
137   
138    appName = getApplicationName();
139    appleMenu = [[NSMenu alloc] initWithTitle:@""];
140   
141    /* Add menu items */
142    title = [@"About " stringByAppendingString:appName];
143    [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
144
145    [appleMenu addItem:[NSMenuItem separatorItem]];
146
147    title = [@"Hide " stringByAppendingString:appName];
148    [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
149
150    menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
151    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
152
153    [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
154
155    [appleMenu addItem:[NSMenuItem separatorItem]];
156
157    title = [@"Quit " stringByAppendingString:appName];
158    [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
159
160   
161    /* Put menu into the menubar */
162    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
163    [menuItem setSubmenu:appleMenu];
164    [[NSApp mainMenu] addItem:menuItem];
165
166    /* Tell the application object that this is now the application menu */
167    [NSApp setAppleMenu:appleMenu];
168
169    /* Finally give up our references to the objects */
170    [appleMenu release];
171    [menuItem release];
172}
173
174/* Create a window menu */
175static void setupWindowMenu(void)
176{
177    NSMenu      *windowMenu;
178    NSMenuItem  *windowMenuItem;
179    NSMenuItem  *menuItem;
180
181    windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
182   
183    /* "Minimize" item */
184    menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
185    [windowMenu addItem:menuItem];
186    [menuItem release];
187   
188    /* Put menu into the menubar */
189    windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
190    [windowMenuItem setSubmenu:windowMenu];
191    [[NSApp mainMenu] addItem:windowMenuItem];
192   
193    /* Tell the application object that this is now the window menu */
194    [NSApp setWindowsMenu:windowMenu];
195
196    /* Finally give up our references to the objects */
197    [windowMenu release];
198    [windowMenuItem release];
199}
200
201/* Replacement for NSApplicationMain */
202static void CustomApplicationMain (int argc, char **argv)
203{
204    NSAutoreleasePool   *pool = [[NSAutoreleasePool alloc] init];
205    SDLMain            *sdlMain;
206
207    /* Ensure the application object is initialised */
208    [SDLApplication sharedApplication];
209   
210#ifdef SDL_USE_CPS
211    {
212        CPSProcessSerNum PSN;
213        /* Tell the dock about us */
214        if (!CPSGetCurrentProcess(&PSN))
215            if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
216                if (!CPSSetFrontProcess(&PSN))
217                    [SDLApplication sharedApplication];
218    }
219#endif /* SDL_USE_CPS */
220
221    /* Set up the menubar */
222    [NSApp setMainMenu:[[NSMenu alloc] init]];
223    setApplicationMenu();
224    setupWindowMenu();
225
226    /* Create SDLMain and make it the app delegate */
227    sdlMain = [[SDLMain alloc] init];
228    [NSApp setDelegate:sdlMain];
229   
230    /* Start the main event loop */
231    [NSApp run];
232   
233    [sdlMain release];
234    [pool release];
235}
236
237#endif
238
239
240/*
241 * Catch document open requests...this lets us notice files when the app
242 *  was launched by double-clicking a document, or when a document was
243 *  dragged/dropped on the app's icon. You need to have a
244 *  CFBundleDocumentsType section in your Info.plist to get this message,
245 *  apparently.
246 *
247 * Files are added to gArgv, so to the app, they'll look like command line
248 *  arguments. Previously, apps launched from the finder had nothing but
249 *  an argv[0].
250 *
251 * This message may be received multiple times to open several docs on launch.
252 *
253 * This message is ignored once the app's mainline has been called.
254 */
255- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
256{
257    const char *temparg;
258    size_t arglen;
259    char *arg;
260    char **newargv;
261
262    if (!gFinderLaunch)  /* MacOS is passing command line args. */
263        return FALSE;
264
265    if (gCalledAppMainline)  /* app has started, ignore this document. */
266        return FALSE;
267
268    temparg = [filename UTF8String];
269    arglen = SDL_strlen(temparg) + 1;
270    arg = (char *) SDL_malloc(arglen);
271    if (arg == NULL)
272        return FALSE;
273
274    newargv = (char **) SDL_realloc(gArgv, sizeof (char *) * (gArgc + 2));
275    if (newargv == NULL)
276    {
277        SDL_free(arg);
278        return FALSE;
279    }
280    gArgv = newargv;
281
282    SDL_strlcpy(arg, temparg, arglen);
283    gArgv[gArgc++] = arg;
284    gArgv[gArgc] = NULL;
285    return TRUE;
286}
287
288
289/* Called when the internal event loop has just started running */
290- (void) applicationDidFinishLaunching: (NSNotification *) note
291{
292    int status;
293
294    /* Set the working directory to the .app's parent directory */
295    [self setupWorkingDirectory:gFinderLaunch];
296
297#if SDL_USE_NIB_FILE
298    /* Set the main menu to contain the real app name instead of "SDL App" */
299    [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
300#endif
301
302    /* Hand off to main application code */
303    gCalledAppMainline = TRUE;
304    status = SDL_main (gArgc, gArgv);
305
306    /* We're done, thank you for playing */
307    exit(status);
308}
309@end
310
311
312@implementation NSString (ReplaceSubString)
313
314- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
315{
316    unsigned int bufferSize;
317    unsigned int selfLen = [self length];
318    unsigned int aStringLen = [aString length];
319    unichar *buffer;
320    NSRange localRange;
321    NSString *result;
322
323    bufferSize = selfLen + aStringLen - aRange.length;
324    buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
325   
326    /* Get first part into buffer */
327    localRange.location = 0;
328    localRange.length = aRange.location;
329    [self getCharacters:buffer range:localRange];
330   
331    /* Get middle part into buffer */
332    localRange.location = 0;
333    localRange.length = aStringLen;
334    [aString getCharacters:(buffer+aRange.location) range:localRange];
335     
336    /* Get last part into buffer */
337    localRange.location = aRange.location + aRange.length;
338    localRange.length = selfLen - localRange.location;
339    [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
340   
341    /* Build output string */
342    result = [NSString stringWithCharacters:buffer length:bufferSize];
343   
344    NSDeallocateMemoryPages(buffer, bufferSize);
345   
346    return result;
347}
348
349@end
350
351
352
353#ifdef main
354#  undef main
355#endif
356
357
358/* Main entry point to executable - should *not* be SDL_main! */
359int main (int argc, char **argv)
360{
361    /* Copy the arguments into a global variable */
362    /* This is passed if we are launched by double-clicking */
363    if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
364        gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
365        gArgv[0] = argv[0];
366        gArgv[1] = NULL;
367        gArgc = 1;
368        gFinderLaunch = YES;
369    } else {
370        int i;
371        gArgc = argc;
372        gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
373        for (i = 0; i <= argc; i++)
374            gArgv[i] = argv[i];
375        gFinderLaunch = NO;
376    }
377
378#if SDL_USE_NIB_FILE
379    [SDLApplication poseAsClass:[NSApplication class]];
380    NSApplicationMain (argc, argv);
381#else
382    CustomApplicationMain (argc, argv);
383#endif
384    return 0;
385}
386
trunk/src/osd/sdl/aueffectutil.m
r250164r250165
1#import <AvailabilityMacros.h>
2#import <AudioUnit/AudioUnit.h>
3#import <AudioUnit/AUCocoaUIView.h>
4#import <AudioToolbox/AudioToolbox.h>
5#import <Cocoa/Cocoa.h>
6#import <CoreAudio/CoreAudio.h>
7#import <CoreAudioKit/CoreAudioKit.h>
8#import <CoreFoundation/CoreFoundation.h>
9#import <CoreServices/CoreServices.h>
10
11#include <utility>
12#include <vector>
13
14#include <stdlib.h>
15
16
17#ifdef MAC_OS_X_VERSION_MAX_ALLOWED
18
19#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
20
21typedef ComponentDescription AudioComponentDescription;
22
23@protocol NSApplicationDelegate <NSObject>
24@end
25
26@protocol NSWindowDelegate <NSObject>
27@end
28
29#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1060
30
31#endif // MAC_OS_X_VERSION_MAX_ALLOWED
32
33
34struct EffectInfo
35{
36   Component   component;
37   OSType      type;
38   OSType      subtype;
39   OSType      manufacturer;
40};
41
42
43static NSString *const AUEffectUtilErrorDomain  = @"AUEffectUtilErrorDomain";
44
45static NSString *const AUEffectDocumentType     = @"AUEffect";
46static NSString *const AUPresetDocumentType     = @"AudioUnit Preset";
47
48static NSString *const ComponentTypeKey         = @"ComponentType";
49static NSString *const ComponentSubTypeKey      = @"ComponentSubType";
50static NSString *const ComponentManufacturerKey = @"ComponentManufacturer";
51static NSString *const ClassInfoKey             = @"ClassInfo";
52static NSString *const ForceGenericViewKey      = @"ForceGenericView";
53static NSString *const WindowFrameKey           = @"WindowFrame";
54
55
56static void UpdateChangeCountCallback(void                      *userData,
57                             void                      *object,
58                             AudioUnitEvent const      *inEvent,
59                             UInt64                    inEventHostTime,
60                             AudioUnitParameterValue   inParameterValue)
61{
62   [(NSDocument *)userData updateChangeCount:NSChangeDone];
63}
64
65
66@interface AUEffectDocument : NSDocument <NSWindowDelegate>
67{
68   IBOutlet NSWindow           *window;
69   IBOutlet NSButton           *genericViewButton;
70   IBOutlet NSPopUpButton      *presetButton;
71   NSView                      *view;
72   NSSize                      headerSize;
73   CFArrayRef                  presets;
74   AUParameterListenerRef      listener;
75   BOOL                        forceGenericView;
76   NSString                    *restoreFrame;
77
78   AudioComponentDescription   description;
79   AUGraph                     graph;
80   AUNode                      outputNode, sourceNode, effectNode;
81   AudioUnit                   outputUnit, sourceUnit, effectUnit;
82}
83
84- (void)dealloc;
85
86- (void)makeWindowControllers;
87- (BOOL)readFromData:(NSData *)data ofType:(NSString *)type error:(NSError **)error;
88- (NSData *)dataOfType:(NSString *)type error:(NSError **)error;
89
90- (IBAction)toggleGenericView:(id)sender;
91- (IBAction)loadPreset:(id)sender;
92
93- (void)viewFrameDidChange:(NSNotification *)notification;
94
95@end
96
97@implementation AUEffectDocument
98
99- (void)loadEffectUI {
100   if ((0 == effectNode) || (nil == window))
101      return;
102
103   BOOL customViewValid = NO;
104   OSStatus status;
105   UInt32 uiDescSize;
106   AudioUnitCocoaViewInfo *viewInfo;
107   status = AudioUnitGetPropertyInfo(effectUnit,
108                             kAudioUnitProperty_CocoaUI,
109                             kAudioUnitScope_Global,
110                             0,
111                             &uiDescSize,
112                             NULL);
113   UInt32 const uiClassCount = 1 + ((uiDescSize - sizeof(*viewInfo)) / sizeof(viewInfo->mCocoaAUViewClass[0]));
114   if ((noErr == status) && (0 < uiClassCount))
115   {
116      viewInfo = (AudioUnitCocoaViewInfo *)malloc(uiDescSize);
117      status = AudioUnitGetProperty(effectUnit,
118                             kAudioUnitProperty_CocoaUI,
119                             kAudioUnitScope_Global,
120                             0,
121                             viewInfo,
122                             &uiDescSize);
123      if (noErr == status)
124      {
125         NSBundle *const bundle = [NSBundle bundleWithPath:[(NSURL *)viewInfo->mCocoaAUViewBundleLocation path]];
126         Class const viewClass = [bundle classNamed:(NSString *)viewInfo->mCocoaAUViewClass[0]];
127         if ((NULL != viewClass)
128          && [viewClass conformsToProtocol:@protocol(AUCocoaUIBase)]
129          && [viewClass instancesRespondToSelector:@selector(uiViewForAudioUnit:withSize:)])
130         {
131            customViewValid = YES;
132            if (!forceGenericView)
133            {
134               id const factory = [[viewClass alloc] init];
135               view = [factory uiViewForAudioUnit:effectUnit
136                                   withSize:[[window contentView] bounds].size];
137               [factory release];
138            }
139         }
140         CFRelease(viewInfo->mCocoaAUViewBundleLocation);
141         for (UInt32 i = 0; i < uiClassCount; i++)
142            CFRelease(viewInfo->mCocoaAUViewClass[i]);
143      }
144      free(viewInfo);
145   }
146   if (nil == view)
147   {
148      view = [[[AUGenericView alloc] initWithAudioUnit:effectUnit] autorelease];
149      [(AUGenericView *)view setShowsExpertParameters:YES];
150   }
151
152   [view setAutoresizingMask:NSViewNotSizable];
153   [view setFrameOrigin:NSMakePoint(0, 0)];
154   NSRect const oldFrame = [window frame];
155   NSRect const desired = [window frameRectForContentRect:[view frame]];
156   NSRect const newFrame = NSMakeRect(oldFrame.origin.x,
157                              oldFrame.origin.y + oldFrame.size.height - headerSize.height - desired.size.height,
158                              desired.size.width,
159                              headerSize.height + desired.size.height);
160   [window setFrame:newFrame display:YES animate:NO];
161   [[window contentView] addSubview:view];
162   [view setPostsFrameChangedNotifications:YES];
163   [[NSNotificationCenter defaultCenter] addObserver:self
164                                  selector:@selector(viewFrameDidChange:)
165                                     name:NSViewFrameDidChangeNotification
166                                    object:view];
167
168   [genericViewButton setEnabled:customViewValid];
169   if (!customViewValid)
170   {
171      forceGenericView = YES;
172      [genericViewButton setState:NSOnState];
173   }
174
175   CFIndex const presetCount = (NULL != presets) ? CFArrayGetCount(presets) : 0;
176   [presetButton setEnabled:(0 < presetCount)];
177   while (1 < [presetButton numberOfItems])
178      [presetButton removeItemAtIndex:1];
179   for (CFIndex i = 0; i < presetCount; i++)
180   {
181      AUPreset const *preset = (AUPreset const*)CFArrayGetValueAtIndex(presets, i);
182      NSMenuItem const *item = [[presetButton menu] addItemWithTitle:(NSString *)preset->presetName
183                                                action:@selector(loadPreset:)
184                                           keyEquivalent:@""];
185      [item setTarget:self];
186      [item setTag:i];
187   }
188}
189
190- (id)init {
191   if (!(self = [super init])) return nil;
192
193   window = nil;
194   genericViewButton = nil;
195   presetButton = nil;
196   view = nil;
197   presets = NULL;
198   listener = NULL;
199   forceGenericView = NO;
200   restoreFrame = nil;
201
202   description.componentType = description.componentSubType = description.componentManufacturer = 0;
203   description.componentFlags = description.componentFlagsMask = 0;
204   graph = NULL;
205   outputNode = sourceNode = effectNode = 0;
206
207   AudioComponentDescription const outputDesc = { kAudioUnitType_Output,
208                                       kAudioUnitSubType_DefaultOutput,
209                                       kAudioUnitManufacturer_Apple,
210                                       0,
211                                       0, };
212   AudioComponentDescription const sourceDesc = { kAudioUnitType_Generator,
213                                       kAudioUnitSubType_AudioFilePlayer,
214                                       kAudioUnitManufacturer_Apple,
215                                       0,
216                                       0, };
217   if ((noErr != NewAUGraph(&graph))
218    || (noErr != AUGraphAddNode(graph, &outputDesc, &outputNode))
219    || (noErr != AUGraphAddNode(graph, &sourceDesc, &sourceNode))
220    || (noErr != AUGraphOpen(graph))
221    || (noErr != AUGraphNodeInfo(graph, outputNode, NULL, &outputUnit))
222    || (noErr != AUGraphNodeInfo(graph, sourceNode, NULL, &sourceUnit))
223    || (noErr != AUGraphInitialize(graph)))
224   {
225      [self release];
226      return nil;
227   }
228
229   return self;
230}
231
232- (void)dealloc {
233   if (NULL != presets)
234      CFRelease(presets);
235
236   if (NULL != listener)
237      AUListenerDispose(listener);
238
239   if (nil != restoreFrame)
240      [restoreFrame release];
241
242   if (NULL != graph)
243   {
244      AUGraphClose(graph);
245      DisposeAUGraph(graph);
246   }
247
248   [super dealloc];
249}
250
251- (void)makeWindowControllers {
252   genericViewButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 18)];
253   [genericViewButton setAutoresizingMask:NSViewNotSizable];
254   [[genericViewButton cell] setControlSize:NSSmallControlSize];
255   [genericViewButton setButtonType:NSSwitchButton];
256   [genericViewButton setBordered:NO];
257   [genericViewButton setAllowsMixedState:NO];
258   [genericViewButton setState:(forceGenericView ? NSOnState : NSOffState)];
259   [genericViewButton setTitle:@"Use generic editor view"];
260   [genericViewButton setAction:@selector(toggleGenericView:)];
261   [genericViewButton setTarget:self];
262   [genericViewButton sizeToFit];
263
264   presetButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 22) pullsDown:YES];
265   [presetButton setAutoresizingMask:NSViewNotSizable];
266   [[presetButton cell] setControlSize:NSSmallControlSize];
267   [[presetButton cell] setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
268   [presetButton setTitle:@"Load preset"];
269   [[[presetButton menu] addItemWithTitle:@"Load preset" action:NULL keyEquivalent:@""] setHidden:YES];
270   [presetButton sizeToFit];
271
272   CGFloat const controlWidth = MAX(NSWidth([genericViewButton frame]), NSWidth([presetButton frame]));
273   NSRect const presetFrame = NSMakeRect(17,
274                                8,
275                                controlWidth,
276                                NSHeight([presetButton frame]));
277   NSRect const genericViewFrame = NSMakeRect(17,
278                                    NSMaxY(presetFrame) + 9,
279                                    controlWidth,
280                                    NSHeight([genericViewButton frame]));
281   [genericViewButton setFrame:genericViewFrame];
282   [presetButton setFrame:presetFrame];
283
284   headerSize = NSMakeSize((2 * 17) + controlWidth, 18 + NSMaxY(genericViewFrame));
285   NSView *const container = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, headerSize.width, headerSize.height)];
286   [container setAutoresizingMask:(NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin)];
287   [container addSubview:genericViewButton];
288   [genericViewButton release];
289   [container addSubview:presetButton];
290   [presetButton release];
291
292   window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, headerSize.width, headerSize.height)
293                               styleMask:(NSTitledWindowMask |
294                                       NSClosableWindowMask |
295                                       NSMiniaturizableWindowMask)
296                                 backing:NSBackingStoreBuffered
297                                  defer:YES];
298   [window setReleasedWhenClosed:NO];
299   [window setDelegate:self];
300   [window setTitle:@"Effect"];
301   [[window contentView] addSubview:container];
302   [container release];
303   [self setWindow:window];
304
305   NSWindowController *const controller = [[NSWindowController alloc] initWithWindow:window];
306   [self addWindowController:controller];
307   [controller release];
308   [window release];
309
310   [self loadEffectUI];
311   if (nil != restoreFrame)
312   {
313      [window setFrameFromString:restoreFrame];
314   }
315   else
316   {
317      NSRect const available = [[NSScreen mainScreen] visibleFrame];
318      NSRect frame = [window frame];
319      frame.origin.x = (NSWidth(available) - NSWidth(frame)) / 4;
320      frame.origin.y = (NSHeight(available) - NSHeight(frame)) * 3 / 4;
321      [window setFrame:frame display:YES animate:NO];
322   }
323}
324
325- (BOOL)readFromData:(NSData *)data ofType:(NSString *)type error:(NSError **)error {
326   OSStatus status;
327   UInt32 propertySize;
328
329   BOOL const hasWrapper = [type isEqualToString:AUEffectDocumentType];
330   if (!hasWrapper && ![type isEqualToString:AUPresetDocumentType])
331   {
332      if (NULL != error)
333      {
334         NSString *const message = [NSString stringWithFormat:@"Unsupported document type %@", type];
335         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,  NSLocalizedDescriptionKey,
336                                                              nil];
337         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
338      }
339      return NO;
340   }
341
342   NSString *errDesc = nil;
343   id const desc = [NSPropertyListSerialization propertyListFromData:data
344                                        mutabilityOption:0
345                                                 format:NULL
346                                        errorDescription:&errDesc];
347   if ((nil == desc) || ![desc isKindOfClass:[NSDictionary class]] || (nil != errDesc))
348   {
349      if (NULL != error)
350      {
351         NSString *const message = [NSString stringWithFormat:@"Error in file format (%@)", errDesc];
352         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,  NSLocalizedDescriptionKey,
353                                                              nil];
354         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
355      }
356      if (nil != errDesc)
357         [errDesc release];
358      return NO;
359   }
360
361   id const typeValue = [desc objectForKey:(hasWrapper ? ComponentTypeKey : (NSString *)CFSTR(kAUPresetTypeKey))];
362   id const subtypeValue = [desc objectForKey:(hasWrapper ? ComponentSubTypeKey : (NSString *)CFSTR(kAUPresetSubtypeKey))];
363   id const manufacturerValue = [desc objectForKey:(hasWrapper ? ComponentManufacturerKey : (NSString *)CFSTR(kAUPresetManufacturerKey))];
364   if ((nil == typeValue)          || ![typeValue isKindOfClass:[NSNumber class]]
365    || (nil == subtypeValue)       || ![subtypeValue isKindOfClass:[NSNumber class]]
366    || (nil == manufacturerValue)  || ![manufacturerValue isKindOfClass:[NSNumber class]]
367    || ([typeValue unsignedLongValue] != kAudioUnitType_Effect))
368   {
369      if (NULL != error)
370      {
371         NSString *const message = @"Error in effect description file format";
372         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,  NSLocalizedDescriptionKey,
373                                                              nil];
374         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
375      }
376      return NO;
377   }
378
379   if (NULL != presets)
380   {
381      CFRelease(presets);
382      presets = NULL;
383   }
384   if (NULL != listener)
385   {
386      AUListenerDispose(listener);
387      listener = NULL;
388   }
389   if (nil != view)
390   {
391      [[NSNotificationCenter defaultCenter] removeObserver:self
392                                          name:NSViewFrameDidChangeNotification
393                                         object:nil];
394      [view removeFromSuperview];
395      view = nil;
396   }
397   if (0 != effectNode)
398   {
399      view = nil;
400      AUGraphRemoveNode(graph, effectNode);
401      effectNode = 0;
402   }
403
404   description.componentType = [typeValue longValue];
405   description.componentSubType = [subtypeValue longValue];
406   description.componentManufacturer = [manufacturerValue longValue];
407   status = noErr;
408   status = AUGraphClearConnections(graph);
409   if (noErr == status) status = AUGraphAddNode(graph, &description, &effectNode);
410   if (noErr == status) status = AUGraphNodeInfo(graph, effectNode, NULL, &effectUnit);
411   if (noErr == status) status = AUGraphConnectNodeInput(graph, sourceNode, 0, effectNode, 0);
412   if (noErr == status) status = AUGraphConnectNodeInput(graph, effectNode, 0, outputNode, 0);
413   if (noErr == status) status = AUGraphUpdate(graph, NULL);
414   if (noErr != status)
415   {
416      if (NULL != error)
417      {
418         NSString * const message = @"Error encountered while configuring AudioUnit graph";
419         NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
420         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
421                                                              underlying,    NSUnderlyingErrorKey,
422                                                              nil];
423         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
424      }
425      return NO;
426   }
427
428   CFPropertyListRef const classInfo = (CFPropertyListRef)(hasWrapper ? [desc objectForKey:ClassInfoKey] : desc);
429   if (NULL != classInfo)
430   {
431      AudioUnitParameter change = { effectUnit, kAUParameterListener_AnyParameter, 0, 0 };
432      status = AudioUnitSetProperty(effectUnit,
433                             kAudioUnitProperty_ClassInfo,
434                             kAudioUnitScope_Global,
435                             0,
436                             &classInfo,
437                             sizeof(classInfo));
438      if (noErr == status) status = AUParameterListenerNotify(NULL, NULL, &change);
439      if (noErr != status)
440      {
441         if (NULL != error)
442         {
443            NSString * const message = @"Error configuring effect";
444            NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
445            NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
446                                                                 underlying,    NSUnderlyingErrorKey,
447                                                                 nil];
448            *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
449         }
450         return NO;
451      }
452   }
453
454   propertySize = 0;
455   status = AudioUnitGetPropertyInfo(
456         effectUnit,
457         kAudioUnitProperty_ParameterList,
458         kAudioUnitScope_Global,
459         0,
460         &propertySize,
461         NULL);
462   if (noErr != status)
463   {
464      if (NULL != error)
465      {
466         NSString * const message = @"Error getting effect parameters";
467         NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
468         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
469                                                              underlying,    NSUnderlyingErrorKey,
470                                                              nil];
471         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
472      }
473      return NO;
474   }
475   UInt32 const paramCount = propertySize / sizeof(AudioUnitParameterID);
476   if (0U < paramCount)
477   {
478      status = AUEventListenerCreate(UpdateChangeCountCallback,
479                              self,
480                              CFRunLoopGetCurrent(),
481                              kCFRunLoopDefaultMode,
482                              0.05,
483                              0.05,
484                              &listener);
485      if (noErr != status)
486      {
487         if (NULL != error)
488         {
489            NSString * const message = @"Error creating AudioUnit event listener";
490            NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
491            NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
492                                                                 underlying,    NSUnderlyingErrorKey,
493                                                                 nil];
494            *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
495         }
496         return NO;
497      }
498      AudioUnitParameterID *const params = (AudioUnitParameterID *)malloc(propertySize);
499      AudioUnitGetProperty(
500            effectUnit,
501            kAudioUnitProperty_ParameterList,
502            kAudioUnitScope_Global,
503            0,
504            params,
505            &propertySize);
506      if (noErr != status)
507      {
508         free(params);
509         if (NULL != error)
510         {
511            NSString * const message = @"Error getting effect parameters";
512            NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
513            NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
514                                                                 underlying,    NSUnderlyingErrorKey,
515                                                                 nil];
516            *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
517         }
518         return NO;
519      }
520      for (UInt32 i = 0; (i < paramCount) && (noErr == status); i++)
521      {
522         AudioUnitEvent event;
523         event.mEventType = kAudioUnitEvent_ParameterValueChange;
524         event.mArgument.mParameter.mAudioUnit = effectUnit;
525         event.mArgument.mParameter.mParameterID = params[i];
526         event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
527         event.mArgument.mParameter.mElement = 0;
528         status = AUEventListenerAddEventType(listener, self, &event);
529      }
530      free(params);
531      if (noErr != status)
532      {
533         free(params);
534         if (NULL != error)
535         {
536            NSString * const message = @"Error getting effect parameters";
537            NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
538            NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
539                                                                 underlying,    NSUnderlyingErrorKey,
540                                                                 nil];
541            *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
542         }
543         return NO;
544      }
545   }
546
547   propertySize = sizeof(presets);
548   status = AudioUnitGetProperty(effectUnit,
549                          kAudioUnitProperty_FactoryPresets,
550                          kAudioUnitScope_Global,
551                          0,
552                          &presets,
553                          &propertySize);
554   if ((noErr != status) && (NULL != presets))
555   {
556      CFRelease(presets);
557      presets = NULL;
558   }
559
560   if (hasWrapper)
561   {
562      if ((nil != [desc objectForKey:ForceGenericViewKey])
563       && [[desc objectForKey:ForceGenericViewKey] respondsToSelector:@selector(boolValue)])
564      {
565         forceGenericView = [[desc objectForKey:ForceGenericViewKey] boolValue];
566         [genericViewButton setState:(forceGenericView ? NSOnState : NSOffState)];
567      }
568      if ((nil != [desc objectForKey:WindowFrameKey])
569       && [[desc objectForKey:WindowFrameKey] isKindOfClass:[NSString class]])
570      {
571         if (nil != restoreFrame) [restoreFrame release];
572         restoreFrame = [[NSString alloc] initWithString:[desc objectForKey:WindowFrameKey]];
573      }
574   }
575
576   [self loadEffectUI];
577
578   return YES;
579}
580
581- (NSData *)dataOfType:(NSString *)type error:(NSError **)error {
582   CFPropertyListRef classInfo;
583   UInt32 infoSize = sizeof(classInfo);
584   OSStatus const status = AudioUnitGetProperty(effectUnit,
585                                     kAudioUnitProperty_ClassInfo,
586                                     kAudioUnitScope_Global,
587                                     0,
588                                     &classInfo,
589                                     &infoSize);
590   if (noErr != status)
591   {
592      if (NULL != error)
593      {
594         NSString const *message = @"Error getting effect settings";
595         NSError const *underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
596         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,      NSLocalizedDescriptionKey,
597                                                              underlying,   NSUnderlyingErrorKey,
598                                                              nil];
599         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
600      }
601      return nil;
602   }
603   NSDictionary *desc = nil;
604   if ([type isEqualToString:AUEffectDocumentType])
605   {
606      NSNumber const *typeVal = [NSNumber numberWithUnsignedLong:description.componentType];
607      NSNumber const *subtypeVal = [NSNumber numberWithUnsignedLong:description.componentSubType];
608      NSNumber const *manufacturerVal = [NSNumber numberWithUnsignedLong:description.componentManufacturer];
609      NSNumber const *forceGenericViewVal = [NSNumber numberWithBool:forceGenericView];
610      NSString const *windowFrameVal = [window stringWithSavedFrame];
611      desc = [NSDictionary dictionaryWithObjectsAndKeys:typeVal,              ComponentTypeKey,
612                                            subtypeVal,           ComponentSubTypeKey,
613                                            manufacturerVal,      ComponentManufacturerKey,
614                                            classInfo,            ClassInfoKey,
615                                            forceGenericViewVal,  ForceGenericViewKey,
616                                            windowFrameVal,       WindowFrameKey,
617                                            nil];
618   }
619   else if ([type isEqualToString:AUPresetDocumentType])
620   {
621      desc = [NSDictionary dictionaryWithDictionary:(NSDictionary *)classInfo];
622   }
623   CFRelease(classInfo);
624   if (nil == desc)
625   {
626         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:@"Unsupported document type", NSLocalizedDescriptionKey,
627                                                              nil];
628         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
629      return nil;
630   }
631
632   NSString *errDesc = nil;
633   NSData *const data = [NSPropertyListSerialization dataFromPropertyList:desc
634                                                   format:NSPropertyListXMLFormat_v1_0
635                                            errorDescription:&errDesc];
636   if ((nil == data) || (nil != errDesc))
637   {
638      if (NULL != error)
639      {
640         NSString *message;
641         if (nil != errDesc)
642            message = [NSString stringWithFormat:@"Error serialising effect settings: %@", errDesc];
643         else
644            message = @"Error serialising effect settings";
645         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,  NSLocalizedDescriptionKey,
646                                                              nil];
647         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
648      }
649      if (nil != errDesc) [errDesc release];
650      return nil;
651   }
652   return data;
653}
654
655- (IBAction)toggleGenericView:(id)sender {
656   forceGenericView = (NSOnState == [sender state]);
657   if (nil != view)
658   {
659      [[NSNotificationCenter defaultCenter] removeObserver:self
660                                          name:NSViewFrameDidChangeNotification
661                                         object:nil];
662      [view removeFromSuperview];
663      view = nil;
664   }
665   if (0 != effectNode)
666      [self loadEffectUI];
667}
668
669- (IBAction)loadPreset:(id)sender {
670   OSStatus status;
671
672   CFIndex const idx = [sender tag];
673   CFIndex const total = (NULL == presets) ? 0 : CFArrayGetCount(presets);
674   if ((0 > idx) || (total <= idx))
675   {
676      NSAlert const *alert = [[NSAlert alloc] init];
677      [alert setMessageText:@"Invalid preset selected"];
678      [alert setInformativeText:[NSString stringWithFormat:@"Tried to select preset %ld of %ld",
679                                              (long)idx + 1,
680                                              (long)total]];
681      [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
682      return;
683   }
684
685   AUPreset const *preset = (AUPreset const *)CFArrayGetValueAtIndex(presets, idx);
686   status = AudioUnitSetProperty(effectUnit,
687                          kAudioUnitProperty_PresentPreset,
688                          kAudioUnitScope_Global,
689                          0,
690                          preset,
691                          sizeof(AUPreset));
692   if (noErr != status)
693   {
694      NSAlert const *alert = [[NSAlert alloc] init];
695      [alert setMessageText:[NSString stringWithFormat:@"Error loading preset %@", preset->presetName]];
696      [alert setInformativeText:[NSString stringWithFormat:@"Error %ld encountered while setting AudioUnit property",
697                                              (long)status]];
698      [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
699      return;
700   }
701
702   AudioUnitParameter change = { effectUnit, kAUParameterListener_AnyParameter, 0, 0 };
703   status = AUParameterListenerNotify(NULL, NULL, &change);
704   if (noErr != status)
705   {
706      NSAlert const *alert = [[NSAlert alloc] init];
707      [alert setMessageText:[NSString stringWithFormat:@"Error notifying of parameter changes for preset %@",
708                                           preset->presetName]];
709      [alert setInformativeText:[NSString stringWithFormat:@"Error %ld encountered while sending notification",
710                                              (long)status]];
711      [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
712      return;
713   }
714}
715
716- (void)viewFrameDidChange:(NSNotification *)notification {
717   NSRect const oldFrame = [window frame];
718   NSRect const desired = [window frameRectForContentRect:[[notification object] frame]];
719   NSRect const newFrame = NSMakeRect(oldFrame.origin.x,
720                              oldFrame.origin.y + oldFrame.size.height - headerSize.height- desired.size.height,
721                              desired.size.width,
722                              headerSize.height + desired.size.height);
723   [window setFrame:newFrame display:YES animate:NO];
724}
725
726@end
727
728
729@interface AUEffectUtilAppDelegate : NSObject <NSApplicationDelegate>
730{
731   EffectInfo      *effects;
732
733   IBOutlet NSMenu *newEffectMenu;
734}
735
736- (id)init;
737- (void)dealloc;
738
739- (IBAction)newEffect:(id)sender;
740
741- (void)applicationWillFinishLaunching:(NSNotification *)notification;
742- (void)applicationDidFinishLaunching:(NSNotification *)notification;
743- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender;
744
745@end
746
747@implementation AUEffectUtilAppDelegate
748
749- (void)appendApplicationMenu:(NSMenu *)parent {
750   NSMenuItem *item;
751   NSMenu *submenu;
752   NSString *const appName = [(NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()) objectForKey:@"CFBundleName"];
753
754   NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Application"];
755   item = [parent addItemWithTitle:@"Application" action:NULL keyEquivalent:@""];
756   [parent setSubmenu:menu forItem:item];
757   [menu release];
758   [menu setValue:@"NSAppleMenu" forKey:@"name"];
759
760   item = [menu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
761   [item setTarget:NSApp];
762
763   [menu addItem:[NSMenuItem separatorItem]];
764
765   item = [menu addItemWithTitle:@"Services" action:NULL keyEquivalent:@""];
766   submenu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Services"];
767   [menu setSubmenu:submenu forItem:item];
768   [submenu release];
769   [NSApp setServicesMenu:submenu];
770
771   [menu addItem:[NSMenuItem separatorItem]];
772   
773   item = [menu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] action:@selector(hide:) keyEquivalent:@"h"];
774   item = [menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
775   [item setKeyEquivalentModifierMask:NSCommandKeyMask | NSAlternateKeyMask];
776   item = [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
777
778   [menu addItem:[NSMenuItem separatorItem]];
779
780   item = [menu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] action:@selector(terminate:) keyEquivalent:@"q"];
781   [item setTarget:NSApp];
782}
783
784- (void)appendFileMenu:(NSMenu *)parent {
785   NSMenuItem *item;
786
787   NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"File"];
788   item = [parent addItemWithTitle:@"File" action:NULL keyEquivalent:@""];
789   [parent setSubmenu:menu forItem:item];
790   [menu release];
791
792   item = [menu addItemWithTitle:@"New" action:NULL keyEquivalent:@""];
793   newEffectMenu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"New"];
794   [menu setSubmenu:newEffectMenu forItem:item];
795   [newEffectMenu release];
796   item = [menu addItemWithTitle:[NSString stringWithFormat:@"Open%C", (unichar)0x2026] action:@selector(openDocument:) keyEquivalent:@"o"];
797   
798   [menu addItem:[NSMenuItem separatorItem]];
799   
800   item = [menu addItemWithTitle:@"Close" action:@selector(performClose:) keyEquivalent:@"w"];
801   item = [menu addItemWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"];
802   item = [menu addItemWithTitle:[NSString stringWithFormat:@"Save As%C", (unichar)0x2026] action:@selector(saveDocumentAs:) keyEquivalent:@"S"];
803   item = [menu addItemWithTitle:@"Save All" action:@selector(saveAllDocuments:) keyEquivalent:@""];
804   item = [menu addItemWithTitle:@"Revert to Saved" action:@selector(revertDocumentToSaved:) keyEquivalent:@"u"];
805}
806
807- (void)appendEditMenu:(NSMenu *)parent {
808   NSMenuItem *item;
809
810   NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Edit"];
811   item = [parent addItemWithTitle:@"Edit" action:NULL keyEquivalent:@""];
812   [parent setSubmenu:menu forItem:item];
813   [menu release];
814
815   item = [menu addItemWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:@"z"];
816   item = [menu addItemWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:@"Z"];
817
818   [menu addItem:[NSMenuItem separatorItem]];
819
820   item = [menu addItemWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"];
821   item = [menu addItemWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"];
822   item = [menu addItemWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"];
823   item = [menu addItemWithTitle:@"Delete" action:@selector(delete:) keyEquivalent:@""];
824   item = [menu addItemWithTitle:@"Select All" action:@selector(selectAll:) keyEquivalent:@"a"];
825}
826
827- (void)appendWindowMenu:(NSMenu *)parent {
828   NSMenuItem *item;
829
830   NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Window"];
831   item = [parent addItemWithTitle:@"Window" action:NULL keyEquivalent:@""];
832   [parent setSubmenu:menu forItem:item];
833   [menu release];
834   [NSApp setWindowsMenu:menu];
835
836   item = [menu addItemWithTitle:@"Minimize" action:@selector(performMinimize:) keyEquivalent:@"m"];
837   item = [menu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
838
839   [menu addItem:[NSMenuItem separatorItem]];
840
841   item = [menu addItemWithTitle:@"Bring All to Front" action:@selector(arrangeInFront:) keyEquivalent:@""];
842}
843
844- (void)appendHelpMenu:(NSMenu *)parent {
845   NSMenuItem *item;
846   NSString *const appName = [(NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()) objectForKey:@"CFBundleName"];
847
848   NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Help"];
849   item = [parent addItemWithTitle:@"Help" action:NULL keyEquivalent:@""];
850   [parent setSubmenu:menu forItem:item];
851   [menu release];
852   [menu setValue:@"NSHelpMenu" forKey:@"name"];
853   if ([NSApp respondsToSelector:@selector(setHelpMenu:)])
854      [NSApp performSelector:@selector(setHelpMenu:) withObject:menu];
855
856   item = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ Help", appName] action:@selector(showHelp:) keyEquivalent:@"?"];
857}
858
859- (id)init {
860   if (!(self = [super init])) return nil;
861   effects = NULL;
862   return self;
863}
864
865- (void)dealloc {
866   if (effects) free(effects);
867   [super dealloc];
868}
869
870- (IBAction)newEffect:(id)sender {
871   int const index = [sender tag];
872   if ((0 > index) || (0 == effects[index].component))
873   {
874      NSAlert *const alert = [[NSAlert alloc] init];
875      [alert setAlertStyle:NSWarningAlertStyle];
876      [alert setMessageText:@"Invalid effect component"];
877      [alert addButtonWithTitle:@"OK"];
878      [alert runModal];
879      [alert release];
880      return;
881   }
882
883   NSNumber *const typeValue = [NSNumber numberWithUnsignedLong:effects[index].type];
884   NSNumber *const subtypeValue = [NSNumber numberWithUnsignedLong:effects[index].subtype];
885   NSNumber *const manufacturerValue = [NSNumber numberWithUnsignedLong:effects[index].manufacturer];
886   NSDictionary *const desc = [NSDictionary dictionaryWithObjectsAndKeys:typeValue,            ComponentTypeKey,
887                                                        subtypeValue,         ComponentSubTypeKey,
888                                                        manufacturerValue,    ComponentManufacturerKey,
889                                                        nil];
890   NSString *errDesc = nil;
891   NSData *const data = [NSPropertyListSerialization dataFromPropertyList:desc
892                                                   format:NSPropertyListXMLFormat_v1_0
893                                            errorDescription:&errDesc];
894   if ((nil == data) || (nil != errDesc))
895   {
896      NSAlert *const alert = [[NSAlert alloc] init];
897      [alert setAlertStyle:NSWarningAlertStyle];
898      [alert setMessageText:@"Error serialising properties for new effect"];
899      if (nil != errDesc) [alert setInformativeText:[errDesc autorelease]];
900      [alert addButtonWithTitle:@"OK"];
901      [alert runModal];
902      [alert release];
903      return;
904   }
905
906   NSError *err = nil;
907   AUEffectDocument *const document = [[AUEffectDocument alloc] init];
908   if ((nil == document) || ![document readFromData:data ofType:AUEffectDocumentType error:&err])
909   {
910      [document release];
911      if (nil != err)
912      {
913         [[NSAlert alertWithError:err] runModal];
914      }
915      else
916      {
917         NSAlert *const alert = [[NSAlert alloc] init];
918         [alert setAlertStyle:NSWarningAlertStyle];
919         [alert setMessageText:@"Error creating new effect document"];
920         [alert addButtonWithTitle:@"OK"];
921         [alert runModal];
922         [alert release];
923      }
924      return;
925   }
926
927   [document makeWindowControllers];
928   [document showWindows];
929   [[NSDocumentController sharedDocumentController] addDocument:document];
930   [document release];
931}
932
933- (void)applicationWillFinishLaunching:(NSNotification *)notification {
934   NSMenu *const menubar = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"MainMenu"];
935   [NSApp setMainMenu:menubar];
936   [menubar release];
937   [self appendApplicationMenu:menubar];
938   [self appendFileMenu:menubar];
939   [self appendEditMenu:menubar];
940   [self appendWindowMenu:menubar];
941   [self appendHelpMenu:menubar];
942
943   ProcessSerialNumber const serial = { 0, kCurrentProcess };
944   OSStatus const status = TransformProcessType(&serial, kProcessTransformToForegroundApplication);
945   if (noErr != status)
946   {
947      NSLog(@"Error transforming to foreground application (%ld)", (long)status);
948      [NSApp terminate:self];
949   }
950   else
951   {
952      [NSApp activateIgnoringOtherApps:YES];
953   }
954}
955
956- (void)applicationDidFinishLaunching:(NSNotification *)notification {
957   ComponentDescription effectFilter = { kAudioUnitType_Effect, 0, 0, 0, 0 };
958   long const count = CountComponents(&effectFilter);
959   if (0 == count)
960   {
961      NSAlert *const alert = [[NSAlert alloc] init];
962      [alert setAlertStyle:NSWarningAlertStyle];
963      [alert setMessageText:@"No AudioUnit effects found"];
964      [alert addButtonWithTitle:@"OK"];
965      [alert runModal];
966      [alert release];
967   }
968
969   std::vector<std::pair<Component, OSStatus> > failed;
970   effects = (EffectInfo *)malloc(count * sizeof(*effects));
971   Component effect = FindNextComponent(0, &effectFilter);
972   for (long i = 0; (i < count) && (effect != 0); i++, effect = FindNextComponent(effect, &effectFilter))
973   {
974      ComponentDescription effectDesc;
975      Handle const nameHandle = NewHandle(4);
976      OSStatus const err = GetComponentInfo(effect, &effectDesc, nameHandle, NULL, NULL);
977      if (noErr == err)
978      {
979         effects[i].component = effect;
980         effects[i].type = effectDesc.componentType;
981         effects[i].subtype = effectDesc.componentSubType;
982         effects[i].manufacturer = effectDesc.componentManufacturer;
983         HLock(nameHandle);
984         CFStringRef name = CFStringCreateWithPascalString(NULL,
985                                               (unsigned char const *)*nameHandle,
986                                               kCFStringEncodingMacRoman);
987         HUnlock(nameHandle);
988         NSMenuItem *const item = [newEffectMenu addItemWithTitle:(NSString *)name
989                                               action:@selector(newEffect:)
990                                          keyEquivalent:@""];
991         [item setTag:i];
992         [item setTarget:self];
993         CFRelease(name);
994      }
995      else
996      {
997         effects[i].component = 0;
998         failed.push_back(std::make_pair(effect, err));
999      }
1000      DisposeHandle(nameHandle);
1001   }
1002
1003   if (!failed.empty())
1004   {
1005      NSString *const message = [NSString stringWithFormat:@"Failed to get info for %lu effect%s",
1006                                              (unsigned long)failed.size(),
1007                                              ((1U == failed.size()) ? "" : "s")];
1008      NSMutableString *const detail = [NSMutableString stringWithCapacity:(16 * failed.size())];
1009      std::vector<std::pair<Component, OSStatus> >::const_iterator it = failed.begin();
1010      [detail appendFormat:@"%lu (%ld)", (unsigned long)it->first, (long)it->second];
1011      ++it;
1012      while (failed.end() != it)
1013      {
1014         [detail appendFormat:@", %lu (%ld)", (unsigned long)it->first, (long)it->second];
1015         ++it;
1016      }
1017      NSAlert *const alert = [[NSAlert alloc] init];
1018      [alert setAlertStyle:NSWarningAlertStyle];
1019      [alert setMessageText:message];
1020      [alert setInformativeText:[NSString stringWithString:detail]];
1021      [alert addButtonWithTitle:@"OK"];
1022      [alert runModal];
1023      [alert release];
1024   }
1025}
1026
1027- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
1028   return NO;
1029}
1030
1031@end
1032
1033
1034int main(int argc, char *argv[])
1035{
1036   NSAutoreleasePool *pool;
1037
1038   // Initialise NSApplication
1039   pool = [[NSAutoreleasePool alloc] init];
1040   [NSApplication sharedApplication];
1041   AUEffectUtilAppDelegate *const delegate = [[AUEffectUtilAppDelegate alloc] init];
1042   [[NSApplication sharedApplication] setDelegate:delegate];
1043   [pool release];
1044
1045   // Let's go!
1046   pool = [[NSAutoreleasePool alloc] init];
1047   [NSApp run];
1048   [delegate release];
1049   [pool release];
1050   return 0;
1051}
trunk/src/osd/sdl/aueffectutil.mm
r0r250165
1#import <AvailabilityMacros.h>
2#import <AudioUnit/AudioUnit.h>
3#import <AudioUnit/AUCocoaUIView.h>
4#import <AudioToolbox/AudioToolbox.h>
5#import <Cocoa/Cocoa.h>
6#import <CoreAudio/CoreAudio.h>
7#import <CoreAudioKit/CoreAudioKit.h>
8#import <CoreFoundation/CoreFoundation.h>
9#import <CoreServices/CoreServices.h>
10
11#include <utility>
12#include <vector>
13
14#include <stdlib.h>
15
16
17#ifdef MAC_OS_X_VERSION_MAX_ALLOWED
18
19#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
20
21typedef ComponentDescription AudioComponentDescription;
22
23@protocol NSApplicationDelegate <NSObject>
24@end
25
26@protocol NSWindowDelegate <NSObject>
27@end
28
29#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1060
30
31#endif // MAC_OS_X_VERSION_MAX_ALLOWED
32
33
34struct EffectInfo
35{
36   Component   component;
37   OSType      type;
38   OSType      subtype;
39   OSType      manufacturer;
40};
41
42
43static NSString *const AUEffectUtilErrorDomain  = @"AUEffectUtilErrorDomain";
44
45static NSString *const AUEffectDocumentType     = @"AUEffect";
46static NSString *const AUPresetDocumentType     = @"AudioUnit Preset";
47
48static NSString *const ComponentTypeKey         = @"ComponentType";
49static NSString *const ComponentSubTypeKey      = @"ComponentSubType";
50static NSString *const ComponentManufacturerKey = @"ComponentManufacturer";
51static NSString *const ClassInfoKey             = @"ClassInfo";
52static NSString *const ForceGenericViewKey      = @"ForceGenericView";
53static NSString *const WindowFrameKey           = @"WindowFrame";
54
55
56static void UpdateChangeCountCallback(void                      *userData,
57                             void                      *object,
58                             AudioUnitEvent const      *inEvent,
59                             UInt64                    inEventHostTime,
60                             AudioUnitParameterValue   inParameterValue)
61{
62   [(NSDocument *)userData updateChangeCount:NSChangeDone];
63}
64
65
66@interface AUEffectDocument : NSDocument <NSWindowDelegate>
67{
68   IBOutlet NSWindow           *window;
69   IBOutlet NSButton           *genericViewButton;
70   IBOutlet NSPopUpButton      *presetButton;
71   NSView                      *view;
72   NSSize                      headerSize;
73   CFArrayRef                  presets;
74   AUParameterListenerRef      listener;
75   BOOL                        forceGenericView;
76   NSString                    *restoreFrame;
77
78   AudioComponentDescription   description;
79   AUGraph                     graph;
80   AUNode                      outputNode, sourceNode, effectNode;
81   AudioUnit                   outputUnit, sourceUnit, effectUnit;
82}
83
84- (void)dealloc;
85
86- (void)makeWindowControllers;
87- (BOOL)readFromData:(NSData *)data ofType:(NSString *)type error:(NSError **)error;
88- (NSData *)dataOfType:(NSString *)type error:(NSError **)error;
89
90- (IBAction)toggleGenericView:(id)sender;
91- (IBAction)loadPreset:(id)sender;
92
93- (void)viewFrameDidChange:(NSNotification *)notification;
94
95@end
96
97@implementation AUEffectDocument
98
99- (void)loadEffectUI {
100   if ((0 == effectNode) || (nil == window))
101      return;
102
103   BOOL customViewValid = NO;
104   OSStatus status;
105   UInt32 uiDescSize;
106   AudioUnitCocoaViewInfo *viewInfo;
107   status = AudioUnitGetPropertyInfo(effectUnit,
108                             kAudioUnitProperty_CocoaUI,
109                             kAudioUnitScope_Global,
110                             0,
111                             &uiDescSize,
112                             NULL);
113   UInt32 const uiClassCount = 1 + ((uiDescSize - sizeof(*viewInfo)) / sizeof(viewInfo->mCocoaAUViewClass[0]));
114   if ((noErr == status) && (0 < uiClassCount))
115   {
116      viewInfo = (AudioUnitCocoaViewInfo *)malloc(uiDescSize);
117      status = AudioUnitGetProperty(effectUnit,
118                             kAudioUnitProperty_CocoaUI,
119                             kAudioUnitScope_Global,
120                             0,
121                             viewInfo,
122                             &uiDescSize);
123      if (noErr == status)
124      {
125         NSBundle *const bundle = [NSBundle bundleWithPath:[(NSURL *)viewInfo->mCocoaAUViewBundleLocation path]];
126         Class const viewClass = [bundle classNamed:(NSString *)viewInfo->mCocoaAUViewClass[0]];
127         if ((NULL != viewClass)
128          && [viewClass conformsToProtocol:@protocol(AUCocoaUIBase)]
129          && [viewClass instancesRespondToSelector:@selector(uiViewForAudioUnit:withSize:)])
130         {
131            customViewValid = YES;
132            if (!forceGenericView)
133            {
134               id const factory = [[viewClass alloc] init];
135               view = [factory uiViewForAudioUnit:effectUnit
136                                   withSize:[[window contentView] bounds].size];
137               [factory release];
138            }
139         }
140         CFRelease(viewInfo->mCocoaAUViewBundleLocation);
141         for (UInt32 i = 0; i < uiClassCount; i++)
142            CFRelease(viewInfo->mCocoaAUViewClass[i]);
143      }
144      free(viewInfo);
145   }
146   if (nil == view)
147   {
148      view = [[[AUGenericView alloc] initWithAudioUnit:effectUnit] autorelease];
149      [(AUGenericView *)view setShowsExpertParameters:YES];
150   }
151
152   [view setAutoresizingMask:NSViewNotSizable];
153   [view setFrameOrigin:NSMakePoint(0, 0)];
154   NSRect const oldFrame = [window frame];
155   NSRect const desired = [window frameRectForContentRect:[view frame]];
156   NSRect const newFrame = NSMakeRect(oldFrame.origin.x,
157                              oldFrame.origin.y + oldFrame.size.height - headerSize.height - desired.size.height,
158                              desired.size.width,
159                              headerSize.height + desired.size.height);
160   [window setFrame:newFrame display:YES animate:NO];
161   [[window contentView] addSubview:view];
162   [view setPostsFrameChangedNotifications:YES];
163   [[NSNotificationCenter defaultCenter] addObserver:self
164                                  selector:@selector(viewFrameDidChange:)
165                                     name:NSViewFrameDidChangeNotification
166                                    object:view];
167
168   [genericViewButton setEnabled:customViewValid];
169   if (!customViewValid)
170   {
171      forceGenericView = YES;
172      [genericViewButton setState:NSOnState];
173   }
174
175   CFIndex const presetCount = (NULL != presets) ? CFArrayGetCount(presets) : 0;
176   [presetButton setEnabled:(0 < presetCount)];
177   while (1 < [presetButton numberOfItems])
178      [presetButton removeItemAtIndex:1];
179   for (CFIndex i = 0; i < presetCount; i++)
180   {
181      AUPreset const *preset = (AUPreset const*)CFArrayGetValueAtIndex(presets, i);
182      NSMenuItem const *item = [[presetButton menu] addItemWithTitle:(NSString *)preset->presetName
183                                                action:@selector(loadPreset:)
184                                           keyEquivalent:@""];
185      [item setTarget:self];
186      [item setTag:i];
187   }
188}
189
190- (id)init {
191   if (!(self = [super init])) return nil;
192
193   window = nil;
194   genericViewButton = nil;
195   presetButton = nil;
196   view = nil;
197   presets = NULL;
198   listener = NULL;
199   forceGenericView = NO;
200   restoreFrame = nil;
201
202   description.componentType = description.componentSubType = description.componentManufacturer = 0;
203   description.componentFlags = description.componentFlagsMask = 0;
204   graph = NULL;
205   outputNode = sourceNode = effectNode = 0;
206
207   AudioComponentDescription const outputDesc = { kAudioUnitType_Output,
208                                       kAudioUnitSubType_DefaultOutput,
209                                       kAudioUnitManufacturer_Apple,
210                                       0,
211                                       0, };
212   AudioComponentDescription const sourceDesc = { kAudioUnitType_Generator,
213                                       kAudioUnitSubType_AudioFilePlayer,
214                                       kAudioUnitManufacturer_Apple,
215                                       0,
216                                       0, };
217   if ((noErr != NewAUGraph(&graph))
218    || (noErr != AUGraphAddNode(graph, &outputDesc, &outputNode))
219    || (noErr != AUGraphAddNode(graph, &sourceDesc, &sourceNode))
220    || (noErr != AUGraphOpen(graph))
221    || (noErr != AUGraphNodeInfo(graph, outputNode, NULL, &outputUnit))
222    || (noErr != AUGraphNodeInfo(graph, sourceNode, NULL, &sourceUnit))
223    || (noErr != AUGraphInitialize(graph)))
224   {
225      [self release];
226      return nil;
227   }
228
229   return self;
230}
231
232- (void)dealloc {
233   if (NULL != presets)
234      CFRelease(presets);
235
236   if (NULL != listener)
237      AUListenerDispose(listener);
238
239   if (nil != restoreFrame)
240      [restoreFrame release];
241
242   if (NULL != graph)
243   {
244      AUGraphClose(graph);
245      DisposeAUGraph(graph);
246   }
247
248   [super dealloc];
249}
250
251- (void)makeWindowControllers {
252   genericViewButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 18)];
253   [genericViewButton setAutoresizingMask:NSViewNotSizable];
254   [[genericViewButton cell] setControlSize:NSSmallControlSize];
255   [genericViewButton setButtonType:NSSwitchButton];
256   [genericViewButton setBordered:NO];
257   [genericViewButton setAllowsMixedState:NO];
258   [genericViewButton setState:(forceGenericView ? NSOnState : NSOffState)];
259   [genericViewButton setTitle:@"Use generic editor view"];
260   [genericViewButton setAction:@selector(toggleGenericView:)];
261   [genericViewButton setTarget:self];
262   [genericViewButton sizeToFit];
263
264   presetButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 22) pullsDown:YES];
265   [presetButton setAutoresizingMask:NSViewNotSizable];
266   [[presetButton cell] setControlSize:NSSmallControlSize];
267   [[presetButton cell] setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
268   [presetButton setTitle:@"Load preset"];
269   [[[presetButton menu] addItemWithTitle:@"Load preset" action:NULL keyEquivalent:@""] setHidden:YES];
270   [presetButton sizeToFit];
271
272   CGFloat const controlWidth = MAX(NSWidth([genericViewButton frame]), NSWidth([presetButton frame]));
273   NSRect const presetFrame = NSMakeRect(17,
274                                8,
275                                controlWidth,
276                                NSHeight([presetButton frame]));
277   NSRect const genericViewFrame = NSMakeRect(17,
278                                    NSMaxY(presetFrame) + 9,
279                                    controlWidth,
280                                    NSHeight([genericViewButton frame]));
281   [genericViewButton setFrame:genericViewFrame];
282   [presetButton setFrame:presetFrame];
283
284   headerSize = NSMakeSize((2 * 17) + controlWidth, 18 + NSMaxY(genericViewFrame));
285   NSView *const container = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, headerSize.width, headerSize.height)];
286   [container setAutoresizingMask:(NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin)];
287   [container addSubview:genericViewButton];
288   [genericViewButton release];
289   [container addSubview:presetButton];
290   [presetButton release];
291
292   window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, headerSize.width, headerSize.height)
293                               styleMask:(NSTitledWindowMask |
294                                       NSClosableWindowMask |
295                                       NSMiniaturizableWindowMask)
296                                 backing:NSBackingStoreBuffered
297                                  defer:YES];
298   [window setReleasedWhenClosed:NO];
299   [window setDelegate:self];
300   [window setTitle:@"Effect"];
301   [[window contentView] addSubview:container];
302   [container release];
303   [self setWindow:window];
304
305   NSWindowController *const controller = [[NSWindowController alloc] initWithWindow:window];
306   [self addWindowController:controller];
307   [controller release];
308   [window release];
309
310   [self loadEffectUI];
311   if (nil != restoreFrame)
312   {
313      [window setFrameFromString:restoreFrame];
314   }
315   else
316   {
317      NSRect const available = [[NSScreen mainScreen] visibleFrame];
318      NSRect frame = [window frame];
319      frame.origin.x = (NSWidth(available) - NSWidth(frame)) / 4;
320      frame.origin.y = (NSHeight(available) - NSHeight(frame)) * 3 / 4;
321      [window setFrame:frame display:YES animate:NO];
322   }
323}
324
325- (BOOL)readFromData:(NSData *)data ofType:(NSString *)type error:(NSError **)error {
326   OSStatus status;
327   UInt32 propertySize;
328
329   BOOL const hasWrapper = [type isEqualToString:AUEffectDocumentType];
330   if (!hasWrapper && ![type isEqualToString:AUPresetDocumentType])
331   {
332      if (NULL != error)
333      {
334         NSString *const message = [NSString stringWithFormat:@"Unsupported document type %@", type];
335         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,  NSLocalizedDescriptionKey,
336                                                              nil];
337         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
338      }
339      return NO;
340   }
341
342   NSString *errDesc = nil;
343   id const desc = [NSPropertyListSerialization propertyListFromData:data
344                                        mutabilityOption:0
345                                                 format:NULL
346                                        errorDescription:&errDesc];
347   if ((nil == desc) || ![desc isKindOfClass:[NSDictionary class]] || (nil != errDesc))
348   {
349      if (NULL != error)
350      {
351         NSString *const message = [NSString stringWithFormat:@"Error in file format (%@)", errDesc];
352         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,  NSLocalizedDescriptionKey,
353                                                              nil];
354         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
355      }
356      if (nil != errDesc)
357         [errDesc release];
358      return NO;
359   }
360
361   id const typeValue = [desc objectForKey:(hasWrapper ? ComponentTypeKey : (NSString *)CFSTR(kAUPresetTypeKey))];
362   id const subtypeValue = [desc objectForKey:(hasWrapper ? ComponentSubTypeKey : (NSString *)CFSTR(kAUPresetSubtypeKey))];
363   id const manufacturerValue = [desc objectForKey:(hasWrapper ? ComponentManufacturerKey : (NSString *)CFSTR(kAUPresetManufacturerKey))];
364   if ((nil == typeValue)          || ![typeValue isKindOfClass:[NSNumber class]]
365    || (nil == subtypeValue)       || ![subtypeValue isKindOfClass:[NSNumber class]]
366    || (nil == manufacturerValue)  || ![manufacturerValue isKindOfClass:[NSNumber class]]
367    || ([typeValue unsignedLongValue] != kAudioUnitType_Effect))
368   {
369      if (NULL != error)
370      {
371         NSString *const message = @"Error in effect description file format";
372         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,  NSLocalizedDescriptionKey,
373                                                              nil];
374         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
375      }
376      return NO;
377   }
378
379   if (NULL != presets)
380   {
381      CFRelease(presets);
382      presets = NULL;
383   }
384   if (NULL != listener)
385   {
386      AUListenerDispose(listener);
387      listener = NULL;
388   }
389   if (nil != view)
390   {
391      [[NSNotificationCenter defaultCenter] removeObserver:self
392                                          name:NSViewFrameDidChangeNotification
393                                         object:nil];
394      [view removeFromSuperview];
395      view = nil;
396   }
397   if (0 != effectNode)
398   {
399      view = nil;
400      AUGraphRemoveNode(graph, effectNode);
401      effectNode = 0;
402   }
403
404   description.componentType = [typeValue longValue];
405   description.componentSubType = [subtypeValue longValue];
406   description.componentManufacturer = [manufacturerValue longValue];
407   status = noErr;
408   status = AUGraphClearConnections(graph);
409   if (noErr == status) status = AUGraphAddNode(graph, &description, &effectNode);
410   if (noErr == status) status = AUGraphNodeInfo(graph, effectNode, NULL, &effectUnit);
411   if (noErr == status) status = AUGraphConnectNodeInput(graph, sourceNode, 0, effectNode, 0);
412   if (noErr == status) status = AUGraphConnectNodeInput(graph, effectNode, 0, outputNode, 0);
413   if (noErr == status) status = AUGraphUpdate(graph, NULL);
414   if (noErr != status)
415   {
416      if (NULL != error)
417      {
418         NSString * const message = @"Error encountered while configuring AudioUnit graph";
419         NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
420         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
421                                                              underlying,    NSUnderlyingErrorKey,
422                                                              nil];
423         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
424      }
425      return NO;
426   }
427
428   CFPropertyListRef const classInfo = (CFPropertyListRef)(hasWrapper ? [desc objectForKey:ClassInfoKey] : desc);
429   if (NULL != classInfo)
430   {
431      AudioUnitParameter change = { effectUnit, kAUParameterListener_AnyParameter, 0, 0 };
432      status = AudioUnitSetProperty(effectUnit,
433                             kAudioUnitProperty_ClassInfo,
434                             kAudioUnitScope_Global,
435                             0,
436                             &classInfo,
437                             sizeof(classInfo));
438      if (noErr == status) status = AUParameterListenerNotify(NULL, NULL, &change);
439      if (noErr != status)
440      {
441         if (NULL != error)
442         {
443            NSString * const message = @"Error configuring effect";
444            NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
445            NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
446                                                                 underlying,    NSUnderlyingErrorKey,
447                                                                 nil];
448            *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
449         }
450         return NO;
451      }
452   }
453
454   propertySize = 0;
455   status = AudioUnitGetPropertyInfo(
456         effectUnit,
457         kAudioUnitProperty_ParameterList,
458         kAudioUnitScope_Global,
459         0,
460         &propertySize,
461         NULL);
462   if (noErr != status)
463   {
464      if (NULL != error)
465      {
466         NSString * const message = @"Error getting effect parameters";
467         NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
468         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
469                                                              underlying,    NSUnderlyingErrorKey,
470                                                              nil];
471         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
472      }
473      return NO;
474   }
475   UInt32 const paramCount = propertySize / sizeof(AudioUnitParameterID);
476   if (0U < paramCount)
477   {
478      status = AUEventListenerCreate(UpdateChangeCountCallback,
479                              self,
480                              CFRunLoopGetCurrent(),
481                              kCFRunLoopDefaultMode,
482                              0.05,
483                              0.05,
484                              &listener);
485      if (noErr != status)
486      {
487         if (NULL != error)
488         {
489            NSString * const message = @"Error creating AudioUnit event listener";
490            NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
491            NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
492                                                                 underlying,    NSUnderlyingErrorKey,
493                                                                 nil];
494            *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
495         }
496         return NO;
497      }
498      AudioUnitParameterID *const params = (AudioUnitParameterID *)malloc(propertySize);
499      AudioUnitGetProperty(
500            effectUnit,
501            kAudioUnitProperty_ParameterList,
502            kAudioUnitScope_Global,
503            0,
504            params,
505            &propertySize);
506      if (noErr != status)
507      {
508         free(params);
509         if (NULL != error)
510         {
511            NSString * const message = @"Error getting effect parameters";
512            NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
513            NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
514                                                                 underlying,    NSUnderlyingErrorKey,
515                                                                 nil];
516            *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
517         }
518         return NO;
519      }
520      for (UInt32 i = 0; (i < paramCount) && (noErr == status); i++)
521      {
522         AudioUnitEvent event;
523         event.mEventType = kAudioUnitEvent_ParameterValueChange;
524         event.mArgument.mParameter.mAudioUnit = effectUnit;
525         event.mArgument.mParameter.mParameterID = params[i];
526         event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
527         event.mArgument.mParameter.mElement = 0;
528         status = AUEventListenerAddEventType(listener, self, &event);
529      }
530      free(params);
531      if (noErr != status)
532      {
533         free(params);
534         if (NULL != error)
535         {
536            NSString * const message = @"Error getting effect parameters";
537            NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
538            NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,       NSLocalizedDescriptionKey,
539                                                                 underlying,    NSUnderlyingErrorKey,
540                                                                 nil];
541            *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
542         }
543         return NO;
544      }
545   }
546
547   propertySize = sizeof(presets);
548   status = AudioUnitGetProperty(effectUnit,
549                          kAudioUnitProperty_FactoryPresets,
550                          kAudioUnitScope_Global,
551                          0,
552                          &presets,
553                          &propertySize);
554   if ((noErr != status) && (NULL != presets))
555   {
556      CFRelease(presets);
557      presets = NULL;
558   }
559
560   if (hasWrapper)
561   {
562      if ((nil != [desc objectForKey:ForceGenericViewKey])
563       && [[desc objectForKey:ForceGenericViewKey] respondsToSelector:@selector(boolValue)])
564      {
565         forceGenericView = [[desc objectForKey:ForceGenericViewKey] boolValue];
566         [genericViewButton setState:(forceGenericView ? NSOnState : NSOffState)];
567      }
568      if ((nil != [desc objectForKey:WindowFrameKey])
569       && [[desc objectForKey:WindowFrameKey] isKindOfClass:[NSString class]])
570      {
571         if (nil != restoreFrame) [restoreFrame release];
572         restoreFrame = [[NSString alloc] initWithString:[desc objectForKey:WindowFrameKey]];
573      }
574   }
575
576   [self loadEffectUI];
577
578   return YES;
579}
580
581- (NSData *)dataOfType:(NSString *)type error:(NSError **)error {
582   CFPropertyListRef classInfo;
583   UInt32 infoSize = sizeof(classInfo);
584   OSStatus const status = AudioUnitGetProperty(effectUnit,
585                                     kAudioUnitProperty_ClassInfo,
586                                     kAudioUnitScope_Global,
587                                     0,
588                                     &classInfo,
589                                     &infoSize);
590   if (noErr != status)
591   {
592      if (NULL != error)
593      {
594         NSString const *message = @"Error getting effect settings";
595         NSError const *underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
596         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,      NSLocalizedDescriptionKey,
597                                                              underlying,   NSUnderlyingErrorKey,
598                                                              nil];
599         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
600      }
601      return nil;
602   }
603   NSDictionary *desc = nil;
604   if ([type isEqualToString:AUEffectDocumentType])
605   {
606      NSNumber const *typeVal = [NSNumber numberWithUnsignedLong:description.componentType];
607      NSNumber const *subtypeVal = [NSNumber numberWithUnsignedLong:description.componentSubType];
608      NSNumber const *manufacturerVal = [NSNumber numberWithUnsignedLong:description.componentManufacturer];
609      NSNumber const *forceGenericViewVal = [NSNumber numberWithBool:forceGenericView];
610      NSString const *windowFrameVal = [window stringWithSavedFrame];
611      desc = [NSDictionary dictionaryWithObjectsAndKeys:typeVal,              ComponentTypeKey,
612                                            subtypeVal,           ComponentSubTypeKey,
613                                            manufacturerVal,      ComponentManufacturerKey,
614                                            classInfo,            ClassInfoKey,
615                                            forceGenericViewVal,  ForceGenericViewKey,
616                                            windowFrameVal,       WindowFrameKey,
617                                            nil];
618   }
619   else if ([type isEqualToString:AUPresetDocumentType])
620   {
621      desc = [NSDictionary dictionaryWithDictionary:(NSDictionary *)classInfo];
622   }
623   CFRelease(classInfo);
624   if (nil == desc)
625   {
626         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:@"Unsupported document type", NSLocalizedDescriptionKey,
627                                                              nil];
628         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
629      return nil;
630   }
631
632   NSString *errDesc = nil;
633   NSData *const data = [NSPropertyListSerialization dataFromPropertyList:desc
634                                                   format:NSPropertyListXMLFormat_v1_0
635                                            errorDescription:&errDesc];
636   if ((nil == data) || (nil != errDesc))
637   {
638      if (NULL != error)
639      {
640         NSString *message;
641         if (nil != errDesc)
642            message = [NSString stringWithFormat:@"Error serialising effect settings: %@", errDesc];
643         else
644            message = @"Error serialising effect settings";
645         NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message,  NSLocalizedDescriptionKey,
646                                                              nil];
647         *error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
648      }
649      if (nil != errDesc) [errDesc release];
650      return nil;
651   }
652   return data;
653}
654
655- (IBAction)toggleGenericView:(id)sender {
656   forceGenericView = (NSOnState == [sender state]);
657   if (nil != view)
658   {
659      [[NSNotificationCenter defaultCenter] removeObserver:self
660                                          name:NSViewFrameDidChangeNotification
661                                         object:nil];
662      [view removeFromSuperview];
663      view = nil;
664   }
665   if (0 != effectNode)
666      [self loadEffectUI];
667}
668
669- (IBAction)loadPreset:(id)sender {
670   OSStatus status;
671
672   CFIndex const idx = [sender tag];
673   CFIndex const total = (NULL == presets) ? 0 : CFArrayGetCount(presets);
674   if ((0 > idx) || (total <= idx))
675   {
676      NSAlert const *alert = [[NSAlert alloc] init];
677      [alert setMessageText:@"Invalid preset selected"];
678      [alert setInformativeText:[NSString stringWithFormat:@"Tried to select preset %ld of %ld",
679                                              (long)idx + 1,
680                                              (long)total]];
681      [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
682      return;
683   }
684
685   AUPreset const *preset = (AUPreset const *)CFArrayGetValueAtIndex(presets, idx);
686   status = AudioUnitSetProperty(effectUnit,
687                          kAudioUnitProperty_PresentPreset,
688                          kAudioUnitScope_Global,
689                          0,
690                          preset,
691                          sizeof(AUPreset));
692   if (noErr != status)
693   {
694      NSAlert const *alert = [[NSAlert alloc] init];
695      [alert setMessageText:[NSString stringWithFormat:@"Error loading preset %@", preset->presetName]];
696      [alert setInformativeText:[NSString stringWithFormat:@"Error %ld encountered while setting AudioUnit property",
697                                              (long)status]];
698      [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
699      return;
700   }
701
702   AudioUnitParameter change = { effectUnit, kAUParameterListener_AnyParameter, 0, 0 };
703   status = AUParameterListenerNotify(NULL, NULL, &change);
704   if (noErr != status)
705   {
706      NSAlert const *alert = [[NSAlert alloc] init];
707      [alert setMessageText:[NSString stringWithFormat:@"Error notifying of parameter changes for preset %@",
708                                           preset->presetName]];
709      [alert setInformativeText:[NSString stringWithFormat:@"Error %ld encountered while sending notification",
710                                              (long)status]];
711      [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
712      return;
713   }
714}
715
716- (void)viewFrameDidChange:(NSNotification *)notification {
717   NSRect const oldFrame = [window frame];
718   NSRect const desired = [window frameRectForContentRect:[[notification object] frame]];
719   NSRect const newFrame = NSMakeRect(oldFrame.origin.x,
720                              oldFrame.origin.y + oldFrame.size.height - headerSize.height- desired.size.height,
721                              desired.size.width,
722                              headerSize.height + desired.size.height);
723   [window setFrame:newFrame display:YES animate:NO];
724}
725
726@end
727
728
729@interface AUEffectUtilAppDelegate : NSObject <NSApplicationDelegate>
730{
731   EffectInfo      *effects;
732
733   IBOutlet NSMenu *newEffectMenu;
734}
735
736- (id)init;
737- (void)dealloc;
738
739- (IBAction)newEffect:(id)sender;
740
741- (void)applicationWillFinishLaunching:(NSNotification *)notification;
742- (void)applicationDidFinishLaunching:(NSNotification *)notification;
743- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender;
744
745@end
746
747@implementation AUEffectUtilAppDelegate
748
749- (void)appendApplicationMenu:(NSMenu *)parent {
750   NSMenuItem *item;
751   NSMenu *submenu;
752   NSString *const appName = [(NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()) objectForKey:@"CFBundleName"];
753
754   NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Application"];
755   item = [parent addItemWithTitle:@"Application" action:NULL keyEquivalent:@""];
756   [parent setSubmenu:menu forItem:item];
757   [menu release];
758   [menu setValue:@"NSAppleMenu" forKey:@"name"];
759
760   item = [menu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
761   [item setTarget:NSApp];
762
763   [menu addItem:[NSMenuItem separatorItem]];
764
765   item = [menu addItemWithTitle:@"Services" action:NULL keyEquivalent:@""];
766   submenu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Services"];
767   [menu setSubmenu:submenu forItem:item];
768   [submenu release];
769   [NSApp setServicesMenu:submenu];
770
771   [menu addItem:[NSMenuItem separatorItem]];
772   
773   item = [menu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] action:@selector(hide:) keyEquivalent:@"h"];
774   item = [menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
775   [item setKeyEquivalentModifierMask:NSCommandKeyMask | NSAlternateKeyMask];
776   item = [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
777
778   [menu addItem:[NSMenuItem separatorItem]];
779
780   item = [menu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] action:@selector(terminate:) keyEquivalent:@"q"];
781   [item setTarget:NSApp];
782}
783
784- (void)appendFileMenu:(NSMenu *)parent {
785   NSMenuItem *item;
786
787   NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"File"];
788   item = [parent addItemWithTitle:@"File" action:NULL keyEquivalent:@""];
789   [parent setSubmenu:menu forItem:item];
790   [menu release];
791
792   item = [menu addItemWithTitle:@"New" action:NULL keyEquivalent:@""];
793   newEffectMenu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"New"];
794   [menu setSubmenu:newEffectMenu forItem:item];
795   [newEffectMenu release];
796   item = [menu addItemWithTitle:[NSString stringWithFormat:@"Open%C", (unichar)0x2026] action:@selector(openDocument:) keyEquivalent:@"o"];
797   
798   [menu addItem:[NSMenuItem separatorItem]];
799   
800   item = [menu addItemWithTitle:@"Close" action:@selector(performClose:) keyEquivalent:@"w"];
801   item = [menu addItemWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"];
802   item = [menu addItemWithTitle:[NSString stringWithFormat:@"Save As%C", (unichar)0x2026] action:@selector(saveDocumentAs:) keyEquivalent:@"S"];
803   item = [menu addItemWithTitle:@"Save All" action:@selector(saveAllDocuments:) keyEquivalent:@""];
804   item = [menu addItemWithTitle:@"Revert to Saved" action:@selector(revertDocumentToSaved:) keyEquivalent:@"u"];
805}
806
807- (void)appendEditMenu:(NSMenu *)parent {
808   NSMenuItem *item;
809
810   NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Edit"];
811   item = [parent addItemWithTitle:@"Edit" action:NULL keyEquivalent:@""];
812   [parent setSubmenu:menu forItem:item];
813   [menu release];
814
815   item = [menu addItemWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:@"z"];
816   item = [menu addItemWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:@"Z"];
817
818   [menu addItem:[NSMenuItem separatorItem]];
819
820   item = [menu addItemWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"];
821   item = [menu addItemWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"];
822   item = [menu addItemWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"];
823   item = [menu addItemWithTitle:@"Delete" action:@selector(delete:) keyEquivalent:@""];
824   item = [menu addItemWithTitle:@"Select All" action:@selector(selectAll:) keyEquivalent:@"a"];
825}
826
827- (void)appendWindowMenu:(NSMenu *)parent {
828   NSMenuItem *item;
829
830   NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Window"];
831   item = [parent addItemWithTitle:@"Window" action:NULL keyEquivalent:@""];
832   [parent setSubmenu:menu forItem:item];
833   [menu release];
834   [NSApp setWindowsMenu:menu];
835
836   item = [menu addItemWithTitle:@"Minimize" action:@selector(performMinimize:) keyEquivalent:@"m"];
837   item = [menu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
838
839   [menu addItem:[NSMenuItem separatorItem]];
840
841   item = [menu addItemWithTitle:@"Bring All to Front" action:@selector(arrangeInFront:) keyEquivalent:@""];
842}
843
844- (void)appendHelpMenu:(NSMenu *)parent {
845   NSMenuItem *item;
846   NSString *const appName = [(NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()) objectForKey:@"CFBundleName"];
847
848   NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Help"];
849   item = [parent addItemWithTitle:@"Help" action:NULL keyEquivalent:@""];
850   [parent setSubmenu:menu forItem:item];
851   [menu release];
852   [menu setValue:@"NSHelpMenu" forKey:@"name"];
853   if ([NSApp respondsToSelector:@selector(setHelpMenu:)])
854      [NSApp performSelector:@selector(setHelpMenu:) withObject:menu];
855
856   item = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ Help", appName] action:@selector(showHelp:) keyEquivalent:@"?"];
857}
858
859- (id)init {
860   if (!(self = [super init])) return nil;
861   effects = NULL;
862   return self;
863}
864
865- (void)dealloc {
866   if (effects) free(effects);
867   [super dealloc];
868}
869
870- (IBAction)newEffect:(id)sender {
871   int const index = [sender tag];
872   if ((0 > index) || (0 == effects[index].component))
873   {
874      NSAlert *const alert = [[NSAlert alloc] init];
875      [alert setAlertStyle:NSWarningAlertStyle];
876      [alert setMessageText:@"Invalid effect component"];
877      [alert addButtonWithTitle:@"OK"];
878      [alert runModal];
879      [alert release];
880      return;
881   }
882
883   NSNumber *const typeValue = [NSNumber numberWithUnsignedLong:effects[index].type];
884   NSNumber *const subtypeValue = [NSNumber numberWithUnsignedLong:effects[index].subtype];
885   NSNumber *const manufacturerValue = [NSNumber numberWithUnsignedLong:effects[index].manufacturer];
886   NSDictionary *const desc = [NSDictionary dictionaryWithObjectsAndKeys:typeValue,            ComponentTypeKey,
887                                                        subtypeValue,         ComponentSubTypeKey,
888                                                        manufacturerValue,    ComponentManufacturerKey,
889                                                        nil];
890   NSString *errDesc = nil;
891   NSData *const data = [NSPropertyListSerialization dataFromPropertyList:desc
892                                                   format:NSPropertyListXMLFormat_v1_0
893                                            errorDescription:&errDesc];
894   if ((nil == data) || (nil != errDesc))
895   {
896      NSAlert *const alert = [[NSAlert alloc] init];
897      [alert setAlertStyle:NSWarningAlertStyle];
898      [alert setMessageText:@"Error serialising properties for new effect"];
899      if (nil != errDesc) [alert setInformativeText:[errDesc autorelease]];
900      [alert addButtonWithTitle:@"OK"];
901      [alert runModal];
902      [alert release];
903      return;
904   }
905
906   NSError *err = nil;
907   AUEffectDocument *const document = [[AUEffectDocument alloc] init];
908   if ((nil == document) || ![document readFromData:data ofType:AUEffectDocumentType error:&err])
909   {
910      [document release];
911      if (nil != err)
912      {
913         [[NSAlert alertWithError:err] runModal];
914      }
915      else
916      {
917         NSAlert *const alert = [[NSAlert alloc] init];
918         [alert setAlertStyle:NSWarningAlertStyle];
919         [alert setMessageText:@"Error creating new effect document"];
920         [alert addButtonWithTitle:@"OK"];
921         [alert runModal];
922         [alert release];
923      }
924      return;
925   }
926
927   [document makeWindowControllers];
928   [document showWindows];
929   [[NSDocumentController sharedDocumentController] addDocument:document];
930   [document release];
931}
932
933- (void)applicationWillFinishLaunching:(NSNotification *)notification {
934   NSMenu *const menubar = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"MainMenu"];
935   [NSApp setMainMenu:menubar];
936   [menubar release];
937   [self appendApplicationMenu:menubar];
938   [self appendFileMenu:menubar];
939   [self appendEditMenu:menubar];
940   [self appendWindowMenu:menubar];
941   [self appendHelpMenu:menubar];
942
943   ProcessSerialNumber const serial = { 0, kCurrentProcess };
944   OSStatus const status = TransformProcessType(&serial, kProcessTransformToForegroundApplication);
945   if (noErr != status)
946   {
947      NSLog(@"Error transforming to foreground application (%ld)", (long)status);
948      [NSApp terminate:self];
949   }
950   else
951   {
952      [NSApp activateIgnoringOtherApps:YES];
953   }
954}
955
956- (void)applicationDidFinishLaunching:(NSNotification *)notification {
957   ComponentDescription effectFilter = { kAudioUnitType_Effect, 0, 0, 0, 0 };
958   long const count = CountComponents(&effectFilter);
959   if (0 == count)
960   {
961      NSAlert *const alert = [[NSAlert alloc] init];
962      [alert setAlertStyle:NSWarningAlertStyle];
963      [alert setMessageText:@"No AudioUnit effects found"];
964      [alert addButtonWithTitle:@"OK"];
965      [alert runModal];
966      [alert release];
967   }
968
969   std::vector<std::pair<Component, OSStatus> > failed;
970   effects = (EffectInfo *)malloc(count * sizeof(*effects));
971   Component effect = FindNextComponent(0, &effectFilter);
972   for (long i = 0; (i < count) && (effect != 0); i++, effect = FindNextComponent(effect, &effectFilter))
973   {
974      ComponentDescription effectDesc;
975      Handle const nameHandle = NewHandle(4);
976      OSStatus const err = GetComponentInfo(effect, &effectDesc, nameHandle, NULL, NULL);
977      if (noErr == err)
978      {
979         effects[i].component = effect;
980         effects[i].type = effectDesc.componentType;
981         effects[i].subtype = effectDesc.componentSubType;
982         effects[i].manufacturer = effectDesc.componentManufacturer;
983         HLock(nameHandle);
984         CFStringRef name = CFStringCreateWithPascalString(NULL,
985                                               (unsigned char const *)*nameHandle,
986                                               kCFStringEncodingMacRoman);
987         HUnlock(nameHandle);
988         NSMenuItem *const item = [newEffectMenu addItemWithTitle:(NSString *)name
989                                               action:@selector(newEffect:)
990                                          keyEquivalent:@""];
991         [item setTag:i];
992         [item setTarget:self];
993         CFRelease(name);
994      }
995      else
996      {
997         effects[i].component = 0;
998         failed.push_back(std::make_pair(effect, err));
999      }
1000      DisposeHandle(nameHandle);
1001   }
1002
1003   if (!failed.empty())
1004   {
1005      NSString *const message = [NSString stringWithFormat:@"Failed to get info for %lu effect%s",
1006                                              (unsigned long)failed.size(),
1007                                              ((1U == failed.size()) ? "" : "s")];
1008      NSMutableString *const detail = [NSMutableString stringWithCapacity:(16 * failed.size())];
1009      std::vector<std::pair<Component, OSStatus> >::const_iterator it = failed.begin();
1010      [detail appendFormat:@"%lu (%ld)", (unsigned long)it->first, (long)it->second];
1011      ++it;
1012      while (failed.end() != it)
1013      {
1014         [detail appendFormat:@", %lu (%ld)", (unsigned long)it->first, (long)it->second];
1015         ++it;
1016      }
1017      NSAlert *const alert = [[NSAlert alloc] init];
1018      [alert setAlertStyle:NSWarningAlertStyle];
1019      [alert setMessageText:message];
1020      [alert setInformativeText:[NSString stringWithString:detail]];
1021      [alert addButtonWithTitle:@"OK"];
1022      [alert runModal];
1023      [alert release];
1024   }
1025}
1026
1027- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
1028   return NO;
1029}
1030
1031@end
1032
1033
1034int main(int argc, char *argv[])
1035{
1036   NSAutoreleasePool *pool;
1037
1038   // Initialise NSApplication
1039   pool = [[NSAutoreleasePool alloc] init];
1040   [NSApplication sharedApplication];
1041   AUEffectUtilAppDelegate *const delegate = [[AUEffectUtilAppDelegate alloc] init];
1042   [[NSApplication sharedApplication] setDelegate:delegate];
1043   [pool release];
1044
1045   // Let's go!
1046   pool = [[NSAutoreleasePool alloc] init];
1047   [NSApp run];
1048   [delegate release];
1049   [pool release];
1050   return 0;
1051}
trunk/src/osd/sdl/osxutils.m
r250164r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  osxutils.m - Mac OS X utilities for SDLMAME
6//
7//  SDLMAME by Olivier Galibert and R. Belmont
8//
9//============================================================
10
11#import <Foundation/Foundation.h>
12
13// MAMEOS headers
14#import "osxutils.h"
15
16
17//============================================================
18//  NewAutoreleasePool
19//============================================================
20
21void * NewAutoreleasePool(void)
22{
23   return [[NSAutoreleasePool alloc] init];
24}
25
26
27//============================================================
28//  ReleaseAutoreleasePool
29//============================================================
30
31void ReleaseAutoreleasePool(void *pool)
32{
33   [(NSAutoreleasePool *)pool release];
34}
trunk/src/osd/sdl/osxutils.mm
r0r250165
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  osxutils.m - Mac OS X utilities for SDLMAME
6//
7//  SDLMAME by Olivier Galibert and R. Belmont
8//
9//============================================================
10
11#import <Foundation/Foundation.h>
12
13// MAMEOS headers
14#import "osxutils.h"
15
16
17//============================================================
18//  NewAutoreleasePool
19//============================================================
20
21void * NewAutoreleasePool(void)
22{
23   return [[NSAutoreleasePool alloc] init];
24}
25
26
27//============================================================
28//  ReleaseAutoreleasePool
29//============================================================
30
31void ReleaseAutoreleasePool(void *pool)
32{
33   [(NSAutoreleasePool *)pool release];
34}


Previous 199869 Revisions Next


© 1997-2024 The MAME Team