给Mate终端与GDB增加快捷键

最近开始学习Linux编程,在Mate终端里试用了GDB的调试方式,对于习惯了用F5、F10和F11来调试的我来说,还真有点不习惯。于是我就把给Mate终端与GDB增加快捷键当作学习Linux编程的第一个实验目标来完成。现在我就把总结出来的方法分享给大家。

下载Mate终端源程序并解压缩:

链接: https://pan.baidu.com/s/1b8DCfkoHuKk0WSlKFXwVxQ密码: u5uu

里面有两个文件:

mate-terminal-1.21.0.tar.gz是原始源码包

mate-terminal-1.21.1.tar.xz是我改完的源码包

不想自己动手的的朋友可以下载我改过的包。编译安装方法在后面。

  1.  添加菜单
    
  1.  先将下面的菜单代码添加到src/terminal-window.c文件中的terminal_window_init函数,menu_entries数组,/* Terminal menu */段的前面。
    

/* Debugmenu */

{

        "DebugProgram", NULL, N_("DebugProgram"), "F2",

        NULL,

        G_CALLBACK (debug_program_callback)

    },

{

        "DebugProcess", NULL,N_("Debug Process"), "F3",

        NULL,

        G_CALLBACK (debug_process_callback)

    },

{

        "DebugStart", NULL, N_("Debug Start"),"F4",

        NULL,

        G_CALLBACK (debug_start_callback)

    },

{

        "DebugContinue", NULL,N_("Debug Continue"), "F5",

        NULL,

        G_CALLBACK (debug_continue_callback)

    },

{

        "DebugNext", NULL, N_("Debug Next"),"F10",

        NULL,

        G_CALLBACK (debug_next_callback)

    },

{

        "DebugStep", NULL, N_("Debug Step"),"F11",

        NULL,

        G_CALLBACK (debug_step_callback)

    },

再在/* Toplevel */段中的{ “Search”, NULL, N_(“_Search”) },下面加入

{ “Debug”, NULL, N_(“Debug”) },

  1.  将下面的菜单项添加到src/terminal.xml文件中的<menuaction="Terminal">段的前面。
    
  1.  打开po/ zh_CN.po文件,查找src/terminal-window.c段,将下面的字段添加到里面。
    

msgid"Debug"

msgstr"调试"

msgid"Debug Program"

msgstr"调试程序"

msgid"Debug Process"

msgstr"调试进程"

msgid"Debug Start"

msgstr"开始调试"

msgid"Debug Continue"

msgstr"继续执行"

msgid"Debug Next"

msgstr"单步执行"

msgid"Debug Step"

msgstr"进入函数"

msgid"Program Name"

msgstr"程序名称"

msgid"Name:"

msgstr"名称:"

msgid"Process Id"

msgstr"进程ID"

  1.  添加调用代码
    
  1.  将下面代码添加到/src/terminal-window.c文件中的terminal_window_init (TerminalWindow *window)函数前面。
    

staticvoid

terminal_get_program_name_dialog_response_cb(GtkWidget *dialog,

                                   intresponse,

                                  TerminalScreen *screen)

{

if (response == GTK_RESPONSE_OK)

{

    GtkEntry *entry;

    const gchar *gtext;

        GString *gstr;


    entry = GTK_ENTRY (g_object_get_data(G_OBJECT (dialog), "name-entry"));

    gtext = gtk_entry_get_text (entry);


        gstr = g_string_new(NULL);

        gstr = g_string_assign(gstr,"gdb ");

        g_string_append(gstr, gtext);

        gstr = g_string_append_c(gstr,'\n');


        vte_terminal_feed_child(screen,gstr->str, gstr->len);


        g_string_free(gstr, TRUE);

}


gtk_widget_destroy (dialog);

}

staticvoid

terminal_get_program_id_dialog_response_cb(GtkWidget *dialog,

                                   int response,

                                  TerminalScreen *screen)

{

if (response == GTK_RESPONSE_OK)

{

    GtkEntry *entry;

    const gchar *gtext;

        GString *gstr;


    entry = GTK_ENTRY (g_object_get_data(G_OBJECT (dialog), "id-entry"));

    gtext = gtk_entry_get_text (entry);


        gstr = g_string_new(NULL);

        gstr = g_string_assign(gstr,"gdb --pid ");

        g_string_append(gstr, gtext);

        gstr = g_string_append_c(gstr,'\n');


        vte_terminal_feed_child(screen,gstr->str, gstr->len);


        g_string_free(gstr, TRUE);

}


gtk_widget_destroy (dialog);

}

staticvoid

debug_program_callback(GtkAction *action,TerminalWindow *window)

