binutils-gdb/gdb/mac-xdep.c
Stan Shebs 58c0b523fe Wed Jun 15 17:36:07 1994 Stan Shebs (shebs@andros.cygnus.com)
* mpw-make.in (.c.o, .gc.o): Prefix segment names with gdb_.
	(top.c.o, annotate.c.o): Add build rules.
	* macgdb.r (SysTypes.r): Include.
	('vers'): New resource, version info.
	(mFile, mEdit, mDebug): Enable all menu items.
	(mDebug): Add key equivalents for continue, step, next.
	(wConsole): Add zoom and close boxes to window.
	* mac-xdep.c (new_console_window): New function, code taken from
	mac_init.
	(mac_command_loop): Use GetCaretTime for wait interval, call
	do_idle on null events.
	(do_idle): New function.
	(zoom_window): Implement zooming.
	(v_scroll_proc): New function, handles vertical scrolling.
	(activate_window): Do activation of console window.
	(do_menu_command): Implement items of file, edit, and debug menus.
	(do_keyboard_command): Fix command extraction.
	(adjust_console_sizes, adjust_console_text): New functions.
	(hacked_fprintf, hacked_vfprintf, hacked_fputs, hacked_fputc,
	hacked_putc): Don't call draw_console.
	* ser-mac.c (mac_open): Add an error message for invalid ports.
	(first_mac_write): New global.
	(mac_write): Use first_mac_write to sleep on first several writes.
1994-06-16 01:03:01 +00:00

995 lines
20 KiB
C

