#include "config.h" #if BX_DEBUGGER && BX_DEBUGGER_GUI #include "bochs.h" #include "enh_dbg.h" #include #include #include // replace the Win32 COLORREF and RGB definitions, for GDK #define RGB(R,G,B) {(R<<16)|(G<<8)|B,(R*65535)/255,(G*65535)/255,(B*65535)/255} // User Customizable Register color table: // background "register type" colors indexed by RegColor value const GdkColor ColorList[16] = { RGB(255,255,255), // white RGB(200,255,255), // blue (aqua) RGB(230,230,230), // gray RGB(248,255,200), // yellow RGB(216,216,255), // purple RGB(200,255,200), // green RGB(255,230,200), // orange RGB(255,255,255), // more user definable RGB(255,255,255), RGB(255,255,255), RGB(255,255,255), RGB(255,255,255), RGB(255,255,255), RGB(255,255,255), RGB(255,255,255), RGB(255,255,255) }; // END of User Customizable settings #define TreeParent GtkTreeIter void DockResize (int j, Bit32u x); // need some function prototypes void SetHorzLimits(); void ParseIDText(char *x); void ShowData(); void UpdateStatus(); void doUpdate(); void RefreshDataWin(); void OnBreak(); void ParseBkpt(); void SetBreak(int i); void SetWatchpoint(unsigned * num_watchpoints, bx_phy_address * watchpoint); void ChangeReg(); int HotKey (int ww, int Alt, int Shift, int Control); void ActivateMenuItem (int LW); void SetMemLine (int L); void MakeBL(TreeParent *tp, bx_param_c *p); #define NUM_CHKS 24 // slight overestimate of # of Optmenu items with checkmarks #define WSChkIdx 19 // "checkmark index" of the first "wordsize" menu item // reverse mapping from command indexes to menu item widgets GtkWidget *Cmd2MI[CMD_IDX_HI - CMD_IDX_LO + 1]; // GTK objects and global stuff GtkTextMark* EndMark; GtkTreeViewColumn *AllCols[24]; GtkCellRenderer *LV_Rend[3]; GdkCursor *SizeCurs; GdkCursor *DockCurs; gulong mmov_hID; // GTK containers GtkWidget *window; GtkWidget *menubar; GtkWidget *CmdMenu; GtkWidget *ViewMenu; GtkWidget *OptMenu; GtkWidget *HelpMenu; GtkWidget *MainVbox; GtkWidget *CmdBHbox; GtkWidget *CpuBHbox; GtkWidget *StatHbox; GtkWidget *TreeTbl; GtkWidget *IOVbox; GtkWidget *ScrlWinOut; GtkWidget *ScrlWin[3]; GtkWidget *LVHbox; GtkWidget *LVEvtBox; GtkWidget *VSepEvtBox1; GtkWidget *VSepEvtBox2; // GTK menu widgets -- titles, then actual menu items GtkWidget *CmdTitle; GtkWidget *ViewTitle; GtkWidget *OptTitle; GtkWidget *HelpTitle; GtkWidget *ContMI; GtkWidget *StepMI; GtkWidget *StepNMI; GtkWidget *BreakMI; GtkWidget *SetBrkMI; GtkWidget *WatchWrMI; GtkWidget *WatchRdMI; GtkWidget *FindMI; GtkWidget *RefreshMI; GtkWidget *PhyDumpMI; GtkWidget *LinDumpMI; GtkWidget *StackMI; GtkWidget *GDTMI; GtkWidget *IDTMI; GtkWidget *PageMI; GtkWidget *ViewBrkMI; GtkWidget *MemDumpMI; GtkWidget *PTreeMI; GtkWidget *DisAsmMI; GtkWidget *ChkMIs[NUM_CHKS]; // menu items with checkmarks //GtkWidget *XceptMI; GtkWidget *DefDisMI; GtkWidget *SyntaxMI; GtkWidget *FontMI; GtkWidget *WrdSizeMI; GtkWidget *WSmenu; GtkWidget *AboutMI; GtkWidget *sep1; // menu separators GtkWidget *sep2; GtkWidget *sep3; GtkWidget *sep4; GtkWidget *sep5; GtkWidget *sep6; GtkWidget *sep7; GtkWidget *sep8; // separators around the ListViews GtkWidget *sep9; // GTK widgets GtkWidget *CmdBtn[5]; // "command" buttonrow GtkWidget *CpuBtn[BX_MAX_SMP_THREADS_SUPPORTED]; // "CPU" buttonrow GtkWidget *CpuB_label[BX_MAX_SMP_THREADS_SUPPORTED]; // "labels" on CPU buttons GtkWidget *Stat[4]; // 4 entry "Status Bar" GtkWidget *StatVSep1; GtkWidget *StatVSep2; GtkWidget *StatVSep3; GtkWidget *IEntry; // Singleline Input Text Window GtkWidget *OText; // Multiline, wrapping, Output Text Window GtkWidget *PTree; // bochs param_tree TreeView GtkWidget *LV[3]; // Register, ASM, MemDump / ListViews (TreeViews) // HIHI put all these colors in an array, and use #defines for them // need a "medium gray" color for inactive lists const GdkColor mgray = RGB(200,200,200); const GdkColor white = { 0xffffff, 0xffff, // need to specify cell background color sometimes 0xffff, 0xffff }; GdkColor fg_red = RGB(255,0,0); GdkColor fg_black = RGB(0,0,0); const GdkColor AsmColors[4] = { RGB(0,0,0), RGB(0,100,0), RGB(150,0,0), RGB(0,0,200) }; const GdkColor PDumpClr[4] = { RGB(0,0,0), RGB(255,0,150), RGB(0,170,255), RGB(130,255,0) }; unsigned int CurXSize; // last known size of main client window int DumpSelRow; // keeps track of "clicks" on MemDump entries int SelectedEntry; // keeps track of "clicks" on ASM entries bx_bool UpdateOWflag = FALSE; bx_bool HitBrkflag = FALSE; bx_bool ForcingCheck = FALSE; // using a hotkey to flip a menu item checkmark int KeyStateShft; int KeyStateAlt; // guint PrevState = GDK_BUTTON1_MASK; // turn on the "mouseup" bit, to detect the first mousedown int SizingDelay = 0; bx_bool EnterSizeMode = FALSE; unsigned int CurScrX; //bx_bool UpdInProgress[3]; // flag -- list update incomplete (not OK to paint) char SelMem[260]; // flag array for which list rows are "selected" char SelAsm[MAX_ASM]; char SelReg[TOT_REG_NUM + EXTRA_REGS]; // "run" the standard dialog box -- get text from the user bx_bool ShowAskDialog() { bx_bool ret = FALSE; static GtkWidget *dialog = NULL; static GtkWidget *AskEntry = NULL; static GtkWidget *AskPrompt = NULL; const gchar *entry_text; if (dialog == NULL) { dialog = gtk_dialog_new (); gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); } // HIHI should the "transient" line be INSIDE the dialog creation "if"? -- when I tried it, it crashed? // The following causes this dialog to stay above the main window // gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window)); gtk_window_set_title (GTK_WINDOW (dialog), ask_str.title); if (AskEntry == NULL) { AskPrompt = gtk_label_new (ask_str.prompt); gtk_widget_show (AskPrompt); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), AskPrompt, TRUE, TRUE, 5); AskEntry = gtk_entry_new (); // "Enter" (activate) = OK button gtk_entry_set_activates_default (GTK_ENTRY (AskEntry), TRUE); // increase the width of the Entry to about 80 chars gtk_entry_set_width_chars (GTK_ENTRY (AskEntry), 80); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), AskEntry, TRUE, TRUE, 5); } gtk_widget_show (AskEntry); gtk_label_set_text (GTK_LABEL (AskPrompt), ask_str.prompt); gtk_widget_grab_focus(AskEntry); // Entry must be visible before it can get focus // and it must have focus before any new text is set, or the dialog will crash gtk_entry_set_text (GTK_ENTRY (AskEntry), ask_str.reply); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { entry_text = gtk_entry_get_text (GTK_ENTRY (AskEntry)); strcpy (ask_str.reply, entry_text); ret = TRUE; } // if any text remains in the Entry, the dialog box will crash on its next use gtk_entry_set_text (GTK_ENTRY (AskEntry), ""); // so clear it gtk_widget_grab_focus(IEntry); gtk_widget_hide (dialog); // for reuse! return ret; } // set all TRUE flags to checked in the Options menu void InitMenus() { //L exception notify is not implemented yet menubar = gtk_menu_bar_new(); CmdMenu = gtk_menu_new(); ViewMenu = gtk_menu_new(); OptMenu = gtk_menu_new(); HelpMenu = gtk_menu_new(); CmdTitle = gtk_menu_item_new_with_label("Commands"); // each menu needs a title ViewTitle = gtk_menu_item_new_with_label("View"); // (and the titles are created as widgets) OptTitle = gtk_menu_item_new_with_label("Options"); HelpTitle = gtk_menu_item_new_with_label("Help"); gtk_menu_item_set_submenu(GTK_MENU_ITEM(CmdTitle), CmdMenu); gtk_menu_item_set_submenu(GTK_MENU_ITEM(ViewTitle), ViewMenu); gtk_menu_item_set_submenu(GTK_MENU_ITEM(OptTitle), OptMenu); gtk_menu_item_set_submenu(GTK_MENU_ITEM(HelpTitle), HelpMenu); gtk_menu_shell_append(GTK_MENU_SHELL(menubar), CmdTitle); gtk_menu_shell_append(GTK_MENU_SHELL(menubar), ViewTitle); gtk_menu_shell_append(GTK_MENU_SHELL(menubar), OptTitle); gtk_menu_shell_append(GTK_MENU_SHELL(menubar), HelpTitle); // build all the menu items // Commands Menu ContMI = gtk_menu_item_new_with_label("Continue [c]\t\t\t\t\tF5"); StepMI = gtk_menu_item_new_with_label("Step [s]\t\t\t\t\t\tF11"); StepNMI = gtk_menu_item_new_with_label("Step #...\t\t\t\t\t\tF9"); BreakMI = gtk_menu_item_new_with_label("Break\t\t\t\t\t\tCtrl+C"); SetBrkMI = gtk_menu_item_new_with_label("Breakpoint (ASM selected)\t\tF6"); WatchWrMI = gtk_menu_item_new_with_label("Watch Write (PhysDump selected)\tShift+F6"); WatchRdMI = gtk_menu_item_new_with_label("Watch Read (PhysDump selected)\tAlt+F6"); FindMI = gtk_menu_item_new_with_label("Find...\t\t\t\t\t\tCtrl+F"); RefreshMI = gtk_menu_item_new_with_label("Refresh Screen\t\t\t\t\tF4"); // View Menu PhyDumpMI = gtk_menu_item_new_with_label("Physical MemDump...\tCtrl+F7"); LinDumpMI = gtk_menu_item_new_with_label("Linear MemDump...\t\tF7"); StackMI = gtk_menu_item_new_with_label("Stack\t\t\t\tF2"); GDTMI = gtk_menu_item_new_with_label("GDT\t\t\t\t\tCtrl+F2"); IDTMI = gtk_menu_item_new_with_label("IDT\t\t\t\t\tShift+F2"); PageMI = gtk_menu_item_new_with_label("Page Table\t\t\tAlt+F2"); ViewBrkMI = gtk_menu_item_new_with_label("Breakpoints\t\t\tCtrl+F6"); MemDumpMI = gtk_menu_item_new_with_label("Current MemDump\t\tEsc"); PTreeMI = gtk_menu_item_new_with_label("Bochs param_tree\t\tCtrl+F3"); DisAsmMI = gtk_menu_item_new_with_label("Disassemble...\t\t\tCtrl+D"); // Options Menu - without checkmarks DefDisMI = gtk_menu_item_new_with_label("Default disassembled lines..."); SyntaxMI = gtk_menu_item_new_with_label("Toggle Intel/ATT syntax\t\tF3"); FontMI = gtk_menu_item_new_with_label ("Font..."); WrdSizeMI = gtk_menu_item_new_with_label("Set MemDump 'Wordsize'..."); WSmenu = gtk_menu_new(); // Options Menu - with checkmarks ChkMIs[MODE_BRK] = gtk_check_menu_item_new_with_label("Break on CPU mode change\tShift+F5"); ChkMIs[ONE_CPU] = gtk_check_menu_item_new_with_label("Show CPU0 only"); ChkMIs[U_CASE] = gtk_check_menu_item_new_with_label("Text in UPPERCASE"); ChkMIs[IO_WIN] = gtk_check_menu_item_new_with_label("Show Input/Output Windows"); ChkMIs[SHOW_BTN] = gtk_check_menu_item_new_with_label("Show Buttons"); ChkMIs[MD_HEX] = gtk_check_menu_item_new_with_label("MemDump in Hex\t\t\tAlt+F7"); ChkMIs[MD_ASC] = gtk_check_menu_item_new_with_label("MemDump in ASCII\t\t\tShift+F7"); ChkMIs[L_END] = gtk_check_menu_item_new_with_label("LittleEndian"); ChkMIs[IGN_SA] = gtk_check_menu_item_new_with_label("Ignore ASM lines"); ChkMIs[IGN_NT] = gtk_check_menu_item_new_with_label("Ignore Next at t="); ChkMIs[R_CLR] = gtk_check_menu_item_new_with_label("Colorize Register Types"); ChkMIs[E_REG] = gtk_check_menu_item_new_with_label("Show 32bit Registers"); ChkMIs[S_REG] = gtk_check_menu_item_new_with_label("Show Segment Registers"); ChkMIs[SYS_R] = gtk_check_menu_item_new_with_label("Show System Registers"); ChkMIs[C_REG] = gtk_check_menu_item_new_with_label("Show Control Registers"); ChkMIs[FPU_R] = gtk_check_menu_item_new_with_label("Show MMX/FPU Registers\tAlt+F3"); ChkMIs[XMM_R] = gtk_check_menu_item_new_with_label("Show SSE Registers\t\tCtrl+F4"); ChkMIs[D_REG] = gtk_check_menu_item_new_with_label("Show Debug Registers\t\tShift+F4"); // ChkMIs[T_REG] = gtk_check_menu_item_new_with_label("Show Test Registers"); ChkMIs[WSChkIdx] = gtk_check_menu_item_new_with_label("1 byte\t\tAlt+1"); ChkMIs[WSChkIdx+1] = gtk_check_menu_item_new_with_label("2 bytes\t\tAlt+2"); ChkMIs[WSChkIdx+2] = gtk_check_menu_item_new_with_label("4 bytes\t\tAlt+4"); ChkMIs[WSChkIdx+3] = gtk_check_menu_item_new_with_label("8 bytes\t\tAlt+8"); ChkMIs[WSChkIdx+4] = gtk_check_menu_item_new_with_label("16 bytes\t\tAlt+6"); // Help Menu AboutMI = gtk_menu_item_new_with_label("About..."); sep1 = gtk_separator_menu_item_new(); // can't reuse menu separators sep2 = gtk_separator_menu_item_new(); sep3 = gtk_separator_menu_item_new(); sep4 = gtk_separator_menu_item_new(); sep5 = gtk_separator_menu_item_new(); sep6 = gtk_separator_menu_item_new(); sep7 = gtk_separator_menu_item_new(); // insert all the menu items into each menu gtk_menu_shell_append(GTK_MENU_SHELL(CmdMenu), ContMI); gtk_menu_shell_append(GTK_MENU_SHELL(CmdMenu), StepMI); gtk_menu_shell_append(GTK_MENU_SHELL(CmdMenu), StepNMI); gtk_menu_shell_append(GTK_MENU_SHELL(CmdMenu), BreakMI); gtk_menu_shell_append(GTK_MENU_SHELL(CmdMenu), sep1); gtk_menu_shell_append(GTK_MENU_SHELL(CmdMenu), SetBrkMI); gtk_menu_shell_append(GTK_MENU_SHELL(CmdMenu), WatchWrMI); gtk_menu_shell_append(GTK_MENU_SHELL(CmdMenu), WatchRdMI); gtk_menu_shell_append(GTK_MENU_SHELL(CmdMenu), sep2); gtk_menu_shell_append(GTK_MENU_SHELL(CmdMenu), FindMI); gtk_menu_shell_append(GTK_MENU_SHELL(CmdMenu), RefreshMI); gtk_menu_shell_append(GTK_MENU_SHELL(ViewMenu), PhyDumpMI); gtk_menu_shell_append(GTK_MENU_SHELL(ViewMenu), LinDumpMI); gtk_menu_shell_append(GTK_MENU_SHELL(ViewMenu), StackMI); gtk_menu_shell_append(GTK_MENU_SHELL(ViewMenu), GDTMI); gtk_menu_shell_append(GTK_MENU_SHELL(ViewMenu), IDTMI); gtk_menu_shell_append(GTK_MENU_SHELL(ViewMenu), PageMI); gtk_menu_shell_append(GTK_MENU_SHELL(ViewMenu), ViewBrkMI); gtk_menu_shell_append(GTK_MENU_SHELL(ViewMenu), MemDumpMI); gtk_menu_shell_append(GTK_MENU_SHELL(ViewMenu), sep3); gtk_menu_shell_append(GTK_MENU_SHELL(ViewMenu), PTreeMI); gtk_menu_shell_append(GTK_MENU_SHELL(ViewMenu), DisAsmMI); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[MODE_BRK]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[ONE_CPU]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), DefDisMI); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), SyntaxMI); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), sep4); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), FontMI); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[U_CASE]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[IO_WIN]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[SHOW_BTN]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), sep5); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[MD_HEX]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[MD_ASC]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[L_END]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), WrdSizeMI); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), sep6); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[IGN_SA]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[IGN_NT]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), sep7); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[R_CLR]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[E_REG]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[S_REG]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[SYS_R]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[C_REG]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[FPU_R]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[XMM_R]); gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[D_REG]); // gtk_menu_shell_append(GTK_MENU_SHELL(OptMenu), ChkMIs[T_REG]); gtk_menu_shell_append(GTK_MENU_SHELL(HelpMenu), AboutMI); gtk_menu_item_set_submenu(GTK_MENU_ITEM(WrdSizeMI), WSmenu); // set up popup menu gtk_menu_shell_append(GTK_MENU_SHELL(WSmenu), ChkMIs[WSChkIdx]); gtk_menu_shell_append(GTK_MENU_SHELL(WSmenu), ChkMIs[WSChkIdx+1]); gtk_menu_shell_append(GTK_MENU_SHELL(WSmenu), ChkMIs[WSChkIdx+2]); gtk_menu_shell_append(GTK_MENU_SHELL(WSmenu), ChkMIs[WSChkIdx+3]); gtk_menu_shell_append(GTK_MENU_SHELL(WSmenu), ChkMIs[WSChkIdx+4]); // init all the checkmarks gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[E_REG]), SeeReg[0]); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[S_REG]), SeeReg[1]); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[SYS_R]), SeeReg[2]); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[C_REG]), SeeReg[3]); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[FPU_R]), SeeReg[4]); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[XMM_R]), SeeReg[5]); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[D_REG]), SeeReg[6]); // gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ShowTRegMI), SeeReg[7]); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[ONE_CPU]), SingleCPU); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[IO_WIN]), ShowIOWindows); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[SHOW_BTN]), ShowButtons); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[U_CASE]), UprCase); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[L_END]), isLittleEndian); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[IGN_SA]), ignSSDisasm); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[IGN_NT]), ignoreNxtT); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[R_CLR]), SeeRegColors); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[WSChkIdx]), TRUE); if (DumpInAsciiMode == 0) // prevent an illegal value DumpInAsciiMode = 3; // I don't know why, but the next 2 "set_active" commands blow up if moved into SpecialInit if ((DumpInAsciiMode & 2) != 0) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[MD_HEX]), TRUE); if ((DumpInAsciiMode & 1) != 0) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[MD_ASC]), TRUE); } // add a whole row of text into a ListView, all at once // Note: LineCount should start at 0 void InsertListRow(char *ColumnText[], int ColumnCount, int listnum, int LineCount, int grouping) { char tmp[4]; GtkTreeIter iter; GtkListStore *Database; *tmp = 0; Database = (GtkListStore *) gtk_tree_view_get_model( GTK_TREE_VIEW(LV[listnum]) ); gtk_list_store_append (GTK_LIST_STORE(Database), &iter); /* Acquire an iterator */ // some rows of the register list only print 2 columns // the dump window always prints 18, but the first 17 may be blank and 0 width if (ColumnCount == 2) gtk_list_store_set (GTK_LIST_STORE(Database), &iter, 0, ColumnText[0], 1, ColumnText[1], 2, tmp, 3, (gint) LineCount, -1); else if (ColumnCount == 3) { gtk_list_store_set (GTK_LIST_STORE(Database), &iter, 0, ColumnText[0], 1, ColumnText[1], 2, ColumnText[2], 3, (gint) LineCount, -1); } else { // it might be easier to use the gtk_list_store_set_valuesv() function? gtk_list_store_set (GTK_LIST_STORE(Database), &iter, 0, ColumnText[0], 1, ColumnText[1], 2, ColumnText[2], 3, ColumnText[3], 4, ColumnText[4], 5, ColumnText[5], 6, ColumnText[6], 7, ColumnText[7], 8, ColumnText[8], 9, ColumnText[9], 10, ColumnText[10], 11, ColumnText[11], 12, ColumnText[12], 13, ColumnText[13], 14, ColumnText[14], 15, ColumnText[15], 16, ColumnText[16], 17, ColumnText[17], 18, (gint) LineCount, -1); } } void ShowFW() { FWflag = TRUE; // the X version of this should be stubbed } // try to get a list repaint to happen void Invalidate(int i) { GdkWindow *LstGdk; LstGdk = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (LV[i])); gdk_window_invalidate_rect (LstGdk, NULL, TRUE); // rect=NULL means "the whole window" gtk_widget_queue_draw(LV[i]); // redraw the selected ListView "bin" window } void SetStatusText(int column, char *buf) { gtk_label_set_text(GTK_LABEL(Stat[column]), buf); } // called by the Find command -- only for LV[ASM] column 2! void GetLIText(int listnum, int itemnum, int column, char *buf) { char *value; GtkTreeIter iter; GtkListStore *Database; Database = (GtkListStore *) gtk_tree_view_get_model( GTK_TREE_VIEW(LV[listnum]) ); // get an iter for row # itemnum gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(Database), &iter, NULL, itemnum); // pull the text out of "row # iter" at the specified column gtk_tree_model_get(GTK_TREE_MODEL(Database), &iter, column, &value, -1); strcpy (buf, value); g_free(value); } // get a bochs command from the user Input window void GetInputEntry(char *buf) { const gchar *gcp; gcp = gtk_entry_get_text(GTK_ENTRY(IEntry)); strcpy (buf, gcp); } // highlights individual rows in ASM or Mem windows void SetLIState(int listnum, int itemnum, bx_bool Select) { char *Sel = SelAsm; int max = MAX_ASM; if (listnum == 2) { Sel = SelMem; max = 256; } if (itemnum >= max) itemnum = max-1; Sel[itemnum] = Select; } // Searches ASM or Reg list for the next (or first) selected row int GetNextSelectedLI(int listnum, int StartPt) { int L = StartPt; char *Sel = SelAsm; int end = MAX_ASM; bx_bool stop = FALSE; if (listnum == REG_WND) { Sel = SelReg; end = TOT_REG_NUM + EXTRA_REGS; } if (L < -1) L = -1; while (stop == FALSE) { if (++L >= end) stop = TRUE; else { if (Sel[L] != FALSE) stop = TRUE; } } if (L >= end) return -1; return L; } // returns the row number of the ASM list that is showing at the top of the window // it is also easy to calculate AsmPgSize and ListLineRatio here, // -- they MUST be calculated somewhere in the os_specific code int GetASMTopIdx() { GtkAdjustment *va; GtkListStore *Database; Database = (GtkListStore *) gtk_tree_view_get_model( GTK_TREE_VIEW(LV[ASM_WND]) ); AsmPgSize = 0; va = gtk_tree_view_get_vadjustment ( GTK_TREE_VIEW(LV[ASM_WND]) ); // calculate the number of vertical "pixels" in one row (as a fraction of the scroll range) if (AsmLineCount == 0) return 0; ListLineRatio = (int) (va->upper - va->lower) / AsmLineCount; if (ListLineRatio == 0) return 0; AsmPgSize = (int) va->page_size / ListLineRatio; return ((int) va->value / ListLineRatio); } // "pixels" is a multiple of (and therefore proportional to) ListLineRatio // -- it does not technically have to really be a pixel count void ScrollASM(int pixels) { GtkAdjustment *va = gtk_tree_view_get_vadjustment ( GTK_TREE_VIEW(LV[ASM_WND]) ); gtk_adjustment_set_value (GTK_ADJUSTMENT(va), va->value + pixels); } // handle checkmarks in the "wordsize" popup menu // Note: setting/clearing a checkmark sends an immediate "activate" signal to the associated menuitem void ToggleWSchecks(int newWS, int oldWS) { if ((bx_bool) gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(ChkMIs[WSChkIdx + newWS])) == FALSE) { ForcingCheck = TRUE; // prevent infinite checkmark loops gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[WSChkIdx + newWS]), TRUE); } if ((bx_bool) gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(ChkMIs[WSChkIdx + oldWS])) != FALSE) { ForcingCheck = TRUE; // prevent infinite checkmark loops gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[WSChkIdx + oldWS]), FALSE); } } // repack the ScrollWindows into the ListHbox using a new DockOrder // FirstListIndex is precalculated in MoveLists, so pass in the value void RepackLists(int FirstListIndex) { gtk_box_pack_start(GTK_BOX(LVHbox), ScrlWin[FirstListIndex], FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(LVHbox), VSepEvtBox1, FALSE, FALSE, 0); gtk_box_pack_end(GTK_BOX(LVHbox), ScrlWin[(DockOrder& 3) -1], FALSE, FALSE, 0); gtk_box_pack_end(GTK_BOX(LVHbox), VSepEvtBox2, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(LVHbox), ScrlWin[CurCenterList], TRUE, TRUE, 0); } // unpack the ScrollWindows from the ListHbox, then repack using a new DockOrder // -- also calculate the X-coords of the "bars" between the lists void MoveLists() { int i; gtk_widget_ref (ScrlWin[0]); // make sure the list widgets do not get deleted gtk_widget_ref (ScrlWin[1]); // when they are removed from their container gtk_widget_ref (ScrlWin[2]); gtk_widget_ref (VSepEvtBox1); gtk_widget_ref (VSepEvtBox2); gtk_container_remove (GTK_CONTAINER(LVHbox), ScrlWin[0]); gtk_container_remove (GTK_CONTAINER(LVHbox), ScrlWin[1]); gtk_container_remove (GTK_CONTAINER(LVHbox), ScrlWin[2]); gtk_container_remove (GTK_CONTAINER(LVHbox), VSepEvtBox1); gtk_container_remove (GTK_CONTAINER(LVHbox), VSepEvtBox2); CurCenterList = ((DockOrder>>4)& 3) -1; // index of center list i = (DockOrder >> 8) -1; // index of left list RepackLists(i); // pack widgets back into container in new DockOrder gtk_widget_unref (ScrlWin[0]); gtk_widget_unref (ScrlWin[1]); // and get rid of the temporary "ref"s gtk_widget_unref (ScrlWin[2]); gtk_widget_unref (VSepEvtBox1); gtk_widget_unref (VSepEvtBox2); // use DockOrder to figure out the table X-coordinates of the 2 v-separators i = ListWidthPix[i]; // BarClix[0] = i; // BarClix[1] = i + ListWidthPix[CurCenterList]; BottomAsmLA = ~0; // force an ASM autoload next time, to resize it doDumpRefresh = TRUE; // force a data window refresh on a break if (AtBreak != FALSE) // can't refresh the windows until a break! { doUpdate(); // refresh the ASM and Register windows RefreshDataWin(); // and whichever data window is up } } // modify the displayed items in the MainVbox void VSizeChange() { if (ShowButtons == FALSE) // set the visibility of the Command Buttons gtk_widget_hide(CmdBHbox); else gtk_widget_show(CmdBHbox); if (SingleCPU == FALSE) // set the visibility of the CPU Buttons gtk_widget_show(CpuBHbox); else gtk_widget_hide(CpuBHbox); if (ShowIOWindows == FALSE) { gtk_widget_hide(IOVbox); GTK_TABLE(TreeTbl)->nrows = 3; // IO windows do not exist, so total table rows = 3 } else { // Note: if an invisible Entry window contains text and is shown, the program can crash // so copy out any text, clear the Entry, make it visible, and then reload it const gchar *gcp; gcp = gtk_entry_get_text(GTK_ENTRY(IEntry)); strcpy (tmpcb, gcp); gtk_entry_set_text(GTK_ENTRY(IEntry),""); GTK_TABLE(TreeTbl)->nrows = 4; // IO windows exist, so total table rows = 4 gtk_widget_show(IOVbox); gtk_widget_grab_focus(IEntry); // Input window loses focus while it is hidden gtk_entry_set_text(GTK_ENTRY(IEntry),tmpcb); } gtk_widget_queue_draw(window); // redraw everything } void TakeInputFocus() { gtk_widget_grab_focus(IEntry); // get the focus back from the VGA window } void MakeListsGray() { if (AtBreak == FALSE) { SetStatusText(0, "Running"); } else SetStatusText(0, "Break"); // It's good to set the background color OUTSIDE the area of the lists // -- except that this seems difficult in gtk // So, the default behavior is not quite as pretty, but it is good enough. } // ParseIDText (*bochs*) calls this when the window needs to be redrawn with new text -- // funct must not call any GTK functions directly, because it is run from the bochs thread void SetOutWinTxt() { UpdateOWflag = TRUE; } // in the Win32 version, the caret is placed at the beginning of each selected history line, // but the exact functionality is not important -- just do what is easy void SelectHistory(int UpDown) { // the History buffer is circular, so wrap 64 to 0, and -1 to 63 CommandHistoryIdx = (CommandHistoryIdx + UpDown) & 63; gtk_entry_set_text(GTK_ENTRY(IEntry),CmdHistory[(CmdHInsert + CommandHistoryIdx) & 63]); } void ClearInputWindow() { gtk_entry_set_text(GTK_ENTRY(IEntry),""); } // set == 0 to clear a check, 1 or 2 to set a check void SetMenuCheckmark (int set, int ChkIdx) { bx_bool flag = TRUE; if (set == 0) flag = FALSE; if ((bx_bool) gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(ChkMIs[ChkIdx])) != flag) { ForcingCheck = TRUE; gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ChkMIs[ChkIdx]), flag); } } // pass in FALSE or 0 to gray out a menu item void GrayMenuItem (int flag, int CmdIndex) { GtkWidget *lbl; GtkWidget *MI = Cmd2MI[CmdIndex - CMD_IDX_LO + 1]; // convert the Command Index to a Menu Item widget, and get its label lbl = GTK_BIN(GTK_MENU_ITEM( MI ))->child; gtk_widget_set_sensitive ( MI, flag ); } // finish initting things that must be initted in several stages // -- this function is usually called only once, during the first doUpdate void SpecialInit() { // Menu items can not be deactivated until after their signals are attached GrayMenuItem (0, CMD_EREG); GrayMenuItem (0, CMD_WPTWR); GrayMenuItem (0, CMD_WPTRD); GrayMenuItem (0, CMD_PAGEV); // GrayMenuItem (0, CMD_XCEPT); if (BX_SMP_PROCESSORS == 1) GrayMenuItem (0, CMD_ONECPU); // one or the other MemDump mode must always be left on! (unchangeable) if ((DumpInAsciiMode & 2) == 0) GrayMenuItem (0, CMD_MASCII); if ((DumpInAsciiMode & 1) == 0) GrayMenuItem (0, CMD_MHEX); #if BX_SUPPORT_FPU == 0 GrayMenuItem (0, CMD_FPUR); #endif #if BX_SUPPORT_SSE == 0 GrayMenuItem (0, CMD_XMMR); #endif doOneTimeInit = FALSE; // make sure this function is never called again } // this routine is stubbed in the GTK version void RedrawColumns(int listnum) { } // autosize the columns that may be used by other dumps, once, on a DViewMode change void SetAutoSize6_9() { AllCols[6]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; AllCols[7]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; AllCols[8]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; AllCols[9]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; } // Show/Hide the typical pattern of Dump window columns (show the first n, hide the rest out to 17) void ShowDListCols (int totcols) { int i = 5; int firsthide = totcols + 5; // convert from a col# to an acolnum while (++i < firsthide) AllCols[i]->visible = TRUE; while (i < 23) AllCols[i++]->visible = FALSE; } // OS-dependent code that runs before each ListFill routine of each type void StartListUpdate(int listnum) { static int PrevDV = -1; // type of previous Dump window that was displayed GtkListStore *Database; // set the scroll position back to the very top GtkAdjustment *va = gtk_tree_view_get_vadjustment ( GTK_TREE_VIEW(LV[listnum]) ); gtk_adjustment_set_value (GTK_ADJUSTMENT(va), 0); // then clear the database for the list that is updating Database = (GtkListStore *) gtk_tree_view_get_model( GTK_TREE_VIEW(LV[listnum]) ); gtk_list_store_clear(GTK_LIST_STORE(Database)); // a DumpAlign change is treated just like a DViewMode change if (DViewMode == VIEW_MEMDUMP && PrevDAD != DumpAlign) PrevDV = -1; // use Upd flag to prevent paint messages, cpu_loop calls, duplicate calls // UpdInProgress[listnum] = TRUE; if (ResizeColmns != FALSE || (listnum == DUMP_WND && PrevDV != DViewMode)) { // autosize Reg "hex" column, Asm "L.Addr" column if (listnum == REG_WND) AllCols[1]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; else if (listnum == ASM_WND) AllCols[3]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; // otherwise, autosize/rename/hide all the proper Dump list columns else { switch (DViewMode) { case VIEW_MEMDUMP: // fix the MemDump column "names" if (DumpInitted == FALSE) { GtkTreeIter iter; ShowDListCols (18); // show all columns -- must be visible to set col titles! // reset a "generic" header for col 0 gtk_tree_view_column_set_title(AllCols[6], "Address"); gtk_tree_view_column_set_title(AllCols[7], "0"); gtk_tree_view_column_set_title(AllCols[8], "1"); gtk_tree_view_column_set_title(AllCols[9], "2"); gtk_tree_view_column_set_title(AllCols[23], "Ascii"); SetAutoSize6_9(); // autosize the usual suspects // add a blank line to "modify the store" -- which will activate autosize gtk_list_store_append (GTK_LIST_STORE(Database), &iter); /* Acquire an iterator */ gtk_list_store_set (GTK_LIST_STORE(Database), &iter, 0, "", -1); } else { AllCols[6]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; if (PrevDV == VIEW_MEMDUMP) // autosizing address column only? break; PrevDAD = DumpAlign; gtk_tree_view_column_set_title(AllCols[23], "Ascii"); if ((DumpInAsciiMode & 2) == 0) // hex bit is turned on? { // if dumping ONLY in ascii, hide ALL the other columns ShowDListCols (2); // show only columns 0 and 17 break; } AllCols[7]->visible = TRUE; // columns must be visible to set col titles! AllCols[8]->visible = TRUE; AllCols[9]->visible = TRUE; gtk_tree_view_column_set_title(AllCols[7], "0"); gtk_tree_view_column_set_title(AllCols[8], "1"); gtk_tree_view_column_set_title(AllCols[9], "2"); for (int i = 7 ; i < 24 ; i++) { if (((i - 7) & (DumpAlign - 1)) == 0) // either autosize, { AllCols[i]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; AllCols[i]->visible = TRUE; } else // or set the column invisible AllCols[i]->visible = FALSE; } } break; case VIEW_GDT: SetAutoSize6_9(); // autosize the usual suspects if (PrevDV == VIEW_GDT) // autosizing only? break; ShowDListCols (5); // show 4 columns, hide the rest out to 17 gtk_tree_view_column_set_title(AllCols[6], "Index"); // header for col 0 gtk_tree_view_column_set_title(AllCols[7], "Base Address"); // header for col 1 gtk_tree_view_column_set_title(AllCols[8], "Size"); // header for col 2 gtk_tree_view_column_set_title(AllCols[9], "DPL"); // header for col 3 gtk_tree_view_column_set_title(AllCols[23], "Info"); // header for col 4 (17) break; case VIEW_IDT: AllCols[6]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; if (PrevDV == VIEW_IDT) // autosizing only? break; ShowDListCols (2); // show 1 column, hide the rest out to 17 gtk_tree_view_column_set_title(AllCols[6], "Interrupt"); // header for col 0 gtk_tree_view_column_set_title(AllCols[23], "L.Address"); // header for col 1 (17) break; case VIEW_PAGING: AllCols[6]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; if (PrevDV == VIEW_PAGING) // autosizing only? break; ShowDListCols (2); // show 1 column, hide the rest out to 17 gtk_tree_view_column_set_title(AllCols[6], "L.Address"); // header for col 0 gtk_tree_view_column_set_title(AllCols[23], "is mapped to P.Address"); // header for col 1 (17) break; case VIEW_STACK: AllCols[6]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; AllCols[7]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; if (PrevDV == VIEW_STACK) // autosizing only? break; ShowDListCols (3); // show 2 columns, hide the rest out to 17 gtk_tree_view_column_set_title(AllCols[6], "L.Address"); // header for col 0 gtk_tree_view_column_set_title(AllCols[7], "Value"); // header for col 1 gtk_tree_view_column_set_title(AllCols[23], "(dec.)"); // header for col 2 (17) break; case VIEW_BREAK: AllCols[6]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; AllCols[7]->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE; if (PrevDV == VIEW_STACK) // autosizing only? break; ShowDListCols (3); // show 2 columns, hide the rest out to 17 gtk_tree_view_column_set_title(AllCols[6], "Address"); // header for col 0 gtk_tree_view_column_set_title(AllCols[7], "Enabled"); // header for col 1 gtk_tree_view_column_set_title(AllCols[23], "ID"); // header for col 2 (17) } PrevDV = DViewMode; } } } void EndListUpdate(int listnum) { int i; // UpdInProgress[listnum] = FALSE; // It's OK to paint the listview now // clear selections for each list on a list update if (listnum == REG_WND) { i = TOT_REG_NUM + EXTRA_REGS; while (--i >= 0) SelReg[i] = 0; } else if (listnum == ASM_WND) { i = MAX_ASM; while (--i >= 0) SelAsm[i] = 0; } else if (DViewMode == VIEW_MEMDUMP) { i = 256; while (--i >= 0) SelMem[i] = 0; } // AUTOSIZE turns off "user resize" mode! Turning resize mode back on will force // autosize back into GROW_ONLY mode -- which is what I want, anyway. i = 23; while (--i >= 0) { // the 3rd column in Reg and Asm lists is not resizable if (i != 2 && i != 5) gtk_tree_view_column_set_resizable (AllCols[i], TRUE); } // Invalidate (listnum); } void DispMessage(char *msg, char *title) { GtkWidget *dialog; dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, msg); gtk_window_set_title(GTK_WINDOW(dialog), title); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } // hide/clear param_tree window when showing a different MemDump window (GDT, IDT, etc.) void HideTree() { GtkTreeStore *treestore; if (DViewMode != VIEW_PTREE) return; treestore = (GtkTreeStore *) gtk_tree_view_get_model( GTK_TREE_VIEW(PTree) ); gtk_container_remove (GTK_CONTAINER(ScrlWin[2]),PTree); gtk_container_add (GTK_CONTAINER(ScrlWin[2]), LV[2]); gtk_tree_store_clear(GTK_TREE_STORE(treestore)); } // exit GDT/IDT/Paging/Stack/Tree -- back to the MemDump window void ShowMemData(bx_bool initting) { int i = 1; if (LinearDump == FALSE) i = 0; if (initting != FALSE) { GrayMenuItem (0, CMD_WPTWR); GrayMenuItem (0, CMD_WPTRD); // update column 0 to say whether its physmem or linear gtk_tree_view_column_set_title(AllCols[6], DC0txt[i]); } HideTree(); gtk_widget_show(LV[DUMP_WND]); DViewMode = VIEW_MEMDUMP; // returning to MemDump mode if (DumpInitted == FALSE) { StartListUpdate(DUMP_WND); // autosize for a blank MemDump window EndListUpdate(DUMP_WND); } else { gtk_tree_view_column_set_title(AllCols[6], DC0txt[i]); if (AtBreak == FALSE) doDumpRefresh = TRUE; else ShowData(); // repopulates & resizes all columns } } // create the top layer of a parameter tree TreeView void FillPTree() { int i; GtkTreeStore *treestore; extern bx_list_c *root_param; // Note: don't multithread this display -- the user expects it to complete if (DViewMode != VIEW_PTREE) { gtk_container_remove (GTK_CONTAINER(ScrlWin[2]),LV[2]); gtk_container_add (GTK_CONTAINER(ScrlWin[2]), PTree); } doDumpRefresh = FALSE; treestore = (GtkTreeStore *) gtk_tree_view_get_model( GTK_TREE_VIEW(PTree) ); gtk_tree_store_clear(GTK_TREE_STORE(treestore)); // Note: all tree strings are hardcoded to be in tmpcb -- don't change! i = root_param->get_size(); while (--i >= 0) MakeBL(NULL, root_param->get(i)); gtk_widget_show(PTree); } void MakeTreeChild (TreeParent *h_P, int ChildCount, TreeParent *h_TC) { GtkTreeStore *treestore; treestore = (GtkTreeStore *) gtk_tree_view_get_model( GTK_TREE_VIEW(PTree) ); gtk_tree_store_append(GTK_TREE_STORE(treestore), h_TC, h_P); // create the "leaf" gtk_tree_store_set(GTK_TREE_STORE(treestore), h_TC, 0, tmpcb, -1); // and put a name (+ data) on it } // technically, this is a copy of a non-os-specific code fragment void DelWatchpoint(bx_phy_address *wp_array, unsigned int *TotEntries, int i) { while (++i < (int) *TotEntries) wp_array[i-1] = wp_array[i]; -- *TotEntries; } bx_bool NewFont() { char *ofn; if (AtBreak == FALSE) return FALSE; // need to know the current font, to highlight it g_object_get( G_OBJECT( LV_Rend[0] ), "font", &ofn, NULL ); GtkWidget *widget = gtk_font_selection_dialog_new ("Choose primary font"); gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG(widget), ofn); if (gtk_dialog_run (GTK_DIALOG (widget)) == GTK_RESPONSE_OK) { int i, width; char *fontname = gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(widget)); g_object_set( G_OBJECT( LV_Rend[0] ), "font", fontname, NULL ); g_object_set( G_OBJECT( LV_Rend[1] ), "font", fontname, NULL ); g_object_set( G_OBJECT( LV_Rend[2] ), "font", fontname, NULL ); g_free (fontname); // calculate a new value for OneCharWide PangoLayout * layout = gtk_widget_create_pango_layout (LV[0], "M"); PangoFontDescription * fontdesc; g_object_get( G_OBJECT( LV_Rend[0] ), "font-desc", &fontdesc, NULL ); pango_layout_set_font_description (layout, fontdesc); pango_layout_get_pixel_size (layout, &width, &i); pango_font_description_free (fontdesc); g_object_unref (layout); OneCharWide = width; // The "width" I'm getting is about half what I expect // OneCharWide = width >> 1; // pretend that an average char width is half an "M" if (OneCharWide > 12) OneCharWide = 12; } g_free (ofn); gtk_widget_destroy (widget); return TRUE; } // turn off any current sizing/docking mode void sizing_cancel() { // cancel presize, size, predock, and dock modes if (Sizing != 0) { gtk_event_box_set_above_child (GTK_EVENT_BOX(LVEvtBox), FALSE); gtk_event_box_set_above_child (GTK_EVENT_BOX(VSepEvtBox1), TRUE); gtk_event_box_set_above_child (GTK_EVENT_BOX(VSepEvtBox2), TRUE); if (Sizing < 10) // cancel (p)resize mode motion detection g_signal_handler_disconnect (LVEvtBox, mmov_hID); gdk_window_set_cursor (GTK_WIDGET(LVEvtBox)->window, NULL); // change the cursor to normal Sizing = 0; } EnterSizeMode = FALSE; SizingDelay = 0; SizeList = 0; xClick = -1; } // conditionally begin a resize operation void enter_resize_mode() { // need reasonably accurate column widths in horz. limit calculations -- update widths int width0, width1; gint totwidth; gint height; EnterSizeMode = FALSE; // presize mode may never have reset this // a GtkAllocation structure (inside every widget) is a rectangle: relative x, y, + width & height width0 = ScrlWin[0]->allocation.width; ListWidthPix[0] = width0; width1 = ScrlWin[1]->allocation.width; ListWidthPix[1] = width1; gdk_drawable_get_size (window->window, &totwidth, &height); ListWidthPix[2] = totwidth - (width0 + width1); if (Sizing < 0) // in presize mode? -- enter full resize mode SetHorzLimits(); } // begin a pre-dock operation -- cancel if a mouseup event happens void Set_PreDock(int ListNum, GdkEventButton *event) { // Sadly, in order to narrow the mousedown event to only the ListView (without the scrollbars) // information seems to get lost about which button is being pressed // -- but the button info seems not reliable anyway (currently) so it must be lived with // enter pre-dock mode, autoactivate full docking mode in 2 VGAW refresh time ticks xClick = (unsigned int) (event->x_root + 0.5); yClick = (unsigned int) (event->y_root + 0.5); SizeList = ListNum + 10; SizingDelay = 2; } // Select one entry in Register ListView gboolean RegMouseDown_cb(GtkWidget *widget, GdkEventButton *event, gpointer data) { int row; GtkTreePath *path; gint *pathdat; bx_bool onrow; Set_PreDock (0, event); GrayMenuItem (0, CMD_WPTWR); // disable watchpoints for physdumps (not selected) GrayMenuItem (0, CMD_WPTRD); GrayMenuItem (1, CMD_BRKPT); // enable ASM breakpoints (window is selected by default) row = TOT_REG_NUM + EXTRA_REGS; while (--row >= 0) SelReg[row] = 0; onrow = (bx_bool) gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW(LV[0]), (gint) (event->x + 0.5), (gint) (event->y + 0.5), &path, NULL, NULL, NULL); if (onrow == FALSE) return FALSE; pathdat = gtk_tree_path_get_indices (path); row = (int) *pathdat; gtk_tree_path_free (path); if (row >= TOT_REG_NUM + EXTRA_REGS || row < 0) row = TOT_REG_NUM + EXTRA_REGS -1; SelReg[row] = TRUE; Invalidate (REG_WND); return FALSE; } // Select multiple entries in ASM ListView gboolean AsmMouseDown_cb(GtkWidget *widget, GdkEventButton *event, gpointer data) { GtkTreePath *path; gint *pathdat; bx_bool onrow; Set_PreDock (1, event); GrayMenuItem (0, CMD_WPTWR); // disable watchpoints for physdumps (not selected) GrayMenuItem (0, CMD_WPTRD); GrayMenuItem (1, CMD_BRKPT); // enable ASM breakpoints (window is selected) if ((event->state & GDK_CONTROL_MASK) == 0) { int i = MAX_ASM; while (--i >= 0) SelAsm[i] = 0; } onrow = (bx_bool) gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW(LV[1]), (gint) (event->x + 0.5), (gint) (event->y + 0.5), &path, NULL, NULL, NULL); if (onrow == FALSE) return FALSE; pathdat = gtk_tree_path_get_indices (path); SelectedEntry = (int) *pathdat; gtk_tree_path_free (path); if (SelectedEntry >= MAX_ASM || SelectedEntry < 0) SelectedEntry = MAX_ASM -1; SelAsm[SelectedEntry] ^= 1; Invalidate (ASM_WND); return FALSE; } // Select multiple entries in Phys or Linear Memdump ListView gboolean MemMouseDown_cb(GtkWidget *widget, GdkEventButton *event, gpointer data) { int column, cellx; GtkTreePath *path; gint *pathdat; bx_bool onrow; Set_PreDock (2, event); if (DViewMode != VIEW_MEMDUMP && DViewMode != VIEW_BREAK) return FALSE; if ((event->state & GDK_CONTROL_MASK) == 0) { int i = 256; while (--i >= 0) SelMem[i] = 0; } onrow = (bx_bool) gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW(LV[2]), (gint) (event->x + 0.5), (gint) (event->y + 0.5), &path, NULL, NULL, NULL); if (onrow == FALSE) return FALSE; pathdat = gtk_tree_path_get_indices (path); DumpSelRow = (int) *pathdat; gtk_tree_path_free (path); // handle enabling/disabling watchpoint menu items if (LinearDump == FALSE && DViewMode == VIEW_MEMDUMP) { GrayMenuItem (1, CMD_WPTWR); // enable watchpoints for physdumps GrayMenuItem (1, CMD_WPTRD); } else { GrayMenuItem (0, CMD_WPTWR); // disable watchpoints for lineardumps GrayMenuItem (0, CMD_WPTRD); } if (DViewMode != VIEW_MEMDUMP) // VIEW_BREAK handling is complete now { GrayMenuItem (1, CMD_BRKPT); // enable ASM breakpoints (window is selected by default) return FALSE; } GrayMenuItem (0, CMD_BRKPT); // disable ASM breakpoints (window is not selected) cellx = 0; column = 6; // loop over the Mem window columns, 6 to 23 while (event->x >= cellx && column < 23) { int j = cellx += AllCols[column]->width; if (event->x >= j){ ++column; cellx = j; } } if (DumpSelRow >= 256 || DumpSelRow < 0) DumpSelRow = 255; KeyStateShft = event->state & GDK_SHIFT_MASK; KeyStateAlt = event->state & GDK_MOD1_MASK; SelMem[DumpSelRow] ^= 1; // only set the SelDataAddy for memdumps with a wordsize of 1 if (DumpAlign == 1 && column > 6) { SA_valid = TRUE; SelectedDataAddress = DumpStart + (DumpSelRow*16) + (column - 7); } Invalidate (DUMP_WND); return FALSE; } // Change the CPU display void CPUb_cb(GtkWidget *widget, gpointer CPUnum) // "CPUnum" is the value supplied at handler creation { unsigned int newCPU = GPOINTER_TO_INT( CPUnum ); if (CurrentCPU != newCPU) { // change text on CurrentCPU button to lowercase and BOLD with markup strcpy (tmpcb, "cpu0"); tmpcb[6] = CurrentCPU + '0'; gtk_label_set_markup (GTK_LABEL(CpuB_label[CurrentCPU]), tmpcb); // change text on newCPU button to uppercase and BOLD with markup strcpy (tmpcb, "CPU0"); tmpcb[6] = newCPU + '0'; gtk_label_set_markup (GTK_LABEL(CpuB_label[newCPU]), tmpcb); CurrentCPU = newCPU; BottomAsmLA = ~0; // force an ASM autoload, to repaint PrevPtime = 0; // force a full update if (AtBreak != FALSE) // if at a break, pretend it just happened OnBreak(); // refresh the ASM and Register windows } } // calls the proper GUI command on activate events -- non breaking void nbCmd_cb(GtkWidget *widget, gpointer CmdIdx) // "CmdIdx" is the value supplied at handler creation { if (ForcingCheck == FALSE) // using a hotkey to flip a menu item checkmark? ActivateMenuItem (GPOINTER_TO_INT (CmdIdx)); ForcingCheck = FALSE; } // calls the proper GUI command on activate events, with a sim break void Cmd_cb(GtkWidget *widget, gpointer CmdIdx) // "CmdIdx" is the value supplied at handler creation { if (AtBreak == FALSE) { // DoBreak = TRUE; -- for multithreading SIM->debug_break(); // On a menu click always break (with some exceptions) } ActivateMenuItem (GPOINTER_TO_INT (CmdIdx)); } // code to run on exit -- arguments are ignored void Close_cb(GtkWidget *widget, gpointer data) { GtkListStore *Database; GtkTreeStore *treestore; // clear all the "store" databases Database = (GtkListStore *) gtk_tree_view_get_model( GTK_TREE_VIEW(LV[0]) ); gtk_list_store_clear(GTK_LIST_STORE(Database)); Database = (GtkListStore *) gtk_tree_view_get_model( GTK_TREE_VIEW(LV[1]) ); gtk_list_store_clear(GTK_LIST_STORE(Database)); Database = (GtkListStore *) gtk_tree_view_get_model( GTK_TREE_VIEW(LV[2]) ); gtk_list_store_clear(GTK_LIST_STORE(Database)); treestore = (GtkTreeStore *) gtk_tree_view_get_model( GTK_TREE_VIEW(PTree) ); gtk_tree_store_clear(GTK_TREE_STORE(treestore)); bx_user_quit = 1; SIM->debug_break(); // holding one extra reference to both ScrlWin[2] widgets // but I "sank" PTree myself, so it is my understanding that I need to "destroy" it myself gtk_widget_destroy (PTree); gtk_widget_unref (PTree); gtk_widget_unref (LV[2]); gdk_cursor_unref (SizeCurs); gdk_cursor_unref (DockCurs); gtk_main_quit(); debug_cmd_ready = TRUE; // kill the "get command sleep loop" bx_dbg_quit_command(); // it's OK to call this from the "wrong" thread } // there is only one widget that receives keystrokes, the Input Entry widget // -- process those keydowns for hotkeys and special keys gboolean keydown_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) { gboolean ret = FALSE; // assume the key is NOT a hotkey -- enter it into the widget int key = (int) (event->keyval & 0xffff); int Control, Shift, Alt; Control= Shift= Alt= 0; if ((event->state & GDK_CONTROL_MASK) != 0) Control = -1; if ((event->state & GDK_SHIFT_MASK) != 0) Shift = -1; if ((event->state & GDK_MOD1_MASK) != 0) // this is the Alt key mask Alt = -1; switch (event->keyval) { case 'c': case 'd': case 'f': if (Control == 0) break; key &= 0xdf; // convert to upper case case VK_UP: case VK_DOWN: case VK_PRIOR: case VK_NEXT: case VK_ESCAPE: case VK_F2: case VK_F3: case VK_F4: case VK_F5: case VK_F6: case VK_F7: case VK_F8: case VK_F9: case VK_F11: case VK_RETURN: HotKey (key, Alt, Shift, Control); ret = TRUE; } return ret; } // Input window appears to be hidden -- main window received a keydown. // Force the event to redirect to the hidden IEntry widget gboolean redirect_keydown(GtkWidget *widget, GdkEvent *event, gpointer data) { // send the event ONLY to IEntry -- do not try to propogate it beyond gtk_widget_event(IEntry, event); return TRUE; } // table (that contains the main windows!) is being resized/moved // Note: the window gets MANY of these events where the size remains constant gboolean TblSizeEvent(GtkWidget *widget, GdkEventConfigure *event, gpointer data) { int i, j, k; bx_bool unchanged = FALSE; gint WinSizeX; gint WinSizeY; GdkWindow *TblGdk = gtk_widget_get_parent_window(TreeTbl); gdk_drawable_get_size (TblGdk, &WinSizeX, &WinSizeY); // don't "resize" on minimize, if window is too small, or if width is (almost) unchanged // -- five pixels spread over 3 windows is negligible if (CurXSize > (unsigned int)WinSizeX - 8 && CurXSize <= (unsigned int)WinSizeX) unchanged = TRUE; if (WinSizeY > 100 && WinSizeX > 150 && unchanged == FALSE) { CurXSize = WinSizeX -4; // assume 4 pixels total for the two VSeparators // need to recalculate List widths, with the same proportions as before i = ListWidthPix[0] + ListWidthPix[1] + ListWidthPix[2]; if (i == 0) i = 1; j = (ListWidthPix[2] * CurXSize) / i; k = (ListWidthPix[1] * CurXSize) / i; i = OneCharWide << 2; if (j < i) j = i; if (k < i) k = i; ListWidthPix[0] = CurXSize - k - j; // Register list ListWidthPix[1] = k; // Asm ListWidthPix[2] = j; // MemDump ListVerticalPix = (WinSizeY * 3) /4; // set the size of the two ScrlWins that are not in the middle // (the middle one automatically takes the rest) i= CurCenterList -1; if (i < 0) // wrap -1 to 2 i = 2; // -1 means "let the window manager decide how big to make it" gtk_widget_set_size_request(ScrlWin[i], ListWidthPix[i], -1); i = CurCenterList + 1; if (i == 3) // wrap 3 to 0 i = 0; gtk_widget_set_size_request(ScrlWin[i], ListWidthPix[i], -1); } return FALSE; } // Note: for some reason, the path shouldn't be freed void Reg_DblClick (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data) { sizing_cancel(); if (AtBreak == FALSE) return; ChangeReg(); } void Asm_DblClick (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data) { sizing_cancel(); if (AtBreak == FALSE) return; SetBreak(SelectedEntry); } void Mem_DblClick (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data) { extern unsigned num_write_watchpoints; extern unsigned num_read_watchpoints; extern bx_phy_address write_watchpoint[]; extern bx_phy_address read_watchpoint[]; sizing_cancel(); if (AtBreak == FALSE || (DViewMode != VIEW_MEMDUMP && DViewMode != VIEW_BREAK)) return; if (DViewMode == VIEW_MEMDUMP) { if (KeyStateShft != 0 && LinearDump == FALSE) SetWatchpoint(&num_write_watchpoints,write_watchpoint); else if (KeyStateAlt != 0 && LinearDump == FALSE) SetWatchpoint(&num_read_watchpoints,read_watchpoint); else //L HIHI Fix how this works in the Windoze version to match GTK? SetMemLine(DumpSelRow); } else // doubleclick to delete a breakpoint in Breakpoint dump { //L HIHI pre-test DumpSelRow < 256 if (DumpSelRow < WWP_BaseEntry) { if (BrkpIDMap[DumpSelRow] == 0) ; // dblclick was on an invalid row else if (DumpSelRow > EndPhyEntry) bx_dbg_del_vbreak(BrkpIDMap[DumpSelRow]); // delete Virtual Brk else if (DumpSelRow > EndLinEntry) bx_dbg_del_pbreak(BrkpIDMap[DumpSelRow]); // delete Phy Brkpt else { bx_dbg_del_lbreak(BrkpIDMap[DumpSelRow]); // delete Lin Brkpt ParseBkpt(); // get a new set of linear breakpoints Invalidate (1); // breakpoint colors may have changed } } else if (DumpSelRow >= WWP_BaseEntry && DumpSelRow < WWP_BaseEntry + WWPSnapCount) { // if a watchpoint was clicked, get its index (0 to 15) int i = DumpSelRow - WWP_BaseEntry; if (WWP_Snapshot[i] == write_watchpoint[i]) DelWatchpoint(write_watchpoint, &num_write_watchpoints, i); } else if (DumpSelRow >= RWP_BaseEntry && DumpSelRow < RWP_BaseEntry + RWPSnapCount) { int i = DumpSelRow - RWP_BaseEntry; if (RWP_Snapshot[i] == read_watchpoint[i]) DelWatchpoint(read_watchpoint, &num_read_watchpoints, i); } RefreshDataWin(); // show the NEW set of break/watchpoints } } // enforce that resize moves remain within the window gboolean LvLeave(GtkWidget *widget, GdkEventCrossing *event, gpointer data) { if (Sizing == 0 && xClick < 0) // anything to cancel? return FALSE; // calculate the position of the top left corner of the LV Event Box unsigned int x_org = (unsigned int) (event->x_root - event->x + 0.5); unsigned int y_org = (unsigned int) (event->y_root - event->y + 0.5); unsigned int absx = (unsigned int) (event->x_root + 0.5); unsigned int absy = (unsigned int) (event->y_root + 0.5); gint width; gint height; // get the width and height of the ListView hbox window gdk_drawable_get_size (event->window, &width, &height); // cursor moved outside the box (not just onto a vert. separator)? if (absx < x_org || absx >= (x_org + width) || absy < y_org || absy >= (y_org + height)) sizing_cancel(); return FALSE; } // doing a resizing operation -- keep track of the cursor position gboolean LV_MouseMove(GtkWidget *widget, GdkEventMotion *event, gpointer data) { int Cur_CliX = (int) (event->x + 0.5); if (EnterSizeMode != FALSE) { // need the "relative" X coordinate of the cursor (wrt the LVEB window) int PrevCliX = CurScrX - (int)(event->x_root - event->x + 0.5); int i= OneCharWide >> 1; Resize_LoX = PrevCliX - i; // set presize horizontal limits Resize_HiX = PrevCliX + i; EnterSizeMode = FALSE; } if (Sizing != 0) { // enforce horizontal limits of the current resize operation if (Cur_CliX > Resize_HiX || Cur_CliX < Resize_LoX) sizing_cancel(); } return FALSE; } // begin a resizing operation gboolean LV_MouseDown(GtkWidget *widget, GdkEventButton *event, gpointer data) { // pre-size mode activated the LVEventBox, and now the user has clicked the mouse enter_resize_mode(); // updates ListWidthPix, verifies presize mode return TRUE; } // mouse is on top of a separator between listviews -- enter presize mode gboolean VsEnter(GtkWidget *widget, GdkEventCrossing *event, gpointer SepNum) { int VsepNum = GPOINTER_TO_INT( SepNum ); // turn on presize mode, if some kind of sizing isn't already running if (Sizing == 0) { Sizing = VsepNum - 2; // Sizing = -1 or -2 for "presize" gdk_window_set_cursor (GTK_WIDGET(LVEvtBox)->window, SizeCurs); EnterSizeMode = TRUE; CurScrX = (unsigned int) (event->x_root + 0.5); gtk_event_box_set_above_child (GTK_EVENT_BOX(LVEvtBox), TRUE); gtk_event_box_set_above_child (GTK_EVENT_BOX(VSepEvtBox1), FALSE); gtk_event_box_set_above_child (GTK_EVENT_BOX(VSepEvtBox2), FALSE); mmov_hID = g_signal_connect (G_OBJECT (LVEvtBox), "motion_notify_event", G_CALLBACK (LV_MouseMove), NULL); } return FALSE; } gboolean LV_MouseUp(GtkWidget *widget, GdkEventButton *event, gpointer data) { SizingDelay = 0; // cancel pre-dock mode on every mouseup SizeList = 0; // -- this will not affect any other sizing modes xClick = -1; return FALSE; } // either cancel or complete a dock or sizing gboolean LEB_MouseUp(GtkWidget *widget, GdkEventButton *event, gpointer data) { int width0, width1, fList, oldcList, dest; gint totwidth, heightLV, x, zip; if (Sizing != 0 || xClick >= 0) // complete a resize or dock operation { int cx = (int)(event->x + 0.5); int cy = (int)(event->y + 0.5); heightLV = ScrlWin[0]->allocation.height; gdk_drawable_get_size (window->window, &totwidth, &zip); dest = fList = (DockOrder >> 8) -1; if (Sizing < 10) // complete a resize operation { width0 = cx; width1 = ListWidthPix[fList] - cx; // "delta" pixels (pos or neg) if (Sizing == 1) // moving Vsep1? gtk_widget_set_size_request(ScrlWin[fList], cx, -1); else { dest = (DockOrder & 3) -1; width0 = totwidth - cx - 4; // assume the Vseps are 2 pixels wide width1 = ListWidthPix[dest] - width0; // "delta" pixels (pos or neg) gtk_widget_set_size_request(ScrlWin[dest], width0, -1); } ListWidthPix[dest] = width0; ListWidthPix[CurCenterList] += width1; // tack the delta pixels onto ctr list } else // complete a Docking operation { // get "local" x mouse coordinate value (main window relative) gdk_window_get_pointer (GTK_WIDGET(LVEvtBox)->window, &x, &zip, NULL); // verify that mouseup was within a LV window if (x >= 0 && cy >= 0 && x < totwidth && cy < heightLV) { // update the widths of the LVs width0 = ScrlWin[0]->allocation.width; ListWidthPix[0] = width0; width1 = ScrlWin[1]->allocation.width; ListWidthPix[1] = width1; ListWidthPix[2] = totwidth - (width0 + width1); oldcList = CurCenterList; if ((unsigned) x < ListWidthPix[fList]) dest = fList; else if ((unsigned) x < ListWidthPix[fList] + ListWidthPix[CurCenterList]) dest = CurCenterList; else dest = (DockOrder & 3) -1; DockResize (dest, (Bit32u) 0); // ParentX is not used for docking // if the center list moved, it will not keep its size properly if (oldcList != CurCenterList) { gtk_widget_set_size_request(ScrlWin[CurCenterList], -1, -1); gtk_widget_set_size_request(ScrlWin[oldcList], ListWidthPix[oldcList], -1); } } } sizing_cancel(); } return TRUE; } // one-time init function to make all the buttons/menu items work void AttachSignals() { int i; g_signal_connect (G_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(Close_cb), (gpointer) NULL); g_signal_connect (G_OBJECT(CmdBtn[0]), "clicked", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) BtnLkup[0]); g_signal_connect (G_OBJECT(CmdBtn[1]), "clicked", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) BtnLkup[1]); g_signal_connect (G_OBJECT(CmdBtn[2]), "clicked", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) BtnLkup[2]); g_signal_connect (G_OBJECT(CmdBtn[3]), "clicked", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) BtnLkup[3]); g_signal_connect (G_OBJECT(CmdBtn[4]), "clicked", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) BtnLkup[4]); i = BX_SMP_PROCESSORS; if (i > 1) { while (--i >= 0) g_signal_connect (G_OBJECT(CpuBtn[i]), "clicked", GTK_SIGNAL_FUNC(CPUb_cb), (gpointer) i); } // activate the menu items g_signal_connect (G_OBJECT(ContMI), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_CONT); g_signal_connect (G_OBJECT(StepMI), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_STEP1); g_signal_connect (G_OBJECT(StepNMI), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_STEPN); g_signal_connect (G_OBJECT(BreakMI), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_BREAK); g_signal_connect (G_OBJECT(SetBrkMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_BRKPT); Cmd2MI[CMD_BRKPT - CMD_IDX_LO + 1] = SetBrkMI; g_signal_connect (G_OBJECT(WatchWrMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_WPTWR); Cmd2MI[CMD_WPTWR - CMD_IDX_LO + 1] = WatchWrMI; g_signal_connect (G_OBJECT(WatchRdMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_WPTRD); Cmd2MI[CMD_WPTRD - CMD_IDX_LO + 1] = WatchRdMI; g_signal_connect (G_OBJECT(FindMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_FIND); g_signal_connect (G_OBJECT(RefreshMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_RFRSH); g_signal_connect (G_OBJECT(PhyDumpMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_PHYDMP); g_signal_connect (G_OBJECT(LinDumpMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_LINDMP); g_signal_connect (G_OBJECT(StackMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_STACK); g_signal_connect (G_OBJECT(GDTMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_GDTV); g_signal_connect (G_OBJECT(IDTMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_IDTV); g_signal_connect (G_OBJECT(PageMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_PAGEV); Cmd2MI[CMD_PAGEV - CMD_IDX_LO + 1] = PageMI; g_signal_connect (G_OBJECT(ViewBrkMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_VBRK); g_signal_connect (G_OBJECT(MemDumpMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_CMEM); g_signal_connect (G_OBJECT(PTreeMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_PTREE); g_signal_connect (G_OBJECT(DisAsmMI), "activate", GTK_SIGNAL_FUNC(Cmd_cb), (gpointer) CMD_DISASM); g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_MODEB]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_MODEB); g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_ONECPU]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_ONECPU); Cmd2MI[CMD_ONECPU - CMD_IDX_LO + 1] = ChkMIs[CHK_CMD_ONECPU]; g_signal_connect (G_OBJECT(DefDisMI), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_DADEF); g_signal_connect (G_OBJECT(SyntaxMI), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_ATTI); g_signal_connect (G_OBJECT(FontMI), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_FONT); g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_UCASE]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_UCASE); g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_IOWIN]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_IOWIN); g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_SBTN]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_SBTN); g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_MHEX]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_MHEX); Cmd2MI[CMD_MHEX - CMD_IDX_LO + 1] = ChkMIs[CHK_CMD_MHEX]; g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_MASCII]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_MASCII); Cmd2MI[CMD_MASCII - CMD_IDX_LO + 1] = ChkMIs[CHK_CMD_MASCII]; g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_LEND]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_LEND); g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_IGNSA]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_IGNSA); g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_IGNNT]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_IGNNT); g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_RCLR]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_RCLR); g_signal_connect (G_OBJECT(ChkMIs[CHK_CMD_EREG]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_EREG); Cmd2MI[CMD_EREG - CMD_IDX_LO + 1] = ChkMIs[CHK_CMD_EREG]; g_signal_connect (G_OBJECT(ChkMIs[S_REG]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_SREG); g_signal_connect (G_OBJECT(ChkMIs[SYS_R]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_SYSR); g_signal_connect (G_OBJECT(ChkMIs[C_REG]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_CREG); g_signal_connect (G_OBJECT(ChkMIs[FPU_R]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_FPUR); Cmd2MI[CMD_FPUR - CMD_IDX_LO + 1] = ChkMIs[FPU_R]; g_signal_connect (G_OBJECT(ChkMIs[XMM_R]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_XMMR); Cmd2MI[CMD_XMMR - CMD_IDX_LO + 1] = ChkMIs[XMM_R]; g_signal_connect (G_OBJECT(ChkMIs[D_REG]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_DREG); Cmd2MI[CMD_DREG - CMD_IDX_LO + 1] = ChkMIs[D_REG]; // g_signal_connect (G_OBJECT(ChkMIs[T_REG]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_TREG); // Cmd2MI[CMD_TREG - CMD_IDX_LO + 1] = ChkMIs[T_REG]; g_signal_connect (G_OBJECT(AboutMI), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_ABOUT); g_signal_connect (G_OBJECT(ChkMIs[WSChkIdx]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_WS_1); g_signal_connect (G_OBJECT(ChkMIs[WSChkIdx+1]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_WS_2); g_signal_connect (G_OBJECT(ChkMIs[WSChkIdx+2]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_WS_4); g_signal_connect (G_OBJECT(ChkMIs[WSChkIdx+3]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_WS_8); g_signal_connect (G_OBJECT(ChkMIs[WSChkIdx+4]), "activate", GTK_SIGNAL_FUNC(nbCmd_cb), (gpointer) CMD_WS16); g_signal_connect (G_OBJECT (IEntry), "key_press_event", G_CALLBACK (keydown_event_cb), NULL); g_signal_connect (G_OBJECT (window), "key_press_event", G_CALLBACK (redirect_keydown), NULL); g_signal_connect (LV[0], "button_press_event", G_CALLBACK (RegMouseDown_cb), NULL); g_signal_connect (LV[0], "row-activated", GTK_SIGNAL_FUNC(Reg_DblClick), (gpointer) 0); g_signal_connect (LV[1], "button_press_event", G_CALLBACK (AsmMouseDown_cb), NULL); g_signal_connect (LV[1], "row-activated", GTK_SIGNAL_FUNC(Asm_DblClick), (gpointer) 1); g_signal_connect (LV[2], "button_press_event", G_CALLBACK (MemMouseDown_cb), NULL); g_signal_connect (LV[2], "row-activated", GTK_SIGNAL_FUNC(Mem_DblClick), NULL); g_signal_connect (G_OBJECT (LVEvtBox), "leave_notify_event", G_CALLBACK (LvLeave), NULL); g_signal_connect (G_OBJECT (VSepEvtBox1), "enter_notify_event", G_CALLBACK (VsEnter), (gpointer) 0); g_signal_connect (G_OBJECT (VSepEvtBox2), "enter_notify_event", G_CALLBACK (VsEnter), (gpointer) 1); g_signal_connect (G_OBJECT (LVEvtBox), "button_press_event", G_CALLBACK (LV_MouseDown), NULL); g_signal_connect (G_OBJECT (LVEvtBox), "button_release_event", G_CALLBACK (LEB_MouseUp), NULL); g_signal_connect (G_OBJECT (LV[0]), "button_release_event", G_CALLBACK (LV_MouseUp), NULL); g_signal_connect (G_OBJECT (LV[1]), "button_release_event", G_CALLBACK (LV_MouseUp), NULL); g_signal_connect (G_OBJECT (LV[2]), "button_release_event", G_CALLBACK (LV_MouseUp), NULL); } // force the screen to "get current" every half a second static gboolean VGAWrefreshTick(GtkWidget *widget) { if (bx_user_quit != FALSE) // may be in the middle of a "destroy" return FALSE; if (SizingDelay > 0) { GdkDisplay * display = gdk_display_get_default(); gint x; gint y; // enter pre-dock mode int i, j; --SizingDelay; gdk_display_get_pointer (display, NULL, &x, &y, NULL); // absolute x and y mouse coords i = x - xClick; j = y - yClick; // calculate the pixel delta from the mousedown event to now if (i < 0) i= -i; if (j < 0) j= -j; if ((SizingDelay == 1 && (i > OneCharWide || j > OneCharWide)) || SizingDelay == 0) { // transition from predock to full dock mode xClick = -1; if (SizeList == 0) return FALSE; gtk_event_box_set_above_child (GTK_EVENT_BOX(VSepEvtBox1), FALSE); gtk_event_box_set_above_child (GTK_EVENT_BOX(VSepEvtBox2), FALSE); gtk_event_box_set_above_child (GTK_EVENT_BOX(LVEvtBox), TRUE); Sizing = SizeList; // Sizing tells which ListView is being moved gdk_window_set_cursor (GTK_WIDGET(LVEvtBox)->window, DockCurs); } } UpdateStatus(); if (PO_Tdelay > 0) // output window is delaying display of a partial line? { if (--PO_Tdelay == 0) // on a timeout, add a lf to complete the line ParseIDText ("\n"); } Invalidate (0); Invalidate (1); if (DViewMode != VIEW_PTREE) Invalidate (2); vgaw_refresh = TRUE; return TRUE; } // Need to keep the bochs thread and the gtk_main threads separate -- bochs thread must not // call GTK functions -- so it needs to set flags to initiate OnBreak, and OutputText updates static gboolean BochsUpdateTick(GtkWidget *widget) { if (bx_user_quit != FALSE) // may be in the middle of a "destroy" return FALSE; if (UpdateOWflag != FALSE) { // replace the entire Output window's text, then scroll the window to the end GtkTextBuffer *OBuffer; // pull model out of the widget UpdateOWflag = FALSE; OBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(OText)); gtk_text_buffer_set_text(OBuffer, OutWindow, -1); gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(OText), EndMark, (gdouble) 0, TRUE, (gdouble) 1, (gdouble) 1); } if (HitBrkflag != FALSE) OnBreak(); HitBrkflag = FALSE; return TRUE; } // called from *bochs* at a simulation break, or other ID command completion -- // so it must not call GTK functions directly, only through a shared memory flag void HitBreak() { if (AtBreak == FALSE) { AtBreak = TRUE; StatusChange = TRUE; } if (bx_user_quit == FALSE) // may be in the middle of a "destroy" HitBrkflag = TRUE; } // special paint procedure for any colors on ListViews void ListClr_PaintCb(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer acolnum) { int colnum = GPOINTER_TO_INT ( acolnum ); gint rownum = 0; extern unsigned num_write_watchpoints; extern unsigned num_read_watchpoints; extern bx_phy_address write_watchpoint[]; extern bx_phy_address read_watchpoint[]; if (AtBreak == FALSE) g_object_set(renderer, "cell-background-gdk", &mgray, "cell-background-set", TRUE, NULL); else if (colnum <3) { // painting REG_WND -- recover the row number for this iter gtk_tree_model_get (model, iter, 3, &rownum, -1); //L HIHI verify rownum in all 3 sections if (colnum == 0 && SelReg[rownum] != FALSE) // is this row selected? { // if selected, foreground of column 0 = white, background = blue g_object_set(renderer, "foreground-gdk", &white, "foreground-set", TRUE, NULL); g_object_set(renderer, "cell-background-gdk", &AsmColors[3], "cell-background-set", TRUE, NULL); return; } // set fg (and bg if requested) according to color list Bit8u ClrFlgs = RegColor[ RitemToRnum[rownum] ]; // RitemToRnum converts a ListView row number to the corresponding Register number. // RegColor has the 0x80 bit set if the register is supposed to be red. // Background color index is in the low nibble of ClrFlgs/RegColor. if (SeeRegColors != FALSE) g_object_set(renderer, "cell-background-gdk", &ColorList[ClrFlgs &7], "cell-background-set", TRUE, NULL); else g_object_set(renderer, "cell-background-gdk", &white, "cell-background-set", TRUE, NULL); if ((ClrFlgs & 0x80) != 0) // should this register be red? g_object_set(renderer, "foreground-gdk", &fg_red, "foreground-set", TRUE, NULL); else g_object_set(renderer, "foreground-gdk", &fg_black, "foreground-set", TRUE, NULL); } else if (colnum < 6) { // painting ASM_WND -- recover the row number and "Linear Address" for this iter gtk_tree_model_get (model, iter, 3, &rownum, -1); bx_address h = (bx_address) AsmLA[rownum]; if (colnum == 3 && SelAsm[rownum] != FALSE) // is this row selected? { // if selected, foreground of column 0 = white, background = blue g_object_set(renderer, "foreground-gdk", &white, "foreground-set", TRUE, NULL); g_object_set(renderer, "cell-background-gdk", &AsmColors[3], "cell-background-set", TRUE, NULL); g_object_set(renderer, "weight", PANGO_WEIGHT_NORMAL, "weight-set", TRUE, "style", PANGO_STYLE_NORMAL, "style-set", TRUE, NULL); return; } // clear out any gray background g_object_set(renderer, "cell-background-gdk", &white, "cell-background-set", TRUE, NULL); // use an ellipsis ... on the bytes column if (colnum == 4) g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, NULL); else g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_NONE, "ellipsize-set", TRUE, NULL); int AsmClrNum = 0; // assume black text if (h == CurrentAsmLA) AsmClrNum = 1; // current opcode is colored dark green int j= BreakCount; while (--j >= 0) // loop over all breakpoints { // brk list is sorted -- if the value goes too low, end the loop if (BrkLAddr[j] < h) j = 0; // force the loop to end if it goes too far else if (BrkLAddr[j] == h) { j= 0; if (h == CurrentAsmLA) AsmClrNum = 3; // breakpoint @ current opcode = blue else AsmClrNum = 2; // active breakpoint is red } } g_object_set(renderer, "foreground-gdk", &AsmColors[AsmClrNum], "foreground-set", TRUE, NULL); // extra visuals for current RIP and breakpoints -- use bold and italic on mnemonics if (colnum == 5 && AsmClrNum != 0) { if ((AsmClrNum&1) != 0) // current RIP g_object_set(renderer, "weight", PANGO_WEIGHT_BOLD, "weight-set", TRUE, NULL); if ((AsmClrNum&2) != 0) // breakpoint g_object_set(renderer, "style", PANGO_STYLE_ITALIC, "style-set", TRUE, NULL); } else { g_object_set(renderer, "weight", PANGO_WEIGHT_NORMAL, "weight-set", TRUE, "style", PANGO_STYLE_NORMAL, "style-set", TRUE, NULL); } } else { // painting some kind of dump window -- stack and physdump are special // clear out any gray background gtk_tree_model_get (model, iter, 18, &rownum, -1); g_object_set(renderer, "cell-background-gdk", &white, "cell-background-set", TRUE, NULL); if (DViewMode == VIEW_STACK) { // highlight changed lines in stack if (rownum < 0 || rownum >= STACK_ENTRIES) // make sure the line # is legal ; else if (StackEntChg[rownum] != FALSE) g_object_set(renderer, "foreground-gdk", &fg_red, "foreground-set", TRUE, NULL); else g_object_set(renderer, "foreground-gdk", &fg_black, "foreground-set", TRUE, NULL); return; } // is this row selected (only applies to Memdump windows)? if (colnum == 6 && SelMem[rownum] != FALSE && DViewMode == VIEW_MEMDUMP) { // if selected, foreground of column 0 = white, background = blue g_object_set(renderer, "foreground-gdk", &white, "foreground-set", TRUE, NULL); g_object_set(renderer, "cell-background-gdk", &AsmColors[3], "cell-background-set", TRUE, NULL); return; } // the only other special painting is for Phys Dump columns, with byte DumpAlign (watchpoints) int DmpClrNum = 0; // assume black text if (colnum > 6 && DumpAlign == 1 && LinearDump == FALSE && DViewMode == VIEW_MEMDUMP) { // For each cell, calculate its equivalent physmem address // byte offset = 0 means colnum = 7 bx_phy_address h = (bx_phy_address) DumpStart + 16*rownum + colnum - 7; int j = num_write_watchpoints; int i = num_read_watchpoints; while (j > 0) { if (write_watchpoint[--j] == h) { DmpClrNum = 1; // write watchpoint j = -1; // on a match j<0 -- else j == 0 } } while (--i >= 0) { if (read_watchpoint[i] == h) { if (j < 0) // BOTH read and write DmpClrNum = 2; else DmpClrNum = 3; // read watchpoint i = 0; // end the loop on a match } } } g_object_set(renderer, "foreground-gdk", &PDumpClr[DmpClrNum], "foreground-set", TRUE, NULL); if (DmpClrNum != 0) g_object_set(renderer, "cell-background-gdk", &fg_black, "cell-background-set", TRUE, NULL); } } // build the columns for each of the three main lists void MakeList(int listnum, char *ColNameArray[]) { int i; int nColumns = 3; char txt[4]; GtkListStore *Database; // "model" that contains the actual data GtkCellRenderer *renderer; // column/cell drawing object GtkTreeViewColumn *column; // column object GtkTreeSelection *sel; // need the tree's selection object sel = gtk_tree_view_get_selection (GTK_TREE_VIEW( LV[listnum]) ); gtk_tree_selection_set_mode (sel, GTK_SELECTION_NONE); // format for next funct is ( # of columns, datatype, ... ); -- really stupid argument arrangement! if (listnum != DUMP_WND) Database = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); else // 18 columns { nColumns = 18; Database = gtk_list_store_new (19, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); } char *cp = ColNameArray[0]; *txt = '0' -1; txt[1] = 0; // allocate one renderer for each ListView renderer = gtk_cell_renderer_text_new(); LV_Rend[listnum]= renderer; for (i=0 ; i < nColumns ; i++) { // when nColumns == 18, there are only two entries in ColNameArray if (nColumns == 3) cp = ColNameArray[i]; column = gtk_tree_view_column_new_with_attributes(cp, renderer, "text", i, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(LV[listnum]), column); gtk_tree_view_column_set_cell_data_func(column, renderer, ListClr_PaintCb, (gpointer) ((listnum*3) + i), NULL); // Note: column and renderer are not technically "GTK Objects", so don't unref them cp = txt; ++*cp; // cheap way to create "0" through "9" and "A" through "F" if (i == 10) *cp = 'A'; else if (i == 16) cp = ColNameArray[1]; // must store copies of all the columns, to change column titles and other "properties" later AllCols[(listnum*3) + i] = column; } gtk_tree_view_set_model(GTK_TREE_VIEW(LV[listnum]), GTK_TREE_MODEL(Database)); // ListView now holds a reference to Database -- don't need the local reference anymore g_object_unref (G_OBJECT (Database)); } // gtk version of multithreading (doesn't seem to work on some platforms?): /* // this function must be called as a new multithread, from the initialization code // -- it runs the main gtk "event loop", which spawns all the "events", // "repaint"s, and callbacks -- and never returns, except on a "quit" gpointer EventLp(gpointer data) { gtk_main(); g_thread_exit(0); return (gpointer) NULL; } void MakeGTKthreads() { // do gtk multithreading initialization FIRST -- before ANYTHING ELSE GError *error = NULL; #ifndef G_THREADS_ENABLED printf ("init err1: thread support not enabled in glib\n"); return FALSE; #endif #ifndef G_THREADS_IMPL_POSIX printf ("init err2: pthread package not found\n"); return FALSE; #endif if (g_thread_supported() == FALSE) { printf ("init err3: pthreads/multithreading is not running? No multithread support.\n"); return FALSE; } g_thread_init(NULL); g_thread_create (EventLp, (gpointer) NULL, FALSE, &error); } */ // multithreading using pure posix threads -- not glib threads void * EventLp(void *data) { gtk_main(); // pthread_exit(0); return NULL; } void MakeGTKthreads() { pthread_t hThread; // g_thread_init(NULL); // if I put this in, it gives me an "undefined reference" of all crazy things! pthread_create (&hThread, NULL, EventLp, NULL); } // This function must be called immediately after bochs starts bx_bool OSInit() { int i, argc; char *argv[2], **argvp; char* LColNames[] = { "Reg Name","Hex Value","Decimal","L.Address","Bytes","Mnemonic","Address","Ascii" }; GtkTextBuffer *Tbuffer; GtkTextIter Titer; GtkWidget *tmpLbl; *bigbuf = 0; // gtk flames out if you pass in a NULL -- sheesh argv[0] = bigbuf; // so I really do have to fake up an "argv" list argv[1] = NULL; argvp = argv; argc = 1; // you MUST call gtk_init, even with faked arguments, because it inits GDK and Glib if (gtk_init_check(&argc, &argvp) == FALSE) printf ("gtk init failed, can not access display?\n"); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "Bochs Enhanced Debugger"); gtk_window_set_default_size(GTK_WINDOW(window), 500, 500); MainVbox = gtk_vbox_new(FALSE, 0); // vbox that contains EVERYTHING gtk_container_add(GTK_CONTAINER(window), MainVbox); // make/init the menu "containers" (shells) and menu items InitMenus(); // build the StatusBar StatHbox = gtk_hbox_new(FALSE, 3); Stat[0] = gtk_label_new("Break"); gtk_label_set_width_chars (GTK_LABEL(Stat[0]), 7); Stat[1] = gtk_label_new("CPU:"); gtk_label_set_width_chars (GTK_LABEL(Stat[1]), 23); Stat[2] = gtk_label_new("t=0"); gtk_label_set_width_chars (GTK_LABEL(Stat[2]), 19); Stat[3] = gtk_label_new("IOPL"); StatVSep1 = gtk_vseparator_new(); StatVSep2 = gtk_vseparator_new(); StatVSep3 = gtk_vseparator_new(); gtk_box_pack_start(GTK_BOX(StatHbox), Stat[0], FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(StatHbox), StatVSep1, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(StatHbox), Stat[1], FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(StatHbox), StatVSep2, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(StatHbox), Stat[2], FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(StatHbox), StatVSep3, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(StatHbox), Stat[3], TRUE, TRUE, 0); // set LEFT, instead of the default centered "justification" of status text gtk_misc_set_alignment(GTK_MISC(Stat[0]), (gfloat) 0., (gfloat) 0.5); gtk_misc_set_alignment(GTK_MISC(Stat[1]), (gfloat) 0., (gfloat) 0.5); gtk_misc_set_alignment(GTK_MISC(Stat[2]), (gfloat) 0., (gfloat) 0.5); gtk_misc_set_alignment(GTK_MISC(Stat[3]), (gfloat) 0., (gfloat) 0.5); gtk_box_pack_start(GTK_BOX(MainVbox), menubar, FALSE, FALSE, 0); gtk_box_pack_end(GTK_BOX(MainVbox), StatHbox, FALSE, FALSE, 0); // build the table that holds the TreeView/Input&Output windows TreeTbl = gtk_table_new(4, 1, TRUE); // proportion the remaining space in quarters, vertically sep8 = gtk_vseparator_new(); // vertical separators between the ListViews sep9 = gtk_vseparator_new(); VSepEvtBox1 = gtk_event_box_new(); // seps need event boxes to catch "Enter" events VSepEvtBox2 = gtk_event_box_new(); gtk_container_add (GTK_CONTAINER(VSepEvtBox1), sep8); gtk_container_add (GTK_CONTAINER(VSepEvtBox2), sep9); gtk_widget_add_events(VSepEvtBox1, GDK_ENTER_NOTIFY_MASK); // masks must be set immediately after creation gtk_widget_add_events(VSepEvtBox2, GDK_ENTER_NOTIFY_MASK); IOVbox = gtk_vbox_new(FALSE, 0); // stack the Input Entry and Output TextView vertically // create Input window IEntry = gtk_entry_new(); gtk_entry_set_max_length (GTK_ENTRY(IEntry), 190); // create Output window ScrlWinOut = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ScrlWinOut), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); OText = gtk_text_view_new(); gtk_text_view_set_editable(GTK_TEXT_VIEW(OText), FALSE); // set it to "read only" GTK_WIDGET_UNSET_FLAGS(OText, GTK_CAN_FOCUS); gtk_container_add (GTK_CONTAINER(ScrlWinOut), OText); // a TextView *already has* a viewport, so DON'T add another one -- or it won't scroll properly! // gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ScrlWinOut), OText); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(OText), GTK_WRAP_WORD); // create a textmark that always points to the very end of OText Tbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(OText)); gtk_text_buffer_get_iter_at_offset (Tbuffer, &Titer, 0); EndMark = gtk_text_buffer_create_mark (Tbuffer, NULL, &Titer, FALSE); gtk_box_pack_start(GTK_BOX(IOVbox), ScrlWinOut, TRUE, TRUE, 0); gtk_box_pack_end(GTK_BOX(IOVbox), IEntry, FALSE, FALSE, 0); LVHbox = gtk_hbox_new(FALSE, 0); // to hold the ListView windows LVEvtBox = gtk_event_box_new(); // need to catch "leave" and "move" events for ListViews gtk_container_add (GTK_CONTAINER(LVEvtBox), LVHbox); gtk_widget_add_events(LVEvtBox, GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK); // make Command and CPU Button rows CmdBHbox = gtk_hbox_new(TRUE, 0); for (i=0 ; i < 5 ; i++) { CmdBtn[i] = gtk_button_new(); tmpLbl = gtk_label_new (""); sprintf (bigbuf, "%s",BTxt[i]); // create "bold" pango markup for buttons gtk_label_set_markup (GTK_LABEL(tmpLbl), bigbuf); gtk_container_add (GTK_CONTAINER(GTK_BUTTON(CmdBtn[i])), tmpLbl); GTK_WIDGET_UNSET_FLAGS(CmdBtn[i], GTK_CAN_FOCUS); gtk_box_pack_start(GTK_BOX(CmdBHbox), CmdBtn[i], TRUE, TRUE, 0); } gtk_box_pack_start(GTK_BOX(MainVbox), CmdBHbox, FALSE, FALSE, 0); // CPU button row does not exist for only 1 cpu if (BX_SMP_PROCESSORS > 1) { CpuBHbox = gtk_hbox_new(TRUE, 0); gtk_box_pack_start(GTK_BOX(MainVbox), CpuBHbox, FALSE, FALSE, 0); i = 0; strcpy (bigbuf, "CPU0"); // Handle CPU0 specially -- it is "selected" while (i < BX_SMP_PROCESSORS) { CpuBtn[i] = gtk_button_new(); tmpLbl = gtk_label_new (""); CpuB_label[i] = tmpLbl; gtk_label_set_markup (GTK_LABEL(tmpLbl), bigbuf); gtk_container_add (GTK_CONTAINER(GTK_BUTTON(CpuBtn[i])), tmpLbl); GTK_WIDGET_UNSET_FLAGS(CpuBtn[i], GTK_CAN_FOCUS); gtk_box_pack_start(GTK_BOX(CpuBHbox), CpuBtn[i], TRUE, TRUE, 0); sprintf (bigbuf, "cpu%d",++i); // create the next CPU button label } } gtk_box_pack_end(GTK_BOX(MainVbox), TreeTbl, TRUE, TRUE, 0); gtk_table_attach_defaults(GTK_TABLE(TreeTbl), LVEvtBox, 0, 1, 0, 3); // order = LRTB gtk_table_attach_defaults(GTK_TABLE(TreeTbl), IOVbox, 0, 1, 3, 4); VSizeChange(); // build the 3 ListView windows i = 3; while (--i >= 0) { ScrlWin[i] = gtk_scrolled_window_new( NULL, NULL ); // always want a horizontal scrollbar, to divide lists from Output window visually gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ScrlWin[i]), GTK_POLICY_ALWAYS, GTK_POLICY_AUTOMATIC); LV[i] = gtk_tree_view_new(); GTK_WIDGET_UNSET_FLAGS(LV[i], GTK_CAN_FOCUS); gtk_container_add (GTK_CONTAINER(ScrlWin[i]), LV[i]); // all TreeViews *already have* a viewport, so DON'T add another one with the ScrollWindow, or it won't scroll properly! MakeList(i, &LColNames[i*3]); } CurCenterList = ((DockOrder>>4)& 3) -1; // index of center list RepackLists((DockOrder >> 8) -1); // index of left list // make the param_tree widget GtkTreeViewColumn *treecol; GtkCellRenderer *renderer; GtkTreeStore *treestore; PTree = gtk_tree_view_new(); treecol = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(treecol, "bochs parameter tree"); gtk_tree_view_append_column(GTK_TREE_VIEW(PTree), treecol); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(treecol, renderer, TRUE); gtk_tree_view_column_add_attribute(treecol, renderer, "text", 0); // pull display text from treestore col 0 GTK_WIDGET_UNSET_FLAGS(PTree, GTK_CAN_FOCUS); treestore = gtk_tree_store_new(1, G_TYPE_STRING); gtk_tree_view_set_model(GTK_TREE_VIEW(PTree), GTK_TREE_MODEL(treestore)); g_object_unref(treestore); // PTree now references treestore itself gtk_widget_ref (PTree); // keep an extra ref to both ScrlWin[2] widgets, gtk_widget_ref (LV[2]); // so they don't get deleted when removed from their container gtk_object_sink (GTK_OBJECT (PTree)); // the PTree reference is "floating", so "sink" it AttachSignals(); // this must be called AFTER InitMenus() TakeInputFocus(); gtk_widget_show_all(window); // In order to catch Enter/Leave events, you need a widget with a Gdk Window. Neither hboxes or VSeps have them, // so it is necessary to add event boxes. The windows should be invisible, and when I want them to WORK, they // must be ON TOP of the child widgets. LVEvtBox is only needed in resize/dock mode. gtk_event_box_set_visible_window (GTK_EVENT_BOX(LVEvtBox), FALSE); gtk_event_box_set_above_child (GTK_EVENT_BOX(LVEvtBox), FALSE); gtk_event_box_set_visible_window (GTK_EVENT_BOX(VSepEvtBox1), FALSE); gtk_event_box_set_above_child (GTK_EVENT_BOX(VSepEvtBox1), TRUE); gtk_event_box_set_visible_window (GTK_EVENT_BOX(VSepEvtBox2), FALSE); gtk_event_box_set_above_child (GTK_EVENT_BOX(VSepEvtBox2), TRUE); // build the sizing/docking cursors SizeCurs = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW); DockCurs = gdk_cursor_new (GDK_CROSSHAIR); gdk_cursor_ref (SizeCurs); gdk_cursor_ref (DockCurs); // the OneCharWide pixel value is used to limit docking and resizing movements int width; PangoLayout * layout = gtk_widget_create_pango_layout (LV[0], "M"); PangoFontDescription * fontdesc; g_object_get( G_OBJECT( LV_Rend[0] ), "font-desc", &fontdesc, NULL ); pango_layout_set_font_description (layout, fontdesc); pango_layout_get_pixel_size (layout, &width, &i); pango_font_description_free (fontdesc); g_object_unref (layout); OneCharWide = width; // The "width" I'm getting is about half what I expect // OneCharWide = width >> 1; // pretend that an average char width is half an "M" if (OneCharWide > 12) OneCharWide = 12; // UpdInProgress[REG_WND] = FALSE; // UpdInProgress[ASM_WND] = FALSE; // UpdInProgress[DUMP_WND] = FALSE; ResizeColmns = TRUE; // force an initial resize on hex, address columns g_timeout_add(500, (GSourceFunc) VGAWrefreshTick, (gpointer) window); g_timeout_add(50, (GSourceFunc) BochsUpdateTick, (gpointer) window); g_signal_connect (G_OBJECT (window), "configure_event", G_CALLBACK (TblSizeEvent), NULL); // could use: gtk_tree_view_column_get_width(), etc. AllCols[4]->fixed_width = AllCols[4]->width; AllCols[4]->column_type = GTK_TREE_VIEW_COLUMN_FIXED; MakeGTKthreads(); return TRUE; } // recurse displaying each leaf/branch of param_tree -- with values for each leaf void MakeBL(TreeParent *h_P, bx_param_c *p) { TreeParent h_new; bx_list_c *as_list = NULL; int i = 0; strcpy (tmpcb, p->get_name()); int j = strlen (tmpcb); switch (p->get_type()) { case BXT_PARAM_NUM: if (((bx_param_num_c*)p)->get_base() == BASE_DEC) sprintf (tmpcb + j,": " FMT_LL "d",((bx_param_num_c*)p)->get64()); else sprintf (tmpcb + j,": 0x" FMT_LL "X",((bx_param_num_c*)p)->get64()); break; case BXT_LIST: as_list = (bx_list_c *)p; i = as_list->get_size(); break; case BXT_PARAM_BOOL: sprintf (tmpcb + j,": %s",((bx_param_bool_c*)p)->get()?"true":"false"); break; case BXT_PARAM_ENUM: sprintf (tmpcb + j,": %s",((bx_param_enum_c*)p)->get_selected()); break; case BXT_PARAM_STRING: if (((bx_param_string_c*)p)->get_options()->get() & bx_param_string_c::RAW_BYTES) { char *cp = tmpcb + j; unsigned char *rp = (unsigned char *)((bx_param_string_c*)p)->getptr(); char sc = ((bx_param_string_c*)p)->get_separator(); int k = ((bx_param_string_c*)p)->get_maxsize(); *(cp++) = ':'; *(cp++) = ' '; while (k-- > 0) { *(cp++) = AsciiHex[2* *rp]; *(cp++) = AsciiHex[2* *rp + 1]; *(cp++) = sc; } *--cp = 0; // overwrite the last separator char } else sprintf (tmpcb + j,": %s",((bx_param_string_c*)p)->getptr()); break; case BXT_PARAM_DATA: sprintf (tmpcb + j,": binary data, size=%d",((bx_shadow_data_c*)p)->get_size()); } MakeTreeChild (h_P, i, &h_new); if (i > 0) { while (--i >= 0) MakeBL(&h_new, as_list->get(i)); // recurse for all children that are lists } } #endif