Warning, /graphics/krita/3rdparty/ext_qt/0045-Android-Add-support-for-changing-cursor.patch is written in an unsupported language. File is not indexed.

0001 From 67a74e329b4cd803f4470de0302d73f5dac9c9a3 Mon Sep 17 00:00:00 2001
0002 From: Sharaf Zaman <shzam@sdf.org>
0003 Date: Tue, 21 Sep 2021 10:14:23 +0000
0004 Subject: [PATCH 45/46] Android: Add support for changing cursor
0005 
0006 ---
0007  src/android/jar/jar.pro                       |   1 +
0008  .../qtproject/qt5/android/QtPointerIcon.java  | 129 ++++++++++++++++++
0009  .../org/qtproject/qt5/android/QtSurface.java  |  11 +-
0010  .../qtproject/qt5/android/SAFFileManager.java |   4 +-
0011  src/plugins/platforms/android/android.pro     |   6 +-
0012  .../android/qandroidplatformcursor.cpp        |  70 ++++++++++
0013  .../android/qandroidplatformcursor.h          |  22 +++
0014  .../android/qandroidplatformscreen.cpp        |   5 +-
0015  .../android/qandroidplatformscreen.h          |   3 +
0016  9 files changed, 242 insertions(+), 9 deletions(-)
0017  create mode 100644 src/android/jar/src/org/qtproject/qt5/android/QtPointerIcon.java
0018  create mode 100644 src/plugins/platforms/android/qandroidplatformcursor.cpp
0019  create mode 100644 src/plugins/platforms/android/qandroidplatformcursor.h
0020 
0021 diff --git a/src/android/jar/jar.pro b/src/android/jar/jar.pro
0022 index 6a610c511d..ccd0f21dde 100644
0023 --- a/src/android/jar/jar.pro
0024 +++ b/src/android/jar/jar.pro
0025 @@ -25,6 +25,7 @@ JAVASOURCES += \
0026      $$PATHPREFIX/EditContextView.java \
0027      $$PATHPREFIX/EditPopupMenu.java \
0028      $$PATHPREFIX/CursorHandle.java \
0029 +    $$PATHPREFIX/QtPointerIcon.java \
0030      $$PATHPREFIX/QtThread.java
0031  
0032  # install
0033 diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtPointerIcon.java b/src/android/jar/src/org/qtproject/qt5/android/QtPointerIcon.java
0034 new file mode 100644
0035 index 0000000000..723f0f5992
0036 --- /dev/null
0037 +++ b/src/android/jar/src/org/qtproject/qt5/android/QtPointerIcon.java
0038 @@ -0,0 +1,129 @@
0039 +package org.qtproject.qt5.android;
0040 +
0041 +import android.app.Activity;
0042 +import android.graphics.Bitmap;
0043 +import android.graphics.BitmapFactory;
0044 +import android.os.Build;
0045 +import android.util.Log;
0046 +import android.util.LruCache;
0047 +import android.view.PointerIcon;
0048 +
0049 +@SuppressWarnings("unused")
0050 +class CursorShape {
0051 +    public static final int ArrowCursor = 0;
0052 +    public static final int UpArrowCursor = 1;
0053 +    public static final int CrossCursor = 2;
0054 +    public static final int WaitCursor = 3;
0055 +    public static final int IBeamCursor = 4;
0056 +    public static final int SizeVerCursor = 5;
0057 +    public static final int SizeHorCursor = 6;
0058 +    public static final int SizeBDiagCursor = 7;
0059 +    public static final int SizeFDiagCursor = 8;
0060 +    public static final int SizeAllCursor = 9;
0061 +    public static final int BlankCursor = 10;
0062 +    public static final int SplitVCursor = 11;
0063 +    public static final int SplitHCursor = 12;
0064 +    public static final int PointingHandCursor = 13;
0065 +    public static final int ForbiddenCursor = 14;
0066 +    public static final int WhatsThisCursor = 15;
0067 +    public static final int BusyCursor = 16;
0068 +    public static final int OpenHandCursor = 17;
0069 +    public static final int ClosedHandCursor = 18;
0070 +    public static final int DragCopyCursor = 19;
0071 +    public static final int DragMoveCursor = 20;
0072 +    public static final int DragLinkCursor = 21;
0073 +    public static final int LastCursor = DragLinkCursor;
0074 +    public static final int BitmapCursor = 24;
0075 +    public static final int CustomCursor = 5;
0076 +
0077 +    public static PointerIcon getPointerIconQt(int type) {
0078 +        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
0079 +            return null;
0080 +        }
0081 +        switch (type) {
0082 +            case ArrowCursor:
0083 +                    return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_ARROW);
0084 +            case CrossCursor:
0085 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_CROSSHAIR);
0086 +            case WaitCursor:
0087 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_WAIT);
0088 +            case BlankCursor:
0089 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_NULL);
0090 +            case IBeamCursor:
0091 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_TEXT);
0092 +            case SizeBDiagCursor:
0093 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW);
0094 +            case SizeFDiagCursor:
0095 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW);
0096 +            case SplitVCursor:
0097 +            case SizeVerCursor:
0098 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW);
0099 +            case SplitHCursor:
0100 +            case SizeHorCursor:
0101 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW);
0102 +            case PointingHandCursor:
0103 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_HAND);
0104 +            case ForbiddenCursor:
0105 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_NO_DROP);
0106 +            case OpenHandCursor:
0107 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_GRAB);
0108 +            case ClosedHandCursor:
0109 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_GRABBING);
0110 +            case DragMoveCursor:
0111 +            case DragCopyCursor:
0112 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_COPY);
0113 +            default:
0114 +                return PointerIcon.getSystemIcon(QtNative.getContext(), PointerIcon.TYPE_DEFAULT);
0115 +        }
0116 +    }
0117 +}
0118 +
0119 +@SuppressWarnings("UnusedDeclaration")
0120 +public class QtPointerIcon {
0121 +
0122 +    private static final String TAG = "QtPointerIcon";
0123 +    private static QtPointerIcon sQtPointer;
0124 +    // we cache on Java side, passing data over Jni can be expensive
0125 +    private final LruCache<Long, PointerIcon> iconCache = new LruCache<>(10);
0126 +    private PointerIcon icon;
0127 +
0128 +    public static QtPointerIcon instance() {
0129 +        if (sQtPointer == null) {
0130 +            sQtPointer = new QtPointerIcon();
0131 +        }
0132 +        return sQtPointer;
0133 +    }
0134 +
0135 +    public PointerIcon getIcon() {
0136 +        return icon;
0137 +    }
0138 +
0139 +    public void setIcon(int type) {
0140 +        // TODO(sh_zam): setPointerIcon?
0141 +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
0142 +            icon = CursorShape.getPointerIconQt(type);
0143 +        }
0144 +    }
0145 +
0146 +    public void setCachedBitmapIcon(long cacheKey) {
0147 +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
0148 +            icon = iconCache.get(cacheKey);
0149 +        }
0150 +    }
0151 +
0152 +    public void setBitmapIcon(byte[] colors, int w, int h, int hX, int hY, long cacheKey) {
0153 +        Bitmap bitmap = BitmapFactory.decodeByteArray(colors, 0, colors.length);
0154 +        if (bitmap == null) {
0155 +            Log.e(TAG, "PointerIcon bitmap is null!");
0156 +            return;
0157 +        }
0158 +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
0159 +            icon = PointerIcon.create(bitmap, hX, hY);
0160 +            iconCache.put(cacheKey, icon);
0161 +        }
0162 +    }
0163 +
0164 +    public boolean existsInCache(long key) {
0165 +        return iconCache.get(key) != null;
0166 +    }
0167 +}
0168 diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java b/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java
0169 index 723a783c6b..8b9f581ef0 100644
0170 --- a/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java
0171 +++ b/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java
0172 @@ -40,15 +40,13 @@
0173  
0174  package org.qtproject.qt5.android;
0175  
0176 -import android.app.Activity;
0177  import android.content.Context;
0178  import android.graphics.PixelFormat;
0179 +import android.view.MotionEvent;
0180 +import android.view.PointerIcon;
0181  import android.view.SurfaceHolder;
0182  import android.view.SurfaceView;
0183  
0184 -import java.lang.reflect.Constructor;
0185 -import java.lang.reflect.Method;
0186 -
0187  public class QtSurface extends SurfaceView implements SurfaceHolder.Callback
0188  {
0189      private Object m_accessibilityDelegate = null;
0190 @@ -87,4 +85,9 @@ public class QtSurface extends SurfaceView implements SurfaceHolder.Callback
0191      {
0192          QtNative.setSurface(getId(), null, 0, 0);
0193      }
0194 +
0195 +    @Override
0196 +    public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
0197 +        return QtPointerIcon.instance().getIcon();
0198 +    }
0199  }
0200 diff --git a/src/android/jar/src/org/qtproject/qt5/android/SAFFileManager.java b/src/android/jar/src/org/qtproject/qt5/android/SAFFileManager.java
0201 index f4f097efcf..df5868d67a 100644
0202 --- a/src/android/jar/src/org/qtproject/qt5/android/SAFFileManager.java
0203 +++ b/src/android/jar/src/org/qtproject/qt5/android/SAFFileManager.java
0204 @@ -671,11 +671,11 @@ public class SAFFileManager {
0205              }
0206  
0207              while (cursor.moveToNext()) {
0208 -                final String docId = cursor.getString(1);
0209 +                final String docId = SAFUtils.getColumnValStringOrNull(cursor, DocumentsContract.Document.COLUMN_DOCUMENT_ID);
0210                  final Uri fileUri = DocumentsContract.buildDocumentUriUsingTree(documentTreeUri, docId);
0211                  cachedDocumentFiles.add(new CachedDocumentFile(mCtx,
0212                          SAFUtils.getColumnValStringOrNull(cursor, DocumentsContract.Document.COLUMN_DISPLAY_NAME),
0213 -                        SAFUtils.getColumnValStringOrNull(cursor, DocumentsContract.Document.COLUMN_DOCUMENT_ID),
0214 +                        docId,
0215                          SAFUtils.getColumnValStringOrNull(cursor, DocumentsContract.Document.COLUMN_MIME_TYPE),
0216                          SAFUtils.getColumnValIntegerOrDefault(cursor, DocumentsContract.Document.COLUMN_SIZE, -1),
0217                          fileUri));
0218 diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro
0219 index 8f62cb4c1e..92a7572563 100644
0220 --- a/src/plugins/platforms/android/android.pro
0221 +++ b/src/plugins/platforms/android/android.pro
0222 @@ -49,7 +49,8 @@ SOURCES += $$PWD/androidplatformplugin.cpp \
0223             $$PWD/qandroideventdispatcher.cpp \
0224             $$PWD/qandroidplatformoffscreensurface.cpp \
0225             $$PWD/qandroidplatformfiledialoghelper.cpp \
0226 -           $$PWD/qandroidplatformwindowmanager.cpp
0227 +           $$PWD/qandroidplatformwindowmanager.cpp \
0228 +           $$PWD/qandroidplatformcursor.cpp
0229  
0230  HEADERS += $$PWD/qandroidplatformintegration.h \
0231             $$PWD/androidcontentfileengine.h \
0232 @@ -81,7 +82,8 @@ HEADERS += $$PWD/qandroidplatformintegration.h \
0233             $$PWD/qandroideventdispatcher.h \
0234             $$PWD/qandroidplatformoffscreensurface.h \
0235             $$PWD/qandroidplatformfiledialoghelper.h \
0236 -           $$PWD/qandroidplatformwindowmanager.h
0237 +           $$PWD/qandroidplatformwindowmanager.h \
0238 +           $$PWD/qandroidplatformcursor.h
0239  
0240  qtConfig(android-style-assets): SOURCES += $$PWD/extract.cpp
0241  else: SOURCES += $$PWD/extract-dummy.cpp
0242 diff --git a/src/plugins/platforms/android/qandroidplatformcursor.cpp b/src/plugins/platforms/android/qandroidplatformcursor.cpp
0243 new file mode 100644
0244 index 0000000000..025093066e
0245 --- /dev/null
0246 +++ b/src/plugins/platforms/android/qandroidplatformcursor.cpp
0247 @@ -0,0 +1,70 @@
0248 +#include "qandroidplatformcursor.h"
0249 +#include "qandroidplatformscreen.h"
0250 +#include <QBitmap>
0251 +#include <QBuffer>
0252 +#include <QPixmap>
0253 +#include <QtCore/private/qjnihelpers_p.h>
0254 +#include <androidjnimain.h>
0255 +#include <private/qguiapplication_p.h>
0256 +#include <private/qhighdpiscaling_p.h>
0257 +#include <private/qjni_p.h>
0258 +#include <qpa/qplatformwindow.h>
0259 +
0260 +QAndroidPlatformCursor::QAndroidPlatformCursor(QAndroidPlatformScreen *screen)
0261 +    : m_qtPointer(QJNIObjectPrivate::callStaticObjectMethod(
0262 +        "org/qtproject/qt5/android/QtPointerIcon", "instance",
0263 +        "()Lorg/qtproject/qt5/android/QtPointerIcon;"))
0264 +    , m_screen(screen)
0265 +{
0266 +}
0267 +
0268 +void QAndroidPlatformCursor::changeCursor(QCursor *cursor, QWindow *window)
0269 +{
0270 +    if (!window || !window->handle()) {
0271 +        return;
0272 +    }
0273 +
0274 +    if (cursor) {
0275 +        if (cursor->shape() == Qt::BitmapCursor) {
0276 +            QImage bitmap = cursor->bitmap()->toImage();
0277 +            qint64 key = cursor->bitmap()->cacheKey();
0278 +            bool exists = m_qtPointer.callMethod<jboolean>("existsInCache", "(J)Z", key);
0279 +            if (exists) {
0280 +                m_qtPointer.callMethod<void>("setCachedBitmapIcon", "(J)V", key);
0281 +                return;
0282 +            }
0283 +
0284 +            QImage mask = cursor->mask()->toImage().convertToFormat(QImage::Format_Mono);
0285 +            mask.invertPixels();
0286 +            bitmap.setAlphaChannel(mask);
0287 +
0288 +            QByteArray bytes;
0289 +            QBuffer buffer(&bytes);
0290 +            buffer.open(QIODevice::WriteOnly);
0291 +            bitmap.save(&buffer, "PNG");
0292 +
0293 +            jbyte *pixels = (jbyte *)bytes.data();
0294 +
0295 +            QJNIEnvironmentPrivate env;
0296 +            // we don't need to release the memory since we don't pin it
0297 +            jbyteArray array = env->NewByteArray(bytes.size());
0298 +            env->SetByteArrayRegion(array, 0, bytes.size(), pixels);
0299 +
0300 +            m_qtPointer.callMethod<void>(
0301 +                "setBitmapIcon", "([BIIIIJ)V", array, bitmap.width(), bitmap.height(),
0302 +                cursor->hotSpot().x(), cursor->hotSpot().y(), key);
0303 +        } else {
0304 +            m_qtPointer.callMethod<void>("setIcon", "(I)V",
0305 +                                         static_cast<int>(cursor->shape()));
0306 +        }
0307 +    } else {
0308 +        m_qtPointer.callMethod<void>("setIcon", "(I)V",
0309 +                                     static_cast<int>(Qt::BlankCursor));
0310 +    }
0311 +}
0312 +
0313 +QPoint QAndroidPlatformCursor::pos() const
0314 +{
0315 +    return QHighDpi::toNativePixels(QGuiApplicationPrivate::lastCursorPosition.toPoint(),
0316 +                                    m_screen->screen());
0317 +}
0318 diff --git a/src/plugins/platforms/android/qandroidplatformcursor.h b/src/plugins/platforms/android/qandroidplatformcursor.h
0319 new file mode 100644
0320 index 0000000000..81a3225f32
0321 --- /dev/null
0322 +++ b/src/plugins/platforms/android/qandroidplatformcursor.h
0323 @@ -0,0 +1,22 @@
0324 +#ifndef __QANDROIDPLATFORMCURSOR_H_
0325 +#define __QANDROIDPLATFORMCURSOR_H_
0326 +
0327 +#include <private/qjni_p.h>
0328 +#include <qpa/qplatformcursor.h>
0329 +
0330 +class QAndroidPlatformScreen;
0331 +
0332 +class QAndroidPlatformCursor : public QPlatformCursor
0333 +{
0334 +public:
0335 +    explicit QAndroidPlatformCursor(QAndroidPlatformScreen *screen);
0336 +
0337 +    void changeCursor(QCursor *windowCursor, QWindow *window) override;
0338 +    QPoint pos() const override;
0339 +
0340 +private:
0341 +    QJNIObjectPrivate m_qtPointer;
0342 +    QAndroidPlatformScreen *m_screen;
0343 +};
0344 +
0345 +#endif // __QANDROIDPLATFORMCURSOR_H_
0346 diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp
0347 index 61ab6f58c7..891c2c372b 100644
0348 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp
0349 +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp
0350 @@ -51,6 +51,7 @@
0351  #include "androidjnimenu.h"
0352  #include "androiddeadlockprotector.h"
0353  #include "qandroidplatformwindowmanager.h"
0354 +#include "qandroidplatformcursor.h"
0355  
0356  #include <android/bitmap.h>
0357  #include <android/native_window_jni.h>
0358 @@ -89,7 +90,9 @@ private:
0359  #endif
0360  
0361  QAndroidPlatformScreen::QAndroidPlatformScreen()
0362 -    : QObject(), QPlatformScreen()
0363 +    : QObject()
0364 +    , QPlatformScreen()
0365 +    , m_cursor(new QAndroidPlatformCursor(this))
0366  {
0367      m_availableGeometry = QRect(0, 0, QAndroidPlatformIntegration::m_defaultGeometryWidth, QAndroidPlatformIntegration::m_defaultGeometryHeight);
0368      m_size = QSize(QAndroidPlatformIntegration::m_defaultScreenWidth, QAndroidPlatformIntegration::m_defaultScreenHeight);
0369 diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h
0370 index 878e33546a..1d489d77a4 100644
0371 --- a/src/plugins/platforms/android/qandroidplatformscreen.h
0372 +++ b/src/plugins/platforms/android/qandroidplatformscreen.h
0373 @@ -85,6 +85,8 @@ public:
0374      void topWindowChanged(QWindow *w);
0375      int rasterSurfaces();
0376  
0377 +    QPlatformCursor *cursor() const override { return m_cursor.data(); }
0378 +
0379  public slots:
0380      void setDirty(const QRect &rect);
0381      void setPhysicalSize(const QSize &size);
0382 @@ -124,6 +126,7 @@ private:
0383      QWaitCondition m_surfaceWaitCondition;
0384      QSize m_size;
0385      QMap<int, QAndroidPlatformWindowManager *> m_windowManagers;
0386 +    QScopedPointer<QPlatformCursor> m_cursor;
0387  };
0388  
0389  QT_END_NAMESPACE
0390 -- 
0391 2.33.0
0392