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.

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

有问题留言是欢迎的。

Posted in Gtk | 1 Comment

My Gtk Tutorial 2

我写这些其实我真的自己都不看的,有用还是没用只有我唯一的那个目标读者来评价。

那么我们来无聊的介绍下Gtk的一些Widget。

1、GtkBox

和 Qt 不同的是,Gtk一般实现一个自己的Widget,都是从一个具体的Widget而不是general的GtkWidget 开始的,其中很多则又是选择了 GtkBox。

当然这里所说的实现一个具体的Widget不是指连draw事件都override的那种widget,而是一组widget的组合,例如文件对话框这种。那么具体实现的时候只要找好你要的那个顶层的Widget作为基类就行了。

曾经的 GtkHBox 和 GtkVBox 已经成为了历史,取而代之的是以一个横纵作为属性的 GtkBox。

一般而言,任何你想要的复杂的布局都可以用GtkBox来实现,一个技巧就是占位符,看起来Gtk里面并没有Qt的Spacer这种专门的占位符,一般用来占位的就是GtkLabel。

例如你希望实现一个上下顶头有Widget的东西,中间是空的,那么你可以new一个Vertical的GtkBox出来,然后使用  gtk_box_pack_start 往里面扔东西。中间用一个GtkLabel来撑开位置。

2、大小

写UI控件最头疼的事情是什么?是大小。说他们的定位难度堪比HTML也不为过。尤其是在你没注意到的时候你把你的窗口设置成为可拖拽,或者进行i18n后出现了一些惨烈的情况(单从语言来说,同一个词,一般汉语最短,英语次之,某些西语会长的要命)。

不过在Gtk3中,GtkWidget终于增加了expand,align,这些用来标明Widget本身的大小和位置属性。

这下终于要谢天谢地了?哦,其实没有,如果你的界面够复杂你可能还是想要掀桌(不过如此的话你是不是应该先考虑下你的设计?),不过也比Gtk2时代好的多就是了。

在处理大小时要考虑到你在进行i18n之后界面可能产生的变化……

处理大小时,GtkBox的默认是参考内部的Widget的属性来确定的,而Gtk2的兼容类GtkHBox,GtkVBox还默认并非如此。

总之这两个属性也不难理解,就是给你一个较大的空间。你的Widget是保持较小状态,还是填满整个区域?是如何在这个区域内进行对齐的?

3、来实现个Widget吧

如果你了解GObject的继承,那么这一步对你来说基本是没有难度的。

如果你不了解GObject的继承,还是去看别的文章吧……

http://garfileo.is-programmer.com/categories/6934/posts

C语言模拟继承是采用了一个非常简单的方式,就是struct的嵌套,在所有模拟继承关系的代码中都采用了这样的方式,这样做的好处就是你可以强制转换子类的指针为基类的指针。

struct Derived {
     Parent parent;
};

这样你就可以简单的去访问parent的值了。至于如何实现private,这里也简单说下。

struct Derived {
     Parent parent;
     Private* priv;
};

然后采用前向声明声明Private,Private的定义则写在c文件里面,而不是h里面,这样就可以保护Private内部是不可见的。当然如果你的类压根就不会给别人用,你也没必要非要用Private。

实现自己的Widget基本上来说,就是定义一个你要的Class的子类的过程,过程非常简单,你大可找个GObject的Skelton的生成器来帮你生成主干代码。

然后在init部分老实填入你自己的内容,写一个自己的new函数(虽然里面无外乎就是g_object_new的wrapper)。

下次来讲个具体类的实现。

Posted in Gtk | 13 Comments

My Gtk Tutorial 1

大概我这样的人还是超少见的,或者你可以称之为傲娇。

于是这个是我自己写Gtk程序的心得。我个人的主力发行版是一个几乎无Gtk的发行版,平时唯一用于测试gtk的程序其实是gtk-demo。不过即使如此我也照样开发着Gtk程序,不过由于发行版没有Glade,虽然用下也不会少块肉,不过界面大部分还是靠手写。反正就是省点事情。

本文基于 Gtk3 和 up to date 的 Glib。

另外我对于所有动态语言抱有一种不信任的态度,另外就是写C比较熟悉,所以还是写C。

那么开始第一个程序吧。

在最新的GLib中,GLib终于也诞生了一个称为Application的概念,对于Gtk2时代的人来说这大概是个没听过的概念。用了有什么好处呢?

1、支持单实例
2、支持Application Menu

说道Application Menu,这究竟又是个什么东西呢?可以理解为“属于这个程序的”菜单,例如Firefox,Opera的大按钮等等。

当然不幸的是,我最近唯一写的Gtk程序是不需要Menu的,而且反正这个功能在非GNOME3环境下惨不忍睹(显示为只有一项的菜单栏,要多难看有多难看),所以这里带过不提。

那么第一个GtkApplication就从这里开始:

https://github.com/fcitx/fcitx-configtool/blob/b68086d4b6773845065e44956875d90bca195eba/gtk3/main.c

