使用 Ghosd 和 Synergy 增强多屏幕用户界面

来源:developerWorks 中国 作者:Nathan Harrington
  
不同于传统的单屏幕设置,多屏幕显示系统要求特别考虑用户界面(UI)。本文提供了专用于跨多个显示屏获得和更改输入焦点的工具和代码。

对工作环境作出少量修改可以提高生产力,其效果和添加额外的监视器一样显著。开源的 Synergy 包提供了一种优秀的方法,可以在无需购买额外硬件的情况下链接多个显示器。

不同于传统的单屏幕设置,多屏幕显示系统要求特别考虑用户界面。本文提供了专用于跨多个显示屏获得和更改输入焦点的工具和代码。通过使用 Ghosd 显示和 Synergy 调试级输出增强现有的 X Window System 焦点信息,多屏幕用户甚至可以精确地知道输入焦点在 4200x3150 像素或更大的像素。

要求

安全注意事项

本文介绍的代码和技术演示了如何创建屏幕警报。这是为在私有网络中运行的计算机设计的。它不能用于直接公开给 Internet 的计算机中,Internet 中的恶意程序可能会尝试在计算机中执行任意代码。

硬件

Synergy 设计用于跨各种硬件和软件工作。建议使用速度较快的网络,对于制作动画或大量使用阿尔法混合(alpha-blended)Ghosd 视觉效果尤其如此。

软件

虽然各种操作系统都支持 Synergy 的基本功能,但是本文将在 Linux® 服务器上使用 Ghosd 来提供增强的屏幕显示(on-screen display,OSD)。按照 Synergy 的定义,服务器是带有主键盘和鼠标或共享键盘和鼠标、主屏幕并运行 Synergy 服务器软件的计算机。所有其他计算机是 Synergy 客户机并运行 Synergy 客户机软件。下面是继续学习本文所需的内容:

Synergy
Synergy 允许在配有不同操作系统、拥有各自显示屏而没有特殊硬件的多个计算机之间共享单个鼠标和键盘。
X Window System
需要在 Synergy 服务器和客户机中运行 Linux® 或兼容的 X Window System 服务器才能得到本文所述的结果。由于运行 Linux 或 UNIX® 的大多数台式机都安装了 X Window System,因此可以放心地假定它已经安装在 Linux 或 UNIX 计算机中。
Pango
Pango 是设置文本布局并呈现文本的库。
GLib library
Pango 依赖于 GLib 库 的 V2.x 系列,可以从 GTK+ Project 获得。
Cairo
Cairo 是支持多个输出设备的 2-D 图形库。
Ghosd
Ghosd 是一个使用一种很吸引人的方式在屏幕中刷新信息的库。
Perl
Perl 是一种稳定的跨平台编程语言。

Ubuntu 用户可以使用以下命令安装上面的大部分软件:sudo apt-get install libgtk2.0-dev libpango1.0-dev libcairo2-dev perl synergy。





一般方法

考虑图 1 中所示的六屏幕 Synergy 设置。此图像显示了下面所示的代码最终生成的焦点内和焦点外指示器。如果离开多屏幕设置几分钟,则会发现很难记住光标所在的位置及位于哪个屏幕中。图 1 在获得焦点的屏幕中显示一系列绿色正方形,并在其他显示屏中显示逐渐淡出的红框。继续阅读本文,了解如何从焦点跟踪指示器开始生成这种视觉效果。


图 1. 六屏幕显示设置
六屏幕显示设置





构建焦点内显示效果

查阅在 下载 小节中找到的文件以获得 Ghosd 源代码归档。将 Ghosd 源代码下载到打算用作 Synergy 服务器的计算机中。用命令 bzip2 -d ghosd-0.0.1.tar.bz2 -c | tar -xvf - 解压缩 Ghosd 代码归档。运行普通的 ./configure; make && make install 命令以构建 Ghosd 源代码和示例文件。如果构建并安装成功,则已经准备好创建第一个焦点显示效果,指示焦点的一系列绿框。

焦点内显示效果

切换到 examples/ 目录并使用命令 mv animation.c original.animation.c 重命名 animation.c 文件。创建名为 animation.c 的新文件并在其中放入清单 1 所示的代码。


清单 1. animation.c 头文件,round_rect 函数
// animation.c - modified ghosd example for Synergy focus designation
// borrows heavily from the ghosd animation.c example file
#include <stdio.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <time.h>
#include <cairo/cairo.h>
#include <ghosd/ghosd.h>

#define RADIUS 20
int sizeX   = 1024;
int sizeY   = 768;
int mode    = 0;    // 0 is alpha blended red border box, 1 is green boxes

typedef struct {
  cairo_surface_t* foot;
  float alpha;
} RenderData;

static void
round_rect(cairo_t *cr, int x, int y, int w, int h, int r) {
  cairo_move_to(cr, x+r, y);
  cairo_line_to(cr, x+w-r, y); /* top edge */
  cairo_curve_to(cr, x+w, y, x+w, y, x+w, y+r);
  cairo_line_to(cr, x+w, y+h-r); /* right edge */
  cairo_curve_to(cr, x+w, y+h, x+w, y+h, x+w-r, y+h);
  cairo_line_to(cr, x+r, y+h); /* bottom edge */
  cairo_curve_to(cr, x, y+h, x, y+h, x, y+h-r);
  cairo_line_to(cr, x, y+r); /* left edge */
  cairo_curve_to(cr, x, y, x, y, x+r, y);
  cairo_close_path(cr);
}

在 include 语句和变量声明后,round_rect 函数被定义为从 Ghosd examples/animation.c 文件中借用 verbatim。round_rect 函数将在焦点内和焦点外显示效果中提供高亮显示。接下来,添加如下所示的 renderFocus 函数。