{

TerminalWindowPrivate *priv =window->priv;

GtkWidget *dialog, *message_area, *hbox,*label, *entry;

if (priv->active_screen == NULL)

        return;

dialog = gtk_message_dialog_new (GTK_WINDOW(window),

                 GTK_DIALOG_MODAL |GTK_DIALOG_DESTROY_WITH_PARENT,

                 GTK_MESSAGE_OTHER,

                 GTK_BUTTONS_OK_CANCEL,

                 "%s","");

gtk_window_set_title (GTK_WINDOW (dialog),_(“Program Name”));

gtk_window_set_resizable (GTK_WINDOW(dialog), FALSE);

gtk_window_set_role (GTK_WINDOW (dialog),“Program Name”);

gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);

g_signal_connect (dialog,“response”,

                 G_CALLBACK(terminal_get_program_name_dialog_response_cb),

                 priv->active_screen);

g_signal_connect (dialog,“delete-event”,

                 G_CALLBACK(terminal_util_dialog_response_on_delete), NULL);

message_area =gtk_message_dialog_get_message_area

                 (GTK_MESSAGE_DIALOG(dialog));

gtk_container_foreach (

                 GTK_CONTAINER(message_area),

                 (GtkCallback)gtk_widget_hide,

                 NULL);

hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);

gtk_box_pack_start (GTK_BOX (message_area),hbox, FALSE, FALSE, 0);

label = gtk_label_new_with_mnemonic(_(“Name:”));

gtk_label_set_xalign (GTK_LABEL (label),0.0);

gtk_label_set_yalign (GTK_LABEL (label),0.5);

gtk_box_pack_start (GTK_BOX (hbox), label,FALSE, FALSE, 0);

entry = gtk_entry_new ();

gtk_entry_set_width_chars (GTK_ENTRY (entry),32);

gtk_entry_set_activates_default (GTK_ENTRY(entry), TRUE);

gtk_label_set_mnemonic_widget (GTK_LABEL(label), entry);

gtk_box_pack_start (GTK_BOX (hbox), entry,TRUE, TRUE, 0);

gtk_widget_show_all (hbox);

gtk_widget_grab_focus (entry);

g_object_set_data (G_OBJECT (dialog),"name-entry", entry);

gtk_window_present (GTK_WINDOW (dialog));

}

staticvoid

debug_process_callback(GtkAction *action,TerminalWindow *window)

{

TerminalWindowPrivate *priv =window->priv;

GtkWidget *dialog, *message_area, *hbox,*label, *entry;

if (priv->active_screen == NULL)

        return;

dialog = gtk_message_dialog_new (GTK_WINDOW(window),

                 GTK_DIALOG_MODAL |GTK_DIALOG_DESTROY_WITH_PARENT,

                 GTK_MESSAGE_OTHER,

                 GTK_BUTTONS_OK_CANCEL,

                 "%s","");

gtk_window_set_title (GTK_WINDOW (dialog),_(“Process Id”));

gtk_window_set_resizable (GTK_WINDOW(dialog), FALSE);

gtk_window_set_role (GTK_WINDOW (dialog),“mate-terminal-change-title”);

gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);

g_signal_connect (dialog,“response”,

                 G_CALLBACK(terminal_get_program_id_dialog_response_cb),

                 priv->active_screen);

g_signal_connect (dialog,“delete-event”,

                 G_CALLBACK(terminal_util_dialog_response_on_delete), NULL);

message_area =gtk_message_dialog_get_message_area

                 (GTK_MESSAGE_DIALOG(dialog));

gtk_container_foreach (

                 GTK_CONTAINER(message_area),

                 (GtkCallback)gtk_widget_hide,

                 NULL);

hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);

gtk_box_pack_start (GTK_BOX (message_area),hbox, FALSE, FALSE, 0);

label = gtk_label_new_with_mnemonic(_(“ID:”));

gtk_label_set_xalign (GTK_LABEL (label),0.0);

gtk_label_set_yalign (GTK_LABEL (label),0.5);

gtk_box_pack_start (GTK_BOX (hbox), label,FALSE, FALSE, 0);

entry = gtk_entry_new ();

gtk_entry_set_width_chars (GTK_ENTRY (entry),32);

gtk_entry_set_activates_default (GTK_ENTRY(entry), TRUE);

gtk_label_set_mnemonic_widget (GTK_LABEL(label), entry);

gtk_box_pack_start (GTK_BOX (hbox), entry,TRUE, TRUE, 0);

gtk_widget_show_all (hbox);

gtk_widget_grab_focus (entry);

g_object_set_data (G_OBJECT (dialog),"id-entry", entry);