(该死的WP贴代码不方便)

如果你用过 Qt 的话,大概就看出了

QApplication app(argc, argv);
app.exec();

的影子,总之就是差不多的东西。

这里还实现了一个函数,activate,这个函数会在执行程序的时候被调用,而且是交给主进程的程序,于是里面的内容很简单,如果有窗口,那就显示出来,如果没有,那就创建一个。

关于 GObject 的 Signal,在下不才其实并不十分了解,你可以参考:

http://nanjingabcdefg.is-programmer.com/posts/24116.html

activate 本身其实也是一个 signal,具体你要实现activate被调用的效果其实有很多方式,在这个小地方怎么实现其实都并无所谓,你可以自己g_signal_connect 一个上去,或者采用别的方式。

但总之单实例就是这么简单就可以用上了。

里面的window部分是我自己实现的window,你如果想要随便测试玩玩的话,可以用 gtk_window_new 随便搞一个简单的出来。这里和Qt的一个差别是,top level的需要是GtkWindow,而Qt里面Toplevel的只要是Widget就可以了。

那么另一个可能的需求就是,你想要处理参数,这里让我当年好是头疼了一会。

那么再来看代码吧。

https://github.com/fcitx/fcitx-configtool/blob/1837cdf9bd0e03e05569c899e09ac9c4e024eb6a/gtk3/main.c

这里我处理参数处理的很简单,就是打开了一个fcitx对应addon的配置窗口。

这段代码存在了许多非常magic的地方,首先是创建Gtk程序的FLAGS变了,变成了,

G_APPLICATION_HANDLES_COMMAND_LINE

首先说明你需要command-line的支持。

其次,由于程序变成了单实例,于是就出现了local-command-line和command-line两个signal,其一,是在当前进程处理的,第二个则是在单实例的程序那边处理的。

这里我们并不需要local处理,于是跳过。然后这里就是magic的地方,当这个flag存在时,activate是不会被自动调用的,于是可以看到我在 fcitx_config_app_handle_command_line 手动调用了activate,然后进行了打开addon窗口的处理,第一次写这个的时候我迷惑了好半天……不如说是默认处理command line的行为就是activate,如果使用了这个flag的话这个行为将被discard而需要自己操作。

至于具体的参数处理,虽然glib也给了一些函数进行处理,不过我还是不善于此道,就直接用了第一个参数。

P. S.

至于这些和浆糊一样的内容究竟是有用还是没用呢?谁知道啊。

有没有2呢,谁知道啊。

Posted in Gtk | 17 Comments

Fcitx 4.2.4

fcitx 4.2.4
1. fix some xim problem
2. add fcitx-gclient for glib and gir binding, can be used to control fcitx or implement fcitx client.
3. merge fcitx-keyboard into fcitx
4. bind specific keyboard layout with inputmethod (you need up to date fcitx-configtool,gtk3 ver or kcm-fcitx to configure this feature)
5. adjust some default hotkey setting.

NOTICE, if you’re using some custom xmodmap script, and if you don’t want to be affected, please disable “override XKB system setting”. Only xkb option is supported for now.

1、修复一些xim的问题。
2、增加fcitx-gclient,提供了glib和gir的绑定,可以用于控制fcitx或实现fcitx的client。
3、fcitx-keyboard 合并进 fcitx
4、将特定键盘布局和输入法绑定(需要最新的fcitx-configtool,gtk3版和或者kcm-fcitx来设置这个功能)
5、修改一些默认设置

注意,如果你使用自定义的xmodmap脚本,并且不希望受到影响,请禁用“覆盖系统XKB设置”,目前fcitx-xkb只支持xkb option里面的设置不受影响。

fcitx-configtool 0.4.4
1. fix a potential crash with newer gtk3
2. rework gtk3 version UI,  able to configure input method from input method page

1、修复一个潜在的崩溃问题
2、重新修改gtk3版的界面,支持从输入法页配置输入法

kcm-fcitx 0.3.4
configure input method from input method page

支持从输入法页配置输入法。

fcitx-table-extra 0.3.1
1. adjust some quick-classic hotkey
2. fix some error in scj6
3. add wubi-large for large charset

1、调整速成古典版的快捷键
2、修复仓颉第六代的一些错误
3、增加五笔大字集的码表

fcitx-table-other 0.2.0
add more table from scim-table

从scim-table移植更多码表

fcitx-sunpinyin 0.3.7 + fcitx-cloudpinyin 0.2.2
need sunpinyin git master to save cloudpinyin result to sunpinyin userdict.

需要sunpinyin的git master,支持将cloudpinyin的输入法保存到sunpinyin用户词典中。

Posted in fcitx development | Tagged | 12 Comments

这里有一个好消息和一个坏消息

好消息就是新版的ATI驱动终于可以用kwin的direct rendering了

坏消息是我正在用着一个本子,双显卡,两个显卡都是ATI的,不过有一半……是不被这个驱动支持的显卡了。

我好想要intel的本子……

Posted in Linux | 7 Comments