我将新的开关信号引入现有测试GUI。
UI具有3个可能的事件来源,两个事件框和一个开关。当单击事件框时,它们会正常行为,但是,如果切换开关,则单击事件框中的一个会导致SEGV(行为1)。
此外,如果从新建运行,请先切换开关,然后单击事件框,还会导致SEGV(行为2)。两者的segv始终发生在同一位置(如果以事件框为例之一)如下:
if (((interface *) toggle)->eth0->ip_enabled) {
我可以在代码方面提出的最简单的表现方式如下(abimecime):
:/*
* STRIPPED DOWN VERSION
*/
#include <arpa/inet.h>
#include <gtk/gtk.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define IPV4_ENABLED 1
#define IPV4_DISABLED 0
#define SELECTED 1
typedef struct {
int ip_enabled;
} net;
typedef struct {
net *eth0;
net *wlan0;
int type;
} interface;
typedef enum {
IT_ETH0,
IT_WLAN0,
IT_UNASSIGNED = 999,
} interface_type;
typedef struct {
int active;
interface *port;
int debug;
} test_parameters;
void wired (net *eth0);
void wifi (net *wlan0);
int main (int argc, char *argv[]) {
GtkBuilder *builder;
GtkWidget *window;
GError *gtk_error = NULL;
net *eth0 = g_slice_new (net);
net *wlan0 = g_slice_new (net);
interface *toggle = g_slice_new (interface);
test_parameters *test = g_slice_new (test_parameters);
test->port->type == IT_UNASSIGNED;
/*Add interfaces to struct "interface" */
toggle->eth0 = eth0;
toggle->wlan0 = wlan0;
toggle->eth0->ip_enabled = 0;
toggle->wlan0->ip_enabled = 0;
if (NULL == toggle->eth0)
fprintf (stdout, "%sn", "eth0 is null ");
if (NULL == toggle->wlan0)
fprintf (stdout, "%sn", "wlan0 is null ");
gtk_init (&argc, &argv);
builder = gtk_builder_new ();
if (!gtk_builder_add_from_file (builder, "glade/window_main.glade", NULL)) {
fprintf (stdout, "%s%sn", "Error loading file with the reason: ", gtk_error->message);
g_free (gtk_error);
exit (EXIT_FAILURE);
}
window = GTK_WIDGET (gtk_builder_get_object (builder, "window_main"));
gtk_builder_connect_signals (builder, toggle);
gtk_builder_connect_signals (builder, test);
g_object_unref (builder);
wired (eth0);
wifi (wlan0);
gtk_widget_show (window);
gtk_main ();
g_slice_free (net, eth0);
g_slice_free (net, wlan0);
g_slice_free (interface, toggle);
return 0;
}
void wifi (net *wlan0) {
if (1) {
wlan0->ip_enabled = IPV4_ENABLED;
}
}
void wired (net *eth0) {
if (1) {
eth0->ip_enabled = IPV4_ENABLED;
}
}
G_MODULE_EXPORT gboolean on_eventbox_image_wired_button_press_event (GtkWidget *widget,
GdkEvent *event, gpointer toggle) {
if (((interface *) toggle)->eth0 == NULL) {
printf("%sn", "WIRED: eth0 IS NULL - REMOVE ME");
}
if (((interface *) toggle) == NULL) {
printf("%sn", "WIRED: toggle IS NULL - REMOVE ME");
}
if (((interface *) toggle)->eth0->ip_enabled) {
printf("%sn", "WIRED: eth0 is ip enabled - REMOVE ME");
((interface *) toggle)->type = IT_ETH0;
if (((interface *) toggle)->wlan0->ip_enabled) {
printf("%sn", "WIRED: wlan0 is ip enabled, adjust - REMOVE ME");
}
}
return 0;
}
G_MODULE_EXPORT gboolean on_eventbox_image_wifi_button_press_event (GtkWidget *widget,
GdkEvent *event, gpointer toggle) {
/* Check to see if we have IP address so we can change the colour otherwise leave it red */
if (((interface *) toggle)->wlan0->ip_enabled) {
printf("%sn", "WLAN has IP enabled");
((interface *) toggle)->type = IT_ETH0;
if (((interface *) toggle)->eth0->ip_enabled) {
printf("%sn", "WLAN: eth0 is ip enabled, adjust - REMOVE ME");
}
}
return 0;
}
G_MODULE_EXPORT gboolean on_switch_test_on_state_set (GtkSwitch *widget,
gboolean state, gpointer test) {
(((test_parameters *) test)->active) = state;
fprintf (stdout, "%s%in", "Signal fired and the state is ", state);
return 0;
}
void on_window_main_destroy () {
gtk_main_quit ();
}
和GDB BT是:
(gdb) run
Starting program: /home/j2/simplified_example/simplified_example
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffed0c4700 (LWP 6979)]
[New Thread 0x7fffec8c3700 (LWP 6980)]
WIRED: eth0 is ip enabled - REMOVE ME
WIRED: wlan0 is ip enabled, adjust - REMOVE ME
Signal fired and the state is 1
Thread 1 "simplified_exam" received signal SIGSEGV, Segmentation fault.
0x0000000000401110 in on_eventbox_image_wired_button_press_event (widget=0x6a7260 [GtkEventBox], event=0x994cb0, toggle=0x624800)
at src/simplified_example1.c:134
134 if (((interface *) toggle)->eth0->ip_enabled) {
(gdb) bt
#0 0x0000000000401110 in on_eventbox_image_wired_button_press_event (widget=0x6a7260 [GtkEventBox], event=0x994cb0, toggle=0x624800)
at src/simplified_example1.c:134
#5 0x00007ffff728008f in <emit signal ??? on instance 0x6a7260 [GtkEventBox]> (instance=instance@entry=0x6a7260, signal_id=<optimised out>, detail=detail@entry=0) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./gobject/gsignal.c:3441
#1 0x00007ffff76bafac in _gtk_marshal_BOOLEAN__BOXED (closure=0x6ffe50, return_value=0x7fffffffd940, n_param_values=<optimised out>, param_values=0x7fffffffd9a0, invocation_hint=<optimised out>, marshal_data=<optimised out>) at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkmarshalers.c:86
#2 0x00007ffff7264fa5 in g_closure_invoke (closure=0x6ffe50, return_value=return_value@entry=0x7fffffffd940, n_param_values=2, param_values=param_values@entry=0x7fffffffd9a0, invocation_hint=invocation_hint@entry=0x7fffffffd920) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./gobject/gclosure.c:804
#3 0x00007ffff7276fc1 in signal_emit_unlocked_R (node=node@entry=0x653b40, detail=detail@entry=0, instance=instance@entry=0x6a7260, emission_return=emission_return@entry=0x7fffffffdab0, instance_and_params=instance_and_params@entry=0x7fffffffd9a0)
at /build/glib2.0-prJhLS/glib2.0-2.48.2/./gobject/gsignal.c:3629
#4 0x00007ffff727f7f9 in g_signal_emit_valist (instance=<optimised out>, signal_id=<optimised out>, detail=<optimised out>, var_args=var_args@entry=0x7fffffffdb60) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./gobject/gsignal.c:3395
#6 0x00007ffff77f8c3c in gtk_widget_event_internal (widget=0x6a7260 [GtkEventBox], event=0x994cb0)
at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkwidget.c:7692
#7 0x00007ffff76b83be in propagate_event (topmost=<optimised out>, event=<optimised out>, widget=0x6a7260 [GtkEventBox])
at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkmain.c:2527
#8 0x00007ffff76b83be in propagate_event (widget=<optimised out>, event=0x994cb0, captured=<optimised out>, topmost=0x0)
at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkmain.c:2629
#9 0x00007ffff76ba1bc in gtk_main_do_event (event=0x994cb0) at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkmain.c:1850
#10 0x00007ffff66dcd92 in gdk_event_source_dispatch (source=<optimised out>, callback=<optimised out>, user_data=<optimised out>)
at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gdk/x11/gdkeventsource.c:369
#11 0x00007ffff6f8e197 in g_main_context_dispatch (context=0x640980) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./glib/gmain.c:3154
---Type <return> to continue, or q <return> to quit---
#12 0x00007ffff6f8e197 in g_main_context_dispatch (context=context@entry=0x640980) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./glib/gmain.c:3769
#13 0x00007ffff6f8e3f0 in g_main_context_iterate (context=0x640980, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimised out>)
at /build/glib2.0-prJhLS/glib2.0-2.48.2/./glib/gmain.c:3840
#14 0x00007ffff6f8e712 in g_main_loop_run (loop=0x8d14b0) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./glib/gmain.c:4034
#15 0x00007ffff76b9395 in gtk_main () at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkmain.c:1241
#16 0x0000000000401065 in main (argc=1, argv=0x7fffffffdfd8) at src/simplified_example1.c:97
(gdb)
(gdb)
(gdb)
请提前感谢您的任何帮助。
编辑:根据要求添加GLADE文件 - 简化用于测试目的:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkWindow" id="window_main">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Main Window</property>
<property name="default_width">640</property>
<property name="default_height">480</property>
<property name="decorated">False</property>
<signal name="destroy" handler="on_window_main_destroy" swapped="no"/>
<child>
<object class="GtkFixed" id="fixed_background">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="image_background">
<property name="name">4</property>
<property name="width_request">640</property>
<property name="height_request">480</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-missing-image</property>
</object>
</child>
<child>
<object class="GtkEventBox" id="eventbox_image_wired">
<property name="width_request">100</property>
<property name="height_request">80</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="visible_window">False</property>
<property name="above_child">True</property>
<signal name="button-press-event" handler="on_eventbox_image_wired_button_press_event" swapped="no"/>
<child>
<object class="GtkImage" id="image_wired">
<property name="width_request">100</property>
<property name="height_request">80</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="icon_name">applications-graphics</property>
</object>
</child>
</object>
<packing>
<property name="x">35</property>
<property name="y">20</property>
</packing>
</child>
<child>
<object class="GtkEventBox" id="eventbox_image_wifi">
<property name="width_request">100</property>
<property name="height_request">80</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="visible_window">False</property>
<property name="above_child">True</property>
<signal name="button-press-event" handler="on_eventbox_image_wifi_button_press_event" swapped="no"/>
<child>
<object class="GtkImage" id="image_wifi">
<property name="width_request">101</property>
<property name="height_request">71</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="icon_name">accessories-text-editor</property>
</object>
</child>
</object>
<packing>
<property name="x">200</property>
<property name="y">20</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="grid_test_parameter">
<property name="width_request">582</property>
<property name="height_request">116</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">10</property>
<property name="column_spacing">4</property>
<child>
<object class="GtkSwitch" id="switch_test_on">
<property name="use_action_appearance">True</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<signal name="state-set" handler="on_switch_test_on_state_set" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
<packing>
<property name="x">15</property>
<property name="y">245</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
问题位于这两行中:
gtk_builder_connect_signals (builder, toggle);
gtk_builder_connect_signals (builder, test);
当您使用此函数时,user_data传递以连接信号将应用于所有信号处理程序。
如果您选择此路径,则您的用户数据应包含所有相关数据,并且处理程序必须相应地解决它。
问题是您的信号处理程序期望不同的东西,但您会给他们相同的数据。
来自gtk_builder_connect_signals
:
user_data
用户数据都用所有信号传递
那你能做什么?
如果要保留相同的方法,那么,例如,让我们创建一个包含所有相关数据的结构,然后将其传递给回调/信号处理程序:
typedef struct {
interface *toggle;
test_parameters *test;
} app_user_data;
然后初始化内容:
app_user_data *user_data = g_slice_new (app_user_data);
user_data->toggle = toggle;
user_data->test = test;
删除冗余gtk_builder_connect_signals
,然后用我们的新结构替换一个:
gtk_builder_connect_signals (builder, user_data);
现在,所有回调都可以使用他们需要的数据:
G_MODULE_EXPORT gboolean on_eventbox_image_wired_button_press_event (GtkWidget *widget, GdkEvent *event, gpointer toggle) {
app_user_data *user_data = (app_user_data *) toggle;
if (((interface *) user_data->toggle)->eth0 == NULL) {
printf("%sn", "WIRED: eth0 IS NULL - REMOVE ME");
}
...
G_MODULE_EXPORT gboolean on_eventbox_image_wifi_button_press_event (GtkWidget *widget, GdkEvent *event, gpointer toggle) {
app_user_data *user_data = (app_user_data *) toggle;
/* Check to see if we have IP address so we can change the colour otherwise leave it red */
if (((interface *) user_data->toggle)->wlan0->ip_enabled) {
...
G_MODULE_EXPORT gboolean on_switch_test_on_state_set (GtkSwitch *widget, gboolean state, gpointer test) {
app_user_data *user_data = (app_user_data *) test;
(((test_parameters *) user_data->test)->active) = state;
...
带有建议更改的代码应该是这样的:
/*
* * STRIPPED DOWN VERSION
* */
#include <arpa/inet.h>
#include <gtk/gtk.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define IPV4_ENABLED 1
#define IPV4_DISABLED 0
#define SELECTED 1
typedef struct {
int ip_enabled;
} net;
typedef struct {
net *eth0;
net *wlan0;
int type;
} interface;
typedef enum {
IT_ETH0,
IT_WLAN0,
IT_UNASSIGNED = 999,
} interface_type;
typedef struct {
int active;
interface *port;
int debug;
} test_parameters;
typedef struct {
interface *toggle;
test_parameters *test;
} app_user_data;
void wired (net *eth0);
void wifi (net *wlan0);
int main (int argc, char *argv[]) {
GtkBuilder *builder;
GtkWidget *window;
GError *gtk_error = NULL;
net *eth0 = g_slice_new (net);
net *wlan0 = g_slice_new (net);
interface *toggle = g_slice_new (interface);
test_parameters *test = g_slice_new (test_parameters);
test->port->type == IT_UNASSIGNED;
/*Add interfaces to struct "interface" */
toggle->eth0 = eth0;
toggle->wlan0 = wlan0;
toggle->eth0->ip_enabled = 0;
toggle->wlan0->ip_enabled = 0;
app_user_data *user_data = g_slice_new (app_user_data);
user_data->toggle = toggle;
user_data->test = test;
if (NULL == toggle->eth0)
fprintf (stdout, "%sn", "eth0 is null ");
if (NULL == toggle->wlan0)
fprintf (stdout, "%sn", "wlan0 is null ");
gtk_init (&argc, &argv);
builder = gtk_builder_new ();
if (!gtk_builder_add_from_file (builder, "glade/window_main.glade", NULL)) {
fprintf (stdout, "%s%sn", "Error loading file with the reason: ", gtk_error->message);
g_free (gtk_error);
exit (EXIT_FAILURE);
}
window = GTK_WIDGET (gtk_builder_get_object (builder, "window_main"));
gtk_builder_connect_signals (builder, user_data);
g_object_unref (builder);
wired (eth0);
wifi (wlan0);
gtk_widget_show (window);
gtk_main ();
g_slice_free (net, eth0);
g_slice_free (net, wlan0);
g_slice_free (interface, toggle);
return 0;
}
void wifi (net *wlan0) {
if (1) {
wlan0->ip_enabled = IPV4_ENABLED;
}
}
void wired (net *eth0) {
if (1) {
eth0->ip_enabled = IPV4_ENABLED;
}
}
G_MODULE_EXPORT gboolean on_eventbox_image_wired_button_press_event (GtkWidget *widget, GdkEvent *event, gpointer toggle) {
app_user_data *user_data = (app_user_data *) toggle;
if (((interface *) user_data->toggle)->eth0 == NULL) {
printf("%sn", "WIRED: eth0 IS NULL - REMOVE ME");
}
if (((interface *) user_data->toggle) == NULL) {
printf("%sn", "WIRED: toggle IS NULL - REMOVE ME");
}
if (((interface *) user_data->toggle)->eth0->ip_enabled) {
printf("%sn", "WIRED: eth0 is ip enabled - REMOVE ME");
((interface *) toggle)->type = IT_ETH0;
if (((interface *) user_data->toggle)->wlan0->ip_enabled) {
printf("%sn", "WIRED: wlan0 is ip enabled, adjust - REMOVE ME");
}
}
return 0;
}
G_MODULE_EXPORT gboolean on_eventbox_image_wifi_button_press_event (GtkWidget *widget, GdkEvent *event, gpointer toggle) {
app_user_data *user_data = (app_user_data *) toggle;
/* Check to see if we have IP address so we can change the colour otherwise leave it red */
if (((interface *) user_data->toggle)->wlan0->ip_enabled) {
printf("%sn", "WLAN has IP enabled");
((interface *) user_data->toggle)->type = IT_ETH0;
if (((interface *) user_data->toggle)->eth0->ip_enabled) {
printf("%sn", "WLAN: eth0 is ip enabled, adjust - REMOVE ME");
}
}
return 0;
}
G_MODULE_EXPORT gboolean on_switch_test_on_state_set (GtkSwitch *widget, gboolean state, gpointer test) {
app_user_data *user_data = (app_user_data *) test;
(((test_parameters *) user_data->test)->active) = state;
fprintf (stdout, "%s%in", "Signal fired and the state is ", state);
return 0;
}
void on_window_main_destroy () {
gtk_main_quit ();
}
它应该像以前那样编译而不是segfault!