gtk_window_present (GTK_WINDOW (dialog));

}

staticvoid

debug_start_callback(GtkAction *action,TerminalWindow *window)

{

GString *gstr;

gstr = g_string_new(NULL);

gstr = g_string_assign(gstr,“start\n”);

vte_terminal_feed_child(VTE_TERMINAL(window->priv->active_screen), gstr->str, gstr->len);

g_string_free(gstr, TRUE);

}

staticvoid

debug_continue_callback(GtkAction *action,TerminalWindow *window)

{

GString *gstr;

gstr = g_string_new(NULL);

gstr = g_string_assign(gstr,“c\n”);

vte_terminal_feed_child(VTE_TERMINAL(window->priv->active_screen), gstr->str, gstr->len);

g_string_free(gstr, TRUE);

}

staticvoid

debug_next_callback(GtkAction *action,TerminalWindow *window)

{

GString *gstr;

gstr = g_string_new(NULL);

gstr = g_string_assign(gstr,“n\n”);

vte_terminal_feed_child(VTE_TERMINAL(window->priv->active_screen), gstr->str, gstr->len);

g_string_free(gstr, TRUE);

}

staticvoid

debug_step_callback(GtkAction *action,TerminalWindow *window)

{

GString *gstr;

gstr = g_string_new(NULL);

gstr = g_string_assign(gstr,“s\n”);

vte_terminal_feed_child(VTE_TERMINAL(window->priv->active_screen), gstr->str, gstr->len);

g_string_free(gstr, TRUE);

}

  1.  本来这样就应该可以了,但试用发现F5、F10和F11这三个键与Mate终端的按键有冲突,不得不加入代码屏蔽掉原有的快捷键。代码如下,将它们添加到window_key_press_cb函数returnFALSE;语句之前。
    

elseif(event->keyval == GDK_KEY_F5)

{

        TerminalWindow *window =TERMINAL_WINDOW (widget);

        GString *gstr;

        gstr = g_string_new(NULL);

        gstr = g_string_assign(gstr,"c\n");


        vte_terminal_feed_child(VTE_TERMINAL(window->priv->active_screen), gstr->str, gstr->len);


        g_string_free(gstr, TRUE);


        return TRUE;

}

else if(event->keyval == GDK_KEY_F10)

{

        TerminalWindow *window =TERMINAL_WINDOW (widget);

        GString *gstr;

        gstr = g_string_new(NULL);

        gstr = g_string_assign(gstr,"n\n");


        vte_terminal_feed_child(VTE_TERMINAL(window->priv->active_screen), gstr->str, gstr->len);


        g_string_free(gstr, TRUE);


        return TRUE;

}

else if(event->keyval == GDK_KEY_F11)

{

        TerminalWindow *window =TERMINAL_WINDOW (widget);

        GString *gstr;

        gstr = g_string_new(NULL);

        gstr = g_string_assign(gstr,"s\n");


        vte_terminal_feed_child(VTE_TERMINAL(window->priv->active_screen), gstr->str, gstr->len);


        g_string_free(gstr, TRUE);


        return TRUE;

}

编译安装

本例是在ubuntukylin-18.04-enhanced-amd64系统下进行的,如果你没有安装过mate-common和yelp-tools执行下面命令安装它们。

sudoapt-get install mate-common

sudoapt-get install yelp-tools

     注意命令执行完后是否有错误提示,如果有重新执行它们即可解决。


     安装依赖库,执行:

sudo apt-get install libglib2.0-dev

sudo apt-get installlibvte-2.91-dev

sudo apt-get installlibdconf-dev

安装Mate终端,执行:

./autogen.sh

make

sudomake install

     安装完成。

添加好的菜单界面如下图:

gdb1.png

使用方法
调试程序:
按F2键弹出程序名称对话框, 在对话框里面填写要调试的程序名称,也可以包含路径,例如:
Test
./ Test
/home/用户名/ mate-terminal-1.21.1/src/ Test
然后点确定即可进入调试了。先按F4开始调试,按F10一行一行的执行程序,如果该行是函数并且系统里面有该函数的源码,按F11即可进入该函数,按F5可以全速运行程序。

调试进程
当一些程序运行起来后会关闭父进程,这时候就需要进程调试了,先在终端中输入ps –d查看要调试的进程ID,然后输入su进入root用户,(如果你是第一次使用su命令,先需要更改root用户密码,命令为sudo passwd root)按F3弹出进程ID对话框,在里面输入需要调试的进程ID,点确定进入调试,然后下断点程序就会停下来,这时我们就可以调试子程序了,方法与调试程序相同。

本次分享到此结束。好了,朋友们再见了。