Chinaunix首页 | 论坛 | 博客
  • 博客访问: 371667
  • 博文数量: 43
  • 博客积分: 1493
  • 博客等级: 上尉
  • 技术积分: 660
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-01 10:57
文章分类

全部博文(43)

文章存档

2015年(1)

2013年(1)

2011年(6)

2010年(13)

2009年(13)

2008年(9)

分类: LINUX

2010-05-09 11:25:59

                             在glib循环中动态加入dbus的支持

需求:

              有时候需要在gtk_main执行以后,加入一些回调函数,希望能在主循环运行过程中被执行,常见的例子是一些插件的运行;

实现原理:

              GLIB的执行原理本质上是类似于select的,只不过,select的单位不是fd而是一个称为GSource的结构,可以简单的理解为,它是对一个fd的封装,里面还包含了一些回调函数及其它,这些回调函数分为,glib本身的循环所需要的,也包括我们自己指定于这个fd对应的回调函数;glib循环本身所需要的回调函数至少包括preparecheckdispatch,它先调用prepare,如果你需要做什么准备工作就在这里面做,如果不需要直接返回false,然后是check,这里比较重要,如果你需要你的dispatch函数得到处理,那么需要返回true,而dispatch函数在check返回true以后就会被执行,在那里你可以调用你先前设置好回调函数;

 

实现步骤:

1,  创建一个GSourceFuncs,如下

GSourceFuncs test_source_funcs =

{

test_source_prepare,

test_source_check,

test_source_dispatch,

NULL

}

                     其中函数内容为:

                     static gboolean  test_source_prepare (GSource *source,

                             gint *timeout)

{

                     return FALSE;

}

static gboolean test_source_check (GSource *source)

{

if (!test_poll_fd.revents & G_IO_IN)

{

        return FALSE;

}

/*something else to check*/

return TRUE;

}

 

static gboolean test_source_dispatch (GSource *source,

            GSourceFunc callback,

            gpointer user_data)

{

if (callback)

{

        return callback(user_data);

}

       return TRUE;

}

       2,    根据上面的结构创建一个GSource

              GSource *source = g_source_new (&test_source_funcs, sizeof(GSource));

       3,    创建文明需要的事件观察GPollFD

              这里需要先open一些fd,或者通过dbus_connection_get_unix_fd(dbus_connection, &fd)取得fd,然后通过:

              test_poll_fd.fd = fd;

              test_poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;

              构造GPollFD

       4 加入到glib主循环

              g_source_add_poll (source, &test_poll_fd);

              g_source_set_callback(source, test_read_callback, NULL, NULL);

              g_source_attach(source, NULL);

              下面是释放这个source:

              g_source_unref (source);

              这个test_read_callback就是我们最关心的回调函数,比如对于dbusfd检测,我们就可以在这个回调函数里面执行dispatch,比如:

              do {
                                  dbus_connection_read_write_dispatch(dbus_connection, 0);
                     } while (dbus_connection_get_dispatch_status(dbus_connection) == DBUS_DISPATCH_DATA_REMAINS);

具体细节,请参阅“沒有glibdbus使用”;

完整的代码如下:

              cat buttons.c

 

#include

#include

#define WYLHISTORY_TEST

/* Create a new hbox with an image and a label packed into it

 * and return the box. */

 

static GtkWidget *xpm_label_box( gchar     *xpm_filename,

                                 gchar     *label_text )

{

    GtkWidget *box;

    GtkWidget *label;

    GtkWidget *image;

 

    /* Create box for image and label */

    box = gtk_hbox_new (FALSE, 0);

    gtk_container_set_border_width (GTK_CONTAINER (box), 2);

 

    /* Now on to the image stuff */

    image = gtk_image_new_from_file (xpm_filename);

 

    /* Create a label for the button */

    label = gtk_label_new (label_text);

 

    /* Pack the image and label into the box */

    gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 3);

    gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 3);

 

    gtk_widget_show (image);

    gtk_widget_show (label);

 

    return box;

}