/* Top level support for Mac interface to GDB, the GNU debugger.
Copyright 1994 Free Software Foundation, Inc.
Contributed by Cygnus Support. Written by Stan Shebs.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "readline.h"
#include "history.h"
#include <Values.h>
#include <Types.h>
#include <Resources.h>
#include <QuickDraw.h>
#include <Fonts.h>
#include <Events.h>
#include <Windows.h>
#include <Menus.h>
#include <TextEdit.h>
#include <Dialogs.h>
#include <Desk.h>
#include <ToolUtils.h>
#include <Memory.h>
#include <SegLoad.h>
#include <Files.h>
#include <Folders.h>
#include <OSUtils.h>
#include <OSEvents.h>
#include <DiskInit.h>
#include <Packages.h>
#include <Traps.h>
#include <Lists.h>
#include <GestaltEqu.h>
#include <PPCToolbox.h>
#include <AppleEvents.h>
#include <StandardFile.h>
#include <Sound.h>
#ifdef MPW
#define QD(whatever) (qd.##whatever)
#define QDPat(whatever) (&(qd.##whatever))
#endif
#ifdef THINK_C
#define QD(whatever) (whatever)
#endif
#define p2c(pstr,cbuf) \
strncpy(cbuf, ((char *) (pstr) + 1), pstr[0]); \
cbuf[pstr[0]] = '\0';
#define pascalify(STR) \
sprintf(tmpbuf, " %s", STR); \
tmpbuf[0] = strlen(STR);
#include "gdbcmd.h"
#include "call-cmds.h"
#include "symtab.h"
#include "inferior.h"
#include "signals.h"
#include "target.h"
#include "breakpoint.h"
#include "gdbtypes.h"
#include "expression.h"
#include "language.h"
#include "mac-defs.h"
int mac_app;
int useWNE;
int hasColorQD;
int inbackground;
Rect dragrect = { -32000, -32000, 32000, 32000 };
Rect sizerect;
int sbarwid = 15;
/* Globals for the console window. */
WindowPtr console_window;
ControlHandle console_v_scrollbar;
Rect console_v_scroll_rect;
TEHandle console_text;
Rect console_text_rect;
/* This will go away eventually. */
gdb_has_a_terminal () { return 1; }
mac_init ()
{
SysEnvRec se;
int eventloopdone = 0;
Boolean gotevent;
Point mouse;
EventRecord event;
WindowPtr win;
RgnHandle cursorRgn;
int i;
Handle menubar;
MenuHandle menu;
/* Do the standard Mac environment setup. */
InitGraf (&QD (thePort));
InitFonts ();
FlushEvents (everyEvent, 0);
InitWindows ();
InitMenus ();
TEInit ();
InitDialogs (NULL);
InitCursor ();
/* Color Quickdraw is different from Classic QD. */
SysEnvirons(2, &se);
hasColorQD = se.hasColorQD;
sizerect.top = 50;
sizerect.left = 50;
sizerect.bottom = 1000;
sizerect.right = 1000;
#if 0
sizerect.bottom = screenBits.bounds.bottom - screenBits.bounds.top;
sizerect.right = screenBits.bounds.right - screenBits.bounds.left;
#endif
/* Set up the menus. */
menubar = GetNewMBar (mbMain);
SetMenuBar (menubar);
/* Add the DAs etc as usual. */
menu = GetMHandle (mApple);
if (menu != nil) {
AddResMenu (menu, 'DRVR');
}
DrawMenuBar ();
new_console_window ();
return 1;
}
new_console_window ()
{
/* Create the main window we're going to play in. */
if (hasColorQD)
console_window = GetNewCWindow (wConsole, NULL, (WindowPtr) -1L);
else
console_window = GetNewWindow (wConsole, NULL, (WindowPtr) -1L);
SetPort (console_window);
console_text_rect = console_window->portRect;
/* Leave 8 pixels of blank space, for aesthetic reasons and to
make it easier to select from the beginning of a line. */
console_text_rect.left += 8;
console_text_rect.bottom -= sbarwid - 1;
console_text_rect.right -= sbarwid - 1;
console_text = TENew (&console_text_rect, &console_text_rect);
TESetSelect (0, 40000, console_text);
TEDelete (console_text);
TEAutoView (1, console_text);
console_v_scroll_rect = console_window->portRect;
console_v_scroll_rect.bottom -= sbarwid - 1;
console_v_scroll_rect.left = console_v_scroll_rect.right - sbarwid;
console_v_scrollbar =
NewControl (console_window, &console_v_scroll_rect,
"\p", 1, 0, 0, 0, scrollBarProc, 0L);
ShowWindow (console_window);
SelectWindow (console_window);
}
mac_command_loop()
{
SysEnvRec se;
int eventloopdone = 0;
Boolean gotevent;
Point mouse;
EventRecord event;
WindowPtr win;
RgnHandle cursorRgn;
int i;
Handle menubar;
MenuHandle menu;
/* Figure out if the WaitNextEvent Trap is available. */
useWNE =
(NGetTrapAddress (0x60, ToolTrap) != NGetTrapAddress (0x9f, ToolTrap));
/* Pass WNE an empty region the 1st time thru. */
cursorRgn = NewRgn ();
/* Go into the main event-handling loop. */
while (!eventloopdone)
{
/* Use WaitNextEvent if it is available, otherwise GetNextEvent. */
if (useWNE)
{
get_global_mouse (&mouse);
adjust_cursor (mouse, cursorRgn);
gotevent = WaitNextEvent (everyEvent, &event, GetCaretTime(), cursorRgn);
}
else
{
SystemTask ();
gotevent = GetNextEvent (everyEvent, &event);
}
/* First decide if the event is for a dialog or is just any old event. */
if (FrontWindow () != nil && IsDialogEvent (&event))
{
short itemhit;
DialogPtr dialog;
/* Handle all the modeless dialogs here. */
if (DialogSelect (&event, &dialog, &itemhit))
{
}
}
else if (gotevent)
{
/* Make sure we have the right cursor before handling the event. */
adjust_cursor (event.where, cursorRgn);
do_event (&event);
}
else
{
do_idle ();
}
}
}
get_global_mouse (mouse)
Point *mouse;
{
EventRecord evt;
OSEventAvail (0, &evt);
*mouse = evt.where;
}
adjust_cursor (mouse, region)
Point mouse;
RgnHandle region;
{
}
/* Decipher an event, maybe do something with it. */
do_event (evt)
EventRecord *evt;
{
short part, err, rslt = 0;
WindowPtr win;
Boolean hit;
char key;
Point pnt;
switch (evt->what)
{
case mouseDown:
/* See if the click happened in a special part of the screen. */
part = FindWindow (evt->where, &win);
switch (part)
{
case inMenuBar:
adjust_menus ();
do_menu_command (MenuSelect (evt->where));
break;
case inSysWindow:
SystemClick (evt, win);
break;
case inContent:
if (win != FrontWindow ())
{
/* Bring the clicked-on window to the front. */
SelectWindow (win);
/* Fix the menu to match the new front window. */
adjust_menus ();
/* We always want to discard the event now, since clicks in a
windows are often irreversible actions. */
} else
/* Mouse clicks in the front window do something useful. */
do_mouse_down (win, evt);
break;
case inDrag:
/* Standard drag behavior, no tricks necessary. */
DragWindow (win, evt->where, &dragrect);
break;
case inGrow:
grow_window (win, evt->where);
break;
case inZoomIn:
case inZoomOut:
zoom_window (win, evt->where, part);
break;
case inGoAway:
close_window (win);
break;
}
break;
case keyDown:
case autoKey:
key = evt->message & charCodeMask;
/* Check for menukey equivalents. */
if (evt->modifiers & cmdKey)
{
if (evt->what == keyDown)
{
adjust_menus ();
do_menu_command (MenuKey (key));
}
}
else
{
if (evt->what == keyDown)
{
/* Random keypress, interpret it. */
do_keyboard_command (key);
}
}
break;
case activateEvt:
activate_window ((WindowPtr) evt->message, evt->modifiers & activeFlag);
break;
case updateEvt:
update_window ((WindowPtr) evt->message);
break;
case diskEvt:
/* Call DIBadMount in response to a diskEvt, so that the user can format
a floppy. (from DTS Sample) */
if (HiWord (evt->message) != noErr)
{
SetPt (&pnt, 50, 50);
err = DIBadMount (pnt, evt->message);
}
break;
case app4Evt:
/* Grab only a single byte. */
switch ((evt->message >> 24) & 0xFF)
{
case 0xfa:
break;
case 1:
inbackground = !(evt->message & 1);
activate_window (FrontWindow (), !inbackground);
break;
}
break;
case kHighLevelEvent:
AEProcessAppleEvent (evt);
break;
case nullEvent:
do_idle ();
rslt = 1;
break;
default:
break;
}
return rslt;
}
/* Do any idle-time activities. */
do_idle ()
{
TEIdle (console_text);
}
grow_window (win, where)
WindowPtr win;
Point where;
{
long winsize;
int h, v;
GrafPtr oldport;
winsize = GrowWindow (win, where, &sizerect);
if (winsize != 0)
{
GetPort (&oldport);
SetPort (win);
EraseRect (&win->portRect);
h = LoWord (winsize);
v = HiWord (winsize);
SizeWindow (win, h, v, 1);
adjust_console_sizes ();
adjust_console_scrollbars ();
adjust_console_text ();
InvalRect (&win->portRect);
SetPort (oldport);
}
}
zoom_window (win, where, part)
WindowPtr win;
Point where;
short part;
{
ZoomWindow (win, part, (win == FrontWindow ()));
adjust_console_sizes ();
adjust_console_scrollbars ();
adjust_console_text ();
InvalRect (&(win->portRect));
}
close_window (win)
WindowPtr win;
{
}
pascal void
v_scroll_proc (ControlHandle control, short part)
{
int oldval, amount = 0, newval;
int pagesize = ((*console_text)->viewRect.bottom - (*console_text)->viewRect.top) / (*console_text)->lineHeight;
if (part)
{
oldval = GetCtlValue (control);
switch (part)
{
case inUpButton:
amount = 1;
break;
case inDownButton:
amount = -1;
break;
case inPageUp:
amount = pagesize;
break;
case inPageDown:
amount = - pagesize;
break;
default:
/* (should freak out) */
break;
}
SetCtlValue(control, oldval - amount);
newval = GetCtlValue (control);
amount = oldval - newval;
if (amount)
TEScroll (0, amount * (*console_text)->lineHeight, console_text);
}
}
do_mouse_down (WindowPtr win, EventRecord *event)
{
short part, value;
Point mouse;
ControlHandle control;
if (1 /*is_app_window(win)*/)
{
SetPort (win);
mouse = event->where;
GlobalToLocal (&mouse);
part = FindControl(mouse, win, &control);
if (control == console_v_scrollbar)
{
switch (part)
{
case inThumb:
value = GetCtlValue (control);
part = TrackControl (control, mouse, nil);
if (part)
{
value -= GetCtlValue (control);
if (value)
TEScroll(0, value * (*console_text)->lineHeight,
console_text);
}
break;
default:
value = TrackControl (control, mouse, (ProcPtr) v_scroll_proc);
break;
}
}
else
{
TEClick (mouse, 0, console_text);
}
}
}
activate_window (win, activate)
WindowPtr win;
int activate;
{
Rect grow_rect;
if (win == nil) return;
/* It's convenient to make the activated window also be the
current GrafPort. */
if (activate)
SetPort(win);
/* Activate the console window's scrollbar. */
if (win == console_window)
{
if (activate)
{
TEActivate (console_text);
/* Cause the grow icon to be redrawn at the next update. */
grow_rect = console_window->portRect;
grow_rect.top = grow_rect.bottom - sbarwid;
grow_rect.left = grow_rect.right - sbarwid;
InvalRect (&grow_rect);
}
else
{
TEDeactivate (console_text);
DrawGrowIcon (console_window);
}
HiliteControl (console_v_scrollbar, (activate ? 0 : 255));
}
}
update_window (win)
WindowPtr win;
{
int controls = 1, growbox = 0;
GrafPtr oldport;
/* Set the updating window to be the current grafport. */
GetPort (&oldport);
SetPort (win);
/* recalc_depths(); */
BeginUpdate (win);
if (win == console_window)
{
draw_console ();
controls = 1;
growbox = 1;
}
if (controls)
UpdateControls (win, win->visRgn);
if (growbox)
DrawGrowIcon (win);
EndUpdate (win);
SetPort (oldport);
}
adjust_menus ()
{
}
do_menu_command (which)
long which;
{
short menuid, menuitem;
short itemHit;
Str255 daname;
short daRefNum;
Boolean handledbyda;
WindowPtr win;
short ditem;
int i;
char cmdbuf[300];
cmdbuf[0] = '\0';
menuid = HiWord (which);
menuitem = LoWord (which);
switch (menuid)
{
case mApple:
switch (menuitem)
{
case miAbout:
Alert (128, nil);
break;
#if 0
case miHelp:
/* (should pop up help info) */
break;
#endif
default:
GetItem (GetMHandle (mApple), menuitem, daname);
daRefNum = OpenDeskAcc (daname);
}
break;
case mFile:
switch (menuitem)
{
case miFileNew:
if (console_window == FrontWindow ())
{
close_window (console_window);
}
new_console_window ();
break;
case miFileOpen:
SysBeep (20);
break;
case miFileQuit:
ExitToShell ();
break;
}
break;
case mEdit:
/* handledbyda = SystemEdit(menuitem-1); */
switch (menuitem)
{
case miEditCut:
TECut (console_text);
break;
case miEditCopy:
TECopy (console_text);
break;
case miEditPaste:
TEPaste (console_text);
break;
case miEditClear:
TEDelete (console_text);
break;
}
/* All of these operations need the same postprocessing. */
adjust_console_sizes ();
adjust_console_scrollbars ();
adjust_console_text ();
break;
case mDebug:
switch (menuitem)
{
case miDebugTarget:
sprintf (cmdbuf, "target %s", "remote");
break;
case miDebugRun:
sprintf (cmdbuf, "run");
break;
case miDebugContinue:
sprintf (cmdbuf, "continue");
break;
case miDebugStep:
sprintf (cmdbuf, "step");
break;
case miDebugNext:
sprintf (cmdbuf, "next");
break;
}
break;
}
HiliteMenu (0);
/* Execute a command if one had been given. Do here because a command
may longjmp before we get a chance to unhilite the menu. */
if (strlen (cmdbuf) > 0)
execute_command (cmdbuf, 0);
}
char commandbuf[1000];
do_keyboard_command (key)
int key;
{
int startpos, endpos, i, len;
char *last_newline;
char buf[10], *text_str, *command, *cmd_start;
CharsHandle text;
if (key == '\015' || key == '\003')
{
text = TEGetText (console_text);
HLock ((Handle) text);
text_str = *text;
startpos = (*console_text)->selStart;
endpos = (*console_text)->selEnd;
if (startpos != endpos)
{
len = endpos - startpos;
cmd_start = text_str + startpos;
}
else
{
for (i = startpos - 1; i >= 0; --i)
if (text_str[i] == '\015')
break;
last_newline = text_str + i;
len = (text_str + startpos) - 1 - last_newline;
cmd_start = last_newline + 1;
}
if (len > 1000) len = 999;
if (len < 0) len = 0;
strncpy (commandbuf + 1, cmd_start, len);
commandbuf[1 + len] = 0;
command = commandbuf + 1;
HUnlock ((Handle) text);
commandbuf[0] = strlen(command);
/* Insert a newline and recalculate before doing any command. */
key = '\015';
TEKey (key, console_text);
TEInsert (buf, 1, console_text);
adjust_console_sizes ();
adjust_console_scrollbars ();
adjust_console_text ();
if (strlen (command) > 0)
{
execute_command (command, 0);
bpstat_do_actions (&stop_bpstat);
}
}
else if (0 /* editing chars... */)
{
}
else
{
/* A self-inserting character. */
TEKey (key, console_text);
}
}
draw_console ()
{
SetPort (console_window);
TEUpdate (&(console_window->portRect), console_text);
#if 0
FrameRect (&((*console_text)->viewRect));
FrameRect (&((*console_text)->destRect));
#endif
}
/* Cause an update of a window's entire contents. */
force_update (win)
WindowPtr win;
{
GrafPtr oldport;
if (win == nil) return;
GetPort (&oldport);
SetPort (win);
EraseRect (&win->portRect);
InvalRect (&win->portRect);
SetPort (oldport);
}
adjust_console_sizes ()
{
Rect tmprect;
tmprect = console_window->portRect;
MoveControl (console_v_scrollbar, tmprect.right - sbarwid, 0);
SizeControl (console_v_scrollbar, sbarwid + 1, tmprect.bottom - sbarwid + 1);
tmprect.left += 7;
tmprect.right -= sbarwid;
tmprect.bottom -= sbarwid;
InsetRect(&tmprect, 1, 1);
(*console_text)->viewRect = tmprect;
(*console_text)->destRect = tmprect;
/* (should fiddle bottom of viewrect to be even multiple of lines?) */
}
adjust_console_scrollbars ()
{
int lines, newmax, value;
(*console_v_scrollbar)->contrlVis = 0;
lines = (*console_text)->nLines;
newmax = lines - (((*console_text)->viewRect.bottom
- (*console_text)->viewRect.top)
/ (*console_text)->lineHeight);
if (newmax < 0) newmax = 0;
SetCtlMax (console_v_scrollbar, newmax);
value = ((*console_text)->viewRect.top - (*console_text)->destRect.top)
/ (*console_text)->lineHeight;
SetCtlValue (console_v_scrollbar, value);
(*console_v_scrollbar)->contrlVis = 0xff;
ShowControl (console_v_scrollbar);
}
/* Scroll the TE record so that it is consistent with the scrollbar(s). */
adjust_console_text ()
{
TEScroll (((*console_text)->viewRect.left
- (*console_text)->destRect.left)
- 0 /* get h scroll value */,
(((*console_text)->viewRect.top
- (*console_text)->destRect.top)
- GetCtlValue (console_v_scrollbar))
* (*console_text)->lineHeight,
console_text);
}
/* Readline substitute. */
char *
readline (char *prrompt)
{
return gdb_readline (prrompt);
}
char *rl_completer_word_break_characters;
char *rl_completer_quote_characters;
int (*rl_completion_entry_function) ();
int rl_point;
char *rl_line_buffer;
char *rl_readline_name;
/* History substitute. */
void
add_history (char *buf)
{
}
void
stifle_history (int n)
{
}
int
unstifle_history ()
{
}
int
read_history (char *name)
{
}
int
write_history (char *name)
{
}
int
history_expand (char *x, char **y)
{
}
extern HIST_ENTRY *
history_get (int xxx)
{
return NULL;
}
int history_base;
char *
filename_completion_function (char *text, char *name)
{
return "?";
}
char *
tilde_expand (char *str)
{
return strsave (str);
}
/* Modified versions of standard I/O. */
#include <stdarg.h>
#undef fprintf
int
hacked_fprintf (FILE *fp, const char *fmt, ...)
{
int ret;
va_list ap;
va_start (ap, fmt);
if (mac_app && (fp == stdout || fp == stderr))
{
char buf[1000];
ret = vsprintf(buf, fmt, ap);
TESetSelect (40000, 40000, console_text);
TEInsert (buf, strlen(buf), console_text);
}
else
ret = vfprintf (fp, fmt, ap);
va_end (ap);
return ret;
}
#undef printf
int
hacked_printf (const char *fmt, ...)
{
int ret;
va_list ap;
va_start (ap, fmt);
if (mac_app)
{
ret = hacked_vfprintf(stdout, fmt, ap);
}
else
ret = vfprintf (stdout, fmt, ap);
va_end (ap);
return ret;
}
#undef vfprintf
int
hacked_vfprintf (FILE *fp, const char *format, va_list args)
{
if (mac_app && (fp == stdout || fp == stderr))
{
char buf[1000];
int ret;
ret = vsprintf(buf, format, args);
TESetSelect (40000, 40000, console_text);
TEInsert (buf, strlen(buf), console_text);
return ret;
}
else
return vfprintf (fp, format, args);
}
#undef fputs
hacked_fputs (const char *s, FILE *fp)
{
if (mac_app && (fp == stdout || fp == stderr))
{
TESetSelect (40000, 40000, console_text);
TEInsert (s, strlen(s), console_text);
return 0;
}
else
return fputs (s, fp);
}
#undef fputc
hacked_fputc (const char c, FILE *fp)
{
if (mac_app && (fp == stdout || fp == stderr))
{
char buf[2];
buf[0] = c;
TESetSelect (40000, 40000, console_text);
TEInsert (buf, 1, console_text);
return 0;
}
else
return fputc (c, fp);
}
#undef putc
hacked_putc (const char c, FILE *fp)
{
if (mac_app && (fp == stdout || fp == stderr))
{
char buf[2];
buf[0] = c;
TESetSelect (40000, 40000, console_text);
TEInsert (buf, 1, console_text);
}
else
return fputc (c, fp);
}
#undef fflush
hacked_fflush (FILE *fp)
{
if (mac_app && (fp == stdout || fp == stderr))
return 0;
return fflush (fp);
}