让notebook在3D中切换不同的虚拟桌面

     使用AIGLX的x server, 实现3d是通过在原先2d的server中添加3d指令部分来实现的,3d效果会经过原先2dserver的一个转发, 因此,我们可以利用这一特性,通过让server实现一些原有2d的一些特性间接实现3d效果。就如同我们需要点击gtk的notebook, 让按下其tag时可以伴随有3d虚拟桌面的转换。
      刚开始解决这个问题的时候,以为3d部分是将workspace虚拟为各个桌面的结果,结果发现使用这个方法切换桌面时失败率很高,但偶尔可以成功。研究 gnome pager, 发现其每次都可以切成功,而且随着3d虚拟桌面的切换,pager也会随之在各区域内切换。 于是研究了一下gnome pager, 并在我们的代码里加入gnome pager的功能,发现2d下很正常, 3d下竟完全没有效果。 绝望之余仔细研究了一下gnome pager的代码,发现它对3d另有一套viewport的处理机制,于是想起用libxfcegui时也使用了viewport,且每次 viewport改变的值都一样,是不是正是因为这个原因导致3d时每次都不成功呢? 于是决定还是重新回到至少对切换有反应的libxfcegui的实现方案上, 测试了去掉viewport语句,改变不同viewport改变值等方法,确定了下面的方法。


步骤:

1.   发射切换信号
在notebook的switch-page相应回调函数nb_switch_page

g_signal_connect (desktop->priv->notebook, "switch-page", G_CALLBACK (nb_switch_page), NULL);
且在此函数中调用如下代码:

  int viewport_x, viewport_y;
  viewport_x  = netk_screen_get_width  (screen) * page_num;
  viewport_y = netk_screen_get_height (screen) * page_num;
  netk_screen_move_viewport(screen, viewport_x, viewport_y);

其中screen是一个全局静态变量
static NetkScreen *screen;

这里,
netk_screen_move_viewport 是一个libxfcegui4的库函数:
/**
 * netk_screen_move_viewport:
 * @screen: a #NetkScreen
 * @x: X offset of viewport
 * @y: Y offset of viewport
 *
 * Ask window manager to move the viewport of the current workspace.
 */
void netk_screen_move_viewport (NetkScreen * screen, int x, int y)

    g_return_if_fail (NETK_IS_SCREEN (screen));
    g_return_if_fail (x >= 0);
    g_return_if_fail (y >= 0);

    p_netk_change_viewport (NETK_SCREEN_XSCREEN (screen), x, y);


void
p_netk_change_viewport (Screen * screen, int x, int y)
{
    XEvent xev;

    xev.xclient.type = ClientMessage;
    xev.xclient.serial = 0;
    xev.xclient.send_event = True;
    xev.xclient.display = gdk_display;
    xev.xclient.window = RootWindowOfScreen (screen);
    xev.xclient.message_type = p_netk_atom_get ("_NET_DESKTOP_VIEWPORT");
    xev.xclient.format = 32;
    xev.xclient.data.l[0] = x;
    xev.xclient.data.l[1] = y;
    xev.xclient.data.l[2] = 0;
    xev.xclient.data.l[3] = 0;

    XSendEvent (gdk_display,
                RootWindowOfScreen (screen),
                False,
                SubstructureRedirectMask | SubstructureNotifyMask, &xev);
}

       可以看到,让notebook不同的page按下时可以跳转到3d桌面的不同面的关键就是要和X server通信,并让其切换当前工作区的viewport(视角)。

2.   接受切换桌面消息
       另一方面, 在3D桌面环境下,当切换到 了立方体的另一个面的时候,需要notebook相应也跳动另一个tag,于是让其建立如下信号连接,  让X server在切换了视角之后,通知notebook

g_signal_connect (screen, "viewports_changed", G_CALLBACK (viewports_changed_callback), desktop->priv->notebook);

viewports_changed_callback的实现如下:
static void
viewports_changed_callback (NetkScreen * screen, gpointer data)
{
     GtkNotebook *notebook = GTK_NOTEBOOK (data);
    NetkWorkspace *space;
    space = netk_screen_get_active_workspace(screen);
    int viewport_x = netk_workspace_get_viewport_x (space);
    int screen_width = netk_screen_get_width  (screen);
    int page_num = viewport_x / screen_width;

   gtk_notebook_set_current_page(notebook, page_num);
}


viewports_changed信号为NetkScreenClass所注册的一个信号:

static void
netk_screen_class_init (NetkScreenClass * klass)
{
 ...
    signals[VIEWPORTS_CHANGED] =
        g_signal_new (I_("viewports_changed"),
                      G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST,
                      G_STRUCT_OFFSET (NetkScreenClass, viewports_changed),
                      NULL, NULL,
                      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
...
}




附:
Netscreen 及其class的定义:

typedef struct _NetkScreen NetkScreen;
typedef struct _NetkScreenClass NetkScreenClass;
typedef struct _NetkScreenPrivate NetkScreenPrivate;

struct _NetkScreen
{
    GObject parent_instance;

    NetkScreenPrivate *priv;
};

struct _NetkScreenClass
{
    GObjectClass parent_class;

    /* focused window changed */
    void (*active_window_changed) (NetkScreen * screen);
    /* current workspace changed */
    void (*active_workspace_changed) (NetkScreen * screen);
    /* stacking order changed */
    void (*window_stacking_changed) (NetkScreen * screen);
 /* window added */
    void (*window_opened) (NetkScreen * screen, NetkWindow * window);
    /* window removed */
    void (*window_closed) (NetkScreen * screen, NetkWindow * window);
    /* new workspace */
    void (*workspace_created) (NetkScreen * screen, NetkWorkspace * space);
    /* workspace gone */
    void (*workspace_destroyed) (NetkScreen * screen, NetkWorkspace * space);
    /* new app */
    void (*application_opened) (NetkScreen * screen, NetkApplication * app);
    /* app gone */
    void (*application_closed) (NetkScreen * screen, NetkApplication * app);
    /* new class group */
    void (* class_group_opened) (NetkScreen *screen, NetkClassGroup *class_group);
    /* class group gone */
    void (* class_group_closed) (NetkScreen *screen, NetkClassGroup *class_group);

    /* New background */
    void (*background_changed) (NetkScreen * screen);

    /* Toggle showing desktop */
    void (*showing_desktop_changed) (NetkScreen * screen);

    /* Viewport stuff changed */
    void (*viewports_changed) (NetkScreen * screen);
    void (*pad1) (void);
    void (*pad2) (void);
    void (*pad3) (void);
    void (*pad4) (void);
    void (*pad5) (void);
    void (*pad6) (void);
    void (*pad7) (void);
    void (*pad8) (void);
};


struct _NetkScreenPrivate
{
    int number;
    Window xroot;
    Screen *xscreen;

    /* in map order */
    GList *mapped_windows;
    /* in stacking order */
    GList *stacked_windows;
    /* in 0-to-N order */
    GList *workspaces;

    NetkWindow *active_window;
    NetkWorkspace *active_workspace;

    Pixmap bg_pixmap;

    guint update_handler;

    guint showing_desktop:1;

    /* if you add flags, be sure to set them
       * when we create the screen so we get an initial update
     */
    guint need_update_stack_list:1;
    guint need_update_workspace_list:1;
    guint need_update_viewport_settings:1;
    guint need_update_active_workspace:1;
    guint need_update_active_window:1;
    guint need_update_workspace_names:1;
    guint need_update_bg_pixmap:1;
    guint need_update_showing_desktop:1;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值