清单 2. renderFocus 函数
static void
renderFocus(Ghosd *ghosd, cairo_t *cr, void* data) {
  RenderData *rdata = data;

  // draw three squares to indicate focus
  cairo_set_line_width( cr, 20);
  cairo_set_source_rgba(cr, 0, 1, 0, rdata->alpha);
  cairo_new_path(cr);
  round_rect(cr, 10, 10, 380, 380, RADIUS);
  cairo_stroke(cr);

  cairo_set_source_rgba(cr, 0, 1, 0, rdata->alpha);
  cairo_new_path(cr);
  round_rect(cr, 40, 40, 320, 320, RADIUS);
  cairo_stroke(cr);

  cairo_set_source_rgba(cr, 0, 1, 0, rdata->alpha);
  cairo_new_path(cr);
  round_rect(cr, 70, 70, 260, 260, RADIUS);
  cairo_stroke(cr);

  cairo_set_source_surface(cr, rdata->foot, 0,0);
}//renderFocus

当显示屏获得焦点时,renderFocus 函数将在可用呈现平面中绘制三个连续缩小的圆矩形区域。清单 3 显示了主程序逻辑并调用 renderFocus 函数。


清单 3. animation.c 主逻辑
int main(int argc, char* argv[]) {
  Ghosd *ghosd;
  RenderData data = {0};
  struct timeval tv_nextupdate;
  const int STEP = 50;
  float dalpha = 0.10;

  if( argc == 4 )
  {
    sizeX = atoi( argv[1] );
    sizeY = atoi( argv[2] );
    mode  = atoi( argv[3] );

  }

  ghosd = ghosd_new();

  if( mode == 0 )
  {
    // create a small canvas and draw the green focus boxes
    data.foot = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400,400);
    data.alpha = 1;
    ghosd_set_position(ghosd, (sizeX/2)-200, (sizeY/2)-200, 400, 400);
    ghosd_set_render(ghosd, renderFocus, &data);
    ghosd_render(ghosd);
    ghosd_show(ghosd);
    ghosd_main_iterations(ghosd);

  }//if focus mode

  // ghosd_flash is not ideal for this example, so fade out quickly and exit
  for (;;) 
  {
    gettimeofday(&tv_nextupdate, NULL);
    tv_nextupdate.tv_usec += STEP*1000;

    ghosd_main_until(ghosd, &tv_nextupdate);

    data.alpha -= dalpha;
    if (data.alpha <= 0.3) { return(0); }

    ghosd_render(ghosd);
  }//for each step fade out

}//main

再次大量借用 Ghosd examples/animation.c 文件的内容,主循环将创建一个 400x400 阿尔法混合平面区域。无论分辨率是多少,此平面都会被定位到屏幕中心,并且将 renderFocus 函数指定为在每次呈现时调用。

虽然 ghosd_flash 为淡入淡出文本提供了有用接口,但是简单的淡出效果更加适合这个显示效果。因此,for 循环将在每次呈现时减少阿尔法混合量,以在程序退出前创建有效的淡出效果。

要构建此文件,请先执行 ./animation 1400 1050 0,然后再执行 make 命令。假定屏幕分辨率为 1400x1050,您应当在屏幕中心看到一系列绿框。

从 Synergy 输出中提取焦点信息

完成显示效果后,应该在屏幕中显示它,同时当前焦点放到 Synergy 配置中。Synergy 使得此过程相对简单,因为它提供了非常适合这项任务的各种调试级输出。

创建以清单 4 内容为开头的名为 processSynergy.pl 的文件。


清单 4. processSynergy.pl 变量,主循环
#!/usr/bin/perl -w
# processSynergy.pl - read Synergys DEBUG2 events
use strict;
my %disp = ();       # record display geometries, focus states
my $delay = 5;       # time in seconds
my $inTimeout = 0;   # timeout mode switcher
my $osdOn     = 0;   # on screen display switcher
my $lastTime = time; # monitor last activity

