# 根窗口

> 原文： [https://zetcode.com/gfx/cairo/root/](https://zetcode.com/gfx/cairo/root/)

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

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

## 透明窗

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

```c
#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()`方法中，我们绘制屏幕的可视对象。 这产生了部分透明的幻觉。

```c
gtk_widget_set_app_paintable(win, TRUE);

```

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

```c
screen = gdk_screen_get_default();

```

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

```c
visual = gdk_screen_get_rgba_visual(screen);

```

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

```c
if (visual != NULL && gdk_screen_is_composited(screen)) {
    gtk_widget_set_visual(win, visual);
}

```

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

```c
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`运算符。

![Transparent window](img/aea5db0df601965bb982c638525eccc6.jpg)

图：透明窗口

## 截屏

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

```c
#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 库来完成这项工作。

```c
gdk_init(&argc, &argv);

```

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

```c
GdkWindow *root_win = gdk_get_default_root_window();

```

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

```c
gint width = gdk_window_get_width(root_win);
gint height = gdk_window_get_height(root_win);

```

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

```c
cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
    width, height);

```

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

```c
GdkPixbuf *pb = gdk_pixbuf_get_from_window(root_win, 0, 0, width, height);

```

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

```c
cairo_t *cr = cairo_create(surface);        
gdk_cairo_set_source_pixbuf(cr, pb, 0, 0);  
cairo_paint(cr);

```

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

```c
cairo_surface_write_to_png(surface, "image.png");

```

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

```c
cairo_destroy(cr);
cairo_surface_destroy(surface);

```

我们清理资源。

## 显示信息

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

```c
#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;
}

```

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

```c
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`以绘制标签窗口小部件。

```c
gtk_widget_set_app_paintable(win, TRUE);

```

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

```c
gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DOCK);

```

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

```c
gtk_window_set_keep_below(GTK_WINDOW(win), TRUE);

```

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

```c
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);
  } 

```

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

```c
lbl = gtk_label_new("ZetCode, tutorials for programmers");

```

我们创建一个消息标签。

```c
PangoFontDescription *fd = pango_font_description_from_string("Serif 20");
gtk_widget_modify_font(lbl, fd);  

```

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

```c
gtk_container_add(GTK_CONTAINER(window), lbl);   

```

标签贴在窗户上。

```c
GdkColor color;
gdk_color_parse("white", &color);
gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, &color);

```

我们将文本修改为白色。

![Message on the root window](img/2ccd02b7ec669399c873fbae2c7fc813.jpg)

图：根窗口上的消息

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