GNOME Desktop
GNOME的桌面中绝大多数应用既是CORBA的Server,同时也有自己的GUI,即它们提供的服务(引出的方法)需要画出图形以供用户访问它们的服务。所以我把GNOME上的应用分成五大类:
对于一般的GNOME Desktop应用来说,好在问题没这么复杂。因为GNOME已经用C语言将大量的CORBA接口包裹了起来,你只需要简单象写GTK+程序一样方便地调用。
举例说明
GNOME Panel
GNOME Panel是方便用户的一个控制桌面环境的接口,panel的功能相当丰富,用户可以通过点击它上面的菜单或图标来启动一个应用,甚至可以在它上面嵌仍诵须一些应用(被称作applet)。我们下面就看一下一个applet是如何写的。
一般的非applet程序
#includeint main(int argc, char **argv) { /* ... we build the user interface ... */ gtk_init(&argc, &argv); /* #1 */ GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); /* #2 */ gtk_window_set_title(GTK_WINDOW(window), PACKAGE); /* controls is the name of the container all our widgets are in */ gtk_container_add(GTK_CONTAINER(window), controls); /* #3 */ gtk_widget_show(window); /* Everything's ready to begin our main loop */ gtk_main(); /* #4 */ return 0; }
将其改造为一个applet
#includeint main(int argc, char **argv) { applet_widget_init(PACKAGE, VERSION, argc, argv, NULL, 0, NULL); /* #1 */ GtkWidget* applet = applet_widget_new(PACKAGE); /* #2 */ applet_widget_add(APPLET_WIDGET(applet), controls); /* #3 */ gtk_widget_show(applet); applet_widget_gtk_main(); /* #4 */ return 0; }
通过下面这个函数为你的applet添加右键菜单:
void applet_widget_register_callback(AppletWidget *applet, char *name, char *menutext, AppletCallbackFunc func, gpointer data);
这样,编译后,在命令行象启动一个普通的GTK应用一样运行它。它会自动出现在你的Panel上,就象普通GTK应用会自动出现在你的GNOME桌面上一样简单。
如果你希望别的程序也可以访问你的applet,就要把它注册到GOAD中。办法是保存一个.gnorba文件,内容可以如下。这个道理我们在前面已经讲过了。
[my_applet] type=exe repo_id=IDL:GNOME/Applet:1.0 description=Example panel applet location_info=my_applet
applet的CORBA实现原理
为了实现GNOME Panel,定义了三个标准的IDL接口:: GNOME::Panel, GNOME::PanelSpot 和 GNOME::Applet。前两个是由panel实现的,第三个由applet实现。Panel接口初始化一个PanelSpot接口供Applet调用。
基本思想是:applet生成一个控件需要显示出来,而panel则提供给这个applet一个画这个控件的窗口。另外applet还要通过Panel的接口告诉它自己的右键菜单。
下面是这三个接口的示意IDL:
module GNOME { struct Color { unsigned short red, green, blue; }; typedef short AppletId; typedef short PanelId; interface Panel { enum OrientType { ORIENT_UP, ORIENT_DOWN, ORIENT_LEFT, ORIENT_RIGHT }; enum BackType { BACK_NONE, BACK_COLOR, BACK_PIXMAP }; union BackInfoType switch(BackType) { case BACK_COLOR: Color c; case BACK_PIXMAP: string pmap; }; enum SizeType { SIZE_TINY, SIZE_STANDARD, SIZE_LARGE, SIZE_HUGE }; PanelSpot add_applet(in Applet panel_applet, in string goad_id, out string cfgpath, out string globcfgpath, out unsigned long winid); oneway void quit (); readonly attribute boolean in_drag; }; interface PanelSpot { // gosh !! i removed many things from here !! oneway void add_callback (in string callback_name, in string stock_item, in string menuitem_text); oneway void remove_callback (in string callback_name); }; interface Applet { // gosh !! i removed many things from here !! oneway void do_callback (in string callback_name); }; };
applet设计的一个技巧是利用了GTK+的Plug和Socket控件。Socket是生成一个绘图窗口;GTK_WINDOW_XWINDOW(widget)将这个控件转换为一个winid;而Plug又将这个winid转回为一个GTK的控件。工作过程如下:
大家看到了生成一个applet的实际过程,其复杂性实在令人头疼。好在已经全被C包裹了。