spice-gtk画鼠标

1、连接notify::cursor通知与回调函数(spice-widget.c)

static void channel_new(SpiceSession *s, SpiceChannel *channel, SpiceDisplay *display)
{
    ...
    if (SPICE_IS_CURSOR_CHANNEL(channel)) {
        gpointer cursor_shape;
        if (id != d->channel_id)
            return;
        d->cursor = SPICE_CURSOR_CHANNEL(channel);
        spice_g_signal_connect_object(channel, "notify::cursor",
                                      G_CALLBACK(cursor_set), display, 0);
        spice_g_signal_connect_object(channel, "cursor-move",
                                      G_CALLBACK(cursor_move), display, 0);
        spice_g_signal_connect_object(channel, "cursor-hide",
                                      G_CALLBACK(cursor_hide), display, 0);
        spice_g_signal_connect_object(channel, "cursor-reset",
                                      G_CALLBACK(cursor_reset), display, 0);
        spice_channel_connect(channel);
        g_object_get(G_OBJECT(channel), "cursor", &cursor_shape, NULL);
        if (cursor_shape != NULL) {
            g_boxed_free(SPICE_TYPE_CURSOR_SHAPE, cursor_shape);
            cursor_set(d->cursor, NULL, display);
        }
        return;
    }
    ...
}

2、cursor_channel消息回调函数(channel-cursor.c)

static void channel_set_handlers(SpiceChannelClass *klass)
{
    static const spice_msg_handler handlers[] = {
        [ SPICE_MSG_CURSOR_INIT ]              = cursor_handle_init,
        [ SPICE_MSG_CURSOR_RESET ]             = cursor_handle_reset,
        [ SPICE_MSG_CURSOR_SET ]               = cursor_handle_set,
        [ SPICE_MSG_CURSOR_MOVE ]              = cursor_handle_move,
        [ SPICE_MSG_CURSOR_HIDE ]              = cursor_handle_hide,
        [ SPICE_MSG_CURSOR_TRAIL ]             = cursor_handle_trail,
        [ SPICE_MSG_CURSOR_INVAL_ONE ]         = cursor_handle_inval_one,
        [ SPICE_MSG_CURSOR_INVAL_ALL ]         = cursor_handle_inval_all,
    };
    spice_channel_set_handlers(klass, handlers, G_N_ELEMENTS(handlers));
}

cursor_handle_set的回调函数实现如下:(channel-cursor.c)

/* coroutine context */
static void cursor_handle_set(SpiceChannel *channel, SpiceMsgIn *in)
{
    SpiceMsgCursorSet *set = spice_msg_in_parsed(in);
    SpiceCursorChannelPrivate *c = SPICE_CURSOR_CHANNEL(channel)->priv;
    display_cursor *cursor;
    g_return_if_fail(c->init_done == TRUE);
    cursor = set_cursor(channel, &set->cursor);
    if (cursor)
        emit_cursor_set(channel, cursor);
    else
        g_coroutine_signal_emit(channel, signals[SPICE_CURSOR_HIDE], 0);
    if (cursor)
        display_cursor_unref(cursor);
}

发送鼠标的通知和SPICE_CURSOR_SET信号(channel-cursor.c)

/* coroutine context */
static void emit_cursor_set(SpiceChannel *channel, display_cursor *cursor)
{
    SpiceCursorChannelPrivate *c;
    g_return_if_fail(cursor != NULL);
    c = SPICE_CURSOR_CHANNEL(channel)->priv;
    c->last_cursor.type = cursor->hdr.type;
    c->last_cursor.width = cursor->hdr.width;
    c->last_cursor.height = cursor->hdr.height;
    c->last_cursor.hot_spot_x = cursor->hdr.hot_spot_x;
    c->last_cursor.hot_spot_y = cursor->hdr.hot_spot_y;
    g_free(c->last_cursor.data);
    c->last_cursor.data = g_memdup(cursor->data, cursor->hdr.width * cursor->hdr.height * 4);
    g_coroutine_object_notify(G_OBJECT(channel), "cursor");
    g_coroutine_signal_emit(channel, signals[SPICE_CURSOR_SET], 0,
                            cursor->hdr.width, cursor->hdr.height,
                            cursor->hdr.hot_spot_x, cursor->hdr.hot_spot_y,
                            cursor->default_cursor ? NULL : cursor->data);
}

