123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599 | // Copyright (C) 2022 The Qt Company Ltd.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#include"qxcbcursor.h"#include"qxcbconnection.h"#include"qxcbwindow.h"#include"qxcbimage.h"#include"qxcbxsettings.h"#include <QtGui/QWindow>#include <QtGui/QBitmap>#include <QtGui/private/qguiapplication_p.h>#include <qpa/qplatformtheme.h>#if QT_CONFIG(xcb_xlib)#include <X11/cursorfont.h>#else#include"qxcbcursorfont.h"#endif#include <xcb/xfixes.h>#include <xcb/xcb_image.h> QT_BEGIN_NAMESPACE using namespaceQt::StringLiterals;static xcb_font_t cursorFont =0;static int cursorCount =0;#ifndef QT_NO_CURSORstatic uint8_t cur_blank_bits[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};static const uint8_t cur_ver_bits[] = {0x00,0x00,0x00,0x00,0x80,0x01,0xc0,0x03,0xe0,0x07,0xf0,0x0f,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xf0,0x0f,0xe0,0x07,0xc0,0x03,0x80,0x01,0x00,0x00};static const uint8_t mcur_ver_bits[] = {0x00,0x00,0x80,0x03,0xc0,0x07,0xe0,0x0f,0xf0,0x1f,0xf8,0x3f,0xfc,0x7f,0xc0,0x07,0xc0,0x07,0xc0,0x07,0xfc,0x7f,0xf8,0x3f,0xf0,0x1f,0xe0,0x0f,0xc0,0x07,0x80,0x03};static const uint8_t cur_hor_bits[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x08,0x30,0x18,0x38,0x38,0xfc,0x7f,0xfc,0x7f,0x38,0x38,0x30,0x18,0x20,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};static const uint8_t mcur_hor_bits[] = {0x00,0x00,0x00,0x00,0x40,0x04,0x60,0x0c,0x70,0x1c,0x78,0x3c,0xfc,0x7f,0xfe,0xff,0xfe,0xff,0xfe,0xff,0xfc,0x7f,0x78,0x3c,0x70,0x1c,0x60,0x0c,0x40,0x04,0x00,0x00};static const uint8_t cur_bdiag_bits[] = {0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x3e,0x00,0x3c,0x00,0x3e,0x00,0x37,0x88,0x23,0xd8,0x01,0xf8,0x00,0x78,0x00,0xf8,0x00,0xf8,0x01,0x00,0x00,0x00,0x00,0x00,0x00};static const uint8_t mcur_bdiag_bits[] = {0x00,0x00,0xc0,0x7f,0x80,0x7f,0x00,0x7f,0x00,0x7e,0x04,0x7f,0x8c,0x7f,0xdc,0x77,0xfc,0x63,0xfc,0x41,0xfc,0x00,0xfc,0x01,0xfc,0x03,0xfc,0x07,0x00,0x00,0x00,0x00};static const uint8_t cur_fdiag_bits[] = {0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x01,0xf8,0x00,0x78,0x00,0xf8,0x00,0xd8,0x01,0x88,0x23,0x00,0x37,0x00,0x3e,0x00,0x3c,0x00,0x3e,0x00,0x3f,0x00,0x00,0x00,0x00};static const uint8_t mcur_fdiag_bits[] = {0x00,0x00,0x00,0x00,0xfc,0x07,0xfc,0x03,0xfc,0x01,0xfc,0x00,0xfc,0x41,0xfc,0x63,0xdc,0x77,0x8c,0x7f,0x04,0x7f,0x00,0x7e,0x00,0x7f,0x80,0x7f,0xc0,0x7f,0x00,0x00};static const uint8_t*cursor_bits16[] = { cur_ver_bits, mcur_ver_bits, cur_hor_bits, mcur_hor_bits, cur_bdiag_bits, mcur_bdiag_bits, cur_fdiag_bits, mcur_fdiag_bits,nullptr,nullptr, cur_blank_bits, cur_blank_bits };static const uint8_t vsplit_bits[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xc0,0x01,0x00,0x00,0xe0,0x03,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x7f,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,0x01,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};static const uint8_t vsplitm_bits[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xc0,0x01,0x00,0x00,0xe0,0x03,0x00,0x00,0xf0,0x07,0x00,0x00,0xf8,0x0f,0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,0x80,0xff,0xff,0x00,0x80,0xff,0xff,0x00,0x80,0xff,0xff,0x00,0x80,0xff,0xff,0x00,0x80,0xff,0xff,0x00,0x80,0xff,0xff,0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,0x00,0xf8,0x0f,0x00,0x00,0xf0,0x07,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,0x01,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};static const uint8_t hsplit_bits[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x41,0x82,0x00,0x80,0x41,0x82,0x01,0xc0,0x7f,0xfe,0x03,0x80,0x41,0x82,0x01,0x00,0x41,0x82,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};static const uint8_t hsplitm_bits[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x07,0x00,0x00,0xe0,0x07,0x00,0x00,0xe0,0x07,0x00,0x00,0xe0,0x07,0x00,0x00,0xe2,0x47,0x00,0x00,0xe3,0xc7,0x00,0x80,0xe3,0xc7,0x01,0xc0,0xff,0xff,0x03,0xe0,0xff,0xff,0x07,0xc0,0xff,0xff,0x03,0x80,0xe3,0xc7,0x01,0x00,0xe3,0xc7,0x00,0x00,0xe2,0x47,0x00,0x00,0xe0,0x07,0x00,0x00,0xe0,0x07,0x00,0x00,0xe0,0x07,0x00,0x00,0xe0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};static const uint8_t whatsthis_bits[] = {0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x05,0xf0,0x07,0x00,0x09,0x18,0x0e,0x00,0x11,0x1c,0x0e,0x00,0x21,0x1c,0x0e,0x00,0x41,0x1c,0x0e,0x00,0x81,0x1c,0x0e,0x00,0x01,0x01,0x07,0x00,0x01,0x82,0x03,0x00,0xc1,0xc7,0x01,0x00,0x49,0xc0,0x01,0x00,0x95,0xc0,0x01,0x00,0x93,0xc0,0x01,0x00,0x21,0x01,0x00,0x00,0x20,0xc1,0x01,0x00,0x40,0xc2,0x01,0x00,0x40,0x02,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, };static const uint8_t whatsthism_bits[] = {0x01,0x00,0x00,0x00,0x03,0xf0,0x07,0x00,0x07,0xf8,0x0f,0x00,0x0f,0xfc,0x1f,0x00,0x1f,0x3e,0x1f,0x00,0x3f,0x3e,0x1f,0x00,0x7f,0x3e,0x1f,0x00,0xff,0x3e,0x1f,0x00,0xff,0x9d,0x0f,0x00,0xff,0xc3,0x07,0x00,0xff,0xe7,0x03,0x00,0x7f,0xe0,0x03,0x00,0xf7,0xe0,0x03,0x00,0xf3,0xe0,0x03,0x00,0xe1,0xe1,0x03,0x00,0xe0,0xe1,0x03,0x00,0xc0,0xe3,0x03,0x00,0xc0,0xe3,0x03,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, };static const uint8_t busy_bits[] = {0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x41,0xe0,0xff,0x00,0x81,0x20,0x80,0x00,0x01,0xe1,0xff,0x00,0x01,0x42,0x40,0x00,0xc1,0x47,0x40,0x00,0x49,0x40,0x55,0x00,0x95,0x80,0x2a,0x00,0x93,0x00,0x15,0x00,0x21,0x01,0x0a,0x00,0x20,0x01,0x11,0x00,0x40,0x82,0x20,0x00,0x40,0x42,0x44,0x00,0x80,0x41,0x4a,0x00,0x00,0x40,0x55,0x00,0x00,0xe0,0xff,0x00,0x00,0x20,0x80,0x00,0x00,0xe0,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};static const uint8_t busym_bits[] = {0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x7f,0xe0,0xff,0x00,0xff,0xe0,0xff,0x00,0xff,0xe1,0xff,0x00,0xff,0xc3,0x7f,0x00,0xff,0xc7,0x7f,0x00,0x7f,0xc0,0x7f,0x00,0xf7,0x80,0x3f,0x00,0xf3,0x00,0x1f,0x00,0xe1,0x01,0x0e,0x00,0xe0,0x01,0x1f,0x00,0xc0,0x83,0x3f,0x00,0xc0,0xc3,0x7f,0x00,0x80,0xc1,0x7f,0x00,0x00,0xc0,0x7f,0x00,0x00,0xe0,0xff,0x00,0x00,0xe0,0xff,0x00,0x00,0xe0,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};static const uint8_t*const cursor_bits32[] = { vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits,nullptr,nullptr,nullptr,nullptr, whatsthis_bits, whatsthism_bits, busy_bits, busym_bits };static const uint8_t forbidden_bits[] = {0x00,0x00,0x00,0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xf0,0x00,0x38,0xc0,0x01,0x7c,0x80,0x03,0xec,0x00,0x03,0xce,0x01,0x07,0x86,0x03,0x06,0x06,0x07,0x06,0x06,0x0e,0x06,0x06,0x1c,0x06,0x0e,0x38,0x07,0x0c,0x70,0x03,0x1c,0xe0,0x03,0x38,0xc0,0x01,0xf0,0xe0,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00,0x00,0x00,0x00};static const uint8_t forbiddenm_bits[] = {0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xff,0x00,0xf8,0xff,0x01,0xfc,0xf0,0x03,0xfe,0xc0,0x07,0xfe,0x81,0x07,0xff,0x83,0x0f,0xcf,0x07,0x0f,0x8f,0x0f,0x0f,0x0f,0x1f,0x0f,0x0f,0x3e,0x0f,0x1f,0xfc,0x0f,0x1e,0xf8,0x07,0x3e,0xf0,0x07,0xfc,0xe0,0x03,0xf8,0xff,0x01,0xf0,0xff,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00};static const uint8_t openhand_bits[] = {0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92,0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00};static const uint8_t openhandm_bits[] = {0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff,0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00};static const uint8_t closedhand_bits[] = {0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50,0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00};static const uint8_t closedhandm_bits[] = {0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f,0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00};static const uint8_t*const cursor_bits20[] = { forbidden_bits, forbiddenm_bits };// ### FIXME This mapping is incomplete - QTBUG-71423static conststd::vector<const char*> cursorNames[] = {{"left_ptr","default","top_left_arrow","left_arrow"},{"up_arrow"},{"cross"},{"wait","watch","0426c94ea35c87780ff01dc239897213"},{"ibeam","text","xterm"},{"size_ver","ns-resize","v_double_arrow","00008160000006810000408080010102"},{"size_hor","ew-resize","h_double_arrow","028006030e0e7ebffc7f7070c0600140"},{"size_bdiag","nesw-resize","50585d75b494802d0151028115016902","fcf1c3c7cd4491d801f1e1c78f100000"},{"size_fdiag","nwse-resize","38c5dff7c7b8962045400281044508d2","c7088f0f3e6c8088236ef8e1e3e70000"},{"size_all"},{"blank"},{"split_v","row-resize","sb_v_double_arrow","2870a09082c103050810ffdffffe0204","c07385c7190e701020ff7ffffd08103c"},{"split_h","col-resize","sb_h_double_arrow","043a9f68147c53184671403ffa811cc5","14fef782d02440884392942c11205230"},{"pointing_hand","pointer","hand1","e29285e634086352946a0e7090d73106"},{"forbidden","not-allowed","crossed_circle","circle","03b6e0fcb3499374a867c041f52298f0"},{"whats_this","help","question_arrow","5c6cd98b3f3ebcb1f9c7f1c204630408","d9ce0ab605698f320427677b458ad60b"},{"left_ptr_watch","half-busy","progress","00000000000000020006000e7e9ffc3f","08e8e1c95fe2fc01f976f1e063a24ccd"},{"openhand","grab","fleur","5aca4d189052212118709018842178c0","9d800788f1b08800ae810202380a0822"},{"closedhand","grabbing","208530c400c041818281048008011002"},{"dnd-copy","copy"},{"dnd-move","move"},{"dnd-link","link"}};QXcbCursorCacheKey::QXcbCursorCacheKey(const QCursor &c):shape(c.shape()),bitmapCacheKey(0),maskCacheKey(0){if(shape ==Qt::BitmapCursor) {const qint64 pixmapCacheKey = c.pixmap().cacheKey();if(pixmapCacheKey) { bitmapCacheKey = pixmapCacheKey;}else{Q_ASSERT(!c.bitmap().isNull());Q_ASSERT(!c.mask().isNull()); bitmapCacheKey = c.bitmap().cacheKey(); maskCacheKey = c.mask().cacheKey();}} hotspotCacheKey.x = c.hotSpot().x(); hotspotCacheKey.y = c.hotSpot().y();}#endif// !QT_NO_CURSORQXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen):QXcbObject(conn),m_screen(screen),m_cursorContext(nullptr),m_callbackForPropertyRegistered(false){#if QT_CONFIG(cursor)// see NUM_BITMAPS in libXcursor/src/xcursorint.h m_bitmapCache.setMaxCost(8);#endifupdateContext();if(cursorCount++)return; cursorFont =xcb_generate_id(xcb_connection());const char*cursorStr ="cursor";xcb_open_font(xcb_connection(), cursorFont,strlen(cursorStr), cursorStr);}QXcbCursor::~QXcbCursor(){ xcb_connection_t *conn =xcb_connection();if(m_callbackForPropertyRegistered) { m_screen->xSettings()->removeCallbackForHandle(this);}if(!--cursorCount)xcb_close_font(conn, cursorFont);#ifndef QT_NO_CURSORfor(xcb_cursor_t cursor :std::as_const(m_cursorHash))xcb_free_cursor(conn, cursor);#endifif(m_cursorContext)xcb_cursor_context_free(m_cursorContext);} QSize QXcbCursor::size()const{if(const QPlatformTheme *theme =QGuiApplicationPrivate::platformTheme())return theme->themeHint(QPlatformTheme::MouseCursorSize).toSize();returnQSize(24,24);}voidQXcbCursor::updateContext(){if(m_cursorContext)xcb_cursor_context_free(m_cursorContext); m_cursorContext =nullptr; xcb_connection_t *conn =xcb_connection();if(xcb_cursor_context_new(conn, m_screen->screen(), &m_cursorContext) <0) {qWarning() <<"xcb: Could not initialize xcb-cursor"; m_cursorContext =nullptr;}}#ifndef QT_NO_CURSORvoidQXcbCursor::changeCursor(QCursor *cursor, QWindow *window){if(!window || !window->handle())return; xcb_cursor_t c = XCB_CURSOR_NONE;if(cursor) {const QXcbCursorCacheKey key(*cursor);constQt::CursorShape shape = cursor->shape();if(shape ==Qt::BitmapCursor) {auto*bitmap = m_bitmapCache.object(key);if(bitmap) { c = bitmap->cursor;}else{ c =createBitmapCursor(cursor); m_bitmapCache.insert(key,newCachedCursor(xcb_connection(), c));}}else{auto it = m_cursorHash.find(key);if(it == m_cursorHash.end()) { c =createFontCursor(shape); m_cursorHash.insert(key, c);}else{ c = it.value();}}}auto*w =static_cast<QXcbWindow *>(window->handle());xcb_change_window_attributes(xcb_connection(), w->xcb_window(), XCB_CW_CURSOR, &c);xcb_flush(xcb_connection());}static intcursorIdForShape(int cshape){int cursorId =0;switch(cshape) {caseQt::ArrowCursor: cursorId = XC_left_ptr;break;caseQt::UpArrowCursor: cursorId = XC_center_ptr;break;caseQt::CrossCursor: cursorId = XC_crosshair;break;caseQt::WaitCursor: cursorId = XC_watch;break;caseQt::IBeamCursor: cursorId = XC_xterm;break;caseQt::SizeAllCursor: cursorId = XC_fleur;break;caseQt::PointingHandCursor: cursorId = XC_hand2;break;caseQt::SizeBDiagCursor: cursorId = XC_top_right_corner;break;caseQt::SizeFDiagCursor: cursorId = XC_bottom_right_corner;break;caseQt::SizeVerCursor:caseQt::SplitVCursor: cursorId = XC_sb_v_double_arrow;break;caseQt::SizeHorCursor:caseQt::SplitHCursor: cursorId = XC_sb_h_double_arrow;break;caseQt::WhatsThisCursor: cursorId = XC_question_arrow;break;caseQt::ForbiddenCursor: cursorId = XC_circle;break;caseQt::BusyCursor: cursorId = XC_watch;break;default:break;}return cursorId;} xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape){ xcb_cursor_t cursor =0; xcb_connection_t *conn =xcb_connection();if(cshape ==Qt::BlankCursor) { xcb_pixmap_t cp =xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits,16,16,1,0,0,nullptr); xcb_pixmap_t mp =xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits,16,16,1,0,0,nullptr); cursor =xcb_generate_id(conn);xcb_create_cursor(conn, cursor, cp, mp,0,0,0,0xFFFF,0xFFFF,0xFFFF,8,8);}else if(cshape >=Qt::SizeVerCursor && cshape <Qt::SizeAllCursor) {int i = (cshape -Qt::SizeVerCursor) *2; xcb_pixmap_t pm =xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),const_cast<uint8_t*>(cursor_bits16[i]),16,16,1,0,0,nullptr); xcb_pixmap_t pmm =xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),const_cast<uint8_t*>(cursor_bits16[i +1]),16,16,1,0,0,nullptr); cursor =xcb_generate_id(conn);xcb_create_cursor(conn, cursor, pm, pmm,0,0,0,0xFFFF,0xFFFF,0xFFFF,8,8);}else if((cshape >=Qt::SplitVCursor && cshape <=Qt::SplitHCursor)|| cshape ==Qt::WhatsThisCursor || cshape ==Qt::BusyCursor) {int i = (cshape -Qt::SplitVCursor) *2; xcb_pixmap_t pm =xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),const_cast<uint8_t*>(cursor_bits32[i]),32,32,1,0,0,nullptr); xcb_pixmap_t pmm =xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),const_cast<uint8_t*>(cursor_bits32[i +1]),32,32,1,0,0,nullptr);int hs = (cshape ==Qt::PointingHandCursor || cshape ==Qt::WhatsThisCursor || cshape ==Qt::BusyCursor) ?0:16; cursor =xcb_generate_id(conn);xcb_create_cursor(conn, cursor, pm, pmm,0,0,0,0xFFFF,0xFFFF,0xFFFF, hs, hs);}else if(cshape ==Qt::ForbiddenCursor) {int i = (cshape -Qt::ForbiddenCursor) *2; xcb_pixmap_t pm =xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),const_cast<uint8_t*>(cursor_bits20[i]),20,20,1,0,0,nullptr); xcb_pixmap_t pmm =xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),const_cast<uint8_t*>(cursor_bits20[i +1]),20,20,1,0,0,nullptr); cursor =xcb_generate_id(conn);xcb_create_cursor(conn, cursor, pm, pmm,0,0,0,0xFFFF,0xFFFF,0xFFFF,10,10);}else if(cshape ==Qt::OpenHandCursor || cshape ==Qt::ClosedHandCursor) {bool open = cshape ==Qt::OpenHandCursor; xcb_pixmap_t pm =xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),const_cast<uint8_t*>(open ? openhand_bits : closedhand_bits),16,16,1,0,0,nullptr); xcb_pixmap_t pmm =xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),const_cast<uint8_t*>(open ? openhandm_bits : closedhandm_bits),16,16,1,0,0,nullptr); cursor =xcb_generate_id(conn);xcb_create_cursor(conn, cursor, pm, pmm,0,0,0,0xFFFF,0xFFFF,0xFFFF,8,8);}else if(cshape ==Qt::DragCopyCursor || cshape ==Qt::DragMoveCursor || cshape ==Qt::DragLinkCursor) { QImage image =QGuiApplicationPrivate::instance()->getPixmapCursor(static_cast<Qt::CursorShape>(cshape)).toImage();if(!image.isNull()) { xcb_pixmap_t pm =qt_xcb_XPixmapFromBitmap(m_screen, image); xcb_pixmap_t pmm =qt_xcb_XPixmapFromBitmap(m_screen, image.createAlphaMask()); cursor =xcb_generate_id(conn);xcb_create_cursor(conn, cursor, pm, pmm,0,0,0,0xFFFF,0xFFFF,0xFFFF,8,8);xcb_free_pixmap(conn, pm);xcb_free_pixmap(conn, pmm);}}return cursor;}voidQXcbCursor::cursorThemePropertyChanged(QXcbVirtualDesktop *screen,const QByteArray &name,const QVariant &property,void*handle){Q_UNUSED(screen);Q_UNUSED(name);Q_UNUSED(property); QXcbCursor *self =static_cast<QXcbCursor *>(handle); self->m_cursorHash.clear(); self->updateContext();} xcb_cursor_t QXcbCursor::createFontCursor(int cshape){if(!m_cursorContext)return XCB_NONE; xcb_connection_t *conn =xcb_connection();int cursorId =cursorIdForShape(cshape); xcb_cursor_t cursor = XCB_NONE;if(!m_callbackForPropertyRegistered && m_screen->xSettings()->initialized()) { m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName", cursorThemePropertyChanged,this); m_callbackForPropertyRegistered =true;}// Try xcb-cursor firstif(cshape >=0&& cshape <=Qt::LastCursor) {for(const char*cursorName : cursorNames[cshape]) { cursor =xcb_cursor_load_cursor(m_cursorContext, cursorName);if(cursor != XCB_NONE)return cursor;}}// Non-standard X11 cursors are created from bitmaps cursor =createNonStandardCursor(cshape);// Create a glyph cursor if everything else failedif(!cursor && cursorId) { cursor =xcb_generate_id(conn);xcb_create_glyph_cursor(conn, cursor, cursorFont, cursorFont, cursorId, cursorId +1,0xFFFF,0xFFFF,0xFFFF,0,0,0);}if(cursor && cshape >=0&& cshape <Qt::LastCursor &&connection()->hasXFixes()) {const char*name = cursorNames[cshape].front();xcb_xfixes_set_cursor_name(conn, cursor,strlen(name), name);}return cursor;} xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor){ QPoint spot = cursor->hotSpot(); xcb_cursor_t c = XCB_NONE;if(cursor->pixmap().depth() >1) {if(connection()->hasXRender(0,5)) c =qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot);elseqCWarning(lcQpaXcb,"xrender >= 0.5 required to create pixmap cursors");}else{ xcb_connection_t *conn =xcb_connection(); xcb_pixmap_t cp =qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap().toImage()); xcb_pixmap_t mp =qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask().toImage()); c =xcb_generate_id(conn);xcb_create_cursor(conn, c, cp, mp,0,0,0,0xFFFF,0xFFFF,0xFFFF, spot.x(), spot.y());xcb_free_pixmap(conn, cp);xcb_free_pixmap(conn, mp);}return c;}#endif/*! \internal Note that the logical state of a device (as seen by means of the protocol) may lag the physical state if device event processing is frozen. See QueryPointer in X11 protocol specification.*/voidQXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos,int*keybMask){if(pos)*pos =QPoint(); xcb_window_t root = c->primaryVirtualDesktop()->root();auto reply =Q_XCB_REPLY(xcb_query_pointer, c->xcb_connection(), root);if(reply) {if(virtualDesktop) {constauto virtualDesktops = c->virtualDesktops();for(QXcbVirtualDesktop *vd : virtualDesktops) {if(vd->root() == reply->root) {*virtualDesktop = vd;break;}}}if(pos)*pos =QPoint(reply->root_x, reply->root_y);if(keybMask)*keybMask = reply->mask;return;}} QPoint QXcbCursor::pos()const{ QPoint p;queryPointer(connection(),nullptr, &p);return p;}voidQXcbCursor::setPos(const QPoint &pos){ QXcbVirtualDesktop *virtualDesktop =nullptr;queryPointer(connection(), &virtualDesktop,nullptr);if(virtualDesktop)xcb_warp_pointer(xcb_connection(), XCB_NONE, virtualDesktop->root(),0,0,0,0, pos.x(), pos.y());xcb_flush(xcb_connection());} QT_END_NAMESPACE
|