原文: https://zetcode.com/gfx/cairo/root/

在 Cairo 图形教程的这一部分中,我们将使用根窗口。 根窗口是我们通常具有图标快捷方式的桌面窗口。

可以使用根窗口进行操作。 从程序员的角度来看,它只是一种特殊的窗口。

透明窗

我们的第一个示例将创建一个透明窗口。 我们将看到窗口对象下方的内容。

  1. #include <cairo.h>
  2. #include <gtk/gtk.h>
  3. static void do_drawing(cairo_t *);
  4. static void tran_setup(GtkWidget *win)
  5. {
  6. GdkScreen *screen;
  7. GdkVisual *visual;
  8. gtk_widget_set_app_paintable(win, TRUE);
  9. screen = gdk_screen_get_default();
  10. visual = gdk_screen_get_rgba_visual(screen);
  11. if (visual != NULL && gdk_screen_is_composited(screen)) {
  12. gtk_widget_set_visual(win, visual);
  13. }
  14. }
  15. static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
  16. gpointer user_data)
  17. {
  18. do_drawing(cr);
  19. return FALSE;
  20. }
  21. static void do_drawing(cairo_t *cr)
  22. {
  23. cairo_set_source_rgba(cr, 0.2, 0.2, 0.2, 0.4);
  24. cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
  25. cairo_paint(cr);
  26. }
  27. int main (int argc, char *argv[])
  28. {
  29. GtkWidget *window;
  30. GtkWidget *darea;
  31. gtk_init(&argc, &argv);
  32. window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  33. tran_setup(window);
  34. darea = gtk_drawing_area_new();
  35. gtk_container_add(GTK_CONTAINER (window), darea);
  36. g_signal_connect(G_OBJECT(darea), "draw",
  37. G_CALLBACK(on_draw_event), NULL);
  38. g_signal_connect(window, "destroy",
  39. G_CALLBACK(gtk_main_quit), NULL);
  40. gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  41. gtk_window_set_default_size(GTK_WINDOW(window), 300, 250);
  42. gtk_window_set_title(GTK_WINDOW(window), "Transparent window");
  43. gtk_widget_show_all(window);
  44. gtk_main();
  45. return 0;
  46. }

为了创建透明窗口,我们获得了屏幕对象的视觉效果并将其设置为我们的窗口。 在on_draw()方法中,我们绘制屏幕的可视对象。 这产生了部分透明的幻觉。

  1. gtk_widget_set_app_paintable(win, TRUE);

我们必须设置要绘制的应用。

  1. screen = gdk_screen_get_default();

gdk_screen_get_default()方法返回屏幕对象。

  1. visual = gdk_screen_get_rgba_visual(screen);

从屏幕窗口中,我们可以看到它。 视觉内容包含低级显示信息。

  1. if (visual != NULL && gdk_screen_is_composited(screen)) {
  2. gtk_widget_set_visual(win, visual);
  3. }

并非所有的显示器都支持此操作。 因此,我们检查屏幕是否支持合成并且返回的视觉效果不是NULL。 我们将屏幕的视觉效果设置为窗口的视觉效果。

  1. static void do_drawing(cairo_t *cr)
  2. {
  3. cairo_set_source_rgba(cr, 0.2, 0.2, 0.2, 0.4);
  4. cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
  5. cairo_paint(cr);
  6. }

我们使用部分透明的源来绘制屏幕窗口。 CAIRO_OPERATOR_SOURCE在我们绘制源代码的地方创建了合成操作。 这是屏幕窗口。 为了获得完全透明,我们将 alpha 值设置为 0 或使用CAIRO_OPERATOR_CLEAR运算符。

根窗口 - 图1

图:透明窗口

截屏

根窗口对于截图也是必不可少的。

  1. #include <cairo.h>
  2. #include <gdk/gdk.h>
  3. int main (int argc, char *argv[])
  4. {
  5. gdk_init(&argc, &argv);
  6. GdkWindow *root_win = gdk_get_default_root_window();
  7. gint width = gdk_window_get_width(root_win);
  8. gint height = gdk_window_get_height(root_win);
  9. cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
  10. width, height);
  11. GdkPixbuf *pb = gdk_pixbuf_get_from_window(root_win, 0, 0, width, height);
  12. cairo_t *cr = cairo_create(surface);
  13. gdk_cairo_set_source_pixbuf(cr, pb, 0, 0);
  14. cairo_paint(cr);
  15. cairo_surface_write_to_png(surface, "image.png");
  16. cairo_destroy(cr);
  17. cairo_surface_destroy(surface);
  18. return 0;
  19. }

该示例捕获整个屏幕的快照。 在此示例中,我们不使用完整的 GTK 窗口系统。 我们使用 Cairo 和 GDK 库来完成这项工作。

  1. gdk_init(&argc, &argv);

gdk_init()初始化 GDK 库并连接到窗口系统。

  1. GdkWindow *root_win = gdk_get_default_root_window();