#ifdef WYLHISTORY_TEST

static GPollFD test_poll_fd;

static gboolean  test_source_prepare (GSource *source,

                gint *timeout)

{

        return FALSE;

}

static gboolean test_source_check (GSource *source)

{

        if (!test_poll_fd.revents & G_IO_IN)

        {

                return FALSE;

        }

        /*something else to check*/

        return TRUE;

}

 

static gboolean test_source_dispatch (GSource *source,

                GSourceFunc callback,

                gpointer user_data)

{

        if (callback)

        {

                return callback(user_data);

        }

        return TRUE;

}

GSourceFuncs test_source_funcs =

{

        test_source_prepare,

        test_source_check,

        test_source_dispatch,

        NULL

};

 

#include

#include

#include

#include

 

 

#define TEST_SERVICE            "com.woojoy.test_dbus"

#define TEST_PATH               "/com/woojoy/test_dbus"

#define MATCH_RULE              "type='signal'"

 

DBusConnection *dbus_connection = NULL;

/*below is the signal filter to receive the others signal,ofcourse you should change the MATCH_RULE,so filter the signals you donot care*/

static DBusHandlerResult message_filter(DBusConnection *connection, DBusMessage *message, void *data)

{

        const char *interface = dbus_message_get_interface(message);

        printf("in test_dbus the interface is %s \n",interface);

        const char *member= dbus_message_get_member(message);

        printf("in test_dbus the member is %s \n",member);

 

        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

}

 

/*below is the message handler,here you should accept the others remote method invoke I just printf some info*/

DBusHandlerResult message_handler(DBusConnection *connection,

                DBusMessage *message,

                void *user_data)

{

        printf("this is test_dbus message_handler\n");

        return (DBUS_HANDLER_RESULT_HANDLED);

}

/*here is to register to dbus server,so that it can send the info to us*/

static void

connect_hook(DBusConnection *connection, void *data)

{

        DBusError error;

        DBusObjectPathVTable vtable = { .message_function = message_handler, };

        dbus_error_init(&error);

        if (!dbus_bus_request_name(connection, TEST_SERVICE, 0, &error)) {

                printf("dbus_bus_request_name error\n");

                return;

        }

        dbus_bus_add_match(connection, MATCH_RULE, &error);

        if (dbus_error_is_set(&error)) {

                printf("after dbus_bus_add_match error\n");

                return;

        }

 

        if (!dbus_connection_register_object_path(connection, TEST_PATH, &vtable, NULL)) {

                printf("dbus_connection_register_object_path error\n");

                return;

        }

 

        dbus_error_free(&error);

        return;

}

int get_dbus_fd()

{

        printf("enter get_dbus_fd\n");

        DBusError derror;

        dbus_error_init(&derror);

        dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &derror);

        if (dbus_connection == NULL) {

                fprintf(stderr,"System DBus connection failed: %s", derror.message);

                dbus_error_free(&derror);

                return -1;

        }

 

        /*above is to get the dbusconnection,which actually is a socket fd*/

        connect_hook(dbus_connection,NULL);

        /*above is to register to dbus server*/

        if (!dbus_connection_add_filter(dbus_connection, message_filter, NULL, NULL)) {

                printf("after dbus_connection_add_filter error\n");

                return -1;

        }

        /*here is add some filter which will get the message before message_handler*/

        int fd=-1;

        dbus_connection_get_unix_fd(dbus_connection, &fd);

        printf("the fd %d\n",fd);

        return fd;

 

}

static gboolean test_read_callback(gpointer user_data)

{

        do {

                dbus_connection_read_write_dispatch(dbus_connection, 0);

        } while (dbus_connection_get_dispatch_status(dbus_connection) == DBUS_DISPATCH_DATA_REMAINS);

        return TRUE;

}

void setup_dbus()

