在 Cairo 图形教程的这一部分中,我们将使用根窗口。 根窗口是我们通常具有图标快捷方式的桌面窗口。
可以使用根窗口进行操作。 从程序员的角度来看,它只是一种特殊的窗口。
透明窗
我们的第一个示例将创建一个透明窗口。 我们将看到窗口对象下方的内容。
#include <cairo.h>#include <gtk/gtk.h>static void do_drawing(cairo_t *);static void tran_setup(GtkWidget *win){GdkScreen *screen;GdkVisual *visual;gtk_widget_set_app_paintable(win, TRUE);screen = gdk_screen_get_default();visual = gdk_screen_get_rgba_visual(screen);if (visual != NULL && gdk_screen_is_composited(screen)) {gtk_widget_set_visual(win, visual);}}static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,gpointer user_data){do_drawing(cr);return FALSE;}static void do_drawing(cairo_t *cr){cairo_set_source_rgba(cr, 0.2, 0.2, 0.2, 0.4);cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);cairo_paint(cr);}int main (int argc, char *argv[]){GtkWidget *window;GtkWidget *darea;gtk_init(&argc, &argv);window = gtk_window_new(GTK_WINDOW_TOPLEVEL);tran_setup(window);darea = gtk_drawing_area_new();gtk_container_add(GTK_CONTAINER (window), darea);g_signal_connect(G_OBJECT(darea), "draw",G_CALLBACK(on_draw_event), NULL);g_signal_connect(window, "destroy",G_CALLBACK(gtk_main_quit), NULL);gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);gtk_window_set_default_size(GTK_WINDOW(window), 300, 250);gtk_window_set_title(GTK_WINDOW(window), "Transparent window");gtk_widget_show_all(window);gtk_main();return 0;}
为了创建透明窗口,我们获得了屏幕对象的视觉效果并将其设置为我们的窗口。 在on_draw()方法中,我们绘制屏幕的可视对象。 这产生了部分透明的幻觉。
gtk_widget_set_app_paintable(win, TRUE);
我们必须设置要绘制的应用。
screen = gdk_screen_get_default();
gdk_screen_get_default()方法返回屏幕对象。
visual = gdk_screen_get_rgba_visual(screen);
从屏幕窗口中,我们可以看到它。 视觉内容包含低级显示信息。
if (visual != NULL && gdk_screen_is_composited(screen)) {gtk_widget_set_visual(win, visual);}
并非所有的显示器都支持此操作。 因此,我们检查屏幕是否支持合成并且返回的视觉效果不是NULL。 我们将屏幕的视觉效果设置为窗口的视觉效果。
static void do_drawing(cairo_t *cr){cairo_set_source_rgba(cr, 0.2, 0.2, 0.2, 0.4);cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);cairo_paint(cr);}
我们使用部分透明的源来绘制屏幕窗口。 CAIRO_OPERATOR_SOURCE在我们绘制源代码的地方创建了合成操作。 这是屏幕窗口。 为了获得完全透明,我们将 alpha 值设置为 0 或使用CAIRO_OPERATOR_CLEAR运算符。