我们通过gdk_get_default_root_window()函数调用获得了根窗口。

  1. gint width = gdk_window_get_width(root_win);
  2. gint height = gdk_window_get_height(root_win);

我们确定根窗口的宽度和高度。

  1. cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
  2. width, height);

空的图像表面被创建。 它具有根窗口的大小。

  1. GdkPixbuf *pb = gdk_pixbuf_get_from_window(root_win, 0, 0, width, height);

我们使用gdk_pixbuf_get_from_window()函数调用从根窗口中获得一个pixbufpixbuf是描述内存中图像的对象。

  1. cairo_t *cr = cairo_create(surface);
  2. gdk_cairo_set_source_pixbuf(cr, pb, 0, 0);
  3. cairo_paint(cr);

在上述代码行中,我们在之前创建的图像表面上创建了 Cairo 绘图上下文。 我们将 pixbuf 放在绘图上下文上并将其绘制在表面上。

  1. cairo_surface_write_to_png(surface, "image.png");

使用write_to_png()方法将图像表面写入 PNG 图像。

  1. cairo_destroy(cr);
  2. cairo_surface_destroy(surface);

我们清理资源。

显示信息

在第三个示例中,我们将在桌面窗口上显示一条消息。

  1. #include <cairo.h>
  2. #include <gtk/gtk.h>
  3. #include <pango/pango.h>
  4. static void do_drawing(cairo_t *);
  5. static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
  6. gpointer user_data)
  7. {
  8. do_drawing(cr);
  9. return FALSE;
  10. }
  11. static void do_drawing(cairo_t *cr)
  12. {
  13. cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
  14. cairo_paint(cr);
  15. cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
  16. }
  17. static void setup(GtkWidget *win)
  18. {
  19. gtk_widget_set_app_paintable(win, TRUE);
  20. gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DOCK);
  21. gtk_window_set_keep_below(GTK_WINDOW(win), TRUE);
  22. GdkScreen *screen = gdk_screen_get_default();
  23. GdkVisual *visual = gdk_screen_get_rgba_visual(screen);
  24. if (visual != NULL && gdk_screen_is_composited(screen)) {
  25. gtk_widget_set_visual(win, visual);
  26. }
  27. }
  28. int main (int argc, char *argv[])
  29. {
  30. GtkWidget *window;
  31. GtkWidget *lbl;
  32. gtk_init(&argc, &argv);
  33. window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  34. setup(window);
  35. lbl = gtk_label_new("ZetCode, tutorials for programmers");
  36. PangoFontDescription *fd = pango_font_description_from_string("Serif 20");
  37. gtk_widget_modify_font(lbl, fd);
  38. gtk_container_add(GTK_CONTAINER(window), lbl);
  39. GdkColor color;
  40. gdk_color_parse("white", &color);
  41. gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, &color);
  42. g_signal_connect(G_OBJECT(window), "draw",
  43. G_CALLBACK(on_draw_event), NULL);
  44. g_signal_connect(window, "destroy",
  45. G_CALLBACK(gtk_main_quit), NULL);
  46. gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  47. gtk_window_set_default_size(GTK_WINDOW(window), 350, 250);
  48. gtk_widget_show_all(window);
  49. gtk_main();
  50. return 0;
  51. }

该代码在根窗口上显示消息标签。

  1. static void do_drawing(cairo_t *cr)
  2. {
  3. cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
  4. cairo_paint(cr);
  5. cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
  6. }

我们使用CAIRO_OPERATOR_CLEAR运算符清除窗口背景。 然后我们设置CAIRO_OPERATOR_OVER以绘制标签窗口小部件。

  1. gtk_widget_set_app_paintable(win, TRUE);

我们将操纵应用窗口,因此我们使其可绘制。

  1. gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DOCK);

实现此窗口提示会删除窗口边框和装饰。

  1. gtk_window_set_keep_below(GTK_WINDOW(win), TRUE);

我们始终将应用始终放在根窗口的底部。

  1. GdkScreen *screen = gdk_screen_get_default();
  2. GdkVisual *visual = gdk_screen_get_rgba_visual(screen);
  3. if (visual != NULL && gdk_screen_is_composited(screen)) {
  4. gtk_widget_set_visual(win, visual);
  5. }

我们将屏幕的外观设置为应用的外观。

  1. lbl = gtk_label_new("ZetCode, tutorials for programmers");

我们创建一个消息标签。

  1. PangoFontDescription *fd = pango_font_description_from_string("Serif 20");
  2. gtk_widget_modify_font(lbl, fd);

在 Pango 模块的帮助下,我们为文本选择特定的字体。

  1. gtk_container_add(GTK_CONTAINER(window), lbl);

标签贴在窗户上。

  1. GdkColor color;
  2. gdk_color_parse("white", &color);
  3. gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, &color);

我们将文本修改为白色。

根窗口 - 图2

图:根窗口上的消息

在本章中,我们使用了 Cairo 的桌面窗口。