{

        printf("enter setup_dbus\n");

        int fd=get_dbus_fd();

        printf("after get_dbus_fd fd %d\n",fd);

        if(fd < 0){

                printf("get_dbus_fd error\n");

                return;

        }

        GSource *source = g_source_new (&test_source_funcs, sizeof(GSource));

        test_poll_fd.fd = fd;

        test_poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;

        g_source_add_poll (source, &test_poll_fd);

        g_source_set_callback(source, test_read_callback, NULL, NULL);

        g_source_attach(source, NULL);

        g_source_unref (source);

        printf("exit setup_dbus\n");

 

}

#endif

 

/* Our usual callback function */

static void callback( GtkWidget *widget,

                      gpointer   data )

{

    g_print ("Hello again - %s was pressed\n", (char *) data);

#ifdef WYLHISTORY_TEST

    static int initialed=FALSE;

    if(!initialed){

            initialed = TRUE;

            setup_dbus();

    }

#endif

}

 

int main( int   argc,

          char *argv[] )

{

    /* GtkWidget is the storage type for widgets */

    GtkWidget *window;

    GtkWidget *button;

    GtkWidget *box;

 

    gtk_init (&argc, &argv);

 

    /* Create a new window */

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

 

    gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");

 

    /* It's a good idea to do this for all windows. */

    g_signal_connect (G_OBJECT (window), "destroy",

                      G_CALLBACK (gtk_main_quit), NULL);

 

    g_signal_connect (G_OBJECT (window), "delete_event",

                      G_CALLBACK (gtk_main_quit), NULL);

 

    /* Sets the border width of the window. */

    gtk_container_set_border_width (GTK_CONTAINER (window), 10);

 

    /* Create a new button */

    button = gtk_button_new ();

 

    /* Connect the "clicked" signal of the button to our callback */

    g_signal_connect (G_OBJECT (button), "clicked",

                      G_CALLBACK (callback), (gpointer) "cool button");

 

    /* This calls our box creating function */

    box = xpm_label_box ("info.xpm", "cool button");

 

    /* Pack and show all our widgets */

    gtk_widget_show (box);

 

    gtk_container_add (GTK_CONTAINER (button), box);

 

    gtk_widget_show (button);

 

    gtk_container_add (GTK_CONTAINER (window), button);

 

    gtk_widget_show (window);

 

    /* Rest in gtk_main and wait for the fun to begin! */

    gtk_main ();

    return 0;

}

Cat Makefile

              CC = gcc

 

CFLAGS = -Wall -Wunused                 \

        -DG_DISABLE_DEPRECATED          \

        -DGDK_DISABLE_DEPRECATED        \

        -DGDK_PIXBUF_DISABLE_DEPRECATED \

        -DGTK_DISABLE_DEPRECATED

 

buttons: buttons.c

        $(CC) buttons.c -o buttons $(CFLAGS) `pkg-config gtk+-2.0 dbus-1 --cflags --libs`

 

clean:

        rm -f *.o buttons

      测试:

                运行   ./buttons

                这时候不点button,那么通过dbus-send发送任何system的消息,是不会有什么打印信息的;

                如果运行以后,点了UI上的button,那么再通过dbus-send发送system的信号的时候,就会看到相关的打印信息了;

           如下:

dbus-send --system --type=signal /org/openmoko/PhoneKit/Network org.openmoko.PhoneKit.Network.signal_changed int32:12

in test_dbus the interface is org.freedesktop.DBus

in test_dbus the member is NameOwnerChanged

in test_dbus the interface is org.openmoko.PhoneKit.Network

in test_dbus the member is signal_changed       

      

That is OK!

备注:

           作者:wylhistory

           联系方式:wylhistory@gmail.com

 

阅读(2450) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-12-16 19:30:35

监听NameOwnerChanged信号, 应该可以判定;

chinaunix网友2010-12-15 11:26:59

很好啊,有个问题请教下你。 当client端异常退出,server端用dbus什么消息能够检测到呢? 我的邮箱是f21@live.cn,望你不吝指教.