My Gtk Tutorial 3

所谓的具体类的实现,其实这个Widget功能不得不说是Gtk里面缺少的功能,虽然其实Qt里面也没,不过我在写代码的时候可以没什么顾虑的用 KDE 提供的 UI 库,于是我又爽了。

这次的Widget就是一个捕获快捷键用的Widget,具体里面代码的实现我是当初从ccsm(compiz那个配置工具)里面的python代码翻译过来的,啊一想起那个青涩的年代……

相信这是个人民群众喜闻乐见的Widget。

原理很简单,本身是一个button,button按下时显示一个window,window负责捕捉按键,捕捉到的按键再存起来。

当然我的实现里面使用了一些Fcitx自己的parse和toString的函数,你当然建议使用GtkAccelerator的方式 来进行parse(如果你需要字符串的话)。

https://github.com/fcitx/fcitx-configtool/blob/master/gtk3/keygrab.h

https://github.com/fcitx/fcitx-configtool/blob/master/gtk3/keygrab.c

具体的实现就是上面的代码(于是我还看到当初有些蛋疼的注释……)

首先就是我继承了一个GtkButton,定义了一个Signal,触发按键在变化时的事件。

    gtk_widget_set_size_request(GTK_WIDGET(keygrabbutton), 150, -1);
    g_signal_connect(G_OBJECT(keygrabbutton), “clicked”, (GCallback) begin_key_grab, NULL);

按键创建时,绑了一个signal给clicked事件,用来显示一个popup。

在clicked里面的回调函数中。

    KeyGrabButton* b = KEYGRAB_BUTTON(self);
    b->popup = popup_new(GTK_WIDGET(self), _("Please press the new key combination"), FALSE);
    gtk_widget_add_events(GTK_WIDGET(b->popup), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
    gtk_widget_show_all(b->popup);
    gtk_window_present(GTK_WINDOW(b->popup));
    b->handler = g_signal_connect(G_OBJECT(b->popup), "key-press-event", (GCallback)on_key_press_event, b);
    GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(b->popup));
    GdkDisplay* display = gdk_window_get_display (window);
    GdkDeviceManager* device_manager = gdk_display_get_device_manager (display);
    GdkDevice* pointer = gdk_device_manager_get_client_pointer (device_manager);
    GdkDevice* keyboard = gdk_device_get_associated_device (pointer);

    while (gdk_device_grab(
        keyboard,
        window,
        GDK_OWNERSHIP_WINDOW, TRUE,
        GDK_KEY_PRESS | GDK_KEY_RELEASE,
        NULL,
        GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
        usleep(100);

进行了这样的操作,popup new中的实现其实很简单,就是弹出一个window,并且将其parent设置为顶层窗口,如果你的函数中需要使用dialog,或者设置为modal窗口的话,你会经常用到gtk_widget_get_toplevel,用于获得顶层的GtkWindow对象,参数就是任意一个已经在GtkWidget树中的Widget即可。

这里的grab事件的地方是非常tricky的,说实话也比gtk2的时候罗嗦了不少,不过大概的意思还是比较好懂,首先是要获得keyboard的GdkDevice指针,然后就是罗嗦个半天获得了,然后就是一个死循环,不断的尝试grab,事件呢则通过key-press-event传递给对应的window,里面 GDK_OWNERSHIP_WINDOW 就是指定了要grab 的事件是针对这个window的。后面的mask则是指定了要grab什么样的事件。这里就是key press和key release。

需要注意的就是,在最后还需要用  gdk_device_ungrab 来结束grab的影响。

P. S.

当然我写完也不会认为这样的文字有什么直接帮助,你觉得有什么帮助吗?我觉得没有,我写了这么久代码之后,我觉得只要给我文档,再没什么外力帮助下再写这些内容对我来说就像呼吸一样简单。一来我也不知道想要了解的人需要知道什么,因为编程本身就是一个自学成才的工作。如果你在大学学习学习过比如数据结构,算法设计等等课程,你可能也注意到了老师是从来不教给你具体编程的技巧的,如果妄图光是看着代码而不去实际尝试做点什么,你一定死得很惨。

有问题留言是欢迎的。

This entry was posted in Gtk. Bookmark the permalink.

One Response to My Gtk Tutorial 3

  1. yyc says:
    Google Chrome 19.0.1084.52 GNU/Linux x64

    看到了更加怨念的东西, 貌似gtkaccelerator是不兼容xkb-redirect的万恶之源啊~~~ (我又小众了)

    [Reply]

Leave a Reply

Your email address will not be published. Required fields are marked *

Note: Commenter is allowed to use '@User+blank' to automatically notify your reply to other commenter. e.g, if ABC is one of commenter of this post, then write '@ABC '(exclude ') will automatically send your comment to ABC. Using '@all ' to notify all previous commenters. Be sure that the value of User should exactly match with commenter's name (case sensitive).

This site uses Akismet to reduce spam. Learn how your comment data is processed.