while( my $line = <STDIN> )
{
  $line =~ s/"//g;

  if( $line =~ /404: received client / )
  {
    # client connection geometry recording an initial setup
    my @parts = split " ", $line;
    my $name = $parts[4];

    $disp{$name}{mode} = 1;
    $disp{$name}{X} = (split "x", $parts[7])[0];
    $disp{$name}{Y} = (split "x", $parts[7])[1];

    print "$name geometry $parts[7]\n";

在声明变量(大多数将在稍后进行焦点超时检查时使用)后,程序将进入一个循环,对 STDIN 侦听 Synergy 事件。第一条 if 语句将处理客户机连接消息并把各个显示信息添加到 %disp hash 中。清单 5 将侦听 “焦点切换” 消息。


清单 5. 焦点切换检查
  }elsif( $line =~ / switch from / )
  {
    # track changes of focus between clients
    my $name = (split " ", $line)[6];

    $disp{$name}{mode} = 0;

    # set all other displays to inactive
    map{ $disp{
不同于传统的单屏幕设置,多屏幕显示系统要求特别考虑用户界面(UI)。本文提供了专用于跨多个显示屏获得和更改输入焦点的工具和代码。

对工作环境作出少量修改可以提高生产力,其效果和添加额外的监视器一样显著。开源的 Synergy 包提供了一种优秀的方法,可以在无需购买额外硬件的情况下链接多个显示器。

不同于传统的单屏幕设置,多屏幕显示系统要求特别考虑用户界面。本文提供了专用于跨多个显示屏获得和更改输入焦点的工具和代码。通过使用 Ghosd 显示和 Synergy 调试级输出增强现有的 X Window System 焦点信息,多屏幕用户甚至可以精确地知道输入焦点在 4200x3150 像素或更大的像素。

要求

安全注意事项

本文介绍的代码和技术演示了如何创建屏幕警报。这是为在私有网络中运行的计算机设计的。它不能用于直接公开给 Internet 的计算机中,Internet 中的恶意程序可能会尝试在计算机中执行任意代码。

硬件

Synergy 设计用于跨各种硬件和软件工作。建议使用速度较快的网络,对于制作动画或大量使用阿尔法混合(alpha-blended)Ghosd 视觉效果尤其如此。

软件

虽然各种操作系统都支持 Synergy 的基本功能,但是本文将在 Linux® 服务器上使用 Ghosd 来提供增强的屏幕显示(on-screen display,OSD)。按照 Synergy 的定义,服务器是带有主键盘和鼠标或共享键盘和鼠标、主屏幕并运行 Synergy 服务器软件的计算机。所有其他计算机是 Synergy 客户机并运行 Synergy 客户机软件。下面是继续学习本文所需的内容:

Synergy
Synergy 允许在配有不同操作系统、拥有各自显示屏而没有特殊硬件的多个计算机之间共享单个鼠标和键盘。
X Window System
需要在 Synergy 服务器和客户机中运行 Linux® 或兼容的 X Window System 服务器才能得到本文所述的结果。由于运行 Linux 或 UNIX® 的大多数台式机都安装了 X Window System,因此可以放心地假定它已经安装在 Linux 或 UNIX 计算机中。
Pango
Pango 是设置文本布局并呈现文本的库。
GLib library
Pango 依赖于 GLib 库 的 V2.x 系列,可以从 GTK+ Project 获得。
Cairo
Cairo 是支持多个输出设备的 2-D 图形库。
Ghosd
Ghosd 是一个使用一种很吸引人的方式在屏幕中刷新信息的库。
Perl
Perl 是一种稳定的跨平台编程语言。

Ubuntu 用户可以使用以下命令安装上面的大部分软件:sudo apt-get install libgtk2.0-dev libpango1.0-dev libcairo2-dev perl synergy。





一般方法

考虑图 1 中所示的六屏幕 Synergy 设置。此图像显示了下面所示的代码最终生成的焦点内和焦点外指示器。如果离开多屏幕设置几分钟,则会发现很难记住光标所在的位置及位于哪个屏幕中。图 1 在获得焦点的屏幕中显示一系列绿色正方形,并在其他显示屏中显示逐渐淡出的红框。继续阅读本文,了解如何从焦点跟踪指示器开始生成这种视觉效果。


图 1. 六屏幕显示设置
六屏幕显示设置





构建焦点内显示效果

查阅在 下载 小节中找到的文件以获得 Ghosd 源代码归档。将 Ghosd 源代码下载到打算用作 Synergy 服务器的计算机中。用命令 bzip2 -d ghosd-0.0.1.tar.bz2 -c | tar -xvf - 解压缩 Ghosd 代码归档。运行普通的 ./configure; make && make install 命令以构建 Ghosd 源代码和示例文件。如果构建并安装成功,则已经准备好创建第一个焦点显示效果,指示焦点的一系列绿框。

焦点内显示效果

切换到 examples/ 目录并使用命令 mv animation.c original.animation.c 重命名 animation.c 文件。创建名为 animation.c 的新文件并在其中放入清单 1 所示的代码。


清单 1. animation.c 头文件,round_rect 函数
// animation.c - modified ghosd example for Synergy focus designation
// borrows heavily from the ghosd animation.c example file
#include <stdio.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <time.h>
#include <cairo/cairo.h>
#include <ghosd/ghosd.h>

#define RADIUS 20
int sizeX   = 1024;
int sizeY   = 768;
int mode    = 0;    // 0 is alpha blended red border box, 1 is green boxes

typedef struct {
  cairo_surface_t* foot;
  float alpha;
} RenderData;

static void
round_rect(cairo_t *cr, int x, int y, int w, int h, int r) {
  cairo_move_to(cr, x+r, y);
  cairo_line_to(cr, x+w-r, y); /* top edge */
  cairo_curve_to(cr, x+w, y, x+w, y, x+w, y+r);
  cairo_line_to(cr, x+w, y+h-r); /* right edge */
  cairo_curve_to(cr, x+w, y+h, x+w, y+h, x+w-r, y+h);
  cairo_line_to(cr, x+r, y+h); /* bottom edge */
  cairo_curve_to(cr, x, y+h, x, y+h, x, y+h-r);
  cairo_line_to(cr, x, y+r); /* left edge */
  cairo_curve_to(cr, x, y, x, y, x+r, y);
  cairo_close_path(cr);
}

在 include 语句和变量声明后,round_rect 函数被定义为从 Ghosd examples/animation.c 文件中借用 verbatim。round_rect 函数将在焦点内和焦点外显示效果中提供高亮显示。接下来,添加如下所示的 renderFocus 函数。


清单 2. renderFocus 函数
static void
renderFocus(Ghosd *ghosd, cairo_t *cr, void* data) {
  RenderData *rdata = data;

  // draw three squares to indicate focus
  cairo_set_line_width( cr, 20);
  cairo_set_source_rgba(cr, 0, 1, 0, rdata->alpha);
  cairo_new_path(cr);
  round_rect(cr, 10, 10, 380, 380, RADIUS);
  cairo_stroke(cr);

  cairo_set_source_rgba(cr, 0, 1, 0, rdata->alpha);
  cairo_new_path(cr);
  round_rect(cr, 40, 40, 320, 320, RADIUS);
  cairo_stroke(cr);

  cairo_set_source_rgba(cr, 0, 1, 0, rdata->alpha);
  cairo_new_path(cr);
  round_rect(cr, 70, 70, 260, 260, RADIUS);
  cairo_stroke(cr);

  cairo_set_source_surface(cr, rdata->foot, 0,0);
}//renderFocus

当显示屏获得焦点时,renderFocus 函数将在可用呈现平面中绘制三个连续缩小的圆矩形区域。清单 3 显示了主程序逻辑并调用 renderFocus 函数。


清单 3. animation.c 主逻辑
int main(int argc, char* argv[]) {
  Ghosd *ghosd;
  RenderData data = {0};
  struct timeval tv_nextupdate;
  const int STEP = 50;
  float dalpha = 0.10;

  if( argc == 4 )
  {
    sizeX = atoi( argv[1] );
    sizeY = atoi( argv[2] );
    mode  = atoi( argv[3] );

  }

  ghosd = ghosd_new();

  if( mode == 0 )
  {
    // create a small canvas and draw the green focus boxes
    data.foot = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400,400);
    data.alpha = 1;
    ghosd_set_position(ghosd, (sizeX/2)-200, (sizeY/2)-200, 400, 400);
    ghosd_set_render(ghosd, renderFocus, &data);
    ghosd_render(ghosd);
    ghosd_show(ghosd);
    ghosd_main_iterations(ghosd);

  }//if focus mode

  // ghosd_flash is not ideal for this example, so fade out quickly and exit
  for (;;) 
  {
    gettimeofday(&tv_nextupdate, NULL);
    tv_nextupdate.tv_usec += STEP*1000;

    ghosd_main_until(ghosd, &tv_nextupdate);

    data.alpha -= dalpha;
    if (data.alpha <= 0.3) { return(0); }

    ghosd_render(ghosd);
  }//for each step fade out

}//main

再次大量借用 Ghosd examples/animation.c 文件的内容,主循环将创建一个 400x400 阿尔法混合平面区域。无论分辨率是多少,此平面都会被定位到屏幕中心,并且将 renderFocus 函数指定为在每次呈现时调用。

虽然 ghosd_flash 为淡入淡出文本提供了有用接口,但是简单的淡出效果更加适合这个显示效果。因此,for 循环将在每次呈现时减少阿尔法混合量,以在程序退出前创建有效的淡出效果。

要构建此文件,请先执行 ./animation 1400 1050 0,然后再执行 make 命令。假定屏幕分辨率为 1400x1050,您应当在屏幕中心看到一系列绿框。

从 Synergy 输出中提取焦点信息

完成显示效果后,应该在屏幕中显示它,同时当前焦点放到 Synergy 配置中。Synergy 使得此过程相对简单,因为它提供了非常适合这项任务的各种调试级输出。

创建以清单 4 内容为开头的名为 processSynergy.pl 的文件。


清单 4. processSynergy.pl 变量,主循环
#!/usr/bin/perl -w
# processSynergy.pl - read Synergys DEBUG2 events
use strict;
my %disp = ();       # record display geometries, focus states
my $delay = 5;       # time in seconds
my $inTimeout = 0;   # timeout mode switcher
my $osdOn     = 0;   # on screen display switcher
my $lastTime = time; # monitor last activity

while( my $line = <STDIN> )
{
  $line =~ s/"//g;

  if( $line =~ /404: received client / )
  {
    # client connection geometry recording an initial setup
    my @parts = split " ", $line;
    my $name = $parts[4];

    $disp{$name}{mode} = 1;
    $disp{$name}{X} = (split "x", $parts[7])[0];
    $disp{$name}{Y} = (split "x", $parts[7])[1];

    print "$name geometry $parts[7]\n";

在声明变量(大多数将在稍后进行焦点超时检查时使用)后,程序将进入一个循环,对 STDIN 侦听 Synergy 事件。第一条 if 语句将处理客户机连接消息并把各个显示信息添加到 %disp hash 中。清单 5 将侦听 “焦点切换” 消息。


清单 5. 焦点切换检查
___FCKpd___4

在 Synergy 跟踪显示之间的焦点更改时,processSynergy.pl 程序将读取消息。在所有显示屏中更新包含信息的数据结构后(会在稍后的焦点超时检查中使用),将用连接客户机时记录的分辨率值调用动画程序。

要创建焦点跟踪指示器,请在设为 Synergy 服务器的计算机中运行以下命令:synergys -f -c configFile --debug DEBUG2 2>&1 | perl processSynergy.pl。您可能必须连接到每个客户机,并发出 xhost + SynergyServer,其中 “SynergySever” 是运行动画程序的计算机的名称。

在各个窗口中到处移动鼠标,查看跨越显示屏跟踪的焦点指示器和淡出效果。





构建超时焦点多屏幕指示器

创建非焦点的显示效果

指示非焦点的一种简单而有效的方法是在阿尔法混合的屏幕快照周围放置一个红框。查看图 1 获得示例效果。要创建与多屏幕焦点指示器结合使用的非焦点显示效果,请把清单 6 中所示的代码添加到 animation.c 的第 57 行中。


清单 6. renderBox 函数
static void
renderBox(Ghosd *ghosd, cairo_t *cr, void* data) {
  RenderData *rdata = data;

  // draw a red box around a alpha blended center
  cairo_set_source_rgba(cr, 0, 0, 0, 0.5);
  cairo_new_path(cr);
  round_rect(cr, 0,0, sizeX,sizeY, RADIUS);
  cairo_fill(cr);


  cairo_set_line_width( cr, 10);

  cairo_set_source_rgba(cr, 1, 0, 0, 1.0);
  cairo_new_path(cr);
  round_rect(cr, 0,0, sizeX, sizeY, RADIUS);
  cairo_stroke(cr);

  cairo_set_source_surface(cr, rdata-<foot, 0,0 );

}//renderBox

Ghosd examples/animation.c 文件再次发挥作用,renderBox 函数将绘制全屏幕阿尔法混合正方形,后接围绕图像的红色边框。要正确调用此函数,请在第 106 行插入清单 7 中所示的代码。


清单 7. 红框逻辑分支
  }else
  {
    // create a full screen box, and draw the red box with faded center
    data.foot = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, sizeX, sizeY);
    data.alpha = 1;
    ghosd_set_position(ghosd, 0, 0, sizeX, sizeY );
    ghosd_set_render(ghosd, renderBox, &data);
    ghosd_render(ghosd);
    ghosd_show(ghosd);
    ghosd_main_iterations(ghosd);

这些特殊显示效果将一直存在,直至被 processSynergy.pl 程序终止。在第 117 行中,把如下所示的代码:


清单 8. 先前的 render 循环
  for (;;) 
  {
    gettimeofday(&tv_nextupdate, NULL);
    tv_nextupdate.tv_usec += STEP*1000;

    ghosd_main_until(ghosd, &tv_nextupdate);

    data.alpha -= dalpha;
    if (data.alpha <= 0.3) { return(0); }

    ghosd_render(ghosd);
  }//for each step fade out


更改为:


清单 9. 新 render 循环
  for (;;) 
  {
    ghosd_main_until(ghosd, &tv_nextupdate);
    ghosd_render(ghosd);
  }//continuous render until program killed

要构建此文件,请执行 make 命令,后接:./animation 1400 1050 1。假定屏幕分辨率为 1400x1050,您应当会看到一个颜色变淡的屏幕,四周围绕了一个红色框。按 Ctrl+c 组合键退出此种显示效果。

针对焦点超时检查修改 processSynergy.pl

要跟踪哪个屏幕拥有焦点以及输入何时停止,请对 processSynergy.pl 做出如下所述的修改。首先删除 47-49 行并替换为清单 10 中的代码。


清单 10. 动作、关键检查逻辑分支;心跳逻辑分支
  }elsif( $line =~ / MotionNotify / || $line =~ / KeyPress / ||
          $line =~ /event: Buton/ )
  {
    # reset time on keyboard and mouse events
    $lastTime = time;  $inTimeout = 0;

  }elsif( $line =~ / writef\(CALV\)/ )
  {
    # check for timeouts at each hearbeat
    next unless ( (time - $lastTime) > $delay && $inTimeout == 0);

    $inTimeout = 1;
    $osdOn =1;

    for my $key ( keys %disp )
    {
      my $res = "export DISPLAY=$key:0; ";
      $res .= "./animation $disp{$key}{X} $disp{$key}{Y} $disp{$key}{mode} &";
      system($res);
    }#for each display name

    print "timer exceeded\n";

  }#if client

在被第一个 elsif 分支处理时,每个新鼠标或键盘事件都将重设 lastTime 变量。第二个 elsif 分支将查找由客户机发送到服务器的 CALV “心跳”。如果自发生上一个动作后已经过了特定秒数,效果将显示在各自相应的屏幕中。在第 71 行添加清单 11 中所示的代码以完成 processSynergy.pl 修改。


清单 11. 在活动中处理 destroy 动画
  if( $inTimeout == 0 && $osdOn == 1)
  {
    # destroy on screen display process
    system("ps -aef | grep animation | perl -lnae '`kill -9 \$F[1]`'");
    $osdOn = 0;
    print "terminate osd\n";
  }#if on screen display is visible

注意,这种方法依赖于来自至少一台客户机的 CALV 心跳连接。如果网络变得不可用或者 CALV 消息没有显示,焦点指示器可能不会正确显示。





用法

要使用这个完成的超时焦点指示器,请在设为 Synergy 服务器的计算机中运行以下命令:synergys -f -c configFile --debug DEBUG2 2>&1 | perl processSynergy.pl。

如果未显示效果,则可能必须再次连接到每台客户机并发出 xhost + SynergyServer。在经过 “延迟” 秒数(在本例中为 5 秒)没有键盘或鼠标活动后,当前持有焦点的屏幕将显示一组绿框,而非焦点屏幕将显示阿尔法混合的红边框。





结束语

使用 Synergy 输出监视代码和 Ghosd 视觉效果可以跟踪焦点,并在达到某个时间阈值后将显示效果提供给当前焦点。现在当您返回到显示屏旁边时,可以省去在所有屏幕中查找光标的时间。

考虑把动画添加到指示器中以获得更加醒目的显示(当心可用库发生内存泄露)。链接终端会话与当前 Synergy 焦点信息以在当前查看的屏幕中提供远程系统的显示更新。如果可以考虑视觉效果,Ghosd 和 Synergy 调试信息可以帮助您显示它。(责任编辑:A6)

}{mode} = 1 if(
不同于传统的单屏幕设置,多屏幕显示系统要求特别考虑用户界面(UI)。本文提供了专用于跨多个显示屏获得和更改输入焦点的工具和代码。

对工作环境作出少量修改可以提高生产力,其效果和添加额外的监视器一样显著。开源的 Synergy 包提供了一种优秀的方法,可以在无需购买额外硬件的情况下链接多个显示器。

不同于传统的单屏幕设置,多屏幕显示系统要求特别考虑用户界面。本文提供了专用于跨多个显示屏获得和更改输入焦点的工具和代码。通过使用 Ghosd 显示和 Synergy 调试级输出增强现有的 X Window System 焦点信息,多屏幕用户甚至可以精确地知道输入焦点在 4200x3150 像素或更大的像素。

要求

安全注意事项

本文介绍的代码和技术演示了如何创建屏幕警报。这是为在私有网络中运行的计算机设计的。它不能用于直接公开给 Internet 的计算机中,Internet 中的恶意程序可能会尝试在计算机中执行任意代码。

硬件

Synergy 设计用于跨各种硬件和软件工作。建议使用速度较快的网络,对于制作动画或大量使用阿尔法混合(alpha-blended)Ghosd 视觉效果尤其如此。

软件

虽然各种操作系统都支持 Synergy 的基本功能,但是本文将在 Linux® 服务器上使用 Ghosd 来提供增强的屏幕显示(on-screen display,OSD)。按照 Synergy 的定义,服务器是带有主键盘和鼠标或共享键盘和鼠标、主屏幕并运行 Synergy 服务器软件的计算机。所有其他计算机是 Synergy 客户机并运行 Synergy 客户机软件。下面是继续学习本文所需的内容:

Synergy
Synergy 允许在配有不同操作系统、拥有各自显示屏而没有特殊硬件的多个计算机之间共享单个鼠标和键盘。
X Window System
需要在 Synergy 服务器和客户机中运行 Linux® 或兼容的 X Window System 服务器才能得到本文所述的结果。由于运行 Linux 或 UNIX® 的大多数台式机都安装了 X Window System,因此可以放心地假定它已经安装在 Linux 或 UNIX 计算机中。
Pango
Pango 是设置文本布局并呈现文本的库。
GLib library
Pango 依赖于 GLib 库 的 V2.x 系列,可以从 GTK+ Project 获得。
Cairo
Cairo 是支持多个输出设备的 2-D 图形库。
Ghosd
Ghosd 是一个使用一种很吸引人的方式在屏幕中刷新信息的库。
Perl
Perl 是一种稳定的跨平台编程语言。

Ubuntu 用户可以使用以下命令安装上面的大部分软件:sudo apt-get install libgtk2.0-dev libpango1.0-dev libcairo2-dev perl synergy。





一般方法

考虑图 1 中所示的六屏幕 Synergy 设置。此图像显示了下面所示的代码最终生成的焦点内和焦点外指示器。如果离开多屏幕设置几分钟,则会发现很难记住光标所在的位置及位于哪个屏幕中。图 1 在获得焦点的屏幕中显示一系列绿色正方形,并在其他显示屏中显示逐渐淡出的红框。继续阅读本文,了解如何从焦点跟踪指示器开始生成这种视觉效果。


图 1. 六屏幕显示设置
六屏幕显示设置





构建焦点内显示效果

查阅在 下载 小节中找到的文件以获得 Ghosd 源代码归档。将 Ghosd 源代码下载到打算用作 Synergy 服务器的计算机中。用命令 bzip2 -d ghosd-0.0.1.tar.bz2 -c | tar -xvf - 解压缩 Ghosd 代码归档。运行普通的 ./configure; make && make install 命令以构建 Ghosd 源代码和示例文件。如果构建并安装成功,则已经准备好创建第一个焦点显示效果,指示焦点的一系列绿框。

焦点内显示效果

切换到 examples/ 目录并使用命令 mv animation.c original.animation.c 重命名 animation.c 文件。创建名为 animation.c 的新文件并在其中放入清单 1 所示的代码。


清单 1. animation.c 头文件,round_rect 函数
// animation.c - modified ghosd example for Synergy focus designation
// borrows heavily from the ghosd animation.c example file
#include <stdio.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <time.h>
#include <cairo/cairo.h>
#include <ghosd/ghosd.h>

#define RADIUS 20
int sizeX   = 1024;
int sizeY   = 768;
int mode    = 0;    // 0 is alpha blended red border box, 1 is green boxes

typedef struct {
  cairo_surface_t* foot;
  float alpha;
} RenderData;

static void
round_rect(cairo_t *cr, int x, int y, int w, int h, int r) {
  cairo_move_to(cr, x+r, y);
  cairo_line_to(cr, x+w-r, y); /* top edge */
  cairo_curve_to(cr, x+w, y, x+w, y, x+w, y+r);
  cairo_line_to(cr, x+w, y+h-r); /* right edge */
  cairo_curve_to(cr, x+w, y+h, x+w, y+h, x+w-r, y+h);
  cairo_line_to(cr, x+r, y+h); /* bottom edge */
  cairo_curve_to(cr, x, y+h, x, y+h, x, y+h-r);
  cairo_line_to(cr, x, y+r); /* left edge */
  cairo_curve_to(cr, x, y, x, y, x+r, y);
  cairo_close_path(cr);
}

在 include 语句和变量声明后,round_rect 函数被定义为从 Ghosd examples/animation.c 文件中借用 verbatim。round_rect 函数将在焦点内和焦点外显示效果中提供高亮显示。接下来,添加如下所示的 renderFocus 函数。


清单 2. renderFocus 函数
static void
renderFocus(Ghosd *ghosd, cairo_t *cr, void* data) {
  RenderData *rdata = data;

  // draw three squares to indicate focus
  cairo_set_line_width( cr, 20);
  cairo_set_source_rgba(cr, 0, 1, 0, rdata->alpha);
  cairo_new_path(cr);
  round_rect(cr, 10, 10, 380, 380, RADIUS);
  cairo_stroke(cr);

  cairo_set_source_rgba(cr, 0, 1, 0, rdata->alpha);
  cairo_new_path(cr);
  round_rect(cr, 40, 40, 320, 320, RADIUS);
  cairo_stroke(cr);

  cairo_set_source_rgba(cr, 0, 1, 0, rdata->alpha);
  cairo_new_path(cr);
  round_rect(cr, 70, 70, 260, 260, RADIUS);
  cairo_stroke(cr);

  cairo_set_source_surface(cr, rdata->foot, 0,0);
}//renderFocus

当显示屏获得焦点时,renderFocus 函数将在可用呈现平面中绘制三个连续缩小的圆矩形区域。清单 3 显示了主程序逻辑并调用 renderFocus 函数。


清单 3. animation.c 主逻辑
int main(int argc, char* argv[]) {
  Ghosd *ghosd;
  RenderData data = {0};
  struct timeval tv_nextupdate;
  const int STEP = 50;
  float dalpha = 0.10;

  if( argc == 4 )
  {
    sizeX = atoi( argv[1] );
    sizeY = atoi( argv[2] );
    mode  = atoi( argv[3] );

  }

  ghosd = ghosd_new();

  if( mode == 0 )
  {
    // create a small canvas and draw the green focus boxes
    data.foot = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400,400);
    data.alpha = 1;
    ghosd_set_position(ghosd, (sizeX/2)-200, (sizeY/2)-200, 400, 400);
    ghosd_set_render(ghosd, renderFocus, &data);
    ghosd_render(ghosd);
    ghosd_show(ghosd);
    ghosd_main_iterations(ghosd);

  }//if focus mode

  // ghosd_flash is not ideal for this example, so fade out quickly and exit
  for (;;) 
  {
    gettimeofday(&tv_nextupdate, NULL);
    tv_nextupdate.tv_usec += STEP*1000;

    ghosd_main_until(ghosd, &tv_nextupdate);

    data.alpha -= dalpha;
    if (data.alpha <= 0.3) { return(0); }

    ghosd_render(ghosd);
  }//for each step fade out

}//main

再次大量借用 Ghosd examples/animation.c 文件的内容,主循环将创建一个 400x400 阿尔法混合平面区域。无论分辨率是多少,此平面都会被定位到屏幕中心,并且将 renderFocus 函数指定为在每次呈现时调用。

虽然 ghosd_flash 为淡入淡出文本提供了有用接口,但是简单的淡出效果更加适合这个显示效果。因此,for 循环将在每次呈现时减少阿尔法混合量,以在程序退出前创建有效的淡出效果。

要构建此文件,请先执行 ./animation 1400 1050 0,然后再执行 make 命令。假定屏幕分辨率为 1400x1050,您应当在屏幕中心看到一系列绿框。

从 Synergy 输出中提取焦点信息

完成显示效果后,应该在屏幕中显示它,同时当前焦点放到 Synergy 配置中。Synergy 使得此过程相对简单,因为它提供了非常适合这项任务的各种调试级输出。

创建以清单 4 内容为开头的名为 processSynergy.pl 的文件。


清单 4. processSynergy.pl 变量,主循环
#!/usr/bin/perl -w
# processSynergy.pl - read Synergys DEBUG2 events
use strict;
my %disp = ();       # record display geometries, focus states
my $delay = 5;       # time in seconds
my $inTimeout = 0;   # timeout mode switcher
my $osdOn     = 0;   # on screen display switcher
my $lastTime = time; # monitor last activity

while( my $line = <STDIN> )
{
  $line =~ s/"//g;

  if( $line =~ /404: received client / )
  {
    # client connection geometry recording an initial setup
    my @parts = split " ", $line;
    my $name = $parts[4];

    $disp{$name}{mode} = 1;
    $disp{$name}{X} = (split "x", $parts[7])[0];
    $disp{$name}{Y} = (split "x", $parts[7])[1];

    print "$name geometry $parts[7]\n";

在声明变量(大多数将在稍后进行焦点超时检查时使用)后,程序将进入一个循环,对 STDIN 侦听 Synergy 事件。第一条 if 语句将处理客户机连接消息并把各个显示信息添加到 %disp hash 中。清单 5 将侦听 “焦点切换” 消息。


清单 5. 焦点切换检查
___FCKpd___4

在 Synergy 跟踪显示之间的焦点更改时,processSynergy.pl 程序将读取消息。在所有显示屏中更新包含信息的数据结构后(会在稍后的焦点超时检查中使用),将用连接客户机时记录的分辨率值调用动画程序。

要创建焦点跟踪指示器,请在设为 Synergy 服务器的计算机中运行以下命令:synergys -f -c configFile --debug DEBUG2 2>&1 | perl processSynergy.pl。您可能必须连接到每个客户机,并发出 xhost + SynergyServer,其中 “SynergySever” 是运行动画程序的计算机的名称。

在各个窗口中到处移动鼠标,查看跨越显示屏跟踪的焦点指示器和淡出效果。





构建超时焦点多屏幕指示器

创建非焦点的显示效果

指示非焦点的一种简单而有效的方法是在阿尔法混合的屏幕快照周围放置一个红框。查看图 1 获得示例效果。要创建与多屏幕焦点指示器结合使用的非焦点显示效果,请把清单 6 中所示的代码添加到 animation.c 的第 57 行中。


清单 6. renderBox 函数
___FCKpd___5

Ghosd examples/animation.c 文件再次发挥作用,renderBox 函数将绘制全屏幕阿尔法混合正方形,后接围绕图像的红色边框。要正确调用此函数,请在第 106 行插入清单 7 中所示的代码。


清单 7. 红框逻辑分支
___FCKpd___6

这些特殊显示效果将一直存在,直至被 processSynergy.pl 程序终止。在第 117 行中,把如下所示的代码:


清单 8. 先前的 render 循环
___FCKpd___7

更改为:


清单 9. 新 render 循环
___FCKpd___8

要构建此文件,请执行 make 命令,后接:./animation 1400 1050 1。假定屏幕分辨率为 1400x1050,您应当会看到一个颜色变淡的屏幕,四周围绕了一个红色框。按 Ctrl+c 组合键退出此种显示效果。

针对焦点超时检查修改 processSynergy.pl

要跟踪哪个屏幕拥有焦点以及输入何时停止,请对 processSynergy.pl 做出如下所述的修改。首先删除 47-49 行并替换为清单 10 中的代码。


清单 10. 动作、关键检查逻辑分支;心跳逻辑分支
___FCKpd___9

在被第一个 elsif 分支处理时,每个新鼠标或键盘事件都将重设 lastTime 变量。第二个 elsif 分支将查找由客户机发送到服务器的 CALV “心跳”。如果自发生上一个动作后已经过了特定秒数,效果将显示在各自相应的屏幕中。在第 71 行添加清单 11 中所示的代码以完成 processSynergy.pl 修改。


清单 11. 在活动中处理 destroy 动画
___FCKpd___10

注意,这种方法依赖于来自至少一台客户机的 CALV 心跳连接。如果网络变得不可用或者 CALV 消息没有显示,焦点指示器可能不会正确显示。





用法

要使用这个完成的超时焦点指示器,请在设为 Synergy 服务器的计算机中运行以下命令:synergys -f -c configFile --debug DEBUG2 2>&1 | perl processSynergy.pl。

如果未显示效果,则可能必须再次连接到每台客户机并发出 xhost + SynergyServer。在经过 “延迟” 秒数(在本例中为 5 秒)没有键盘或鼠标活动后,当前持有焦点的屏幕将显示一组绿框,而非焦点屏幕将显示阿尔法混合的红边框。





结束语

使用 Synergy 输出监视代码和 Ghosd 视觉效果可以跟踪焦点,并在达到某个时间阈值后将显示效果提供给当前焦点。现在当您返回到显示屏旁边时,可以省去在所有屏幕中查找光标的时间。

考虑把动画添加到指示器中以获得更加醒目的显示(当心可用库发生内存泄露)。链接终端会话与当前 Synergy 焦点信息以在当前查看的屏幕中提供远程系统的显示更新。如果可以考虑视觉效果,Ghosd 和 Synergy 调试信息可以帮助您显示它。(责任编辑:A6)

ne $name ) } keys %disp; $lastTime = time; $inTimeout = 0; print "switch to $name\n"; my $res = "export DISPLAY=$name:0; "; $res .= "./animation $disp{$name}{X} $disp{$name}{Y} $disp{$name}{mode} &"; system($res); }#if switch screen catch }#while line in

在 Synergy 跟踪显示之间的焦点更改时,processSynergy.pl 程序将读取消息。在所有显示屏中更新包含信息的数据结构后(会在稍后的焦点超时检查中使用),将用连接客户机时记录的分辨率值调用动画程序。

要创建焦点跟踪指示器,请在设为 Synergy 服务器的计算机中运行以下命令:synergys -f -c configFile --debug DEBUG2 2>&1 | perl processSynergy.pl。您可能必须连接到每个客户机,并发出 xhost + SynergyServer,其中 “SynergySever” 是运行动画程序的计算机的名称。

在各个窗口中到处移动鼠标,查看跨越显示屏跟踪的焦点指示器和淡出效果。





构建超时焦点多屏幕指示器

创建非焦点的显示效果

指示非焦点的一种简单而有效的方法是在阿尔法混合的屏幕快照周围放置一个红框。查看图 1 获得示例效果。要创建与多屏幕焦点指示器结合使用的非焦点显示效果,请把清单 6 中所示的代码添加到 animation.c 的第 57 行中。


清单 6. renderBox 函数
___FCKpd___5

Ghosd examples/animation.c 文件再次发挥作用,renderBox 函数将绘制全屏幕阿尔法混合正方形,后接围绕图像的红色边框。要正确调用此函数,请在第 106 行插入清单 7 中所示的代码。


清单 7. 红框逻辑分支
___FCKpd___6

这些特殊显示效果将一直存在,直至被 processSynergy.pl 程序终止。在第 117 行中,把如下所示的代码:


清单 8. 先前的 render 循环
___FCKpd___7

更改为:


清单 9. 新 render 循环
___FCKpd___8

要构建此文件,请执行 make 命令,后接:./animation 1400 1050 1。假定屏幕分辨率为 1400x1050,您应当会看到一个颜色变淡的屏幕,四周围绕了一个红色框。按 Ctrl+c 组合键退出此种显示效果。

针对焦点超时检查修改 processSynergy.pl

要跟踪哪个屏幕拥有焦点以及输入何时停止,请对 processSynergy.pl 做出如下所述的修改。首先删除 47-49 行并替换为清单 10 中的代码。


清单 10. 动作、关键检查逻辑分支;心跳逻辑分支
___FCKpd___9

在被第一个 elsif 分支处理时,每个新鼠标或键盘事件都将重设 lastTime 变量。第二个 elsif 分支将查找由客户机发送到服务器的 CALV “心跳”。如果自发生上一个动作后已经过了特定秒数,效果将显示在各自相应的屏幕中。在第 71 行添加清单 11 中所示的代码以完成 processSynergy.pl 修改。


清单 11. 在活动中处理 destroy 动画
___FCKpd___10

注意,这种方法依赖于来自至少一台客户机的 CALV 心跳连接。如果网络变得不可用或者 CALV 消息没有显示,焦点指示器可能不会正确显示。





用法

要使用这个完成的超时焦点指示器,请在设为 Synergy 服务器的计算机中运行以下命令:synergys -f -c configFile --debug DEBUG2 2>&1 | perl processSynergy.pl。

如果未显示效果,则可能必须再次连接到每台客户机并发出 xhost + SynergyServer。在经过 “延迟” 秒数(在本例中为 5 秒)没有键盘或鼠标活动后,当前持有焦点的屏幕将显示一组绿框,而非焦点屏幕将显示阿尔法混合的红边框。





结束语

使用 Synergy 输出监视代码和 Ghosd 视觉效果可以跟踪焦点,并在达到某个时间阈值后将显示效果提供给当前焦点。现在当您返回到显示屏旁边时,可以省去在所有屏幕中查找光标的时间。

考虑把动画添加到指示器中以获得更加醒目的显示(当心可用库发生内存泄露)。链接终端会话与当前 Synergy 焦点信息以在当前查看的屏幕中提供远程系统的显示更新。如果可以考虑视觉效果,Ghosd 和 Synergy 调试信息可以帮助您显示它。(责任编辑:A6)


时间:2008-10-31 10:27 来源:developerWorks 中国 作者:Nathan Harrington 原文链接

好文,顶一下
(0)
0%
文章真差,踩一下
(0)
0%
------分隔线----------------------------


把开源带在你的身边-精美linux小纪念品
无觅相关文章插件,快速提升流量