/*
Copyright (C) 1998,1999,2000,2001
T. Scott Dattalo and Ralf Forsberg
This file is part of gpsim.
gpsim 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, or (at your option)
any later version.
gpsim 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 gpsim; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "../config.h"
#ifdef HAVE_GUI
#include <unistd.h>
#define GTK_ENABLE_BROKEN
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <glib.h>
#include <string.h>
#include <ctype.h>
#include <map>
#include <gtkextra/gtkbordercombo.h>
#include <gtkextra/gtkcolorcombo.h>
#include <gtkextra/gtksheet.h>
#include "gui.h"
#include "gui_src.h"
#include "gui_profile.h"
#include "gui_symbols.h"
#include "gui_statusbar.h"
#include "gui_watch.h"
#include <assert.h>
#include "../src/fopen-path.h"
#include "../xpms/pc.xpm"
#include "../xpms/break.xpm"
#include "../xpms/canbreak.xpm"
#include "../xpms/startp.xpm"
#include "../xpms/stopp.xpm"
#define PAGE_BORDER 3
#define PIXMAP_SIZE 14
extern int gui_question(char *question, char *a, char *b);
static int load_fonts(SOURCE_WINDOW *sbaw);
static void find_char_and_skip(char **str, char c)
{
char *res = strrchr(*str,c);
if(res) {
*str = ++res;
}
}
//------------------------------------------------------------------------
//
static char *strReverse(const char *start, char *dest, int nChars)
{
*dest-- = 0;
while (nChars--)
*dest-- = *start++;
dest++;
return dest;
}
#if 0 // defined but not used
static int strFindSubString(const char *cPsrc, const char *cPpattern)
{
const char *found = strstr(cPsrc, cPpattern);
return found ? (found - cPsrc) : - 1;
}
#endif
//========================================================================
class SourceXREF : public CrossReferenceToGUI
{
public:
void Update(int new_value)
{
SOURCE_WINDOW *sbaw = (SOURCE_WINDOW*)(parent_window);
#if defined(NEW_SOURCE_BROWSER)
if(sbaw->bSourceLoaded())
sbaw->SetPC(new_value);
#else
if(sbaw->m_bSourceLoaded)
sbaw->SetPC(new_value);
#endif
}
void Remove(void) {}
};
#define BP_PIXEL_SIZE 10
#define PC_PIXEL_SIZE 10
#define MARGIN_WIDTH (PC_PIXEL_SIZE + BP_PIXEL_SIZE)
#define PC_START (MARGIN_WIDTH - PC_PIXEL_SIZE)
#define BP_START (MARGIN_WIDTH - PC_PIXEL_SIZE-BP_PIXEL_SIZE)
static map<GtkTextView*, NSourcePage *> PageMap;
/* This function is taken from gtk+/tests/testtext.c */
static void
gtk_source_view_get_lines (GtkTextView *text_view,
gint first_y,
gint last_y,
GArray *buffer_coords,
GArray *numbers,
gint *countp)
{
GtkTextIter iter;
gint count;
gint size;
gint last_line_num = -1;
g_array_set_size (buffer_coords, 0);
g_array_set_size (numbers, 0);
/* Get iter at first y */
gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
/* For each iter, get its location and add it to the arrays.
* Stop when we pass last_y
*/
count = 0;
size = 0;
while (!gtk_text_iter_is_end (&iter))
{
gint y, height;
gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
g_array_append_val (buffer_coords, y);
last_line_num = gtk_text_iter_get_line (&iter);
g_array_append_val (numbers, last_line_num);
++count;
if ((y + height) >= last_y)
break;
gtk_text_iter_forward_line (&iter);
}
if (gtk_text_iter_is_end (&iter))
{
gint y, height;
gint line_num;
gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
line_num = gtk_text_iter_get_line (&iter);
if (line_num != last_line_num)
{
g_array_append_val (buffer_coords, y);
g_array_append_val (numbers, line_num);
++count;
}
}
*countp = count;
}
//------------------------------------------------------------------------
//
gint
NSourcePage::KeyPressHandler(GtkTextView *pView,
GdkEventKey *key,
SourceWindow *pSW)
{
GtkTextBuffer *pBuffer = gtk_text_view_get_buffer(pView);
GtkTextMark *pMark = gtk_text_buffer_get_insert(pBuffer);
GtkTextIter iter;
gtk_text_buffer_get_iter_at_mark (pBuffer, &iter, pMark);
int line = gtk_text_iter_get_line (&iter);
NSourcePage *page = PageMap[pView];
Dprintf(("Received key press for view. line=%d page%p\n",line,page));
switch (key->keyval) {
case 'b':
case 'B':
pSW->toggleBreak(page,line);
break;
default:
return FALSE;
}
return TRUE;
}
gint
NSourcePage::ViewExposeEventHandler(GtkTextView *pView,
GdkEventExpose *pEvent,
SourceWindow *pSW)
{
if (pEvent->window == gtk_text_view_get_window (pView,
GTK_TEXT_WINDOW_LEFT))
{
//gtk_source_view_paint_margin (view, event);
//event_handled = TRUE;
Dprintf(("Expose event for view margin %p\n",pSW));
gint y1 = pEvent->area.y;
gint y2 = y1 + pEvent->area.height;
NSourcePage *pPage = PageMap[pView];
gtk_text_view_window_to_buffer_coords (pView,
GTK_TEXT_WINDOW_LEFT,
0,
y1,
NULL,
&y1);
gtk_text_view_window_to_buffer_coords (pView,
GTK_TEXT_WINDOW_LEFT,
0,
y2,
NULL,
&y2);
pPage->updateMargin(y1,y2);
}
else {
Dprintf(("Expose event for view %p\n",pSW));
}
return FALSE;
}
//------------------------------------------------------------------------
//
gint
SourceWindow::KeyPressHandler(GtkWidget *widget,
GdkEventKey *key,
SourceWindow *pSW)
{
if (!pSW || !key)
return FALSE;
switch (key->keyval) {
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
pSW->step(key->keyval - '0');
break;
case 's':
case 'S':
case GDK_F7:
pSW->step();
break;
case 'o':
case 'O':
case GDK_F8:
pSW->step_over();
break;
case 'r':
case 'R':
case GDK_F9:
pSW->run();
break;
case 'f':
case 'F':
pSW->finish();
break;
case GDK_Escape:
pSW->stop();
break;
default:
return FALSE;
}
return TRUE;
}
//======================================================================
//
// When a user right-clicks in the source browser, a menu will popup.
// There can only be one menu active at any given time.
//
// 'aPopupMenu' pointer is a local pointer to a GtkMenu.
//
static GtkWidget *aPopupMenu=0;
//
// 'pViewContainingPopup' is a pointer to the GtkTextView that was active
// when the popup menu was opened.
//
static GtkTextView *pViewContainingPopup=0;
typedef enum {
MENU_FIND_TEXT,
MENU_FIND_PC,
MENU_MOVE_PC,
MENU_RUN_HERE,
MENU_BP_HERE,
MENU_SELECT_SYMBOL,
MENU_STEP,
MENU_STEP_OVER,
MENU_RUN,
MENU_STOP,
MENU_FINISH,
MENU_RESET,
MENU_SETTINGS,
MENU_PROFILE_START_HERE,
MENU_PROFILE_STOP_HERE,
MENU_ADD_TO_WATCH,
} menu_id;
typedef struct _menu_item {
char *name;
menu_id id;
GtkWidget *item;
} menu_item;
static menu_item menu_items[] = {
{"Find PC", MENU_FIND_PC,0},
{"Run to here", MENU_RUN_HERE,0},
{"Move PC here", MENU_MOVE_PC,0},
{"Breakpoint here", MENU_BP_HERE,0},
{"Profile start here", MENU_PROFILE_START_HERE,0},
{"Profile stop here", MENU_PROFILE_STOP_HERE,0},
{"Add to watch", MENU_ADD_TO_WATCH,0},
{"Find text...", MENU_FIND_TEXT,0},
{"Settings...", MENU_SETTINGS,0},
};
static menu_item submenu_items[] = {
{"Step", MENU_STEP,0},
{"Step Over", MENU_STEP_OVER,0},
{"Run", MENU_RUN,0},
{"Stop", MENU_STOP,0},
{"Reset", MENU_RESET,0},
{"Finish", MENU_FINISH,0},
};
//------------------------------------------------------------------------
// ButtonPressHandler
// Event handler for text view mouse clicks.
gint
NSourcePage::ButtonPressHandler(GtkTextView *pView,
GdkEventButton *pButton,
SourceWindow *pSW)
{
if (pButton->window == gtk_text_view_get_window (pView,
GTK_TEXT_WINDOW_LEFT))
{
// Margin
NSourcePage *pPage = PageMap[pView];
gint x = (gint) pButton->x;
gint y = (gint) pButton->y;
gtk_text_view_window_to_buffer_coords (pView,
GTK_TEXT_WINDOW_LEFT,
x,
y,
&x,
&y);
GtkTextIter iter;
gint line;
gtk_text_view_get_line_at_y (pView, &iter, y, NULL);
line = gtk_text_iter_get_line (&iter);
pSW->toggleBreak(pPage, line);
} else {
// Text (i.e. not the margin
if (pButton->button == 3) {
if (aPopupMenu) {
if (GTK_IS_TEXT_VIEW(pView))
pViewContainingPopup = pView;
gtk_menu_popup(GTK_MENU(aPopupMenu), 0, 0, 0, 0,
3, pButton->time);
}
return TRUE;
}
}
return FALSE;
}
//========================================================================
int SourceWindow::DeleteEventHandler(GtkWidget *widget,
GdkEvent *event,
SourceWindow *sw)
{
sw->ChangeView(VIEW_HIDE);
return TRUE;
}
//========================================================================
// Helper functions for parsing
static int isString(const char *cP)
{
int i=0;
if (isalpha(*cP) || *cP=='_')
while (isalnum(cP[i]) || cP[i]=='_')
i++;
return i;
}
static int isWhiteSpace(const char *cP)
{
int i=0;
while (cP[i]==' ' || cP[i]=='\t')
i++;
return i;
}
static int isHexNumber(const char *cP)
{
int i=0;
if ((*cP == '0' && toupper(cP[1])=='X') ||
(*cP == '$')) {
i = (*cP=='0') ? 2 : 1;
while (isxdigit(cP[i]))
i++;
}
return i;
}
static int isNumber(const char *cP)
{
int i=isHexNumber(cP);
if (!i)
while (isdigit(cP[i]))
i++;
return i;
}
static bool isEnd(const char c)
{
return c=='\n' || c==0;
}
static int isComment(const char *cP)
{
int i = (*cP==';') ? 1 : 0;
if (i)
while (!isEnd(cP[i]))
i++;
return i;
}
//------------------------------------------------------------------------
static bool isButtonEvent (GdkEventType type)
{
return
type == GDK_BUTTON_PRESS ||
type == GDK_2BUTTON_PRESS ||
type == GDK_3BUTTON_PRESS ||
type == GDK_BUTTON_RELEASE;
}
//------------------------------------------------------------------------
static gboolean TagEvent (GtkTextTag *texttag,
GObject *arg1,
GdkEvent *event,
GtkTextIter *arg2,
TextStyle *pTextStyle)
{
/*
static int seq=0;
printf("Received tag event signal Tag:%p arg1:%p seq %d Event:%p iter:%p user:%p %08X Line:%d\n",
texttag, arg1,seq++,event,arg2, pTextStyle, event->type, gtk_text_iter_get_line(arg2));
*/
if (isButtonEvent(event->type)) {
GdkEventButton *evtButton = (GdkEventButton *) event;
if (event->type == GDK_2BUTTON_PRESS && evtButton->button == 1) {
Dprintf (("Double click left mouse\n"));
if (pTextStyle)
pTextStyle->doubleClickEvent(arg2);
gint signal_id = g_signal_lookup ("button_press_event",
G_TYPE_FROM_INSTANCE(arg1));
GSignalQuery query;
g_signal_query (signal_id, &query);
Dprintf (("Signal id=%d name=%s n_params=%d\n",signal_id,query.signal_name,
query.n_params));
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (arg1));
gboolean b=FALSE;
if (GTK_WIDGET_TOPLEVEL (toplevel)) {
//g_signal_emit_by_name (toplevel, "button_press_event",evtButton,&b);
g_signal_emit_by_name (GTK_WIDGET (arg1), "button_press_event",evtButton,&b);
} else
printf("TagEvent: arg1 is not toplevel\n");
}
/*
printf("Button Event: button:%d modifier:%d coords(%g,%g)\n",
evtButton->button, evtButton->state, evtButton->x,evtButton->y);
*/
// If the right mouse button is pressed then suppress the GTK pop up menu.
if (evtButton->button == 3) {
if (aPopupMenu) {
if (GTK_IS_TEXT_VIEW(arg1)) {
pViewContainingPopup = GTK_TEXT_VIEW(arg1);
NSourcePage *pPage = PageMap[pViewContainingPopup];
gint x = (gint) evtButton->x;
gint y = (gint) evtButton->y;
gtk_text_view_window_to_buffer_coords (pViewContainingPopup,
GTK_TEXT_WINDOW_LEFT,
x,
y,
&x,
&y);
GtkTextIter iter;
gtk_text_view_get_line_at_y (pViewContainingPopup, &iter, y, NULL);
pPage->getParent()->m_LineAtButtonClick =
gtk_text_iter_get_line (&iter);
}
gtk_menu_popup(GTK_MENU(aPopupMenu), 0, 0, 0, 0,
3, evtButton->time);
}
return TRUE;
}
return FALSE;
}
return FALSE;
}
//------------------------------------------------------------------------
class SearchDialog
{
public:
SearchDialog();
void Build();
void Show(SourceWindow *);
bool bDirection();
bool bCase();
protected:
bool m_bIsBuilt;
bool m_bFound;
bool m_bLooped;
int m_iStart;
int m_iLast;
int m_iLastID;
GtkWidget *m_Window; // The Search Dialog Window
GtkWidget *m_Entry; // Widget that holds the search text.
GtkWidget *m_BackButton; //
GtkWidget *m_CaseButton; //
GList *m_comboStrings; //
SourceWindow *m_pSourceWindow; // The last source window that requested a search.
static void find_cb(GtkWidget *w, SearchDialog *);
static void find_clear_cb(GtkWidget *w, SearchDialog *pSearchDialog);
void find(const char *);
static gint configure_event(GtkWidget *widget, GdkEventConfigure *e, gpointer data);
};
//------------------------------------------------------------------------
SearchDialog::SearchDialog()
: m_bIsBuilt(false), m_bFound(false),
m_bLooped(false),m_iStart(0),m_iLast(0),m_iLastID(0),
m_pSourceWindow(0)
{
}
gint SearchDialog::configure_event(GtkWidget *widget, GdkEventConfigure *e, gpointer data)
{
static int dlg_x=200, dlg_y=200;
if(widget->window==0)
return 0;
gdk_window_get_root_origin(widget->window,&dlg_x,&dlg_y);
return 0;
}
bool SearchDialog::bDirection()
{
return GTK_TOGGLE_BUTTON(m_BackButton)->active == TRUE;
}
bool SearchDialog::bCase()
{
return GTK_TOGGLE_BUTTON(m_CaseButton)->active == TRUE;
}
void SearchDialog::find_cb(GtkWidget *w, SearchDialog *pSearchDialog)
{
const char *p=gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(pSearchDialog->m_Entry)->entry));
pSearchDialog->find(p);
}
void SearchDialog::find(const char *cpPattern)
{
if (m_pSourceWindow)
m_iStart = m_pSourceWindow->findText(cpPattern,m_iStart,!bDirection(), bCase());
}
void SearchDialog::find_clear_cb(GtkWidget *w, SearchDialog *pSearchDialog)
{
//gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(searchdlg.entry)->entry),"");
printf("find_clear_cb\n");
}
//------------------------------------------------------------------------
void SearchDialog::Build()
{
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *label;
if (m_bIsBuilt)
return;
m_iLastID=-1; // will reset search
m_Window = gtk_dialog_new();
gtk_signal_connect(GTK_OBJECT(m_Window),
"configure_event",GTK_SIGNAL_FUNC(configure_event),0);
gtk_signal_connect_object(GTK_OBJECT(m_Window),
"delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide),
GTK_OBJECT(m_Window));
gtk_window_set_title(GTK_WINDOW(m_Window),"Find");
hbox = gtk_hbox_new(FALSE,15);
gtk_widget_show(hbox);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(m_Window)->vbox),hbox,
FALSE,TRUE,5);
label = gtk_label_new("Find:");
gtk_widget_show(label);
gtk_box_pack_start(GTK_BOX(hbox),label,
FALSE,FALSE,5);
m_Entry = gtk_combo_new();
gtk_widget_show(m_Entry);
gtk_box_pack_start(GTK_BOX(hbox),m_Entry,
TRUE,TRUE,5);
gtk_combo_disable_activate(GTK_COMBO(m_Entry));
gtk_signal_connect(GTK_OBJECT(GTK_COMBO(m_Entry)->entry),"activate",
GTK_SIGNAL_FUNC(find_cb),this);
hbox = gtk_hbox_new(FALSE,15);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(m_Window)->vbox),hbox,
FALSE,TRUE,5);
gtk_widget_show(hbox);
m_CaseButton = gtk_check_button_new_with_label("Case Sensitive");
gtk_widget_show(m_CaseButton);
gtk_box_pack_start(GTK_BOX(hbox),m_CaseButton,
FALSE,FALSE,5);
m_BackButton = gtk_check_button_new_with_label("Find Backwards");
gtk_widget_show(m_BackButton);
gtk_box_pack_start(GTK_BOX(hbox),m_BackButton,
FALSE,FALSE,5);
button = gtk_button_new_with_label("Find");
gtk_widget_show(button);
gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(m_Window)->action_area),button);
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(find_cb),this);
GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT);
gtk_widget_grab_default(button);
button = gtk_button_new_with_label("Clear");
gtk_widget_show(button);
gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(m_Window)->action_area),button);
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(find_clear_cb),this);
button = gtk_button_new_with_label("Close");
gtk_widget_show(button);
gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(m_Window)->action_area),button);
gtk_signal_connect_object(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(m_Window));
m_bIsBuilt = true;
}
void SearchDialog::Show(SourceWindow *pSourceWindow)
{
if (!m_bIsBuilt)
Build();
m_pSourceWindow = pSourceWindow;
m_iStart = 0;
if (m_Window)
gtk_widget_show(m_Window);
}
//------------------------------------------------------------------------
ColorHolder::ColorHolder (const char *pcColor)
/* : m_cpCurr(0), m_cpTemp(0) */
{
if (pcColor) {
gdk_color_parse(pcColor, &mCurrentColor);
mSaveColor = mCurrentColor;
}
}
bool ColorHolder::set(GdkColor *pNewColor, bool saveOld)
{
if (!saveOld)
mSaveColor = *pNewColor;
if (!gdk_color_equal(pNewColor,&mCurrentColor)) {
mCurrentColor = *pNewColor;
return true;
}
return false;
}
char *ColorHolder::get(char *cParr, int size)
{
if (cParr)
snprintf(cParr,size,"#%04X%04X%04X",
mCurrentColor.red,mCurrentColor.green,mCurrentColor.blue);
return cParr;
}
void ColorHolder::apply()
{
mSaveColor = mCurrentColor;
}
bool ColorHolder::revert()
{
return set(&mSaveColor,true);
}
GdkColor *ColorHolder::CurrentColor()
{
return &mCurrentColor;
}
//------------------------------------------------------------------------
TextStyle::TextStyle (const char *cpName,
const char *pFGColor,
const char *pBGColor)
: mFG(pFGColor), mBG(pBGColor)
{
m_pTag = gtk_text_tag_new(cpName);
g_object_set(G_OBJECT (m_pTag),
"foreground-gdk", mFG.CurrentColor(),
"background-gdk", mBG.CurrentColor(),NULL);
g_signal_connect (G_OBJECT (m_pTag), "event",
GTK_SIGNAL_FUNC(TagEvent),
this);
}
void TextStyle::setFG(GdkColor *pNewColor)
{
if (mFG.set(pNewColor,true)) {
g_object_set(G_OBJECT (m_pTag),
"foreground-gdk", mFG.CurrentColor(),NULL);
}
}
//------------------------------------------------------------------------
void TextStyle::doubleClickEvent(GtkTextIter *pIter)
{
}
void TextStyle::apply()
{
mFG.apply();
mBG.apply();
}
void TextStyle::revert()
{
if (mBG.revert())
g_object_set(G_OBJECT (m_pTag),
"background-gdk", mBG.CurrentColor(),NULL);
if (mFG.revert())
g_object_set(G_OBJECT (m_pTag),
"foreground-gdk", mFG.CurrentColor(),NULL);
}
//========================================================================
//========================================================================
SourcePageMargin::SourcePageMargin()
: m_bShowLineNumbers(true), m_bShowAddresses(false), m_bShowOpcodes(true)
{
}
//========================================================================
//========================================================================
SourceBuffer::SourceBuffer(GtkTextTagTable *pTagTable, FileContext *pFC,
SourceBrowserParent_Window *pParent)
: m_pParent(pParent), m_pFC(pFC), m_SourceFile_t(eUnknownSource),
m_bParsed(false)
{
assert(pTagTable);
assert(pParent);
m_buffer = gtk_text_buffer_new (pTagTable);
assert(m_buffer);
}
//------------------------------------------------------------------------
eSourceFileType SourceBuffer::getSrcType()
{
return m_SourceFile_t;
}
void SourceBuffer::setSrcType(eSourceFileType new_SrcType)
{
m_SourceFile_t = new_SrcType;
}
//------------------------------------------------------------------------
// addTagRange(TextStyle *pStyle,int start_index, int end_index)
//
// Addtag range applies the tag state to a range of text in the buffer
// using a given text style (i.e. the style contains a gtkTextTag)
void SourceBuffer::addTagRange(TextStyle *pStyle,
int start_index, int end_index)
{
if (!pStyle)
return;
GtkTextIter start;
GtkTextIter end;
gtk_text_buffer_get_iter_at_offset (m_buffer, &start, start_index);
gtk_text_buffer_get_iter_at_offset (m_buffer, &end, end_index);
gtk_text_buffer_apply_tag (m_buffer, pStyle->tag(), &start, &end);
}
//------------------------------------------------------------------------
bool SourceBuffer::IsParsed()
{
return m_bParsed;
}
//------------------------------------------------------------------------
void SourceBuffer::parse()
{
if (IsParsed() || !m_pParent)
return;
Dprintf(("parsing source buffer %s\n",m_pFC->name().c_str()));
m_pParent->parseSource(this, m_pFC);
m_bParsed = true;
}
GtkTextBuffer *SourceBuffer::getBuffer()
{
parse();
return m_buffer;
}
//------------------------------------------------------------------------
//
/*
void SourceBuffer::setBreak(int line)
{
Dprintf ((" setBreak line %d\n",line));
GtkTextIter iBegin, iEnd;
gtk_text_buffer_get_iter_at_line_offset
(m_buffer,
&iBegin,
line,
STROFFSET_OF_OPCODE);
gtk_text_buffer_get_iter_at_line_offset
(m_buffer,
&iEnd,
line,
STROFFSET_OF_OPCODE+STRLEN_OF_OPCODE);
gtk_text_buffer_apply_tag (m_buffer,
m_pParent->mBreakpointTag->tag(),
&iBegin,
&iEnd);
}
*/
//------------------------------------------------------------------------
/*
void SourceBuffer::clearBreak(int line)
{
Dprintf ((" clearBreak line %d\n",line));
GtkTextIter iBegin, iEnd;
gtk_text_buffer_get_iter_at_line_offset
(m_buffer,
&iBegin,
line,
STROFFSET_OF_OPCODE);
gtk_text_buffer_get_iter_at_line_offset
(m_buffer,
&iEnd,
line,
STROFFSET_OF_OPCODE+STRLEN_OF_OPCODE);
gtk_text_buffer_remove_tag (m_buffer,
m_pParent->mBreakpointTag->tag(),
&iBegin,
&iEnd);
}
*/
//========================================================================
NSourcePage::NSourcePage(SourceWindow *pParent,
SourceBuffer *pBuffer,
int file_id,
GtkWidget *pContainer)
: m_fileid(file_id),
m_pBuffer(pBuffer),
m_marginWidth(0),
m_Parent(pParent),
m_cpFont(0),
m_pContainer(pContainer),
m_view(0)
{
}
GtkTextBuffer *NSourcePage::buffer()
{
return m_pBuffer ? m_pBuffer->getBuffer() : 0;
}
//------------------------------------------------------------------------
SourceWindow::SourceWindow(GUI_Processor *pgp,
SourceBrowserParent_Window *pParent,
bool bUseConfig,
const char *newName)
: GUI_Object (),
pma(0),
status_bar(0),
last_simulation_mode(eSM_INITIAL),
m_pParent(pParent)
{
Dprintf(("Constructor \n"));
gp = pgp;
stPSearchDialog=0;
m_bLoadSource = false;
m_bSourceLoaded = false;
m_LineAtButtonClick = -1;
if (newName)
set_name(newName);
else
set_name("source_browser");
wc = WC_source;
wt = WT_SourceWindow;
m_Notebook = 0;
mProgramCounter.bIsActive = false;
pages = new NSourcePage *[SBAW_NRFILES];
for (int i=0; i<SBAW_NRFILES; i++)
pages[i] = 0;
if (bUseConfig) {
get_config();
if (enabled)
Build();
}
}
//------------------------------------------------------------------------
void SourceWindow::step(int n)
{
if (pma)
pma->step(n);
}
//------------------------------------------------------------------------
void SourceWindow::step_over()
{
if (pma)
pma->step_over();
}
//------------------------------------------------------------------------
void SourceWindow::stop()
{
if (pma)
pma->stop();
}
//------------------------------------------------------------------------
void SourceWindow::run()
{
if (pma)
pma->run();
}
//------------------------------------------------------------------------
void SourceWindow::finish()
{
if (pma)
pma->finish();
}
//------------------------------------------------------------------------
void SourceWindow::reset()
{
if (gp && gp->cpu)
gp->cpu->reset(POR_RESET);
}
//------------------------------------------------------------------------
void SourceWindow::set_style_colors(const char *fg_color, const char *bg_color, GtkStyle **style)
{
GdkColor text_fg;
GdkColor text_bg;
gdk_color_parse(fg_color, &text_fg);
gdk_color_parse(bg_color, &text_bg);
*style = gtk_style_new();
(*style)->base[GTK_STATE_NORMAL] = text_bg;
(*style)->fg[GTK_STATE_NORMAL] = text_fg;
}
//------------------------------------------------------------------------
// toggleBreak
//
//
void SourceWindow::toggleBreak(NSourcePage *pPage, int line)
{
if (pma && pPage) {
int address = pma->find_address_from_line(pPage->getFC(),line+1);
if (address >= 0)
pma->toggle_break_at_address(address);
}
}
//------------------------------------------------------------------------
// movePC
//
//
void SourceWindow::movePC(int line)
{
}
//------------------------------------------------------------------------
void SourceWindow::findText()
{
if (!stPSearchDialog)
stPSearchDialog = new SearchDialog();
stPSearchDialog->Show(this);
}
//------------------------------------------------------------------------
// strcasestr is a non standard function
//
#if defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__
char *strcasestr(const char *searchee, const char *lookfor)
{
if (*searchee == '\0')
{
if (*lookfor)
return NULL;
return (char *) searchee;
}
while (*searchee != '\0')
{
size_t i;
for (i = 0; ; ++i)
{
if (lookfor[i] == '\0')
return (char *) searchee;
if (tolower(lookfor[i]) != tolower(searchee[i]))
break;
}
searchee++;
}
return NULL;
}
#endif
//------------------------------------------------------------------------
// findText
//
// Search for the pattern 'pText' in the source window.
// if bDirection is true then search forward.
int SourceWindow::findText(const char *pText, int start, bool bDirection, bool bCase)
{
if (!pText)
return 0;
int patternLen = strlen(pText);
char buff[1024];
patternLen = (patternLen < sizeof(buff)) ? patternLen : sizeof(buff);
const char *pattern = bDirection ? pText :
strReverse(pText, &buff[patternLen], patternLen);
//printf("findText %s view:%p\n",pattern,pViewContainingPopup);
NSourcePage *pPage = PageMap[pViewContainingPopup];
if (!pPage)
return 0;
GtkTextIter iStart;
GtkTextIter iEnd;
int line = 0;
int offset = 0;
int totalLines = gtk_text_buffer_get_line_count(pPage->buffer());
if (!start) {
if (bDirection) {
gtk_text_buffer_get_start_iter(pPage->buffer(),
&iStart);
gtk_text_buffer_get_iter_at_line(pPage->buffer(),
&iEnd,
line+1);
} else {
gtk_text_buffer_get_end_iter(pPage->buffer(),
&iEnd);
gtk_text_buffer_get_end_iter(pPage->buffer(),
&iStart);
gtk_text_iter_backward_line (&iStart);
line = totalLines-2;
}
} else {
gtk_text_buffer_get_iter_at_offset(pPage->buffer(),
&iStart,
start);
line = gtk_text_iter_get_line (&iStart);
if (bDirection) {
if (line >= totalLines) {
line = 0;
gtk_text_buffer_get_iter_at_offset(pPage->buffer(),
&iStart,
0);
}
} else {
if (line <= 0) {
line = totalLines-1;
gtk_text_buffer_get_iter_at_line(pPage->buffer(),
&iStart,
line--);
}
}
gtk_text_buffer_get_iter_at_line(pPage->buffer(),
&iEnd,
line);
offset = start - gtk_text_iter_get_offset (&iEnd);
gtk_text_buffer_get_iter_at_line(pPage->buffer(),
&iEnd,
line+1);
}
while (totalLines--) {
const char *str = gtk_text_buffer_get_text(pPage->buffer(),
&iStart, &iEnd, FALSE);
int srcLen = strlen(str);
const char *cpSource = str;
char buffer2[1024];
if (!bDirection) {
srcLen = (srcLen < sizeof(buffer2)) ? srcLen : sizeof(buffer2);
cpSource = strReverse(cpSource, &buffer2[srcLen], srcLen);
}
const char *pFound = bCase ? strstr(cpSource, pattern) : strcasestr(cpSource, pattern);
if (pFound) {
int pos = bDirection ? (pFound - cpSource) : (srcLen - (pFound - cpSource));
pos += offset;
//printf("Found %s in %s starting at %s, pos=%d\n",pattern, str, pFound,pos);
gtk_text_view_scroll_to_iter (pViewContainingPopup,
&iStart,
0.0,
TRUE,
0.0, 0.3);
gtk_text_buffer_get_iter_at_line_offset(pPage->buffer(),
&iStart,
line, pos);
gtk_text_buffer_get_iter_at_line_offset(pPage->buffer(),
&iEnd,
line,
pos+ (bDirection ? patternLen : -patternLen));
gtk_text_buffer_select_range (pPage->buffer(),
&iStart,
&iEnd);
return gtk_text_iter_get_offset(bDirection ? &iEnd : &iStart);
}
// Now we'll search whole lines.
offset = 0;
if (bDirection) {
if (gtk_text_iter_forward_line (&iStart)==FALSE)
return 0;
gtk_text_iter_forward_line (&iEnd);
line++;
} else {
if (gtk_text_iter_backward_line (&iStart)==FALSE)
return gtk_text_buffer_get_char_count(pPage->buffer()) - 1;
gtk_text_iter_backward_line (&iEnd);
line--;
}
}
printf("Did not find %s\n",pattern);
return 0;
}
//------------------------------------------------------------------------
gint SourceWindow::cb_notebook_switchpage (GtkNotebook *notebook,
GtkNotebookPage *page,
guint page_num,
SourceWindow *pSW)
{
return pSW->switch_page_cb(page_num);
}
gint SourceWindow::switch_page_cb(guint newPage)
{
Dprintf((" Switch page call back-- page=%d\n",newPage));
if (m_currentPage != newPage) {
m_currentPage = newPage;
NSourcePage *pPage = pages[m_currentPage];
if (!pPage)
return TRUE;
pPage->setSource();
pPage->invalidateView();
}
return TRUE;
}
//------------------------------------------------------------------------
//
void NSourcePage::invalidateView()
{
if (m_view) {
GdkRectangle vRect;
vRect.x=0;
vRect.y=0;
vRect.width=100;
vRect.height=100;
gdk_window_invalidate_rect
(gtk_text_view_get_window (m_view,
GTK_TEXT_WINDOW_LEFT),
&vRect,
TRUE);
}
}
static int settings_dialog(SOURCE_WINDOW *sbaw);
//------------------------------------------------------------------------
void
SourceWindow::PopupMenuHandler(GtkWidget *widget, gpointer data)
{
int address;
menu_item *item;
SourceWindow *pSW = 0;
NSourcePage *pPage = 0;
// pViewContainingPopup is initialized when the view_button_press()
// event handler is called. That function also initiates the event
// that invokes this callback.
if (!pViewContainingPopup) {
printf("Warning popup without a textview\n");
} else {
pPage = PageMap[pViewContainingPopup];
pSW = pPage ? pPage->getParent() : 0;
}
if (!pSW) {
printf ("Warning (bug?): popup cannot be associate with any source\n");
return;
}
item = (menu_item *)data;
switch(item->id) {
case MENU_SETTINGS:
#if defined(NEW_SOURCE_BROWSER)
settings_dialog(pSW);
#endif
break;
case MENU_FIND_TEXT:
pSW->findText();
break;
case MENU_FIND_PC:
address=pSW->pma->get_PC();
pSW->SetPC(address);
break;
case MENU_MOVE_PC:
if(-1 != pSW->m_LineAtButtonClick) {
address = pSW->pma->find_closest_address_to_line(
pPage->m_fileid,pSW->m_LineAtButtonClick + 1);
if(address!=INVALID_VALUE) {
pSW->pma->set_PC(address);
pSW->SetPC(pSW->pma->get_PC());
}
}
break;
case MENU_RUN_HERE:
if(-1 != pSW->m_LineAtButtonClick) {
address = pSW->pma->find_closest_address_to_line(
pPage->m_fileid,pSW->m_LineAtButtonClick + 1);
if(address!=INVALID_VALUE) {
pSW->gp->cpu->run_to_address(address);
}
}
break;
case MENU_BP_HERE:
if(-1 != pSW->m_LineAtButtonClick) {
pSW->toggleBreak(pPage, pSW->m_LineAtButtonClick);
}
break;
case MENU_PROFILE_START_HERE:
if(-1 != pSW->m_LineAtButtonClick) {
address = pSW->pma->find_closest_address_to_line(
pPage->m_fileid,pSW->m_LineAtButtonClick + 1);
pSW->gp->profile_window->StartExe(address);
}
break;
case MENU_PROFILE_STOP_HERE:
if(-1 != pSW->m_LineAtButtonClick) {
address = pSW->pma->find_closest_address_to_line(
pPage->m_fileid,pSW->m_LineAtButtonClick + 1);
pSW->gp->profile_window->StopExe(address);
}
break;
case MENU_SELECT_SYMBOL:
case MENU_ADD_TO_WATCH: {
GtkTextBuffer *pBuffer = pPage->buffer();
GtkTextIter itBegin, itEnd;
if(gtk_text_buffer_get_selection_bounds(
pBuffer, &itBegin, &itEnd) ) {
gchar *text = gtk_text_buffer_get_text(pBuffer, &itBegin, &itEnd, FALSE);
if(text != 0) {
TrimWhiteSpaceFromString(text);
if(text[0] != 0) {
register_symbol *pReg = get_symbol_table().findRegisterSymbol(text);
if(pReg == NULL) {
// We also try upper cased.
string sName(text);
toupper(sName);
pReg = get_symbol_table().findRegisterSymbol(sName.c_str());
}
if(pReg == NULL) {
// We also try with a '_' prefix.
string sName("_");
sName.append(text);
pReg = get_symbol_table().findRegisterSymbol(sName.c_str());
if(pReg == NULL) {
// We also try upper cased.
toupper(sName);
pReg = get_symbol_table().findRegisterSymbol(sName.c_str());
}
}
if(pReg == NULL) {
GtkWidget *dialog = gtk_message_dialog_new( GTK_WINDOW(pSW->window),
GTK_DIALOG_MODAL,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_OK,
"The symbol '%s' does not exist as a register symbol.\n"
"Only register based symbols may be added to the Watch window.",
text);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
}
else {
pSW->gp->watch_window->Add(pReg);
}
}
}
}
}
break;
case MENU_STEP:
if (pSW)
pSW->step();
break;
case MENU_STEP_OVER:
if (pSW)
pSW->step_over();
break;
case MENU_RUN:
if (pSW)
pSW->run();
break;
case MENU_STOP:
if (pSW)
pSW->stop();
break;
case MENU_RESET:
if (pSW)
pSW->reset();
break;
case MENU_FINISH:
if (pSW)
pSW->finish();
break;
default:
puts("Unhandled menuitem?");
break;
}
}
//------------------------------------------------------------------------
GtkWidget *
SourceWindow::BuildPopupMenu()
{
GtkWidget *menu;
GtkWidget *submenu;
GtkWidget *item;
unsigned int i;
menu=gtk_menu_new();
for (i=0; i < (sizeof(menu_items)/sizeof(menu_items[0])) ; i++){
item=gtk_menu_item_new_with_label(menu_items[i].name);
menu_items[i].item=item;
gtk_signal_connect(GTK_OBJECT(item),"activate",
(GtkSignalFunc) PopupMenuHandler,
&menu_items[i]);
gtk_widget_show(item);
gtk_menu_append(GTK_MENU(menu),item);
}
submenu=gtk_menu_new();
item = gtk_tearoff_menu_item_new ();
gtk_menu_append (GTK_MENU (submenu), item);
gtk_widget_show (item);
for (i=0; i < (sizeof(submenu_items)/sizeof(submenu_items[0])) ; i++){
item=gtk_menu_item_new_with_label(submenu_items[i].name);
submenu_items[i].item=item;
gtk_signal_connect(GTK_OBJECT(item),"activate",
(GtkSignalFunc) PopupMenuHandler,
&submenu_items[i]);
GTK_WIDGET_SET_FLAGS (item, GTK_SENSITIVE | GTK_CAN_FOCUS);
gtk_widget_show(item);
gtk_menu_append(GTK_MENU(submenu),item);
}
item = gtk_menu_item_new_with_label ("Controls");
gtk_menu_append (GTK_MENU (menu), item);
gtk_widget_show (item);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
return menu;
}
//------------------------------------------------------------------------
// Build
//
//
void SourceWindow::Build()
{
char *fontstring;
Dprintf((" \n"));
if(bIsBuilt)
return;
Dprintf((" \n"));
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
// get_config();
gtk_window_set_default_size(GTK_WINDOW(window), width,height);
gtk_widget_set_uposition(GTK_WIDGET(window),x,y);
gtk_window_set_wmclass(GTK_WINDOW(window),name(),"Gpsim");
g_signal_connect(GTK_OBJECT(window),"key_press_event",
(GtkSignalFunc) KeyPressHandler,
(gpointer) this);
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC(DeleteEventHandler),
(gpointer) this);
gtk_container_set_border_width (GTK_CONTAINER (window), 0);
SetTitle();
GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
gtk_widget_show(vbox);
gtk_container_add (GTK_CONTAINER (window), vbox);
m_Notebook = gtk_notebook_new();
m_currentPage = 0;
gtk_signal_connect (GTK_OBJECT (m_Notebook), "switch-page",
GTK_SIGNAL_FUNC(cb_notebook_switchpage),
(gpointer) this);
gtk_notebook_set_tab_pos((GtkNotebook*)m_Notebook,m_TabPosition);
gtk_notebook_set_scrollable ((GtkNotebook*)m_Notebook, TRUE);
gtk_box_pack_start (GTK_BOX (vbox), m_Notebook, TRUE, TRUE, 0);
status_bar = new StatusBar_Window();
if(status_bar) {
Dprintf ((" creating status bar\n"));
status_bar->Create(vbox);
}
gtk_widget_show_all(window);
gtk_widget_show_all(vbox);
gtk_widget_show_all(m_Notebook);
aPopupMenu = BuildPopupMenu();
set_style_colors("black", "white", &default_text_style);
set_style_colors("dark green", "white", &symbol_text_style);
set_style_colors("orange", "white", &label_text_style);
set_style_colors("red", "white", &instruction_text_style);
set_style_colors("blue", "white", &number_text_style);
set_style_colors("dim gray", "white", &comment_text_style);
#define DEFAULT_COMMENTFONT "-adobe-courier-bold-o-*-*-*-120-*-*-*-*-*-*"
#define DEFAULT_SOURCEFONT "-adobe-courier-bold-r-*-*-*-120-*-*-*-*-*-*"
if(config_get_string(name(),"commentfont",&fontstring))
strcpy(commentfont_string,fontstring);
else
strcpy(commentfont_string,DEFAULT_COMMENTFONT);
if(config_get_string(name(),"sourcefont",&fontstring))
strcpy(sourcefont_string,fontstring);
else
strcpy(sourcefont_string,DEFAULT_SOURCEFONT);
#if defined(NEW_SOURCE_BROWSER)
while(!load_fonts(this)) {
if(gui_question("Some fonts did not load.","Open font dialog","Try defaults")==FALSE)
{
strcpy(sourcefont_string,DEFAULT_SOURCEFONT);
strcpy(commentfont_string,DEFAULT_COMMENTFONT);
config_set_string(name(),"sourcefont",sourcefont_string);
config_set_string(name(),"commentfont",commentfont_string);
}
else
{
settings_dialog(this);
}
}
#endif
symbol_font = gtk_style_get_font(symbol_text_style);
label_font = gtk_style_get_font(label_text_style);
instruction_font = gtk_style_get_font(instruction_text_style);
number_font = gtk_style_get_font(number_text_style);
comment_font = gtk_style_get_font(comment_text_style);
default_font = gtk_style_get_font(default_text_style);
bIsBuilt = true;
if(m_bLoadSource) {
Dprintf((" \n"));
NewSource(gp);
}
}
//------------------------------------------------------------------------
//
void SourceWindow::SetTitle()
{
if (!gp || !gp->cpu || !pma)
return;
if (last_simulation_mode != eSM_INITIAL &&
((last_simulation_mode == eSM_RUNNING &&
gp->cpu->simulation_mode == eSM_RUNNING) ||
(last_simulation_mode != eSM_RUNNING &&
gp->cpu->simulation_mode != eSM_RUNNING)) &&
sLastPmaName == pma->name()) {
return;
}
last_simulation_mode = gp->cpu->simulation_mode;
char * sStatus;
if (gp->cpu->simulation_mode == eSM_RUNNING)
sStatus = "Run";
else // if (gp->cpu->simulation_mode == eSM_STOPPED)
sStatus = "Stopped";
char buffer[256];
snprintf(buffer,sizeof(buffer), "Source Browser: [%s] %s", sStatus, pma != NULL ?
pma->name().c_str() : "" );
sLastPmaName = pma->name();
gtk_window_set_title (GTK_WINDOW (window), buffer);
}
//------------------------------------------------------------------------
//
void SourceWindow::set_pma(ProgramMemoryAccess *new_pma)
{
Dprintf((" \n"));
pma = new_pma;
if(window && pma) {
SetTitle();
}
if(status_bar)
status_bar->NewProcessor(gp, pma);
}
void SourceWindow::Create(void)
{
Dprintf((" \n"));
}
void SourceWindow::SelectAddress(int address)
{
Dprintf((" \n"));
}
void SourceWindow::SelectAddress(Value *)
{
Dprintf((" \n"));
}
//------------------------------------------------------------------------
// Update
//
// Called whenever the source window needs to be updated (like after break points).
void SourceWindow::Update()
{
Dprintf((" \n"));
if (!window || !enabled)
return;
if (m_Notebook &&
((gtk_notebook_get_show_tabs(GTK_NOTEBOOK(m_Notebook))==FALSE
&& m_pParent->getTabPosition()<0) ||
(m_pParent->getTabPosition() != gtk_notebook_get_tab_pos(GTK_NOTEBOOK(m_Notebook))))) {
if (m_pParent->getTabPosition()<0) {
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_Notebook),FALSE);
} else {
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(m_Notebook),TRUE);
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(m_Notebook), (GtkPositionType) m_pParent->getTabPosition());
}
}
if (m_Notebook) {
gint currPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(m_Notebook));
if (currPage>=0 && currPage < SBAW_NRFILES) {
pages[currPage]->setSource();
pages[currPage]->setFont(m_pParent->getFont());
}
}
if(!gp || !pma || ! window)
return;
SetTitle();
SetPC(pma->get_PC());
if(status_bar)
status_bar->Update();
}
//------------------------------------------------------------------------
void SourceWindow::UpdateLine(int address)
{
assert(address>=0);
Dprintf((" UpdateLine at address=%d\n",address));
if(!bSourceLoaded() || !pma || !enabled)
return;
gint currPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(m_Notebook));
NSourcePage *pPage = pages[currPage];
if (!pPage)
return;
pPage->setSource();
int line = (pPage->getFC()->IsList()) ?
pma->getFromAddress(address)->get_lst_line() :
pma->get_src_line(address);
//int line = pma->get_src_line(address) - 1;
line -= 1;
GtkTextIter iBegin;
gtk_text_buffer_get_iter_at_line
(gtk_text_view_get_buffer(pPage->getView()),
&iBegin,
line);
int y, h;
gtk_text_view_get_line_yrange (pPage->getView(),
&iBegin,
&y,
&h);
if (pPage->m_marginWidth) {
GdkRectangle vRect;
gtk_text_view_buffer_to_window_coords
(pPage->getView(),
GTK_TEXT_WINDOW_LEFT,
0,
y,
NULL,
&y);
vRect.x=0;
vRect.y=y;
vRect.width=pPage->m_marginWidth;
vRect.height=h;
Dprintf((" UpdateLine line=%d invalidating region %d,%d %d,%d\n",line,0,y,vRect.width,h));
// Send an expose event to repaint the whole margin
gdk_window_invalidate_rect
(gtk_text_view_get_window (pPage->getView(), GTK_TEXT_WINDOW_LEFT), &vRect, TRUE);
}
return;
}
//------------------------------------------------------------------------
//
int SourceWindow::getPCLine(int page)
{
if (mProgramCounter.bIsActive && mProgramCounter.page == page)
return mProgramCounter.line;
NSourcePage *pPage = pages[page];
return (pPage->getFC()->IsList()) ?
pma->getFromAddress(pma->get_PC())->get_lst_line() :
pma->get_src_line(pma->get_PC());
}
int SourceWindow::getAddress(NSourcePage *pPage, int line)
{
return pma->find_address_from_line(pPage->getFC(),line);
}
bool SourceWindow::bAddressHasBreak(int address)
{
return address>=0 && pma->address_has_break(address);
}
int SourceWindow::getOpcode(int address)
{
return (address >= 0) ? gp->cpu->pma->get_opcode(address) : address;
}
//------------------------------------------------------------------------
bool SourcePageMargin::formatMargin(char *str, int len, int line, int addr, int opcode, bool bBreak)
{
if (str) {
int pos = 0;
int npos = 0;
*str=0;
npos = bBreak ? g_snprintf(&str[pos], len, "<span foreground=\"red\"><b>") : 0;
pos += npos;
len -= npos;
npos = m_bShowLineNumbers ? g_snprintf(&str[pos], len, "%d",line) : 0;
pos += npos;
len -= npos;
npos = (m_bShowAddresses && addr >= 0) ? g_snprintf(&str[pos], len, " %04X",addr) : 0;
pos += npos;
len -= npos;
npos = (m_bShowOpcodes && opcode >= 0) ?
g_snprintf(&str[pos], len, "%c%04X", m_bShowAddresses?':':' ', opcode)
: 0;
pos += npos;
len -= npos;
pos += bBreak ? g_snprintf(&str[pos], len, "</b></span>") : 0;
return pos != 0;
}
return false;
}
//------------------------------------------------------------------------
SourceWindow *NSourcePage::getParent()
{
return m_Parent;
}
//------------------------------------------------------------------------
bool NSourcePage::bHasSource()
{
return m_pBuffer != 0;
}
FileContext * NSourcePage::getFC()
{
return m_pBuffer ? m_pBuffer->m_pFC : 0;
}
//------------------------------------------------------------------------
GtkTextView *NSourcePage::getView()
{
setSource();
return m_view;
}
//------------------------------------------------------------------------
void NSourcePage::setSource()
{
Dprintf((" \n"));
if (!m_pBuffer)
return;
if (m_view)
return;
if (!m_pContainer)
return;
Dprintf(("SetSource fileid %d\n",m_fileid));
m_pBuffer->parse();
m_view = (GtkTextView *)gtk_text_view_new_with_buffer(m_pBuffer->getBuffer());
Dprintf(("NSourcePage::setSource() - view=%p\n",m_view));
gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (m_view),
GTK_TEXT_WINDOW_LEFT,
MARGIN_WIDTH);
PageMap[m_view] = this;
g_signal_connect(GTK_OBJECT(m_view),"key_press_event",
(GtkSignalFunc) KeyPressHandler,
(gpointer) m_Parent);
g_signal_connect(GTK_OBJECT(m_view),"button_press_event",
(GtkSignalFunc) ButtonPressHandler,
(gpointer) m_Parent);
g_signal_connect(GTK_OBJECT(m_view),"expose_event",
(GtkSignalFunc) ViewExposeEventHandler,
(gpointer) m_Parent);
GtkWidget *pSW = gtk_scrolled_window_new (0,0);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (pSW),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (m_pContainer), pSW);
gtk_container_add (GTK_CONTAINER (pSW), GTK_WIDGET(m_view));
gtk_text_view_set_wrap_mode (m_view, GTK_WRAP_NONE);
gtk_text_view_set_editable (m_view, FALSE);
setFont(m_Parent->getFont());
gtk_widget_show_all(m_pContainer);
}
//------------------------------------------------------------------------
void NSourcePage::updateMargin(int y1, int y2)
{
Dprintf((" updateMargin y1=%d y2=%d\n",y1,y2));
GtkTextView * text_view = m_view;
GArray *numbers;
GArray *pixels;
gint count;
int PCline = m_Parent->getPCLine(m_fileid);
numbers = g_array_new (FALSE, FALSE, sizeof (gint));
pixels = g_array_new (FALSE, FALSE, sizeof (gint));
GdkWindow *win = gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_LEFT);
if (y1 < 0) {
gint width;
y1 = 0;
gdk_window_get_size(win,&width,&y2);
Dprintf((" updateMargin updating whole margin y1=%d y2=%d\n",y1,y2));
}
/* get the line numbers and y coordinates. */
gtk_source_view_get_lines (text_view,
y1,
y2,
pixels,
numbers,
&count);
/* set size. */
gchar str [256];
PangoLayout *layout=0;
gint text_width=0;
FileContext *pFC = getFC();
gint addr_opcode = (pFC && !pFC->IsList()) ? 0x9999 : -1;
if ( m_Parent->margin().formatMargin(str, sizeof(str),
MAX (99, gtk_text_buffer_get_line_count (text_view->buffer)),
addr_opcode, addr_opcode,false) ) {
layout = gtk_widget_create_pango_layout (GTK_WIDGET (text_view), str);
pango_layout_get_pixel_size (layout, &text_width, NULL);
text_width+=2;
}
m_marginWidth = text_width + MARGIN_WIDTH;
gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (text_view),
GTK_TEXT_WINDOW_LEFT,
m_marginWidth);
int i=0;
while (i < count) {
gint pos;
gint line = g_array_index (numbers, gint, i) + 1;
gtk_text_view_buffer_to_window_coords (text_view,
GTK_TEXT_WINDOW_LEFT,
0,
g_array_index (pixels, gint, i),
NULL,
&pos);
int address = pFC && !pFC->IsList() ? m_Parent->getAddress(this,line) : - 1;
int opcode = pFC && !pFC->IsList() ? m_Parent->getOpcode(address) : -1;
bool bHasBreak = m_Parent->bAddressHasBreak(m_Parent->getAddress(this,line));
if (layout) {
if ( m_Parent->margin().formatMargin(str, sizeof(str),
line, address,opcode,bHasBreak)) {
pango_layout_set_markup (layout, str, -1);
gtk_paint_layout (GTK_WIDGET (text_view)->style,
win,
GTK_STATE_NORMAL,
FALSE,
NULL,
GTK_WIDGET (text_view),
NULL,
2, //text_width + 2,
pos,
layout);
}
}
if (line == PCline) {
gtk_paint_arrow
(GTK_WIDGET (text_view)->style,
win,
GTK_STATE_NORMAL,
GTK_SHADOW_OUT, // GtkShadowType shadow_type,
NULL,
GTK_WIDGET (text_view),
NULL,
GTK_ARROW_RIGHT, //GtkArrowType arrow_type,
TRUE, //gboolean fill,
text_width+PC_START,pos, PC_PIXEL_SIZE,15);
Dprintf((" updating PC at line %d\n", line));
}
if (m_Parent->getAddress(this,line) >= 0) {
// There is code associated with this line.
gtk_paint_diamond
(GTK_WIDGET (text_view)->style,
win,
GTK_STATE_NORMAL,
bHasBreak ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
NULL,
GTK_WIDGET (text_view),
NULL,
text_width+BP_START,
pos,
BP_PIXEL_SIZE,
BP_PIXEL_SIZE);
}
++i;
}
g_array_free (pixels, TRUE);
g_array_free (numbers, TRUE);
}
//------------------------------------------------------------------------
void NSourcePage::setFont(const char *cp_newFont)
{
if (m_view && cp_newFont) {
if (m_cpFont && strcmp(cp_newFont,m_cpFont)==0)
return;
g_free(m_cpFont);
m_cpFont = g_strndup(cp_newFont,256);
/* Change default font throughout the widget */
PangoFontDescription *font_desc;
font_desc = pango_font_description_from_string (m_cpFont);
gtk_widget_modify_font (GTK_WIDGET (m_view), font_desc);
pango_font_description_free (font_desc);
}
}
//------------------------------------------------------------------------
// SetPC
//
// Highlight the line corresponding to the current program counter.
//
void SourceWindow::SetPC(int address)
{
Dprintf((" \n"));
if (!bSourceLoaded() || !pma)
return;
int currPage = m_Notebook ?
gtk_notebook_get_current_page (GTK_NOTEBOOK(m_Notebook)) :
-1;
if (currPage>=0 && currPage < SBAW_NRFILES)
pages[currPage]->setSource();
// Get the file id associated with the program counter address
unsigned int sbawFileId = pma->get_file_id(address);
if(sbawFileId == 0xffffffff)
return;
int id = -1;
int PCline=-1;
if (currPage>=0 && pages[currPage]->getFC()->IsList()) {
// Don't automatically switch away from a page if it is a list file
id = currPage;
PCline = pma->getFromAddress(address)->get_lst_line();
} else {
for (id=0; id<SBAW_NRFILES; id++)
if(pages[id]->m_fileid == sbawFileId)
break;
if (id >= SBAW_NRFILES)
return; // page was not found.
// Switch to the source browser page that contains the program counter.
if (currPage != id)
gtk_notebook_set_page(GTK_NOTEBOOK(m_Notebook),id);
// Get the source line number associated with the program counter address.
PCline = pma->get_src_line(address);
if(PCline==(int)INVALID_VALUE)
return;
//PCline--;
}
int oldPCpage = -1;
bool bFirstUpdate=true;
if (mProgramCounter.bIsActive) {
oldPCpage = mProgramCounter.page;
bFirstUpdate=false;
} else
GTKWAIT;
mProgramCounter.page = id;
mProgramCounter.line = PCline;
// Get a pointer to text_view margin window.
GdkWindow *win = gtk_text_view_get_window (pages[id]->getView(), GTK_TEXT_WINDOW_LEFT);
GdkRectangle PCloc;
mProgramCounter.bIsActive = true;
mProgramCounter.pBuffer = pages[id]->buffer();
gtk_text_buffer_get_iter_at_line(mProgramCounter.pBuffer,
&mProgramCounter.iBegin,
PCline);
// Now we're going to check if the program counter is in view or not.
// Get the program counter location
gtk_text_view_get_iter_location (pages[id]->getView(),
&mProgramCounter.iBegin,
&PCloc);
// Get the viewable region of the text buffer. The region is in buffer coordinates.
GdkRectangle vRect;
gtk_text_view_get_visible_rect (pages[id]->getView(),
&vRect);
// Now normalize the program counter's location. If yloc is between
// 0 and 1.0 then the program counter is viewable. If not, then we
// we need to scroll the text view so that the program counter is
// viewable.
double yloc = (PCloc.y - vRect.y) / (double) (vRect.height);
if ( yloc < 0.05 || yloc > 0.95 || bFirstUpdate) {
gtk_text_view_scroll_to_iter (pages[id]->getView(),
&mProgramCounter.iBegin,
0.0,
TRUE,
0.0, 0.3);
gtk_text_view_get_visible_rect (pages[id]->getView(),
&vRect);
}
// If there is a margin, then invalidate it so gtk will go off and redraw it.
if (pages[id]->m_marginWidth) {
vRect.x=0;
vRect.y=0;
vRect.width=pages[id]->m_marginWidth;
// Send an expose event to repaint the whole margin
gdk_window_invalidate_rect
(win, &vRect, TRUE);
}
}
void SourceWindow::CloseSource(void)
{
Dprintf((" \n"));
}
SourcePageMargin &SourceWindow::margin()
{
return m_pParent->margin();
}
const char *SourceWindow::getFont()
{
return m_pParent->getFont();
}
void SourceWindow::NewSource(GUI_Processor *gp)
{
Dprintf((" \n"));
int i;
unsigned int address;
if(!gp || !gp->cpu || !gp->cpu->pma)
return;
Dprintf((" \n"));
Processor * pProc = gp->cpu;
if(!enabled)
{
m_bLoadSource=true;
return;
}
Dprintf((" \n"));
if(!pma)
pma = pProc->pma;
assert(wt==WT_SourceWindow);
CloseSource();
m_bLoadSource=true;
Dprintf(("NewSource\n"));
/* Now create a cross-reference link that the
* simulator can use to send information back to the gui
*/
if(pProc->pc) {
SourceXREF *cross_reference = new SourceXREF();
cross_reference->parent_window_type = WT_asm_source_window;
cross_reference->parent_window = (gpointer) this;
cross_reference->data = (gpointer) 0;
pProc->pc->add_xref((gpointer) cross_reference);
if(pProc->pc != pma->GetProgramCounter()) {
pma->GetProgramCounter()->add_xref((gpointer) cross_reference);
}
}
i=0;
while (m_pParent->ppSourceBuffers[i]) {
AddPage(m_pParent->ppSourceBuffers[i]);
i++;
}
m_bSourceLoaded = 1;
// update breakpoint widgets
unsigned uPMMaxIndex = pProc->program_memory_size();
for(unsigned int uPMIndex=0; uPMIndex < uPMMaxIndex; uPMIndex++) {
int address = pProc->map_pm_index2address(uPMIndex);
if(pma->address_has_break(address))
UpdateLine(address);
}
address=pProc->pma->get_PC();
if(address==INVALID_VALUE)
puts("Warning, PC is invalid?");
else
SetPC(address);
Dprintf((" Source is loaded\n"));
}
//------------------------------------------------------------------------
// AddPage
// Adds a page to the notebook, and returns notebook-id for that page.
//
int SourceWindow::AddPage(SourceBuffer *pSourceBuffer)
{
if (pSourceBuffer && pSourceBuffer->m_pFC)
return AddPage(pSourceBuffer, pSourceBuffer->m_pFC->name().c_str());
return -1;
}
int SourceWindow::AddPage(SourceBuffer *pSourceBuffer, const char *fName)
{
if (!bIsBuilt || !pSourceBuffer)
return -1;
GTKWAIT;
char str[256], *label_string;
GtkWidget *label;
strncpy(str,fName,sizeof(str));
label_string=str;
find_char_and_skip(&label_string,'/');
find_char_and_skip(&label_string,'\\');
label=gtk_label_new(label_string);
GtkWidget *pFrame = gtk_frame_new(NULL);
gtk_notebook_append_page(GTK_NOTEBOOK(m_Notebook),pFrame,label);
int id = gtk_notebook_page_num(GTK_NOTEBOOK(m_Notebook),pFrame);
assert(id<SBAW_NRFILES && id >=0);
NSourcePage *page = new NSourcePage(this, pSourceBuffer, id,pFrame);
pages[id] = page;
//page->setSource();
gtk_widget_show_all(pFrame);
return id;
}
//########################################################################
//
// Everything below is in the process of being deprecated...
//
//########################################################################
//#define PIXMAP_POS(sbaw,e) ((e)->pixel+(sbaw)->layout_offset+-PIXMAP_SIZE/2-(e)->font_center)
static int file_id_to_source_mode[100];
// this should be in SourceBrowserAsm struct FIXME
static struct {
int found; //
int looped; // if search hit start or end of text
int start; //
int lastfound; // index into text for start of last found string
int i; //
int lastid; //
GtkWidget *window; // the window for find dialog
GtkWidget *entry; // string GtkCombo
GtkWidget *backwards_button; // togglebutton for direction
GtkWidget *case_button; // togglebutton for case sensitivity
GList *combo_strings; // list of strings for combo
char *string; // current string, extracted from entry
} searchdlg = {0,0,-1,0,0,0,0,0,0,0};
#if !defined(NEW_SOURCE_BROWSER)
static bool bSearchdlgInitialized = false;
#endif
static int dlg_x=200, dlg_y=200;
//========================================================================
void PixmapObject::CreateFromXPM(GdkWindow *window,
GdkColor *transparent_color,
gchar **xpm)
{
pixmap = gdk_pixmap_create_from_xpm_d(window,
&mask,
transparent_color,
(gchar**)xpm);
widget = gtk_pixmap_new(pixmap,mask);
}
//========================================================================
BreakPointInfo::BreakPointInfo(int _address, int _line, int _index, int _pos)
: address(_address), pos(_pos), index(_index), line(_line),
break_widget(0), canbreak_widget(0)
{
}
BreakPointInfo::BreakPointInfo(BreakPointInfo & Dup)
{
address = Dup.address;
index = Dup.index;
line = Dup.line;
pos = Dup.pos;
break_widget = 0;
canbreak_widget = 0;
}
BreakPointInfo::~BreakPointInfo()
{
if (break_widget)
gtk_widget_destroy (break_widget);
if (canbreak_widget)
gtk_widget_destroy (canbreak_widget);
}
void BreakPointInfo::Set(GtkWidget *layout, GdkPixmap *pixmap_break, GdkBitmap *bp_mask)
{
if(!break_widget) {
break_widget = gtk_pixmap_new(pixmap_break,bp_mask);
gtk_layout_put(GTK_LAYOUT(layout),
break_widget,
PIXMAP_SIZE*0,
pos
);
}
if(canbreak_widget) {
gtk_widget_hide(canbreak_widget);
}
gtk_widget_show(break_widget);
}
void BreakPointInfo::Clear(GtkWidget *layout, GdkPixmap *pixmap_canbreak, GdkBitmap *bp_mask)
{
if(break_widget) {
gtk_widget_hide(break_widget);
}
if(!canbreak_widget) {
canbreak_widget = gtk_pixmap_new(pixmap_canbreak,bp_mask);
gtk_layout_put(GTK_LAYOUT(layout),
canbreak_widget,
PIXMAP_SIZE*0,
pos
);
}
gtk_widget_show(canbreak_widget);
}
void BreakPointInfo::setBreakWidget(GtkWidget *pBreak)
{
assert (break_widget==0);
break_widget=pBreak;
}
void BreakPointInfo::setCanBreakWidget(GtkWidget *pCanBreak)
{
assert (canbreak_widget==0);
canbreak_widget=pCanBreak;
}
//========================================================================
// all of these gui_xxxx_to_entry() do linear search.
// Binary search is possible, the list is sorted.
// pixel is 0 -> maxfont-1 for line zero.
// maxfont -> maxfont*2-1 for line one
// ...
BreakPointInfo *SourceBrowserAsm_Window::getBPatPixel(int id, int pixel)
{
BreakPointInfo *e; // to simplify expressions
GList *p; // iterator
if(!sa_xlate_list[id])
return 0;
if(pixel<0)
return (BreakPointInfo*)sa_xlate_list[id]->data;
p=sa_xlate_list[id];
// find listentry with address larger than argument
while(p->next!=0) {
e = (BreakPointInfo*)p->data;
if(e->pos+12 > pixel)
break;
p=p->next;
}
e=(BreakPointInfo*)p->data;
return e;
}
BreakPointInfo *SourceBrowserAsm_Window::getBPatLine(int id, unsigned int line)
{
BreakPointInfo *e;
GList *p;
if(!sa_xlate_list[id])
return 0;
if(line>0xffff0000)
return 0;
p=sa_xlate_list[id];
/*
locate listentry with index larger than argument
*/
while(p->next!=0)
{
e = (BreakPointInfo*)p->data;
if(e->getLine() > (int)line)
break;
p=p->next;
}
assert(p->prev); // FIXME, happens if only one line of source
p=p->prev;
e=(BreakPointInfo*)p->data;
return e;
}
BreakPointInfo *SourceBrowserAsm_Window::getBPatIndex(int id, unsigned int index)
{
BreakPointInfo *e;
GList *p;
if(!sa_xlate_list[id] || index<0)
return 0;
p=sa_xlate_list[id];
/*
locate listentry with index larger than argument
*/
while(p->next!=0)
{
e = (BreakPointInfo*)p->data;
if(e->index > index)
break;
p=p->next;
}
assert(p->prev); // FIXME, could happen
p=p->prev;
e=(BreakPointInfo*)p->data;
return e;
}
class CFormattedTextFragment : public gpsimObject {
public:
CFormattedTextFragment(const char *pFragment, int length,
GtkStyle *pStyle, GdkFont *font);
GdkFont * m_font;
GtkStyle * m_text_style;
static int s_lineascent;
static int s_linedescent;
int m_length;
string & m_Fragment;
int s_TotalLength;
void SetText(GtkText *source_text);
int GetLength();
};
int CFormattedTextFragment::s_lineascent =-1;
int CFormattedTextFragment::s_linedescent = -1;
CFormattedTextFragment::CFormattedTextFragment(
const char *pFragment, int length,
GtkStyle *pStyle, GdkFont *font)
: m_Fragment(name_str)
{
s_TotalLength = 0;
m_text_style = pStyle;
m_font = font;
// Capture the largest line ascent and descent for
// use in BreakPointInfo.
if (s_lineascent < m_font->ascent)
s_lineascent = m_font->ascent;
if (s_linedescent < m_font->descent)
s_linedescent = m_font->descent;
if(length>0)
m_Fragment.assign(pFragment, length);
else
m_Fragment.assign(pFragment);
m_length = length;
}
void CFormattedTextFragment::SetText(GtkText *source_text)
{
gtk_text_insert(source_text,
m_font,
&m_text_style->fg[GTK_STATE_NORMAL],
&m_text_style->base[GTK_STATE_NORMAL],
m_Fragment.c_str(),
m_length);
}
void SourceBrowserAsm_Window::DetermineBreakinfos(int id)
{
GList *iter = sa_xlate_list[id];
/*
for(iter=sa_xlate_list[id];iter!=0;)
{
GList *next=iter->next;
free( (BreakPointInfo*)iter->data );
g_list_remove(iter,iter->data);
iter=next;
}
*/
while (iter) {
free( (BreakPointInfo*)iter->data );
iter = g_list_remove(iter,iter->data);
}
sa_xlate_list[id]=0;
for(iter=s_global_sa_xlate_list[id];iter!=0;) {
GList *next=iter->next;
BreakPointInfo *pGlobal = (BreakPointInfo*)iter->data;
BreakPointInfo *entry= new BreakPointInfo(*pGlobal);
sa_xlate_list[id]=g_list_append(sa_xlate_list[id],entry);
iter=next;
}
}
void SourceBrowserAsm_Window::SetPC(int address)
{
BreakPointInfo *e;
int row;
gdouble inc;
unsigned int i;
unsigned int sbawFileId;
GtkWidget *new_pcw;
int id=-1;
if(!m_bSourceLoaded)
return;
if(!pma)
return;
// find notebook page containing address 'address'
sbawFileId = pma->get_file_id(address);
if(sbawFileId == 0xffffffff)
return;
for(i=0;i<SBAW_NRFILES;i++) {
if(pages[i].pageindex_to_fileid == sbawFileId)
id=i;
else {
if( pages[i].source_pcwidget!=0 &&
GTK_WIDGET_VISIBLE(pages[i].source_pcwidget) ) {
//cout << " SetPC: " << name() << " hiding page " << i << endl;
gtk_widget_hide(pages[i].source_pcwidget);
}
}
}
if(id==-1) {
puts("SourceBrowserAsm_set_pc(): could not find notebook page");
return;
}
new_pcw = pages[id].source_pcwidget;
row = pma->get_src_line(address);
if(row==(int)INVALID_VALUE)
return;
row--;
if((int)current_page != id)
gtk_notebook_set_page(GTK_NOTEBOOK(notebook),id);
if(layout_offset<0)
{ // can it normally be less than zero?
// FIXME, this should be done whenever windows are reconfigured.
int xtext,ytext;
int xfixed, yfixed;
if(GTK_TEXT(pages[id].source_text)->text_area!=0 &&
pages[id].source_layout->window!=0)
{
gdk_window_get_origin(GTK_TEXT(pages[id].source_text)->text_area,&xtext,&ytext);
gdk_window_get_origin(pages[id].source_layout->window,&xfixed,&yfixed);
layout_offset = ytext-yfixed;
//cout << " SetPC: " << name() << " updating layout offset " << layout_offset << endl;
}
}
e = getBPatLine(id, row);
if(e==0)
return;
inc = GTK_ADJUSTMENT(GTK_TEXT(pages[id].source_text)->vadj)->page_increment;
if( (unsigned int)e->pos< GTK_TEXT(pages[id].source_text)->first_onscreen_ver_pixel ||
(unsigned int)e->pos> GTK_TEXT(pages[id].source_text)->first_onscreen_ver_pixel+inc ) {
GtkAdjustment *adj = GTK_ADJUSTMENT( GTK_TEXT(pages[id].source_text)->vadj);
gdouble nvalue = e->pos - inc/2;
//printf("%d: setting adjustment to %g old value = %g\n",__LINE__,nvalue,adj->value);
gtk_adjustment_set_value(adj, nvalue);
}
if(!GTK_WIDGET_VISIBLE(new_pcw)) {
gtk_widget_show(new_pcw);
}
gtk_layout_move(GTK_LAYOUT(pages[id].source_layout),
new_pcw,
PIXMAP_SIZE,
e->pos+1
);
}
void SourceBrowserAsm_Window::SelectAddress(int address)
{
BreakPointInfo *e;
int id=-1, i;
gdouble inc;
unsigned int line;
if(!m_bSourceLoaded)
return;
if(!pma)
return;
for(i=0;i<SBAW_NRFILES;i++) {
if(pages[i].pageindex_to_fileid==pma->get_file_id(address))
id=i;
}
if(id==-1)
{
puts("SourceBrowserAsm_select_address(): could not find notebook page");
return;
}
gtk_notebook_set_page(GTK_NOTEBOOK(notebook),id);
line = pma->get_src_line(address);
if(line==INVALID_VALUE)
return;
e = getBPatLine(id, line);
if(e==0)
return;
inc = GTK_ADJUSTMENT(GTK_TEXT(pages[id].source_text)->vadj)->page_increment;
if( (unsigned int)e->pos <= GTK_TEXT(pages[id].source_text)->first_onscreen_ver_pixel ||
(unsigned int)e->pos >= GTK_TEXT(pages[id].source_text)->first_onscreen_ver_pixel+inc ) {
gtk_adjustment_set_value(GTK_ADJUSTMENT( GTK_TEXT( pages[id].source_text)->vadj),
e->pos-inc/2);
}
}
void SourceBrowserAsm_Window::SelectAddress(Value *addrSym)
{
SourceBrowser_Window::SelectAddress(addrSym);
}
void SourceBrowserAsm_Window::Update(void)
{
if(!gp || !pma || ! window)
return;
SetTitle();
//animate didn't work if (gp->cpu->simulation_mode == eSM_RUNNING ||
//gp->cpu->simulation_mode == eSM_SINGLE_STEPPING)
//return;
SetPC(pma->get_PC());
if(status_bar)
status_bar->Update();
}
/*
this happens when breakpoint is set or unset
( Can it happen for another reason? )
*/
void SourceBrowserAsm_Window::UpdateLine(int address)
{
unsigned int row;
int i,id=-1;
BreakPointInfo *e;
assert(address>=0);
if(!m_bSourceLoaded || !pma)
return;
for(i=0;i<SBAW_NRFILES && id<0;i++) {
if(pages[i].pageindex_to_fileid==pma->get_file_id(address))
id=i;
}
if(id==-1)
{
static int warned=0;
if(warned<10) {
puts("SourceBrowserAsm_update_line(): could not find notebook page");
warned++;
}
return;
}
if(id != (int)current_page) {
return;
}
row = pma->get_src_line(address);
if(row==INVALID_VALUE)
return;
row--;
e = getBPatLine(id,row);
if(e==0)
return;
/*
printf("SrcBrowserAsm_Window::UpdateLine - address=%d line=%d\n",
address,e->getLine());
*/
breakpoints.Remove(address);
notify_start_list.Remove(address);
notify_stop_list.Remove(address);
if(pma->address_has_profile_start(address))
notify_start_list.Add(address,
gtk_pixmap_new(pixmap_profile_start,startp_mask),
pages[id].source_layout,
e->pos);
else if(pma->address_has_profile_stop(address))
notify_stop_list.Add(address,
gtk_pixmap_new(pixmap_profile_stop,stopp_mask),
pages[id].source_layout,
e->pos);
else if(pma->address_has_break(address)) {
e->Set(pages[id].source_layout,pixmap_break, bp_mask);
breakpoints.Add(address,
gtk_pixmap_new(pixmap_break,bp_mask),
pages[id].source_layout,
e->pos);
} else {
e->Clear(pages[id].source_layout, pixmap_canbreak, canbp_mask);
}
}
SourceBrowserAsm_Window *popup_sbaw;
void
SourceBrowserAsm_Window::PopupMenuHandler(GtkWidget *widget, gpointer data)
{
menu_item *item;
unsigned int id, address, line;
char text[256];
if(!popup_sbaw || !popup_sbaw->gp || !popup_sbaw->gp->cpu || !popup_sbaw->pma)
return;
item = (menu_item *)data;
id = gtk_notebook_get_current_page(GTK_NOTEBOOK(popup_sbaw->notebook));
switch(item->id) {
case MENU_SETTINGS:
#if ! defined(NEW_SOURCE_BROWSER)
settings_dialog(popup_sbaw);
#endif
break;
case MENU_FIND_TEXT:
gtk_widget_set_uposition(GTK_WIDGET(searchdlg.window),dlg_x,dlg_y);
gtk_widget_show(searchdlg.window);
break;
case MENU_FIND_PC:
address=popup_sbaw->pma->get_PC();
popup_sbaw->SetPC(address);
break;
case MENU_MOVE_PC:
line = popup_sbaw->menu_data->getLine();
address = popup_sbaw->pma->find_closest_address_to_line(popup_sbaw->pages[id].pageindex_to_fileid,line+1);
if(address!=INVALID_VALUE)
popup_sbaw->pma->set_PC(address);
break;
case MENU_RUN_HERE:
line = popup_sbaw->menu_data->getLine()+1;
address = popup_sbaw->pma->find_closest_address_to_line(popup_sbaw->pages[id].pageindex_to_fileid,line);
if(address!=INVALID_VALUE)
popup_sbaw->gp->cpu->run_to_address(address);
break;
case MENU_BP_HERE:
line = popup_sbaw->menu_data->getLine() + 1;
popup_sbaw->pma->toggle_break_at_line(popup_sbaw->pages[id].pageindex_to_fileid,line);
break;
case MENU_PROFILE_START_HERE:
/*
line = popup_sbaw->menu_data->line;
address = popup_sbaw->pma->find_closest_address_to_line(popup_sbaw->pages[id].pageindex_to_fileid,line+1);
popup_sbaw->gp->profile_window->StartExe(address);
*/
break;
case MENU_PROFILE_STOP_HERE:
/*
line = popup_sbaw->menu_data->line;
address = popup_sbaw->pma->find_closest_address_to_line(popup_sbaw->pages[id].pageindex_to_fileid,line+1);
popup_sbaw->gp->profile_window->StopExe(address);
*/
break;
case MENU_SELECT_SYMBOL:
case MENU_ADD_TO_WATCH:
{
gint i, temp;
gint start, end;
#if GTK_MAJOR_VERSION >= 2
if (!gtk_editable_get_selection_bounds(
GTK_EDITABLE(popup_sbaw->pages[id].source_text),
&start, &end))
break;
#else
start=GTK_EDITABLE(popup_sbaw->pages[id].source_text)->selection_start_pos;
end=GTK_EDITABLE(popup_sbaw->pages[id].source_text)->selection_end_pos;
#endif
if(start != end) {
if(start>end)
{
temp=start;
start=end;
end=temp;
}
if((end-start+2)>256) // FIXME bounds?
end=start+256-2;
for(i=start;i<end;i++)
text[i-start]=GTK_TEXT_INDEX(GTK_TEXT(popup_sbaw->pages[id].source_text),(guint)i);
unsigned int uLastCharIndex = i-start;
text[uLastCharIndex]=0;
TrimWhiteSpaceFromString(text);
if(text[0] != 0) {
register_symbol *pReg = get_symbol_table().findRegisterSymbol(text);
if(pReg == NULL) {
// We also try upper cased.
string sName(text);
toupper(sName);
pReg = get_symbol_table().findRegisterSymbol(sName.c_str());
}
if(pReg == NULL) {
// We also try with a '_' prefix.
string sName("_");
sName.append(text);
pReg = get_symbol_table().findRegisterSymbol(sName.c_str());
if(pReg == NULL) {
// We also try upper cased.
toupper(sName);
pReg = get_symbol_table().findRegisterSymbol(sName.c_str());
}
}
if(pReg == NULL) {
GtkWidget *dialog = gtk_message_dialog_new( GTK_WINDOW(popup_sbaw->window),
GTK_DIALOG_MODAL,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_OK,
"The symbol '%s' does not exist as a register symbol.\n"
"Only register based symbols may be added to the Watch window.",
text);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
}
else {
popup_sbaw->gp->watch_window->Add(pReg);
}
}
}
// popup_sbaw->gp->symbol_window->SelectSymbolName(text);
}
break;
case MENU_STEP:
popup_sbaw->pma->step(1);
break;
case MENU_STEP_OVER:
popup_sbaw->pma->step_over();
break;
case MENU_RUN:
popup_sbaw->gp->cpu->run();
break;
case MENU_STOP:
popup_sbaw->pma->stop();
break;
case MENU_RESET:
popup_sbaw->gp->cpu->reset(POR_RESET);
break;
case MENU_FINISH:
popup_sbaw->pma->finish();
break;
default:
puts("Unhandled menuitem?");
break;
}
}
GtkWidget *
SourceBrowserAsm_Window::BuildPopupMenu(GtkWidget *sheet, SourceBrowserAsm_Window *sbaw)
{
GtkWidget *menu;
GtkWidget *submenu;
GtkWidget *item;
unsigned int i;
int id;
popup_sbaw=sbaw;
id = gtk_notebook_get_current_page(GTK_NOTEBOOK(popup_sbaw->notebook));
menu=gtk_menu_new();
for (i=0; i < (sizeof(menu_items)/sizeof(menu_items[0])) ; i++){
item=gtk_menu_item_new_with_label(menu_items[i].name);
menu_items[i].item=item;
gtk_signal_connect(GTK_OBJECT(item),"activate",
(GtkSignalFunc) PopupMenuHandler,
&menu_items[i]);
gtk_widget_show(item);
gtk_menu_append(GTK_MENU(menu),item);
}
submenu=gtk_menu_new();
item = gtk_tearoff_menu_item_new ();
gtk_menu_append (GTK_MENU (submenu), item);
gtk_widget_show (item);
for (i=0; i < (sizeof(submenu_items)/sizeof(submenu_items[0])) ; i++){
item=gtk_menu_item_new_with_label(submenu_items[i].name);
submenu_items[i].item=item;
gtk_signal_connect(GTK_OBJECT(item),"activate",
(GtkSignalFunc) PopupMenuHandler,
&submenu_items[i]);
GTK_WIDGET_SET_FLAGS (item, GTK_SENSITIVE | GTK_CAN_FOCUS);
gtk_widget_show(item);
gtk_menu_append(GTK_MENU(submenu),item);
}
item = gtk_menu_item_new_with_label ("Controls");
gtk_menu_append (GTK_MENU (menu), item);
gtk_widget_show (item);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
return menu;
}
//========================================================================
// BreakPointList - a helper class to assist in managing breakpoints
BreakPointList::BreakPointList(void)
{
iter = 0;
}
//----------------------------------------
// Remove items from a breakpoint list
//
// Input: address - if this is less than 0 then all items are removed from
// the list. Otherwise, only the items that match the address field
// in the breakpoint structure are removed.
void BreakPointList::Remove(int address = -1)
{
GList *li = iter;
while(li)
{
GList *next = li->next;
BreakPointInfo *bpi = (BreakPointInfo*)li->data;
// remove the breakpoint
if(address<0 || bpi->address==address) {
iter = g_list_remove(li,li->data);
if(bpi)
delete bpi;
}
li = next;
}
if(address<0)
iter = 0;
}
//----------------------------------------
// Add - add a new item to the breakpoint list.
//
void BreakPointList::Add(int address, GtkWidget *pwidget, GtkWidget *layout, int pos)
{
BreakPointInfo *bpi= new BreakPointInfo(address, 0,0,0);
//printf("Add: address:%d, pos:%d\n",address,pos);
bpi->setBreakWidget(pwidget);
gtk_layout_put(GTK_LAYOUT(layout),
pwidget,
PIXMAP_SIZE*0,
pos
);
gtk_widget_show(pwidget);
iter=g_list_append(iter,bpi);
}
void SourceBrowserAsm_Window::remove_all_points(
SourceBrowserAsm_Window *sbaw)
{
sbaw->breakpoints.Remove();
sbaw->notify_start_list.Remove();
sbaw->notify_stop_list.Remove();
}
gint SourceBrowserAsm_Window::switch_page_cb(
GtkNotebook *notebook,
GtkNotebookPage *page,
guint page_num,
SourceBrowserAsm_Window *sbaw)
{
if(!sbaw || !sbaw->gp || !sbaw->gp->cpu)
return 1;
if(sbaw->current_page!=page_num) {
//printf("switch_page_cb: %s, from:%d to%d\n",sbaw->name(),sbaw->current_page,page_num);
int id;
unsigned int address;
sbaw->current_page=page_num;
id=sbaw->pages[page_num].pageindex_to_fileid;
if (id != -1)
sbaw->pma->set_hll_mode(file_id_to_source_mode[id]);
// Update pc widget
// address=sbaw->gp->cpu->pc->get_raw_value();
address = sbaw->pma->get_PC();
sbaw->SetPC(address);
remove_all_points(sbaw);
// update breakpoint widgets
unsigned uPMMaxIndex = sbaw->gp->cpu->program_memory_size();
for(unsigned int uPMIndex=0; uPMIndex < uPMMaxIndex; uPMIndex++)
sbaw->UpdateLine(sbaw->gp->cpu->map_pm_index2address(uPMIndex));
}
return 1;
}
/*
button event handler for sbaw->pages[id].source_text.
If we get button1 doubleclick event then we toggle breakpoint
If we get button3 buttonpress then we popup menu.
*/
gint SourceBrowserAsm_Window::sigh_button_event(
GtkWidget *widget,
GdkEventButton *event,
SourceBrowserAsm_Window *sbaw)
{
int id;
unsigned int i;
GtkWidget *item;
int vadj_value=0;
assert(event&&sbaw);
assert(sbaw->notebook != 0);
id = gtk_notebook_get_current_page(GTK_NOTEBOOK(sbaw->notebook));
assert(id >= 0 && id < SBAW_NRFILES);
assert(sbaw->pages[id].source_text != 0);
assert(GTK_TEXT(sbaw->pages[id].source_text)->vadj != 0);
vadj_value=(int)GTK_TEXT(sbaw->pages[id].source_text)->vadj->value;
if(event->type==GDK_BUTTON_PRESS &&
event->button==3)
{
popup_sbaw=sbaw;
sbaw->menu_data = sbaw->getBPatPixel(id, (int) (event->y+vadj_value));
for (i=0; i < (sizeof(menu_items)/sizeof(menu_items[0])) ; i++) {
item=menu_items[i].item;
switch(menu_items[i].id){
case MENU_SELECT_SYMBOL:
#if GTK_MAJOR_VERSION >= 2
{
gint start, end;
if (!gtk_editable_get_selection_bounds(
GTK_EDITABLE(popup_sbaw->pages[id].source_text),
&start, &end))
{
gtk_widget_set_sensitive (item, FALSE);
}
else
{
gtk_widget_set_sensitive (item, TRUE);
}
break;
}
#else
// Why does "if(editable->has_selection)" not work? FIXME
assert(GTK_EDITABLE(popup_sbaw->pages[id].source_text));
if(GTK_EDITABLE(popup_sbaw->pages[id].source_text)->selection_start_pos
== GTK_EDITABLE(popup_sbaw->pages[id].source_text)->selection_end_pos)
{
gtk_widget_set_sensitive (item, FALSE);
}
else
{
gtk_widget_set_sensitive (item, TRUE);
}
break;
#endif
default:
break;
}
}
assert(GTK_MENU(sbaw->popup_menu));
gtk_menu_popup(GTK_MENU(sbaw->popup_menu), 0, 0, 0, 0,
3, event->time);
#if GTK_MAJOR_VERSION < 2
// override pages[id].source_text's handler
// is there a better way? FIXME
gtk_signal_emit_stop_by_name(GTK_OBJECT(sbaw->pages[id].source_text),"button_press_event");
#endif
return 1;
}
// FIXME, doesn't get button4/5 in gtk2???
//printf("event->type %d, event->button %d\n",event->type,event->button);
if(event->type==GDK_BUTTON_PRESS && event->button==4)
{ // wheel scroll up
printf("scroll up\n");
GTK_TEXT(sbaw->pages[id].source_text)->vadj->value-=GTK_TEXT(sbaw->pages[id].source_text)->vadj->page_increment/4.0;
if(GTK_TEXT(sbaw->pages[id].source_text)->vadj->value < GTK_TEXT(sbaw->pages[id].source_text)->vadj->lower)
GTK_TEXT(sbaw->pages[id].source_text)->vadj->value = GTK_TEXT(sbaw->pages[id].source_text)->vadj->lower;
gtk_adjustment_value_changed(GTK_TEXT(sbaw->pages[id].source_text)->vadj);
return 1;
}
if(event->type==GDK_BUTTON_PRESS && event->button==5)
{ // wheel scroll down
printf("scroll down\n");
GTK_TEXT(sbaw->pages[id].source_text)->vadj->value+=GTK_TEXT(sbaw->pages[id].source_text)->vadj->page_increment/4.0;
if(GTK_TEXT(sbaw->pages[id].source_text)->vadj->value > GTK_TEXT(sbaw->pages[id].source_text)->vadj->upper-GTK_TEXT(sbaw->pages[id].source_text)->vadj->page_increment)
GTK_TEXT(sbaw->pages[id].source_text)->vadj->value = GTK_TEXT(sbaw->pages[id].source_text)->vadj->upper-GTK_TEXT(sbaw->pages[id].source_text)->vadj->page_increment;
gtk_adjustment_value_changed(GTK_TEXT(sbaw->pages[id].source_text)->vadj);
return 1;
}
return 0;
}
static gint text_adj_cb(GtkAdjustment *adj, GtkAdjustment *adj_to_update)
{
// when sbaw->pages[id].source_text adjustment changes, we update the layout adj.
// I assume that both adjustments count pixels
assert(adj_to_update&&adj);
if(adj_to_update && adj )
{
if (adj_to_update->upper >= adj->value )
{
//printf("%d: setting adjustment to %g old value %g\n",__LINE__,adj->value, adj_to_update->value);
gtk_adjustment_set_value(adj_to_update, adj->value);
}
}
return 0;
}
#if 0 //warning: 'gint drag_scroll_cb(void*)' defined but not used
static float drag_scroll_speed;
static gint drag_scroll_cb(gpointer data)
{
SourceBrowserAsm_Window *sbaw = (SourceBrowserAsm_Window*)data;
int id = gtk_notebook_get_current_page(GTK_NOTEBOOK(sbaw->notebook));
puts("scroll");
GTK_TEXT(sbaw->pages[id].source_text)->vadj->value+=
GTK_TEXT(sbaw->pages[id].source_text)->vadj->step_increment*drag_scroll_speed;
if(GTK_TEXT(sbaw->pages[id].source_text)->vadj->value < GTK_TEXT(sbaw->pages[id].source_text)->vadj->lower ||
GTK_TEXT(sbaw->pages[id].source_text)->vadj->value > GTK_TEXT(sbaw->pages[id].source_text)->vadj->upper-GTK_TEXT(sbaw->pages[id].source_text)->vadj->page_increment)
{
if(drag_scroll_speed > 0)
GTK_TEXT(sbaw->pages[id].source_text)->vadj->value = GTK_TEXT(sbaw->pages[id].source_text)->vadj->upper-GTK_TEXT(sbaw->pages[id].source_text)->vadj->page_increment;
else
GTK_TEXT(sbaw->pages[id].source_text)->vadj->value = GTK_TEXT(sbaw->pages[id].source_text)->vadj->lower;
}
gtk_adjustment_value_changed(GTK_TEXT(sbaw->pages[id].source_text)->vadj);
return TRUE; // refresh timer
}
#endif
/*
This is handler for motion, button press and release for source_layout.
The GdkEventMotion and GdkEventButton are very similar so I (Ralf) use
the same for both!
This function is too complex, FIXME.
*/
static gint marker_cb(GtkWidget *w1,
GdkEventButton *event,
SourceBrowserAsm_Window *sbaw)
{
static int button_pressed;
static int button_pressed_y;
static int button_pressed_x;
static gdouble vadj_value=0.0;
static int timeout_tag=-1;
if(!sbaw || !sbaw->gp || !sbaw->gp->cpu)
return 1;
int id = gtk_notebook_get_current_page(GTK_NOTEBOOK(sbaw->notebook));
#if GTK_MAJOR_VERSION >= 2
vadj_value=GTK_TEXT(sbaw->pages[id].source_text)->vadj->value;
#endif
switch(event->type) {
case GDK_MOTION_NOTIFY:
break;
case GDK_BUTTON_PRESS:
if(button_pressed==1)
break; // click number two(/three?) of a double click?
button_pressed = 1;
button_pressed_x = (int)event->x; // and initial position of
button_pressed_y = (int)event->y; // possible drag action
break;
case GDK_2BUTTON_PRESS:
if(event->button == 1) {
int pos = (int)event->y - sbaw->layout_offset;
BreakPointInfo *e = sbaw->getBPatPixel(id, pos);
int line = e->getLine();
sbaw->pma->toggle_break_at_line(sbaw->pages[id].pageindex_to_fileid ,line+1);
}
break;
case GDK_BUTTON_RELEASE:
button_pressed=0;
if(timeout_tag!=-1)
{
gtk_timeout_remove(timeout_tag);
timeout_tag=-1;
}
break;
default:
printf("Whoops? event type %d\n",event->type);
break;
}
return 0;
}
/*
Adds a page to the notebook, and returns notebook-id for that page.
*/
int SourceBrowserAsm_Window::add_page(
SourceBrowserAsm_Window *sbaw, int file_id)
{
char str[256], *label_string;
GtkWidget *hbox, *label, *vscrollbar;
GtkStyle *style=0;
int id;
hbox = gtk_hbox_new(0,0);
gtk_container_set_border_width (GTK_CONTAINER (hbox), PAGE_BORDER);
FileContext *fc = sbaw->gp->cpu->files[file_id];
strncpy(str,fc->name().c_str(),sizeof(str));
label_string=str;
find_char_and_skip(&label_string,'/');
find_char_and_skip(&label_string,'\\');
label=gtk_label_new(label_string);
gtk_notebook_append_page(GTK_NOTEBOOK(sbaw->notebook),hbox,label);
id=gtk_notebook_page_num(GTK_NOTEBOOK(sbaw->notebook),hbox);
assert(id<SBAW_NRFILES && id >=0);
sbaw->pages[id].pageindex_to_fileid = file_id;
sbaw->pages[id].notebook_child=hbox;
gtk_widget_show(hbox);
// Create the Gray column to the left of the Source text.
sbaw->pages[id].source_layout_adj = (GtkAdjustment*)gtk_adjustment_new(0.0,0.0,0.0,0.0,0.0,0.0);
sbaw->pages[id].source_layout = gtk_layout_new(0,sbaw->pages[id].source_layout_adj);
gtk_widget_set_events(sbaw->pages[id].source_layout,
gtk_widget_get_events(sbaw->pages[id].source_layout)|
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_MOTION_MASK |
GDK_BUTTON_RELEASE_MASK);
gtk_widget_show(sbaw->pages[id].source_layout);
gtk_widget_set_usize(GTK_WIDGET(sbaw->pages[id].source_layout),PIXMAP_SIZE*2,0);
gtk_box_pack_start(GTK_BOX(hbox), sbaw->pages[id].source_layout,
FALSE,FALSE, 0);
// Create the Scroll bar.
vscrollbar = gtk_vscrollbar_new(0);
gtk_widget_show(vscrollbar);
// Create the text object for holding the Source text
sbaw->pages[id].source_text = gtk_text_new(0,GTK_RANGE(vscrollbar)->adjustment);
gtk_text_set_word_wrap(GTK_TEXT(sbaw->pages[id].source_text),0);
gtk_text_set_line_wrap(GTK_TEXT(sbaw->pages[id].source_text),0);
gtk_widget_show(sbaw->pages[id].source_text);
style=gtk_style_new();
style->base[GTK_STATE_NORMAL].red=65535;
style->base[GTK_STATE_NORMAL].green=65535;
style->base[GTK_STATE_NORMAL].blue=65535;
gtk_widget_set_style(GTK_WIDGET(sbaw->pages[id].source_text),style);
gtk_signal_connect(GTK_OBJECT(sbaw->pages[id].source_text), "button_press_event",
GTK_SIGNAL_FUNC(sigh_button_event), sbaw);
gtk_box_pack_start_defaults(GTK_BOX(hbox), sbaw->pages[id].source_text);
gtk_box_pack_start(GTK_BOX(hbox), vscrollbar,
FALSE,FALSE, 0);
gtk_signal_connect(GTK_OBJECT(GTK_TEXT(sbaw->pages[id].source_text)->vadj),
"value_changed",GTK_SIGNAL_FUNC(text_adj_cb),sbaw->pages[id].source_layout_adj);
gtk_signal_connect(GTK_OBJECT(sbaw->pages[id].source_layout),"motion-notify-event",
GTK_SIGNAL_FUNC(marker_cb),sbaw);
gtk_signal_connect(GTK_OBJECT(sbaw->pages[id].source_layout),"button_press_event",
GTK_SIGNAL_FUNC(marker_cb),sbaw);
gtk_signal_connect(GTK_OBJECT(sbaw->pages[id].source_layout),"button_release_event",
GTK_SIGNAL_FUNC(marker_cb),sbaw);
// display everything, so that gtk_notebook_get_current_page() works
GTKWAIT;
// We create pixmaps here, where the gtk_widget_get_style() call will
// succeed. I tried putting this code in CreateSourceBrowserAsmWindow()
// but then the window was not realized. And if I manually realized
// it, then the call to gtk_window_set_default_size() was ignored.
// Was that a bug in gtk? (gtk version 1.2.3)
if(sbaw->pixmap_pc==0)
{
style = gtk_style_new();
sbaw->pc_mask = 0;
sbaw->bp_mask = 0;
sbaw->canbp_mask = 0;
sbaw->startp_mask = 0;
sbaw->stopp_mask = 0;
sbaw->pixmap_pc = gdk_pixmap_create_from_xpm_d(sbaw->window->window,
&sbaw->pc_mask,
&style->bg[GTK_STATE_NORMAL],
(gchar**)pc_xpm);
sbaw->pixmap_break = gdk_pixmap_create_from_xpm_d(sbaw->window->window,
&sbaw->bp_mask,
&style->bg[GTK_STATE_NORMAL],
(gchar**)break_xpm);
sbaw->pixmap_canbreak = gdk_pixmap_create_from_xpm_d(sbaw->window->window,
&sbaw->canbp_mask,
&style->bg[GTK_STATE_NORMAL],
(gchar**)canbreak_xpm);
sbaw->pixmap_profile_start = gdk_pixmap_create_from_xpm_d(sbaw->window->window,
&sbaw->startp_mask,
&style->bg[GTK_STATE_NORMAL],
(gchar**)startp_xpm);
sbaw->pixmap_profile_stop = gdk_pixmap_create_from_xpm_d(sbaw->window->window,
&sbaw->stopp_mask,
&style->bg[GTK_STATE_NORMAL],
(gchar**)stopp_xpm);
}
sbaw->pages[id].source_pcwidget = gtk_pixmap_new(sbaw->pixmap_pc,sbaw->pc_mask);
gtk_layout_put(GTK_LAYOUT(sbaw->pages[id].source_layout),
sbaw->pages[id].source_pcwidget,PIXMAP_SIZE,0);
gtk_widget_show(sbaw->pages[id].source_pcwidget);
return id;
}
// Return true of there are instructions corresponding to the source line
int source_line_represents_code(Processor *cpu,
FileContext *fc,
unsigned int line)
{
int address;
address = cpu->pma->find_address_from_line(fc,line);
return address>=0;
}
#if GTK_MAJOR_VERSION < 2
static GdkFont *gtk_style_get_font(GtkStyle *style)
{
return style->font;
}
#endif
static int s_TotalTextLength = 0;
static CFormattedTextFragment * s_pLast = NULL;
static void InitCache(FileContext::Cache &FileCache) {
s_TotalTextLength = 0;
s_pLast = NULL;
}
static void AddCache(FileContext::Cache &FileCache, const char *pFragment,
int length,
GtkStyle *pStyle, GdkFont *font)
{
if(s_pLast && s_pLast->m_text_style == pStyle) {
if(length == -1) {
s_pLast->m_length = -1;
s_pLast->m_Fragment.append(pFragment);
}
else {
s_pLast->m_length += length;
s_pLast->m_Fragment.append(pFragment, length);
}
}
else {
s_pLast = new CFormattedTextFragment(pFragment, length, pStyle,
font);
FileCache.push_back(s_pLast);
}
s_TotalTextLength += (length == -1) ? strlen(pFragment) : length;
}
/*
Fills sbaw->pages[id].source_text with text from
file pointer sbaw->sbw.gui_obj.gp->p->files[file_id].file_ptr
*/
void SourceBrowserAsm_Window::SetText(int id, int file_id, FileContext *fc)
{
bool instruction_done;
char text_buffer[256];
int cblock=0;
int index;
int line=0;
FileContext::Cache &FileCache = fc->m_cache;
// get a manageable pointer to the processor
Processor *cpu = gp->cpu;
GtkWidget *pSourceWindow = pages[id].source_text;
gtk_text_freeze(GTK_TEXT(pSourceWindow));
gtk_editable_delete_text(GTK_EDITABLE(pSourceWindow),0,-1);
remove_all_points(this);
// Check the type of file (ASM or C), and seperate the pattern matching
// into set_text_asm() and set_text_c().
// These functions fill the page with the colored source, and also fills
// the sa_xlate_list[id] structure list with values, so that the pixmaps
// are put on the right place.
if(FileCache.size() == 0) {
s_totallinesheight[id]=0;
InitCache(FileCache);
ParseSourceToFormattedText(
id,
s_totallinesheight[id],
instruction_done,
text_buffer,
cblock,
index,
line,
FileCache,
cpu,
pSourceWindow,
fc,
file_id );
}
FileContext::Cache::iterator it;
FileContext::Cache::iterator itEnd = FileCache.end();
for(it = FileCache.begin(); it != itEnd; it++) {
CFormattedTextFragment* pFragment = (CFormattedTextFragment*)*it;
pFragment->SetText(GTK_TEXT(pSourceWindow));
}
DetermineBreakinfos(id);
gtk_layout_set_size(GTK_LAYOUT(pages[id].source_layout),
2*PIXMAP_SIZE,
s_totallinesheight[id]+5*PIXMAP_SIZE);
gtk_text_thaw(GTK_TEXT(pSourceWindow));
}
void SourceBrowserAsm_Window::ParseSourceToFormattedText(
int id,
int &totallinesheight,
bool &instruction_done,
char *text_buffer,
int &cblock,
int &index,
int &line,
FileContext::Cache &FileCache,
Processor *cpu,
GtkWidget *pSourceWindow,
FileContext *fc,
int file_id )
{
GList *iter = s_global_sa_xlate_list[id];
/*
for(iter=s_global_sa_xlate_list[id];iter!=0;)
{
GList *next=iter->next;
free( (BreakPointInfo*)iter->data );
g_list_remove(iter,iter->data);
iter=next;
}
*/
while (iter) {
free( (BreakPointInfo*)iter->data );
iter = g_list_remove(iter,iter->data);
}
s_global_sa_xlate_list[id]=0;
BreakPointInfo *entry;
char *p;
fc->rewind();
while(fc->gets(text_buffer, 256))
{
char *end, *q;
instruction_done=false; // to separate instruction from other text (symbols)
index = s_TotalTextLength;
p=text_buffer;
if(file_id_to_source_mode[file_id]==ProgramMemoryAccess::ASM_MODE) {
if(*p=='#' || !strncmp(p,"include",7))
{ // not a label
q=p;
q++;
while(isalnum(*q) || *q=='_')
q++;
AddCache(FileCache, p, q-p,default_text_style,
default_font);
p=q;
instruction_done=true; // well, variable misnamed
}
else if( (isalnum(*p) || *p=='_'))
{ // a label
// locate end of label
q=p;
while(isalnum(*q) || *q=='_')
q++;
AddCache(FileCache, text_buffer, q-p,
label_text_style, label_font);
// advance the pointer p
p=q;
}
}
// 'end' is end of line
end = text_buffer + strlen(text_buffer);
// loop through the rest of the line
while( p < end )
{
if(!source_line_represents_code(cpu,fc,line+1)) {
AddCache(FileCache, p, -1,comment_text_style,
instruction_font);
break;
}
if(file_id_to_source_mode[file_id]==ProgramMemoryAccess::HLL_MODE)
{
AddCache(FileCache, p, -1,
default_text_style, default_font);
break;
} else {
// Asm mode.
if( *p == ';') { // comment
comment_font = gtk_style_get_font(comment_text_style);
AddCache(FileCache, p, -1,
comment_text_style, comment_font);
break;
}
else if(isalpha(*p) || *p=='_')
{ // instruction, symbol or cblock
q=p;
while(isalnum(*q) || *q=='_')
q++;
if( ( !instruction_done && cblock==0) || !strncasecmp(p,"endc",4) )
{ // instruction or cblock
instruction_done=true;
cblock=0;
if(!strncasecmp(p,"cblock",6))
cblock=1;
AddCache(FileCache, p, q-p,
instruction_text_style, instruction_font);
}
else
{ // symbol
AddCache(FileCache, p, q-p,
symbol_text_style, symbol_font);
}
p=q;
}
else if( isxdigit(*p))
{ // number
q=p;
if(*p=='0' && toupper(*(p+1))=='X')
q+=2;
while(isxdigit(*q))
q++;
AddCache(FileCache, p, q-p,
number_text_style, number_font);
p=q;
}
else
{ // default
// FIXME, add a 'whitespace_text_style'
// There is a small annoyance here. If the source
// initially on a line have whitespace, followed by
// a comment. Now if the comment have a smaller font
// than the default font then the line will have line
// spacing larger than nessesary.
AddCache(FileCache, p, 1,
default_text_style, default_font);
p++;
}
}
} //end of while( p < end )
totallinesheight += CFormattedTextFragment::s_linedescent +
CFormattedTextFragment::s_lineascent;
// create an entry in sa_xlate_list for this source line.
// 'this source line' is the one in 'buf' with line number
// 'line' and index 'index' into text
int pos = totallinesheight -
(CFormattedTextFragment::s_lineascent -
CFormattedTextFragment::s_linedescent) -
PIXMAP_SIZE/2 + PAGE_BORDER;
entry= new BreakPointInfo(0, line,index,pos);
s_global_sa_xlate_list[id]=g_list_append(s_global_sa_xlate_list[id],entry);
line++;
}
// this made the end case of the search simpler once
AddCache(FileCache, " ", 1,
default_text_style, default_font);
}
void SourcePage::Close(void)
{
if(notebook != NULL && notebook_child != NULL)
{
int num=gtk_notebook_page_num(GTK_NOTEBOOK(notebook),notebook_child);
gtk_notebook_remove_page(GTK_NOTEBOOK(notebook),num);
// JRH - looks like gtk_notebook_remove_page() is also
// deallocating notebook_chile.
// gtk_widget_destroy(notebook_child);
// this is all that is needed to destroy all child widgets
// of notebook_child.
notebook_child=0;
source_layout_adj = 0;
source_layout = 0;
source_text = 0;
pageindex_to_fileid = INVALID_VALUE;
source_pcwidget = 0;
}
}
void SourceBrowserAsm_Window::CloseSource(void)
{
m_bLoadSource=0;
m_bSourceLoaded = 0;
if(!enabled)
return;
pixmap_pc=0;
pixmap_break=0;
pixmap_profile_start=0;
pixmap_profile_stop=0;
remove_all_points(this);
layout_offset=-1;
for(int i=0;i<SBAW_NRFILES;i++)
pages[i].Close();
}
void SourceBrowserAsm_Window::NewSource(GUI_Processor *_gp)
{
int i;
int id;
const char *file_name;
int file_id;
unsigned int address;
if(!gp || !gp->cpu || !gp->cpu->pma)
return;
Processor * pProc = gp->cpu;
if(!enabled)
{
m_bLoadSource=1;
return;
}
if(!pma)
pma = pProc->pma;
assert(wt==WT_asm_source_window);
CloseSource();
m_bLoadSource=1;
Dprintf(("NewSource\n"));
/* Now create a cross-reference link that the
* simulator can use to send information back to the gui
*/
if(pProc->pc) {
SourceXREF *cross_reference = new SourceXREF();
cross_reference->parent_window_type = WT_asm_source_window;
cross_reference->parent_window = (gpointer) this;
cross_reference->data = (gpointer) 0;
pProc->pc->add_xref((gpointer) cross_reference);
if(pProc->pc != pma->GetProgramCounter()) {
pma->GetProgramCounter()->add_xref((gpointer) cross_reference);
}
}
if(pProc->files.nsrc_files() != 0) {
for(i=0;i<pProc->files.nsrc_files();i++) {
FileContext *fc = pProc->files[i];
file_name = fc->name().c_str();
int iNameLength = strlen(file_name);
if(strcmp(file_name+iNameLength-4,".lst")
&&strcmp(file_name+iNameLength-4,".LST")
&&strcmp(file_name+iNameLength-4,".cod")
&&strcmp(file_name+iNameLength-4,".COD"))
{
if(!strcmp(file_name+iNameLength-2,".c")
||!strcmp(file_name+iNameLength-2,".C")
||!strcmp(file_name+iNameLength-4,".jal")
||!strcmp(file_name+iNameLength-4,".JAL")
)
{
// These are HLL sources
file_id_to_source_mode[i]=ProgramMemoryAccess::HLL_MODE;
pma->set_hll_mode(ProgramMemoryAccess::HLL_MODE);
}
// FIXME, gpsim may change sometime making this fail
file_id = i;
// Make sure that the file is open
fc->open("r");
id = add_page(this,file_id);
SetText(id,file_id, fc);
} else {
if(verbose)
printf ("SourceBrowserAsm_new_source: skipping file: <%s>\n",
file_name);
}
}
m_bSourceLoaded = 1;
}
// Why is this needed? set_page() in SourceBrowserAsm_set_pc()
// fails with widget_map() -> not visible
GTKWAIT;
address=pProc->pma->get_PC();
if(address==INVALID_VALUE)
puts("Warning, PC is invalid?");
else
SetPC(address);
// update breakpoint widgets
unsigned uPMMaxIndex = pProc->program_memory_size();
for(unsigned int uPMIndex=0; uPMIndex < uPMMaxIndex; uPMIndex++)
UpdateLine(pProc->map_pm_index2address(uPMIndex));
GTKWAIT;
Dprintf((" Source is loaded\n"));
}
static gint configure_event(GtkWidget *widget, GdkEventConfigure *e, gpointer data)
{
if(widget->window==0)
return 0;
gdk_window_get_root_origin(widget->window,&dlg_x,&dlg_y);
return 0;
}
static int load_fonts(SOURCE_WINDOW *sbaw)
{
#if GTK_MAJOR_VERSION >= 2
gtk_style_set_font(sbaw->comment_text_style,
gdk_font_from_description(pango_font_description_from_string(sbaw->commentfont_string)));
GdkFont *font = gdk_font_from_description(pango_font_description_from_string(sbaw->sourcefont_string));
gtk_style_set_font(sbaw->default_text_style, font);
gtk_style_set_font(sbaw->label_text_style, font);
gtk_style_set_font(sbaw->symbol_text_style, font);
gtk_style_set_font(sbaw->instruction_text_style, font);
gtk_style_set_font(sbaw->number_text_style, font);
if (gtk_style_get_font(sbaw->comment_text_style) == 0)
return 0;
if (gtk_style_get_font(sbaw->default_text_style) == 0)
return 0;
#else
sbaw->comment_text_style->font=
gdk_fontset_load(sbaw->commentfont_string);
sbaw->default_text_style->font=
sbaw->label_text_style->font=
sbaw->symbol_text_style->font=
sbaw->instruction_text_style->font=
sbaw->number_text_style->font=
gdk_fontset_load(sbaw->sourcefont_string);
if(sbaw->comment_text_style->font==0)
return 0;
if(sbaw->default_text_style->font==0)
return 0;
#endif
return 1;
}
/*************** Font selection dialog *********************/
class DialogFontSelect {
public:
static gint DialogRun(GtkWidget *w, gpointer user_data);
static GtkWidget *m_pFontSelDialog;
};
GtkWidget * DialogFontSelect::m_pFontSelDialog = NULL;
gint DialogFontSelect::DialogRun(GtkWidget *w, gpointer user_data)
{
GtkEntry *entry=GTK_ENTRY(user_data);
const char *fontstring;
gchar *fontname;
if(m_pFontSelDialog==0)
{
m_pFontSelDialog=gtk_font_selection_dialog_new("Select font");
fontstring=gtk_entry_get_text(entry);
#if GTK_MAJOR_VERSION < 2
gchar *spacings[] = { "c", "m", 0 };
gtk_font_selection_dialog_set_filter (GTK_FONT_SELECTION_DIALOG (m_pFontSelDialog),
GTK_FONT_FILTER_BASE, GTK_FONT_ALL,
0, 0, 0, 0, spacings, 0);
#endif
}
gint result = gtk_dialog_run (GTK_DIALOG (m_pFontSelDialog));
switch (result) {
case GTK_RESPONSE_OK:
fontname=gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(m_pFontSelDialog));
gtk_widget_hide(m_pFontSelDialog);
gtk_entry_set_text(entry,fontname);
g_free(fontname);
break;
default:
break;
}
gtk_widget_hide(m_pFontSelDialog);
return result;
}
// To give access to reg and opcode windows
int font_dialog_browse(GtkWidget *w, gpointer user_data) {
return DialogFontSelect::DialogRun(w, user_data);
}
/********************** Settings dialog ***************************/
#if 0 // defined but not used
static int settings_active;
static void settingsok_cb(GtkWidget *w, gpointer user_data)
{
if(settings_active)
{
settings_active=0;
// gtk_main_quit();
}
}
#endif
static int settings_dialog(SOURCE_WINDOW *sbaw)
{
static GtkWidget *dialog=0;
GtkWidget *button;
static int retval;
GtkWidget *hbox;
static GtkWidget *commentfontstringentry;
static GtkWidget *sourcefontstringentry;
GtkWidget *label;
int fonts_ok=0;
if(dialog==0)
{
dialog = gtk_dialog_new();
gtk_window_set_title (GTK_WINDOW (dialog), "Source browser settings");
gtk_signal_connect(GTK_OBJECT(dialog),
"configure_event",GTK_SIGNAL_FUNC(configure_event),0);
gtk_signal_connect_object(GTK_OBJECT(dialog),
"delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(dialog));
// Source font
hbox = gtk_hbox_new(0,0);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox,FALSE,FALSE,20);
gtk_widget_show(hbox);
label=gtk_label_new("Font for source:");
gtk_box_pack_start(GTK_BOX(hbox), label,
FALSE,FALSE, 20);
gtk_widget_show(label);
sourcefontstringentry=gtk_entry_new();
gtk_widget_set_size_request(sourcefontstringentry,
200, -1);
gtk_box_pack_start(GTK_BOX(hbox), sourcefontstringentry,
TRUE, TRUE, 0);
gtk_widget_show(sourcefontstringentry);
button = gtk_button_new_with_label("Browse...");
gtk_widget_show(button);
gtk_box_pack_start(GTK_BOX(hbox), button,
FALSE,FALSE,10);
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(DialogFontSelect::DialogRun),
(gpointer)sourcefontstringentry);
// Comment font
hbox = gtk_hbox_new(0,0);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
hbox,FALSE,FALSE,20);
gtk_widget_show(hbox);
label=gtk_label_new("Font for comments:");
gtk_box_pack_start(GTK_BOX(hbox), label,
FALSE,FALSE, 20);
gtk_widget_show(label);
commentfontstringentry=gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), commentfontstringentry,
TRUE, TRUE, 0);
gtk_widget_show(commentfontstringentry);
button = gtk_button_new_with_label("Browse...");
gtk_widget_show(button);
gtk_box_pack_start(GTK_BOX(hbox), button,
FALSE,FALSE,10);
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(DialogFontSelect::DialogRun),
(gpointer)commentfontstringentry);
// OK button
gtk_dialog_add_button(GTK_DIALOG(dialog), "OK", GTK_RESPONSE_OK);
}
gtk_entry_set_text(GTK_ENTRY(sourcefontstringentry), sbaw->sourcefont_string);
gtk_entry_set_text(GTK_ENTRY(commentfontstringentry), sbaw->commentfont_string);
gtk_widget_set_uposition(GTK_WIDGET(dialog),dlg_x,dlg_y);
gtk_widget_show_now(dialog);
while(fonts_ok!=2)
{
char fontname[256];
#if GTK_MAJOR_VERSION >= 2
PangoFontDescription *font;
#else
GdkFont *font;
#endif
gtk_dialog_run (GTK_DIALOG (dialog));
fonts_ok=0;
strcpy(fontname,gtk_entry_get_text(GTK_ENTRY(sourcefontstringentry)));
#if GTK_MAJOR_VERSION >= 2
if((font=pango_font_description_from_string(fontname))==0)
#else
if((font=gdk_fontset_load(fontname))==0)
#endif
{
if(gui_question("Sourcefont did not load!","Try again","Ignore/Cancel")==FALSE)
break;
}
else
{
#if GTK_MAJOR_VERSION >= 2
#else
gdk_font_unref(font);
#endif
strcpy(sbaw->sourcefont_string,gtk_entry_get_text(GTK_ENTRY(sourcefontstringentry)));
config_set_string(sbaw->name(),"sourcefont",sbaw->sourcefont_string);
fonts_ok++;
}
strcpy(fontname,gtk_entry_get_text(GTK_ENTRY(commentfontstringentry)));
#if GTK_MAJOR_VERSION >= 2
if((font=pango_font_description_from_string(fontname))==0)
#else
if((font=gdk_fontset_load(fontname))==0)
#endif
{
if(gui_question("Commentfont did not load!","Try again","Ignore/Cancel")==FALSE)
break;
}
else
{
#if GTK_MAJOR_VERSION >= 2
#else
gdk_font_unref(font);
#endif
strcpy(sbaw->commentfont_string,gtk_entry_get_text(GTK_ENTRY(commentfontstringentry)));
config_set_string(sbaw->name(),"commentfont",sbaw->commentfont_string);
fonts_ok++;
}
}
load_fonts(sbaw);
if(sbaw->m_bLoadSource)
sbaw->NewSource(sbaw->gp);
gtk_widget_hide(dialog);
return retval;
}
/*********************** gui message dialog *************************/
static gboolean
message_close_cb(GtkWidget *widget, gpointer d)
{
gtk_widget_hide(GTK_WIDGET(d));
return FALSE;
}
int gui_message(char *message)
{
static GtkWidget *dialog=0;
static GtkWidget *label;
GtkWidget *button;
GtkWidget *hbox;
assert(message);
if(dialog==0)
{
dialog = gtk_dialog_new();
gtk_signal_connect(GTK_OBJECT(dialog),
"configure_event",GTK_SIGNAL_FUNC(configure_event),0);
gtk_signal_connect_object(GTK_OBJECT(dialog),
"delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(dialog));
hbox = gtk_hbox_new(0,0);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox,FALSE,FALSE,20);
button = gtk_button_new_with_label("OK");
gtk_widget_show(button);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button,
FALSE,FALSE,10);
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(message_close_cb),(gpointer)dialog);
GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT);
gtk_widget_grab_default(button);
label=gtk_label_new(message);
gtk_box_pack_start(GTK_BOX(hbox), label,
FALSE,FALSE, 20);
gtk_widget_show(hbox);
gtk_widget_show(label);
}
else
{
gtk_label_set_text(GTK_LABEL(label),message);
}
gtk_widget_set_uposition(GTK_WIDGET(dialog),dlg_x,dlg_y);
gtk_widget_show_now(dialog);
return 0;
}
/****************** gui question dialog **************************/
static void a_cb(GtkWidget *w, gpointer user_data)
{
*(int*)user_data=TRUE;
}
static void b_cb(GtkWidget *w, gpointer user_data)
{
*(int*)user_data=FALSE;
}
// modal dialog, asking a yes/no question
int gui_question(char *question, char *a, char *b)
{
static GtkWidget *dialog=0;
static GtkWidget *label;
static GtkWidget *abutton;
static GtkWidget *bbutton;
GtkWidget *hbox;
static int retval=-1;
if(dialog==0)
{
dialog = gtk_dialog_new();
gtk_signal_connect(GTK_OBJECT(dialog),
"configure_event",GTK_SIGNAL_FUNC(configure_event),0);
gtk_signal_connect_object(GTK_OBJECT(dialog),
"delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(dialog));
hbox = gtk_hbox_new(0,0);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox,FALSE,FALSE,20);
abutton = gtk_button_new_with_label(a);
gtk_widget_show(abutton);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), abutton,
FALSE,FALSE,10);
gtk_signal_connect(GTK_OBJECT(abutton),"clicked",
GTK_SIGNAL_FUNC(a_cb),(gpointer)&retval);
GTK_WIDGET_SET_FLAGS (abutton, GTK_CAN_DEFAULT);
gtk_widget_grab_default(abutton);
bbutton = gtk_button_new_with_label(b);
gtk_widget_show(bbutton);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), bbutton,
FALSE,FALSE,10);
gtk_signal_connect(GTK_OBJECT(bbutton),"clicked",
GTK_SIGNAL_FUNC(b_cb),(gpointer)&retval);
label=gtk_label_new(question);
gtk_box_pack_start(GTK_BOX(hbox), label,
FALSE,FALSE, 20);
gtk_widget_show(hbox);
gtk_widget_show(label);
}
else
{
gtk_label_set_text(GTK_LABEL(label),question);
gtk_label_set_text(GTK_LABEL(GTK_BIN(abutton)->child),a);
gtk_label_set_text(GTK_LABEL(GTK_BIN(bbutton)->child),b);
}
gtk_widget_set_uposition(GTK_WIDGET(dialog),dlg_x,dlg_y);
gtk_widget_show_now(dialog);
gtk_grab_add(dialog);
while(retval==-1 && GTK_WIDGET_VISIBLE(dialog))
gtk_main_iteration();
gtk_grab_remove(dialog);
gtk_widget_hide(dialog);
// puts(retval==1?"Yes":"No");
return retval;
}
/*
A rather long function, simplify main loop. FIXME.
*/
void SourceBrowserAsm_Window::find_cb(
GtkWidget *w, SourceBrowserAsm_Window *sbaw)
{
const char *p;
GList *l;
int casesensitive;
int direction;
int last_matched=0;
int k=0;
int char1, char2;
int j; // index into search string
int tlen;
int id;
SourceBrowserAsm_Window * pSrcWindow = popup_sbaw;
if(!pSrcWindow->m_bSourceLoaded) return;
id = gtk_notebook_get_current_page(GTK_NOTEBOOK(pSrcWindow->notebook));
SourcePage & SrcPage = pSrcWindow->pages[id];
if(id != searchdlg.lastid)
{ // Changed notebook tab since last search reset search.
searchdlg.lastid=id;
searchdlg.found=0;
searchdlg.looped=0;
searchdlg.start=0;
searchdlg.lastfound=0;
searchdlg.i=0;
}
if(GTK_TOGGLE_BUTTON(searchdlg.case_button)->active)
casesensitive=TRUE;
else
casesensitive=FALSE;
if(GTK_TOGGLE_BUTTON(searchdlg.backwards_button)->active)
direction=-1;
else
direction=1;
p=gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(searchdlg.entry)->entry));
if(*p=='\0')
return;
if(searchdlg.string==0 || strcmp(searchdlg.string,p))
{ // not same string as last time
// search list to prevent duplicates
l=searchdlg.combo_strings;
while(l)
{
if(!strcmp((char*)l->data,p))
{
// the string p already is in list
// move it first?, FIXME
searchdlg.string = (char*)l->data;
break;
}
l=l->next;
}
if(l == 0)
{ // we didn't find string in history, create a new one
searchdlg.string=(char*)malloc(strlen(p)+1);
strcpy(searchdlg.string,p);
searchdlg.combo_strings = g_list_prepend(searchdlg.combo_strings,searchdlg.string);
gtk_combo_set_popdown_strings(GTK_COMBO(searchdlg.entry),searchdlg.combo_strings);
}
// initialize variables for a new search
searchdlg.found=0;
searchdlg.looped=0;
searchdlg.i = pSrcWindow->getBPatPixel(id,0)->index;
searchdlg.start = searchdlg.i; // remember where we started searching
}
tlen =gtk_text_get_length(GTK_TEXT(SrcPage.source_text));
j=0;
for(;searchdlg.i>=0 && searchdlg.i<tlen;searchdlg.i+=direction)
{
if(searchdlg.string[j]=='\0')
{ // match! We found the string in text.
int start_i, end_i;
searchdlg.found++;
start_i = k+ (direction==-1); // comparing backwards means
end_i = searchdlg.i+ (direction==-1); // we have to add 1
if(start_i>end_i)
{
int temp=end_i; // swap, so that k is the smaller
end_i=start_i;
start_i=temp;
}
assert(start_i<end_i);
if(start_i==searchdlg.lastfound)
{ // we found the same position as last time
// happens when searching backwards
j=0;
if(direction==1)
searchdlg.i++; // skip this match
else
searchdlg.i--; // skip this match
last_matched=0;
}
else
{
int pixel;
float inc;
searchdlg.lastfound=start_i;
pixel = pSrcWindow->getBPatPixel(id,start_i)->pos + 12;
inc = (float)GTK_ADJUSTMENT(GTK_TEXT(SrcPage.source_text)->vadj)->page_increment;
gtk_adjustment_set_value(GTK_ADJUSTMENT( GTK_TEXT( SrcPage.source_text)->vadj),
pixel-inc/2);
//printf("%d: setting adjustment to %g\n",__LINE__,pixel-inc/2);
gtk_editable_select_region(GTK_EDITABLE(SrcPage.source_text),start_i,end_i);
return;
}
}
if(searchdlg.looped && (searchdlg.start == searchdlg.i))
{
if(searchdlg.found==0)
{
gui_message("Not found");
return;
}
else if(searchdlg.found==1)
{
gui_message("Just a single occurance in text");
// so that the next next call marks text too, we do:
searchdlg.found=0;
searchdlg.looped=0;
searchdlg.lastfound=-1;
return;
}
}
// get another character
char1=GTK_TEXT_INDEX(GTK_TEXT(SrcPage.source_text),(unsigned)searchdlg.i);
if(direction==1)
char2=searchdlg.string[j];
else
char2=searchdlg.string[strlen(searchdlg.string)-1-j];
//FIXME, many calls to strlen
if(casesensitive==FALSE)
{
char1=toupper(char1); // FIXME, what about native letters?
char2=toupper(char2);
}
if(char1!=char2)
{ // if these characters don't match
j=0; // set search index for string back to zero
last_matched=0; // char in this loop didn't match
}
else
{
if(!last_matched)
{
k=searchdlg.i; // remember first matching index for later
last_matched=1; // char in this loop matched
}
j++; // forward string index to compare next char
}
}
// the string was not found in text between index 'search start' and
// one end of text (index '0' or index 'tlen')
// We ask user it he want to search from other end of file
if(direction==1)
{
if(gui_question("End of file\ncontinue from start?","Yes","No")==(int)TRUE)
{
searchdlg.i=0;
searchdlg.looped=1;
find_cb(w,pSrcWindow); // tail recursive, FIXME
return;
}
else
searchdlg.i=tlen-1;
}
else
{
if(gui_question("Top of file\ncontinue from end?","Yes", "No")==(int)TRUE)
{
searchdlg.i=tlen-1;
searchdlg.looped=1;
find_cb(w,pSrcWindow); // tail recursive, FIXME
return;
}
else
searchdlg.i=0;
}
}
void SourceBrowserAsm_Window::find_clear_cb(
GtkWidget *w, SourceBrowserAsm_Window *sbaw)
{
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(searchdlg.entry)->entry),"");
}
#if 0 // defined but not used
static void set_style_colors(const char *fg_color, const char *bg_color, GtkStyle **style)
{
GdkColor text_fg;
GdkColor text_bg;
gdk_color_parse(fg_color, &text_fg);
gdk_color_parse(bg_color, &text_bg);
*style = gtk_style_new();
(*style)->base[GTK_STATE_NORMAL] = text_bg;
(*style)->fg[GTK_STATE_NORMAL] = text_fg;
}
#endif
#if !defined(NEW_SOURCE_BROWSER)
static void BuildSearchDlg(SourceBrowserAsm_Window *sbaw)
{
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *label;
searchdlg.lastid=-1; // will reset search
searchdlg.window = gtk_dialog_new();
gtk_signal_connect(GTK_OBJECT(searchdlg.window),
"configure_event",GTK_SIGNAL_FUNC(configure_event),0);
gtk_signal_connect_object(GTK_OBJECT(searchdlg.window),
"delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(searchdlg.window));
gtk_window_set_title(GTK_WINDOW(searchdlg.window),"Find");
hbox = gtk_hbox_new(FALSE,15);
gtk_widget_show(hbox);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(searchdlg.window)->vbox),hbox,
FALSE,TRUE,5);
label = gtk_label_new("Find:");
gtk_widget_show(label);
gtk_box_pack_start(GTK_BOX(hbox),label,
FALSE,FALSE,5);
searchdlg.entry = gtk_combo_new();
gtk_widget_show(searchdlg.entry);
gtk_box_pack_start(GTK_BOX(hbox),searchdlg.entry,
TRUE,TRUE,5);
gtk_combo_disable_activate(GTK_COMBO(searchdlg.entry));
gtk_signal_connect(GTK_OBJECT(GTK_COMBO(searchdlg.entry)->entry),
"activate",
GTK_SIGNAL_FUNC(SourceBrowserAsm_Window::find_cb),sbaw);
hbox = gtk_hbox_new(FALSE,15);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(searchdlg.window)->vbox),
hbox,FALSE,TRUE,5);
gtk_widget_show(hbox);
searchdlg.case_button = gtk_check_button_new_with_label("Case Sensitive");
gtk_widget_show(searchdlg.case_button);
gtk_box_pack_start(GTK_BOX(hbox),searchdlg.case_button,
FALSE,FALSE,5);
searchdlg.backwards_button = gtk_check_button_new_with_label("Find Backwards");
gtk_widget_show(searchdlg.backwards_button);
gtk_box_pack_start(GTK_BOX(hbox),searchdlg.backwards_button,
FALSE,FALSE,5);
button = gtk_button_new_with_label("Find");
gtk_widget_show(button);
gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(searchdlg.window)->action_area),button);
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(SourceBrowserAsm_Window::find_cb),sbaw);
GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT);
gtk_widget_grab_default(button);
button = gtk_button_new_with_label("Clear");
gtk_widget_show(button);
gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(searchdlg.window)->action_area),button);
gtk_signal_connect(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(SourceBrowserAsm_Window::find_clear_cb),0);
button = gtk_button_new_with_label("Close");
gtk_widget_show(button);
gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(searchdlg.window)->action_area),button);
gtk_signal_connect_object(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(searchdlg.window));
}
void SourceBrowserAsm_Window::Build(void)
{
if(bIsBuilt)
return;
char *fontstring;
Dprintf(("Build\n"));
SourceBrowser_Window::Create();
SetTitle();
gtk_window_set_default_size(GTK_WINDOW(window), width,height);
gtk_widget_set_uposition(GTK_WIDGET(window),x,y);
notebook = gtk_notebook_new();
gtk_notebook_set_tab_pos((GtkNotebook*)notebook,GTK_POS_LEFT);
gtk_notebook_set_scrollable((GtkNotebook*)notebook,TRUE);
for(int i=0;i<SBAW_NRFILES;i++) {
pages[i].notebook = notebook;
}
gtk_signal_connect(GTK_OBJECT(notebook),
"switch_page",GTK_SIGNAL_FUNC(switch_page_cb),this);
gtk_widget_show(notebook);
popup_menu=BuildPopupMenu(notebook,this);
gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
set_style_colors("black", "white", &default_text_style);
set_style_colors("dark green", "white", &symbol_text_style);
set_style_colors("orange", "white", &label_text_style);
set_style_colors("red", "white", &instruction_text_style);
set_style_colors("blue", "white", &number_text_style);
set_style_colors("dim gray", "white", &comment_text_style);
//#if GTK_MAJOR_VERSION >= 2
//#define DEFAULT_COMMENTFONT "Courier Bold Oblique 12"
//#define DEFAULT_SOURCEFONT "Courier Bold 12"
//#else
//#endif
if(config_get_string(name(),"commentfont",&fontstring))
strcpy(commentfont_string,fontstring);
else
strcpy(commentfont_string,DEFAULT_COMMENTFONT);
if(config_get_string(name(),"sourcefont",&fontstring))
strcpy(sourcefont_string,fontstring);
else
strcpy(sourcefont_string,DEFAULT_SOURCEFONT);
while(!load_fonts(this)) {
if(gui_question("Some fonts did not load.","Open font dialog","Try defaults")==FALSE)
{
strcpy(sourcefont_string,DEFAULT_SOURCEFONT);
strcpy(commentfont_string,DEFAULT_COMMENTFONT);
config_set_string(name(),"sourcefont",sourcefont_string);
config_set_string(name(),"commentfont",commentfont_string);
}
else
{
settings_dialog(this);
}
}
symbol_font = gtk_style_get_font(symbol_text_style);
label_font = gtk_style_get_font(label_text_style);
instruction_font = gtk_style_get_font(instruction_text_style);
number_font = gtk_style_get_font(number_text_style);
comment_font = gtk_style_get_font(comment_text_style);
default_font = gtk_style_get_font(default_text_style);
if(!bSearchdlgInitialized) {
BuildSearchDlg(this);
bSearchdlgInitialized = true;
}
gtk_signal_connect_after(GTK_OBJECT(window), "configure_event",
GTK_SIGNAL_FUNC(gui_object_configure_event),this);
if(status_bar)
status_bar->Create(vbox);
gtk_widget_show(window);
bIsBuilt = true;;
if(m_bLoadSource)
NewSource(gp);
UpdateMenuItem();
}
#endif
void SourceBrowser_Window::set_pma(ProgramMemoryAccess *new_pma)
{
pma = new_pma;
if(window && pma) {
SetTitle();
}
if(status_bar)
status_bar->NewProcessor(gp, pma);
}
SourceBrowserAsm_Window::SourceBrowserAsm_Window(GUI_Processor *_gp, char* new_name=0)
{
m_SourceWindowIndex = m_SourceWindowCount;
m_SourceWindowCount++;
menu = "<main>/Windows/Source";
window = 0;
gp = _gp;
pma = 0;
if(new_name)
set_name(new_name);
else
set_name("source_browser");
wc = WC_source;
wt = WT_asm_source_window;
status_bar = new StatusBar_Window();
breakpoints.iter=0;
notify_start_list.iter=0;
notify_stop_list.iter=0;
layout_offset=-1;
pixmap_pc = 0; // these are created somewhere else
pixmap_break=0;
pixmap_profile_start=0;
pixmap_profile_stop=0;
m_bSourceLoaded = 0;
m_bLoadSource=0;
get_config();
current_page = 0xffffffff;
for(int i=0; i<SBAW_NRFILES; i++) {
if(!bGlobalInitialized) {
s_global_sa_xlate_list[i] = 0;
}
sa_xlate_list[i] = 0;
}
bGlobalInitialized = true;
if(enabled)
Build();
}
bool SourceBrowserAsm_Window::bGlobalInitialized = false;
GList * SourceBrowserAsm_Window::s_global_sa_xlate_list[SBAW_NRFILES];
int SourceBrowserAsm_Window::s_totallinesheight[SBAW_NRFILES];
int SourceBrowserAsm_Window::m_SourceWindowCount = 0;
//========================================================================
//
// SourceBrowserParent_Window
//
// Here is some experimental code that allows multiple source browser
// windows.
SourceBrowserParent_Window::SourceBrowserParent_Window(GUI_Processor *_gp)
: GUI_Object()
{
gp = _gp;
set_name("source_browser_parent");
#if defined(NEW_SOURCE_BROWSER)
pma = 0;
m_TabType = GTK_POS_BOTTOM;
mpTagTable = gtk_text_tag_table_new();
const char *sName = "source_config";
char *fg=0;
mLabel = new TextStyle("Label",
config_get_string(sName, "label_fg", &fg) ? fg : "orange",
"white");
fg=0;
mMnemonic = new TextStyle("Mnemonic",
config_get_string(sName, "mnemonic_fg", &fg) ? fg : "red",
"white");
fg=0;
mSymbol = new TextStyle("Symbols",
config_get_string(sName, "symbol_fg", &fg) ? fg : "dark green",
"white");
fg=0;
mComment = new TextStyle("Comments",
config_get_string(sName, "comment_fg", &fg) ? fg : "dim gray",
"white");
fg=0;
mConstant = new TextStyle("Constants",
config_get_string(sName, "constant_fg", &fg) ? fg : "blue",
"white");
fg=0;
mDefault = new TextStyle("Default",
"black",
"white");
if (!config_get_variable(sName, "tab_position", &m_TabType))
m_TabType = GTK_POS_LEFT;
int b=1;
config_get_variable(sName, "line_numbers", &b);
margin().enableLineNumbers(b!=0);
config_get_variable(sName, "addresses", &b);
margin().enableAddresses(b!=0);
config_get_variable(sName, "opcodes", &b);
margin().enableOpcodes(b!=0);
mBreakpointTag = new TextStyle("BreakPoint","black", "red");
mNoBreakpointTag = new TextStyle("NoBreakPoint","black", "white");
mCurrentLineTag = new TextStyle("CurrentLine","black", "light green");
gtk_text_tag_table_add (mpTagTable, mLabel->tag());
gtk_text_tag_table_add (mpTagTable, mMnemonic->tag());
gtk_text_tag_table_add (mpTagTable, mSymbol->tag());
gtk_text_tag_table_add (mpTagTable, mComment->tag());
gtk_text_tag_table_add (mpTagTable, mConstant->tag());
gtk_text_tag_table_add (mpTagTable, mDefault->tag());
gtk_text_tag_table_add (mpTagTable, mBreakpointTag->tag());
gtk_text_tag_table_add (mpTagTable, mNoBreakpointTag->tag());
gtk_text_tag_table_add (mpTagTable, mCurrentLineTag->tag());
m_FontDescription = 0;
if (config_get_string(sName, "font", &fg))
setFont(fg);
else
setFont("Serif 8");
ppSourceBuffers = new SourceBuffer *[SBAW_NRFILES];
for (int i=0; i<SBAW_NRFILES; i++)
ppSourceBuffers[i] = 0;
children.push_back(new SourceWindow(_gp,this,true));
#else
children.push_back(new SOURCE_WINDOW(_gp));
#endif
}
SOURCE_WINDOW *SourceBrowserParent_Window::getChild(int n)
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
sbaw_iterator = children.begin();
return (sbaw_iterator != children.end()) ? *sbaw_iterator : 0;
}
void SourceBrowserParent_Window::Build(void)
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
for (sbaw_iterator = children.begin();
sbaw_iterator != children.end();
sbaw_iterator++)
(*sbaw_iterator)->Build();
UpdateMenuItem();
}
void SourceBrowserParent_Window::NewProcessor(GUI_Processor *gp)
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
list <ProgramMemoryAccess *> :: iterator pma_iterator;
sbaw_iterator = children.begin();
pma_iterator = gp->cpu->pma_context.begin();
#if defined(NEW_SOURCE_BROWSER)
CreateSourceBuffers(gp);
#endif
int child = 1;
SOURCE_WINDOW *sbaw=0;
while( (sbaw_iterator != children.end()) ||
(pma_iterator != gp->cpu->pma_context.end()))
{
char child_name[64];
if(sbaw_iterator == children.end())
{
child++;
sprintf(child_name,"source_browser%d",child);
#if defined(NEW_SOURCE_BROWSER)
sbaw = new SOURCE_WINDOW(gp,this, true, child_name);
#else
sbaw = new SOURCE_WINDOW(gp,child_name);
#endif
children.push_back(sbaw);
}
else
sbaw = *sbaw_iterator++;
if(pma_iterator != gp->cpu->pma_context.end())
{
sbaw->set_pma(*pma_iterator);
pma_iterator++;
}
else
{
sbaw->set_pma(gp->cpu->pma);
}
}
}
void SourceBrowserParent_Window::SelectAddress(int address)
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
for (sbaw_iterator = children.begin();
sbaw_iterator != children.end();
sbaw_iterator++)
(*sbaw_iterator)->SelectAddress(address);
}
void SourceBrowserParent_Window::SelectAddress(Value *addrSym)
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
for (sbaw_iterator = children.begin();
sbaw_iterator != children.end();
sbaw_iterator++)
(*sbaw_iterator)->SelectAddress(addrSym);
}
void SourceBrowserParent_Window::Update(void)
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
for (sbaw_iterator = children.begin();
sbaw_iterator != children.end();
sbaw_iterator++)
(*sbaw_iterator)->Update();
}
void SourceBrowserParent_Window::UpdateLine(int address)
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
for (sbaw_iterator = children.begin();
sbaw_iterator != children.end();
sbaw_iterator++)
(*sbaw_iterator)->UpdateLine(address);
}
void SourceBrowserParent_Window::SetPC(int address)
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
for (sbaw_iterator = children.begin();
sbaw_iterator != children.end();
sbaw_iterator++)
(*sbaw_iterator)->SetPC(address);
}
void SourceBrowserParent_Window::CloseSource(void)
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
for (sbaw_iterator = children.begin();
sbaw_iterator != children.end();
sbaw_iterator++)
(*sbaw_iterator)->CloseSource();
}
void SourceBrowserParent_Window::NewSource(GUI_Processor *gp)
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
#if defined(NEW_SOURCE_BROWSER)
CreateSourceBuffers(gp);
#endif
for (sbaw_iterator = children.begin();
sbaw_iterator != children.end();
sbaw_iterator++)
(*sbaw_iterator)->NewSource(gp);
}
void SourceBrowserParent_Window::ChangeView(int view_state)
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
for (sbaw_iterator = children.begin();
sbaw_iterator != children.end();
sbaw_iterator++)
(*sbaw_iterator)->ChangeView(view_state);
}
int SourceBrowserParent_Window::set_config()
{
list <SOURCE_WINDOW *> :: iterator sbaw_iterator;
for (sbaw_iterator = children.begin();
sbaw_iterator != children.end();
sbaw_iterator++)
(*sbaw_iterator)->set_config();
#if defined(NEW_SOURCE_BROWSER)
const char *sName = "source_config";
char buff[100];
config_set_string(sName,"mnemonic_fg",mMnemonic->mFG.get(buff, sizeof(buff)));
config_set_string(sName,"label_fg",mLabel->mFG.get(buff, sizeof(buff)));
config_set_string(sName,"symbol_fg",mSymbol->mFG.get(buff, sizeof(buff)));
config_set_string(sName,"comment_fg",mComment->mFG.get(buff, sizeof(buff)));
config_set_string(sName,"constant_fg",mConstant->mFG.get(buff, sizeof(buff)));
config_set_string(sName,"font", getFont());
config_set_variable(sName, "tab_position", getTabPosition());
config_set_variable(sName, "line_numbers", margin().bLineNumbers());
config_set_variable(sName, "addresses", margin().bAddresses());
config_set_variable(sName, "opcodes", margin().bOpcodes());
#endif
return 0;
}
//------------------------------------------------------------------------
// parseLine
//
// Added a line of text to the source buffer. Apply syntax highlighting.
//
void SourceBuffer::parseLine(const char *cP,
int parseStyle)
{
GtkTextIter iEnd;
GtkTextBuffer *pTextBuffer = m_buffer;
gtk_text_buffer_get_end_iter (pTextBuffer, &iEnd);
int offset = gtk_text_iter_get_offset (&iEnd);
gtk_text_buffer_insert (pTextBuffer, &iEnd, cP, -1);
if (parseStyle<0) {
addTagRange(m_pParent->mComment,offset,offset + strlen(cP));
return;
}
int i=0;
int j=0;
bool bHaveMnemonic = false;
if (i != (j = isString(cP))) {
addTagRange(m_pParent->mLabel,i+offset,j+offset);
i=j;
}
while (!isEnd(cP[i])) {
if ( (j=isWhiteSpace(&cP[i])) != 0) {
i += j;
} else if ( (j=isString(&cP[i])) != 0) {
if (bHaveMnemonic)
addTagRange(m_pParent->mSymbol,i+offset,i+j+offset);
else
addTagRange(m_pParent->mMnemonic,i+offset,i+j+offset);
bHaveMnemonic = true;
i += j;
} else if ( (j=isNumber(&cP[i])) != 0) {
addTagRange(m_pParent->mConstant,i+offset,i+j+offset);
i += j;
} else if ( (j=isComment(&cP[i])) != 0) {
addTagRange(m_pParent->mComment,i+offset,i+j+offset);
i += j;
return;
} else
i++;
}
}
//------------------------------------------------------------------------
SourcePageMargin &SourceBrowserParent_Window::margin()
{
return m_margin;
}
//------------------------------------------------------------------------
void SourceBrowserParent_Window::setTabPosition(int tt)
{
m_TabType = tt;
Update();
}
//------------------------------------------------------------------------
void SourceBrowserParent_Window::setFont(const char *cpNewFont)
{
if (cpNewFont) {
g_free(m_FontDescription);
m_FontDescription = g_strndup(cpNewFont,256);
Update();
}
}
const char *SourceBrowserParent_Window::getFont()
{
return m_FontDescription;
}
//------------------------------------------------------------------------
// parseSource
void SourceBrowserParent_Window::parseSource(SourceBuffer *pBuffer,FileContext *pFC)
{
pFC->rewind();
char text_buffer[256];
int line = 1;
while(pFC->gets(text_buffer, sizeof(text_buffer))) {
int address;
// The syntax highlighting doesn't work on list files
address = pFC->IsList() ? -1 : gp->cpu->pma->find_address_from_line(pFC,line);
pBuffer->parseLine(text_buffer,address);
line++;
}
}
//------------------------------------------------------------------------
void SourceBrowserParent_Window::CreateSourceBuffers(GUI_Processor *gp)
{
Dprintf((" \n"));
int i;
const char *file_name;
if(!gp || !gp->cpu || !gp->cpu->pma)
return;
Dprintf((" \n"));
Processor * pProc = gp->cpu;
if(!pma)
pma = pProc->pma;
CloseSource();
Dprintf(("NewSource\n"));
if(pProc->files.nsrc_files() != 0) {
for(i=0;i<pProc->files.nsrc_files();i++) {
FileContext *fc = pProc->files[i];
file_name = fc->name().c_str();
int iNameLength = strlen(file_name);
if(strcmp(file_name+iNameLength-4,".cod")
&& strcmp(file_name+iNameLength-4,".COD")
&& (i < SBAW_NRFILES) )
ppSourceBuffers[i] = new SourceBuffer(mpTagTable, fc, this);
else {
if(verbose)
printf ("SourceBrowserAsm_new_source: skipping file: <%s>\n",
file_name);
}
}
}
Dprintf((" Source is loaded\n"));
}
#endif // HAVE_GUI
syntax highlighted by Code2HTML, v. 0.9.1