135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2014 Red Hat, Inc.
335c4bbdfSmrg *
435c4bbdfSmrg * Permission is hereby granted, free of charge, to any person obtaining a
535c4bbdfSmrg * copy of this software and associated documentation files (the "Software"),
635c4bbdfSmrg * to deal in the Software without restriction, including without limitation
735c4bbdfSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
835c4bbdfSmrg * and/or sell copies of the Software, and to permit persons to whom the
935c4bbdfSmrg * Software is furnished to do so, subject to the following conditions:
1035c4bbdfSmrg *
1135c4bbdfSmrg * The above copyright notice and this permission notice (including the next
1235c4bbdfSmrg * paragraph) shall be included in all copies or substantial portions of the
1335c4bbdfSmrg * Software.
1435c4bbdfSmrg *
1535c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1635c4bbdfSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1735c4bbdfSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1835c4bbdfSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1935c4bbdfSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2035c4bbdfSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2135c4bbdfSmrg * DEALINGS IN THE SOFTWARE.
2235c4bbdfSmrg *
2335c4bbdfSmrg * Author:
2435c4bbdfSmrg *      Adam Jackson <ajax@redhat.com>
2535c4bbdfSmrg */
2635c4bbdfSmrg
271b5d61b8Smrg#ifdef HAVE_DIX_CONFIG_H
281b5d61b8Smrg#include <dix-config.h>
2935c4bbdfSmrg#endif
3035c4bbdfSmrg#include "ephyr.h"
3135c4bbdfSmrg#include "ephyrlog.h"
3235c4bbdfSmrg#include "hostx.h"
3335c4bbdfSmrg#include "cursorstr.h"
3435c4bbdfSmrg#include <xcb/render.h>
3535c4bbdfSmrg#include <xcb/xcb_renderutil.h>
3635c4bbdfSmrg
3735c4bbdfSmrgstatic DevPrivateKeyRec ephyrCursorPrivateKey;
3835c4bbdfSmrg
3935c4bbdfSmrgtypedef struct _ephyrCursor {
4035c4bbdfSmrg    xcb_cursor_t cursor;
4135c4bbdfSmrg} ephyrCursorRec, *ephyrCursorPtr;
4235c4bbdfSmrg
4335c4bbdfSmrgstatic ephyrCursorPtr
4435c4bbdfSmrgephyrGetCursor(CursorPtr cursor)
4535c4bbdfSmrg{
4635c4bbdfSmrg    return dixGetPrivateAddr(&cursor->devPrivates, &ephyrCursorPrivateKey);
4735c4bbdfSmrg}
4835c4bbdfSmrg
4935c4bbdfSmrgstatic void
5035c4bbdfSmrgephyrRealizeCoreCursor(EphyrScrPriv *scr, CursorPtr cursor)
5135c4bbdfSmrg{
5235c4bbdfSmrg    ephyrCursorPtr hw = ephyrGetCursor(cursor);
5335c4bbdfSmrg    xcb_connection_t *conn = hostx_get_xcbconn();
5435c4bbdfSmrg    xcb_pixmap_t source, mask;
5535c4bbdfSmrg    xcb_image_t *image;
5635c4bbdfSmrg    xcb_gcontext_t gc;
5735c4bbdfSmrg    int w = cursor->bits->width, h = cursor->bits->height;
5835c4bbdfSmrg    uint32_t gcmask = XCB_GC_FUNCTION |
5935c4bbdfSmrg                      XCB_GC_PLANE_MASK |
6035c4bbdfSmrg                      XCB_GC_FOREGROUND |
6135c4bbdfSmrg                      XCB_GC_BACKGROUND |
6235c4bbdfSmrg                      XCB_GC_CLIP_MASK;
6335c4bbdfSmrg    uint32_t val[] = {
6435c4bbdfSmrg        XCB_GX_COPY,    /* function */
6535c4bbdfSmrg        ~0,             /* planemask */
6635c4bbdfSmrg        1L,             /* foreground */
6735c4bbdfSmrg        0L,             /* background */
6835c4bbdfSmrg        None,           /* clipmask */
6935c4bbdfSmrg    };
7035c4bbdfSmrg
7135c4bbdfSmrg    source = xcb_generate_id(conn);
7235c4bbdfSmrg    mask = xcb_generate_id(conn);
7335c4bbdfSmrg    xcb_create_pixmap(conn, 1, source, scr->win, w, h);
7435c4bbdfSmrg    xcb_create_pixmap(conn, 1, mask, scr->win, w, h);
7535c4bbdfSmrg
7635c4bbdfSmrg    gc = xcb_generate_id(conn);
7735c4bbdfSmrg    xcb_create_gc(conn, gc, source, gcmask, val);
7835c4bbdfSmrg
7935c4bbdfSmrg    image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_XY_BITMAP,
8035c4bbdfSmrg                                    1, NULL, ~0, NULL);
8135c4bbdfSmrg    image->data = cursor->bits->source;
8235c4bbdfSmrg    xcb_image_put(conn, source, gc, image, 0, 0, 0);
8335c4bbdfSmrg    xcb_image_destroy(image);
8435c4bbdfSmrg
8535c4bbdfSmrg    image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_XY_BITMAP,
8635c4bbdfSmrg                                    1, NULL, ~0, NULL);
8735c4bbdfSmrg    image->data = cursor->bits->mask;
8835c4bbdfSmrg    xcb_image_put(conn, mask, gc, image, 0, 0, 0);
8935c4bbdfSmrg    xcb_image_destroy(image);
9035c4bbdfSmrg
9135c4bbdfSmrg    xcb_free_gc(conn, gc);
9235c4bbdfSmrg
9335c4bbdfSmrg    hw->cursor = xcb_generate_id(conn);
9435c4bbdfSmrg    xcb_create_cursor(conn, hw->cursor, source, mask,
9535c4bbdfSmrg                      cursor->foreRed, cursor->foreGreen, cursor->foreBlue,
9635c4bbdfSmrg                      cursor->backRed, cursor->backGreen, cursor->backBlue,
9735c4bbdfSmrg                      cursor->bits->xhot, cursor->bits->yhot);
9835c4bbdfSmrg
9935c4bbdfSmrg    xcb_free_pixmap(conn, source);
10035c4bbdfSmrg    xcb_free_pixmap(conn, mask);
10135c4bbdfSmrg}
10235c4bbdfSmrg
10335c4bbdfSmrgstatic xcb_render_pictformat_t
10435c4bbdfSmrgget_argb_format(void)
10535c4bbdfSmrg{
10635c4bbdfSmrg    static xcb_render_pictformat_t format;
10735c4bbdfSmrg    if (format == None) {
10835c4bbdfSmrg        xcb_connection_t *conn = hostx_get_xcbconn();
10935c4bbdfSmrg        xcb_render_query_pict_formats_cookie_t cookie;
11035c4bbdfSmrg        xcb_render_query_pict_formats_reply_t *formats;
11135c4bbdfSmrg
11235c4bbdfSmrg        cookie = xcb_render_query_pict_formats(conn);
11335c4bbdfSmrg        formats =
11435c4bbdfSmrg            xcb_render_query_pict_formats_reply(conn, cookie, NULL);
11535c4bbdfSmrg
11635c4bbdfSmrg        format =
11735c4bbdfSmrg            xcb_render_util_find_standard_format(formats,
11835c4bbdfSmrg                                                 XCB_PICT_STANDARD_ARGB_32)->id;
11935c4bbdfSmrg
12035c4bbdfSmrg        free(formats);
12135c4bbdfSmrg    }
12235c4bbdfSmrg
12335c4bbdfSmrg    return format;
12435c4bbdfSmrg}
12535c4bbdfSmrg
12635c4bbdfSmrgstatic void
12735c4bbdfSmrgephyrRealizeARGBCursor(EphyrScrPriv *scr, CursorPtr cursor)
12835c4bbdfSmrg{
12935c4bbdfSmrg    ephyrCursorPtr hw = ephyrGetCursor(cursor);
13035c4bbdfSmrg    xcb_connection_t *conn = hostx_get_xcbconn();
13135c4bbdfSmrg    xcb_gcontext_t gc;
13235c4bbdfSmrg    xcb_pixmap_t source;
13335c4bbdfSmrg    xcb_render_picture_t picture;
13435c4bbdfSmrg    xcb_image_t *image;
13535c4bbdfSmrg    int w = cursor->bits->width, h = cursor->bits->height;
13635c4bbdfSmrg
13735c4bbdfSmrg    /* dix' storage is PICT_a8r8g8b8 */
13835c4bbdfSmrg    source = xcb_generate_id(conn);
13935c4bbdfSmrg    xcb_create_pixmap(conn, 32, source, scr->win, w, h);
14035c4bbdfSmrg
14135c4bbdfSmrg    gc = xcb_generate_id(conn);
14235c4bbdfSmrg    xcb_create_gc(conn, gc, source, 0, NULL);
14335c4bbdfSmrg    image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_Z_PIXMAP,
14435c4bbdfSmrg                                    32, NULL, ~0, NULL);
14535c4bbdfSmrg    image->data = (void *)cursor->bits->argb;
14635c4bbdfSmrg    xcb_image_put(conn, source, gc, image, 0, 0, 0);
14735c4bbdfSmrg    xcb_free_gc(conn, gc);
14835c4bbdfSmrg    xcb_image_destroy(image);
14935c4bbdfSmrg
15035c4bbdfSmrg    picture = xcb_generate_id(conn);
15135c4bbdfSmrg    xcb_render_create_picture(conn, picture, source, get_argb_format(),
15235c4bbdfSmrg                              0, NULL);
15335c4bbdfSmrg    xcb_free_pixmap(conn, source);
15435c4bbdfSmrg
15535c4bbdfSmrg    hw->cursor = xcb_generate_id(conn);
15635c4bbdfSmrg    xcb_render_create_cursor(conn, hw->cursor, picture,
15735c4bbdfSmrg                             cursor->bits->xhot, cursor->bits->yhot);
15835c4bbdfSmrg
15935c4bbdfSmrg    xcb_render_free_picture(conn, picture);
16035c4bbdfSmrg}
16135c4bbdfSmrg
16235c4bbdfSmrgstatic Bool
16335c4bbdfSmrgcan_argb_cursor(void)
16435c4bbdfSmrg{
16535c4bbdfSmrg    static const xcb_render_query_version_reply_t *v;
16635c4bbdfSmrg
16735c4bbdfSmrg    if (!v)
16835c4bbdfSmrg        v = xcb_render_util_query_version(hostx_get_xcbconn());
16935c4bbdfSmrg
17035c4bbdfSmrg    return v->major_version == 0 && v->minor_version >= 5;
17135c4bbdfSmrg}
17235c4bbdfSmrg
17335c4bbdfSmrgstatic Bool
17435c4bbdfSmrgephyrRealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor)
17535c4bbdfSmrg{
17635c4bbdfSmrg    KdScreenPriv(screen);
17735c4bbdfSmrg    KdScreenInfo *kscr = pScreenPriv->screen;
17835c4bbdfSmrg    EphyrScrPriv *scr = kscr->driver;
17935c4bbdfSmrg
18035c4bbdfSmrg    if (cursor->bits->argb && can_argb_cursor())
18135c4bbdfSmrg        ephyrRealizeARGBCursor(scr, cursor);
18235c4bbdfSmrg    else
18335c4bbdfSmrg    {
18435c4bbdfSmrg        ephyrRealizeCoreCursor(scr, cursor);
18535c4bbdfSmrg    }
18635c4bbdfSmrg    return TRUE;
18735c4bbdfSmrg}
18835c4bbdfSmrg
18935c4bbdfSmrgstatic Bool
19035c4bbdfSmrgephyrUnrealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor)
19135c4bbdfSmrg{
19235c4bbdfSmrg    ephyrCursorPtr hw = ephyrGetCursor(cursor);
19335c4bbdfSmrg
19435c4bbdfSmrg    if (hw->cursor) {
19535c4bbdfSmrg        xcb_free_cursor(hostx_get_xcbconn(), hw->cursor);
19635c4bbdfSmrg        hw->cursor = None;
19735c4bbdfSmrg    }
19835c4bbdfSmrg
19935c4bbdfSmrg    return TRUE;
20035c4bbdfSmrg}
20135c4bbdfSmrg
20235c4bbdfSmrgstatic void
20335c4bbdfSmrgephyrSetCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor, int x,
20435c4bbdfSmrg               int y)
20535c4bbdfSmrg{
20635c4bbdfSmrg    KdScreenPriv(screen);
20735c4bbdfSmrg    KdScreenInfo *kscr = pScreenPriv->screen;
20835c4bbdfSmrg    EphyrScrPriv *scr = kscr->driver;
20935c4bbdfSmrg    uint32_t attr = None;
21035c4bbdfSmrg
21135c4bbdfSmrg    if (cursor)
21235c4bbdfSmrg        attr = ephyrGetCursor(cursor)->cursor;
21335c4bbdfSmrg    else
21435c4bbdfSmrg        attr = hostx_get_empty_cursor();
21535c4bbdfSmrg
21635c4bbdfSmrg    xcb_change_window_attributes(hostx_get_xcbconn(), scr->win,
21735c4bbdfSmrg                                 XCB_CW_CURSOR, &attr);
21835c4bbdfSmrg    xcb_flush(hostx_get_xcbconn());
21935c4bbdfSmrg}
22035c4bbdfSmrg
22135c4bbdfSmrgstatic void
22235c4bbdfSmrgephyrMoveCursor(DeviceIntPtr dev, ScreenPtr screen, int x, int y)
22335c4bbdfSmrg{
22435c4bbdfSmrg}
22535c4bbdfSmrg
22635c4bbdfSmrgstatic Bool
22735c4bbdfSmrgephyrDeviceCursorInitialize(DeviceIntPtr dev, ScreenPtr screen)
22835c4bbdfSmrg{
22935c4bbdfSmrg    return TRUE;
23035c4bbdfSmrg}
23135c4bbdfSmrg
23235c4bbdfSmrgstatic void
23335c4bbdfSmrgephyrDeviceCursorCleanup(DeviceIntPtr dev, ScreenPtr screen)
23435c4bbdfSmrg{
23535c4bbdfSmrg}
23635c4bbdfSmrg
23735c4bbdfSmrgmiPointerSpriteFuncRec EphyrPointerSpriteFuncs = {
23835c4bbdfSmrg    ephyrRealizeCursor,
23935c4bbdfSmrg    ephyrUnrealizeCursor,
24035c4bbdfSmrg    ephyrSetCursor,
24135c4bbdfSmrg    ephyrMoveCursor,
24235c4bbdfSmrg    ephyrDeviceCursorInitialize,
24335c4bbdfSmrg    ephyrDeviceCursorCleanup
24435c4bbdfSmrg};
24535c4bbdfSmrg
24635c4bbdfSmrgBool
24735c4bbdfSmrgephyrCursorInit(ScreenPtr screen)
24835c4bbdfSmrg{
249d9252ffbSmrg    if (!dixRegisterPrivateKey(&ephyrCursorPrivateKey, PRIVATE_CURSOR,
25035c4bbdfSmrg                               sizeof(ephyrCursorRec)))
25135c4bbdfSmrg        return FALSE;
25235c4bbdfSmrg
25335c4bbdfSmrg    miPointerInitialize(screen,
25435c4bbdfSmrg                        &EphyrPointerSpriteFuncs,
25535c4bbdfSmrg                        &ephyrPointerScreenFuncs, FALSE);
25635c4bbdfSmrg
25735c4bbdfSmrg    return TRUE;
25835c4bbdfSmrg}
259