3、将鼠标图片数据保存到mouse_pixbuf中(channel-cursor.c)

static void cursor_set(SpiceCursorChannel *channel,
                       G_GNUC_UNUSED GParamSpec *pspec,
                       gpointer data)
{
    SpiceDisplay *display = data;
    SpiceDisplayPrivate *d = display->priv;
    SpiceCursorShape *cursor_shape;
    g_object_get(G_OBJECT(channel), "cursor", &cursor_shape, NULL);
    if (G_UNLIKELY(cursor_shape == NULL || cursor_shape->data == NULL)) {
        if (cursor_shape != NULL) {
            g_boxed_free(SPICE_TYPE_CURSOR_SHAPE, cursor_shape);
        }
        return;
    }
    cursor_invalidate(display);
    g_clear_object(&d->mouse_pixbuf);
    d->mouse_pixbuf = gdk_pixbuf_new_from_data(cursor_shape->data,
                                               GDK_COLORSPACE_RGB,
                                               TRUE, 8,
                                               cursor_shape->width,
                                               cursor_shape->height,
                                               cursor_shape->width * 4,
                                               cursor_shape_destroy, cursor_shape);
    d->mouse_hotspot.x = cursor_shape->hot_spot_x;
    d->mouse_hotspot.y = cursor_shape->hot_spot_y;
    update_mouse_cursor(display);
}

4、update_mouse_cursor通过gdk_cairo_surface_create_from_pixbuf画鼠标形状

static void update_mouse_cursor(SpiceDisplay *display)
{
    SpiceDisplayPrivate *d = display->priv;
    GdkCursor *cursor = NULL;
    cairo_t *cursor_ctx;
    cairo_surface_t *surface, *target;
    double scale;
    gint scale_factor;
    gint hotspot_x, hotspot_y;

    if (G_UNLIKELY(!d->mouse_pixbuf)) {
        return;
    }

    if (!d->ready || !d->monitor_ready) {
        return;
    }

    spice_display_get_scaling(display, &scale, NULL, NULL, NULL, NULL);
    scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(display));
    scale = MAX(0.5, scale);
    cairo_surface_destroy(d->cursor_surface);

    /* 缩放鼠标形状 */
    surface = gdk_cairo_surface_create_from_pixbuf(d->mouse_pixbuf, 0, gtk_widget_get_window(GTK_WIDGET(display)));
    target = cairo_image_surface_create(cairo_image_surface_get_format(surface),
                                        scale * gdk_pixbuf_get_width(d->mouse_pixbuf),
                                        scale * gdk_pixbuf_get_height(d->mouse_pixbuf));
    cairo_surface_set_device_scale(target, scale_factor, scale_factor);
    cursor_ctx = cairo_create(target);
    cairo_scale(cursor_ctx, scale, scale);
    cairo_set_source_surface(cursor_ctx, surface, 0, 0);
    cairo_paint(cursor_ctx);

    d->cursor_surface = cairo_surface_reference(cairo_get_target(cursor_ctx));
    cairo_surface_destroy(target);
    cairo_surface_destroy(surface);
    cairo_destroy(cursor_ctx);

    hotspot_x = d->mouse_hotspot.x * scale;
    hotspot_y = d->mouse_hotspot.y * scale;

#ifdef GDK_WINDOWING_X11
    /* undo hotspot scaling in gdkcursor */
    if (GDK_IS_X11_DISPLAY(gtk_widget_get_display(GTK_WIDGET(display)))) {
        hotspot_x /= scale_factor;
        hotspot_y /= scale_factor;
    }
#endif
    cursor = gdk_cursor_new_from_surface(gtk_widget_get_display(GTK_WIDGET(display)),
                                         d->cursor_surface,
                                         hotspot_x,
                                         hotspot_y);

#if HAVE_EGL
    if (egl_enabled(d))
        spice_egl_cursor_set(display);
#endif

    if (d->show_cursor) {
        /* unhide */
        g_clear_object(&d->show_cursor);
        if (d->mouse_mode == SPICE_MOUSE_MODE_SERVER) {
            /* keep a hidden cursor, will be shown in cursor_move() */
            d->show_cursor = cursor;
            return;
        }
    }

    if (d->mouse_cursor != NULL) {
        g_object_unref(d->mouse_cursor);
    }
    d->mouse_cursor = cursor;

    update_mouse_pointer(display);
    cursor_invalidate(display);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值