图:透明窗口
截屏
根窗口对于截图也是必不可少的。
#include <cairo.h>#include <gdk/gdk.h>int main (int argc, char *argv[]){gdk_init(&argc, &argv);GdkWindow *root_win = gdk_get_default_root_window();gint width = gdk_window_get_width(root_win);gint height = gdk_window_get_height(root_win);cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,width, height);GdkPixbuf *pb = gdk_pixbuf_get_from_window(root_win, 0, 0, width, height);cairo_t *cr = cairo_create(surface);gdk_cairo_set_source_pixbuf(cr, pb, 0, 0);cairo_paint(cr);cairo_surface_write_to_png(surface, "image.png");cairo_destroy(cr);cairo_surface_destroy(surface);return 0;}
该示例捕获整个屏幕的快照。 在此示例中,我们不使用完整的 GTK 窗口系统。 我们使用 Cairo 和 GDK 库来完成这项工作。
gdk_init(&argc, &argv);
gdk_init()初始化 GDK 库并连接到窗口系统。
GdkWindow *root_win = gdk_get_default_root_window();
我们通过gdk_get_default_root_window()函数调用获得了根窗口。
gint width = gdk_window_get_width(root_win);gint height = gdk_window_get_height(root_win);
我们确定根窗口的宽度和高度。
cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,width, height);
空的图像表面被创建。 它具有根窗口的大小。
GdkPixbuf *pb = gdk_pixbuf_get_from_window(root_win, 0, 0, width, height);
我们使用gdk_pixbuf_get_from_window()函数调用从根窗口中获得一个pixbuf。 pixbuf是描述内存中图像的对象。
cairo_t *cr = cairo_create(surface);gdk_cairo_set_source_pixbuf(cr, pb, 0, 0);cairo_paint(cr);
在上述代码行中,我们在之前创建的图像表面上创建了 Cairo 绘图上下文。 我们将 pixbuf 放在绘图上下文上并将其绘制在表面上。
cairo_surface_write_to_png(surface, "image.png");
使用write_to_png()方法将图像表面写入 PNG 图像。
cairo_destroy(cr);cairo_surface_destroy(surface);
我们清理资源。
显示信息
在第三个示例中,我们将在桌面窗口上显示一条消息。
#include <cairo.h>#include <gtk/gtk.h>#include <pango/pango.h>static void do_drawing(cairo_t *);static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,gpointer user_data){do_drawing(cr);return FALSE;}static void do_drawing(cairo_t *cr){cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);cairo_paint(cr);cairo_set_operator(cr, CAIRO_OPERATOR_OVER);}static void setup(GtkWidget *win){gtk_widget_set_app_paintable(win, TRUE);gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DOCK);gtk_window_set_keep_below(GTK_WINDOW(win), TRUE);GdkScreen *screen = gdk_screen_get_default();GdkVisual *visual = gdk_screen_get_rgba_visual(screen);if (visual != NULL && gdk_screen_is_composited(screen)) {gtk_widget_set_visual(win, visual);}}int main (int argc, char *argv[]){GtkWidget *window;GtkWidget *lbl;gtk_init(&argc, &argv);window = gtk_window_new(GTK_WINDOW_TOPLEVEL);setup(window);lbl = gtk_label_new("ZetCode, tutorials for programmers");PangoFontDescription *fd = pango_font_description_from_string("Serif 20");gtk_widget_modify_font(lbl, fd);gtk_container_add(GTK_CONTAINER(window), lbl);GdkColor color;gdk_color_parse("white", &color);gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, &color);g_signal_connect(G_OBJECT(window), "draw",G_CALLBACK(on_draw_event), NULL);g_signal_connect(window, "destroy",G_CALLBACK(gtk_main_quit), NULL);gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);gtk_window_set_default_size(GTK_WINDOW(window), 350, 250);gtk_widget_show_all(window);gtk_main();return 0;}
该代码在根窗口上显示消息标签。
static void do_drawing(cairo_t *cr){cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);cairo_paint(cr);cairo_set_operator(cr, CAIRO_OPERATOR_OVER);}
我们使用CAIRO_OPERATOR_CLEAR运算符清除窗口背景。 然后我们设置CAIRO_OPERATOR_OVER以绘制标签窗口小部件。
gtk_widget_set_app_paintable(win, TRUE);
我们将操纵应用窗口,因此我们使其可绘制。
gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DOCK);
实现此窗口提示会删除窗口边框和装饰。
gtk_window_set_keep_below(GTK_WINDOW(win), TRUE);
我们始终将应用始终放在根窗口的底部。
GdkScreen *screen = gdk_screen_get_default();GdkVisual *visual = gdk_screen_get_rgba_visual(screen);if (visual != NULL && gdk_screen_is_composited(screen)) {gtk_widget_set_visual(win, visual);}
我们将屏幕的外观设置为应用的外观。
lbl = gtk_label_new("ZetCode, tutorials for programmers");
我们创建一个消息标签。
PangoFontDescription *fd = pango_font_description_from_string("Serif 20");gtk_widget_modify_font(lbl, fd);
在 Pango 模块的帮助下,我们为文本选择特定的字体。
gtk_container_add(GTK_CONTAINER(window), lbl);
标签贴在窗户上。
GdkColor color;gdk_color_parse("white", &color);gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, &color);
我们将文本修改为白色。

图:根窗口上的消息
在本章中,我们使用了 Cairo 的桌面窗口。
