显示器用于在物理硬件(如计算机显示器或触摸屏显示器)上显示窗口的内容。
屏幕API提供的功能允许我们创建同时写入多个窗口和显示的应用程序。屏幕支持多个显示器,但创建和管理使用多个显示器的应用程序可能会非常棘手。你需要考虑线程、性能和图形优化。显示器彼此独立,每个窗口只能与一个显示器相关联。
我们可以在配置文件graphics.conf中提供要应用于平台支持的物理显示器的配置。有关更多信息,请参阅配置屏幕。
显示器通常由窗口管理器控制。但是,在没有窗口管理器的情况下,应用程序可以选择显示器。
Screen使用默认显示的概念。默认显示是Screen在没有明确指定与窗口关联的显示时,进行显示的显示。
要配置要作为默认显示的显示器,请在图形配置文件(例如graphics.conf)的全局子部分中指定默认显示参数。有关更多信息,请参阅“配置屏幕”。如果在配置时未指定默认显示,Screen将指定默认显示。
默认显示始终是使用SCREEN_PROPERTY_DISPLAYS属性调用screen_get_context_property_pv()后检索到的显示列表中的第一个元素。要确定默认显示:
例如:
...
int ndisplays = 0;
screen_context_t screen_ctx;
...
screen_get_context_property_iv(screen_ctx, SCREEN_PROPERTY_DISPLAY_COUNT, &ndisplays);
...
例如:
screen_display_t *screen_dpy = calloc(ndisplays, sizeof(screen_display_t));
例如screen_dpy[0]。
你需要从了解在你的环境中可以使用的显示器是什么以及有多少个显示器开始。
在上下文中使用带有SCREEN_PROPERTY_DISPLAY_COUNT属性的screen_get_context_property_iv()函数。
int ndisplays = 0;
screen_context_t screen_ctx;
...
screen_get_context_property_iv(screen_ctx, SCREEN_PROPERTY_DISPLAY_COUNT, &ndisplays);
...
screen_display_t *screen_dpy = calloc(ndisplays, sizeof(screen_display_t));
screen_get_context_property_pv(screen_ctx, SCREEN_PROPERTY_DISPLAYS, (void **)screen_dpy);
如果你使用多个显示器,你可能希望使用某种数据结构来跟踪你的显示器和每个显示器的状态。例如
struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
enum { detached, attached, focused } state;
} *displays;
displays = calloc(ndisplays, sizeof(*displays));
在上面的例子中,每个显示器的结构除了显示器的状态外,还跟踪互斥量和条件对象。这个例子跟踪显示器的三种状态:分离、连接和聚焦。你的应用程序会影响你需要跟踪的显示状态。显示属性SCREEN_PROPERTY_ATTACHED为你提供了显示器的连接或分离状态,但如果你也在跟踪该状态,你必须从你的应用程序中确定哪个显示器是焦点。
对于每个连接的显示器,本示例初始化一个互斥量并调用pthread_create()来创建一个新线程,以处理该显示器特有的渲染。它向新线程传递一个处理该显示器图形操作的启动例程。本示例中使用的方法有助于使用多个显示器。如果你生成一个子线程来处理每个显示器的处理,每个显示器将在自己的进程中写入和更新。这允许图形处理器处理密集操作,并确保如果发生错误或显示器分离,应用程序本身不会失败。
int i, idx = -1;
for (i = 0; i < ndisplays; i++) {
int active = 0;
screen_get_display_property_iv(screen_dpy[i], SCREEN_PROPERTY_ATTACHED, &active);
if (active) {
if (idx == -1) {
displays[i].state = focused;
idx = i;
} else {
displays[i].state = attached;
}
} else {
displays[i].state = detached;
}
pthread_mutex_init(&displays[i].mutex, NULL);
pthread_cond_init(&displays[i].cond, NULL);
pthread_t thread;
pthread_create(&thread, NULL, display, (void *)i);
}
在上面的例子中,display()函数作为线程的启动例程传递进来。该函数负责设置显示和窗口,然后锁定互斥量以确定当前显示是否处于活动状态并具有焦点。该函数还发布窗口,以便显示其内容。