复制粘贴——QT实现原理

news2024/11/16 9:53:33

复制粘贴——QT实现原理

QT 剪贴板相关类

QClipboard

对外通用的剪贴板类,一般通过QGuiApplication::clipboard() 来获取对应的剪贴板实例。

// qtbase/src/gui/kernel/qclipboard.h
class Q_GUI_EXPORT QClipboard : public QObject
{
    Q_OBJECT
private:
    explicit QClipboard(QObject *parent);
    ~QClipboard();

public:
    enum Mode { Clipboard, Selection, FindBuffer, LastMode = FindBuffer };

    void clear(Mode mode = Clipboard);

    bool supportsSelection() const;
    bool supportsFindBuffer() const;

    bool ownsSelection() const;
    bool ownsClipboard() const;
    bool ownsFindBuffer() const;

    QString text(Mode mode = Clipboard) const;
    QString text(QString& subtype, Mode mode = Clipboard) const;
    void setText(const QString &, Mode mode = Clipboard);

    const QMimeData *mimeData(Mode mode = Clipboard ) const;
    void setMimeData(QMimeData *data, Mode mode = Clipboard);

    QImage image(Mode mode = Clipboard) const;
    QPixmap pixmap(Mode mode = Clipboard) const;
    void setImage(const QImage &, Mode mode  = Clipboard);
    void setPixmap(const QPixmap &, Mode mode  = Clipboard);

Q_SIGNALS:
    void changed(QClipboard::Mode mode);
    void selectionChanged();
    void findBufferChanged();
    void dataChanged();

protected:
    friend class QApplication;
    friend class QApplicationPrivate;
    friend class QGuiApplication;
    friend class QBaseApplication;
    friend class QDragManager;
    friend class QPlatformClipboard;

private:
    Q_DISABLE_COPY(QClipboard)

    bool supportsMode(Mode mode) const;
    bool ownsMode(Mode mode) const;
    void emitChanged(Mode mode);
};

QPlatformClipboard

系统剪切板平台接口类,各种桌面平台(Windows,X11,Wayland等)通过这个类提供统一的剪贴板操作接口。

// qtbase/src/gui/kernel/qplatformclipboard.h
class Q_GUI_EXPORT QPlatformClipboard
{
public:
    virtual ~QPlatformClipboard();

    virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard);
    virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard);
    virtual bool supportsMode(QClipboard::Mode mode) const;
    virtual bool ownsMode(QClipboard::Mode mode) const;
    void emitChanged(QClipboard::Mode mode);
};

QXcbClipboard

X11平台实现的剪贴板接口类,继承自QPlatformClipboard,它主要实现了基类的大部分接口,除了emitChanged 这个接口。

// qtbase/src/plugins/platforms/xcb/qxcbclipboard.h
class QXcbClipboard : public QXcbObject, public QPlatformClipboard
{
public:
    QXcbClipboard(QXcbConnection *connection);
    ~QXcbClipboard();

    QMimeData *mimeData(QClipboard::Mode mode) override;
    void setMimeData(QMimeData *data, QClipboard::Mode mode) override;

    bool supportsMode(QClipboard::Mode mode) const override;
    bool ownsMode(QClipboard::Mode mode) const override;
...
};

QWindowsClipboard

Windows平台下的剪贴板接口类,继承自QPlatformClipboard

// qtbase/src/plugins/platforms/windows/qwindowsclipboard.h
class QWindowsClipboard : public QPlatformClipboard
{
public:
    QWindowsClipboard();
    ~QWindowsClipboard();
    void registerViewer(); // Call in initialization, when context is up.
    void cleanup();

    QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
    void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) override;
    bool supportsMode(QClipboard::Mode mode) const override;
    bool ownsMode(QClipboard::Mode mode) const override;
...
}

可以看出,同一目录下还有其他各种平台的实现接口:
在这里插入图片描述

QWaylandClipboard

Wayland平台实现的剪贴板接口.

// qtwayland/src/client/qwaylandclipboard_p.h
class Q_WAYLAND_CLIENT_EXPORT QWaylandClipboard : public QPlatformClipboard
{
public:
    QWaylandClipboard(QWaylandDisplay *display);

    ~QWaylandClipboard() override;

    QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
    void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) override;
    bool supportsMode(QClipboard::Mode mode) const override;
    bool ownsMode(QClipboard::Mode mode) const override;

private:
    QWaylandDisplay *mDisplay = nullptr;
    QMimeData m_emptyData;
};

QT 剪贴板相关接口

通过查看QClipboard 类的定义,我们比较关心的接口有:

    const QMimeData *mimeData(Mode mode = Clipboard ) const;
    void setMimeData(QMimeData *data, Mode mode = Clipboard);
Q_SIGNALS:
    void changed(QClipboard::Mode mode);
    void selectionChanged();
    void findBufferChanged();
    void dataChanged();

获取剪贴板最基础的应该是mimeData 这个接口:

const QMimeData* QClipboard::mimeData(Mode mode) const
{
    // 获取一个QPlatformClipboard对象,根据不同平台返回的应该是不同的子类,比如x11下就返回的是QXcbClipboard
    QPlatformClipboard *clipboard = QGuiApplicationPrivate::platformIntegration()->clipboard();
    if (!clipboard->supportsMode(mode)) return 0;
    return clipboard->mimeData(mode);
}

可以看出,最终是通过X11接口拿到的。

另外,我们关系剪贴板变化的信号在什么情况下发出来,从实现可以看出,基本是在emitChanged 里发出来的。

/*!
    \internal
    Emits the appropriate changed signal for \a mode.
*/
void QClipboard::emitChanged(Mode mode)
{
    switch (mode) {
        case Clipboard:
            emit dataChanged();
        break;
        case Selection:
            emit selectionChanged();
        break;
        case FindBuffer:
            emit findBufferChanged();
        break;
        default:
        break;
    }
    emit changed(mode);
}

还有一个地方会通过emitChanged发出变化的信号:

void QPlatformClipboard::emitChanged(QClipboard::Mode mode)
{
    if (!QGuiApplicationPrivate::is_app_closing) // QTBUG-39317, prevent emission when closing down.
        QGuiApplication::clipboard()->emitChanged(mode);
}

可以再往下看下谁会调用emitChanged ,可以发现是QPlatformClipboard 的子类QXcbClipboard

// qtbase/src/plugins/platforms/xcb/qxcbclipboard.cpp
void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
{
    if (mode > QClipboard::Selection)
        return;

    QXcbClipboardMime *xClipboard = 0;
    // verify if there is data to be cleared on global X Clipboard.
    if (!data) {
        xClipboard = qobject_cast<QXcbClipboardMime *>(mimeData(mode));
        if (xClipboard) {
            if (xClipboard->isEmpty())
                return;
        }
    }

    if (!xClipboard && (m_clientClipboard[mode] == data))
        return;

    xcb_atom_t modeAtom = atomForMode(mode);
    xcb_window_t newOwner = XCB_NONE;

    if (m_clientClipboard[mode]) {
        if (m_clientClipboard[QClipboard::Clipboard] != m_clientClipboard[QClipboard::Selection])
            delete m_clientClipboard[mode];
        m_clientClipboard[mode] = 0;
        m_timestamp[mode] = XCB_CURRENT_TIME;
    }

    if (connection()->time() == XCB_CURRENT_TIME)
        connection()->setTime(connection()->getTimestamp());

    if (data) {
        newOwner = owner();

        m_clientClipboard[mode] = data;
        m_timestamp[mode] = connection()->time();
    }

    xcb_set_selection_owner(xcb_connection(), newOwner, modeAtom, connection()->time());

    if (getSelectionOwner(modeAtom) != newOwner) {
        qWarning("QXcbClipboard::setMimeData: Cannot set X11 selection owner");
    }

    emitChanged(mode);
}

void QXcbClipboard::handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event)
{
    QClipboard::Mode mode = modeForAtom(event->selection);
    if (mode > QClipboard::Selection)
        return;

    // Note1: Here we care only about the xfixes events that come from other processes.
    // Note2: If the QClipboard::clear() is issued, event->owner is XCB_NONE,
    // so we check selection_timestamp to not handle our own QClipboard::clear().
    if (event->owner != owner() && event->selection_timestamp > m_timestamp[mode]) {
        if (!m_xClipboard[mode]) {
            m_xClipboard[mode].reset(new QXcbClipboardMime(mode, this));
        } else {
            m_xClipboard[mode]->reset();
        }
        emitChanged(mode);
    } else if (event->subtype == XCB_XFIXES_SELECTION_EVENT_SELECTION_CLIENT_CLOSE ||
               event->subtype == XCB_XFIXES_SELECTION_EVENT_SELECTION_WINDOW_DESTROY)
        emitChanged(mode);
}

至此,我们可以知道QClipboard是如何发出剪贴板内容变化的信号了:

  1. QClipboard设置剪贴板内容(setMimeData),QXcbClipboard设置完剪贴板内容,emitChanged通知内容变化
  2. QXcbClipboard收到X11剪贴板变化的事件,主动emitChanged通知QClipboard剪贴板变化

总结

qt的剪贴板底层是由各个平台的剪贴板接口驱动的,如果是X11平台,那么整个剪贴板就是X11接口驱动的。关于如何使用X11原生剪贴板接口,参考:https://stackoverflow.com/questions/27378318/c-get-string-from-clipboard-on-linux

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1310249.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为OD试题五(数列描述、矩阵最大值、数据分类)

1. 数列描述 示例代码&#xff1a; # 核心 从第一项 推 第N项目 # 第一项 a0 1 # 推到 第N项 N 4 def fun(a0):# 计算每一项的具体值result left 0cursor 0while cursor < len(a0):if a0[cursor] ! a0[left]:count cursor -leftresult "{}{}".format(str(…

2.2 模型基础

建模流程 作业 这次搞了10天左右终于把作业做完了。 先是去学习了下如何建模->然后将模型导入Substance Painter里绘制贴图->最后导入到unity中&#xff08;虽然最后效果很差&#xff09;&#xff0c;但是回过头来看整个过程学习到了次时代美术的工作流&#xff0c;思考…

智慧公交:提高城市出行效率的数字化之路

随着城市化进程的不断加速&#xff0c;公共交通成为人们日常出行的主要方式之一。为了提高公共交通的效率和服务质量&#xff0c;智慧公交应运而生。智慧公交是一种基于物联网、大数据、人工智能等技术&#xff0c;对公共交通进行数字化、智能化改造的新型公共交通系统。 以此为…

[Kubernetes]1.Kubernetes(K8S)介绍,基于腾讯云的K8S环境搭建集群以及裸机搭建K8S集群

一. Kubernetes(K8S)简介 Kubernetes (K8S) 是一个为 容器化应用 提供 集群部署 和 管理 的开源工具,和docker swarm类似,由 Google 开发. Kubernetes 这个名字源于希腊语,意为 “ 舵手 ” 或 “ 飞行员 ” , k8s 这个缩写是因为 k 和 s 之间有八个字符的关系, Google…

【Jmeter】Jmeter基础8-Jmeter元件介绍之断言

断言主要用于对服务器响应的数据做验证。Jmeter提供了多个断言元件&#xff0c;其中最常用的是响应断言。 2.8.1、响应断言 作用&#xff1a;对Jmeter取样器返回值进行断言。参数说明&#xff1a; 测试字段 响应文本&#xff1a;从服务器返回的响应文本&#xff0c;Response B…

Nacos-NacosRule 负载均衡—设置集群使本地服务优先访问

userservice: ribbon: NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则 NacosRule 权重计算方法 目录 一、介绍 二、示例&#xff08;案例截图&#xff09; 三、总结 一、介绍 NacosRule是AlibabaNacos自己实现的一个负载均衡策略&…

白日门引擎传奇手游架设教程-GM的成长之路

准备工具 服务器一台&#xff08;Windows系统&#xff09;白日门引擎服务端版本一个 前言&#xff1a; 此次教程使用的是版本是一个决战斗罗的一个版本、服务器使用的是驰网科技的游戏高频系列服务器。 教程开始 在我们拿到版本之后、我们需要先把版本解压到服务器D盘的根目录…

关于impdp导入时候索引是否使用了并行了?

关于impdp导入时候索引是否使用了并行的问题&#xff0c;不是看sqlfile&#xff0c;而是看实际worker 参看&#xff1a;Impdp Parallel Index Creation Always Creates Indexes with Degree 1 (Doc ID 1289032.1&#xff09; Oracle Database - Enterprise Edition - Version …

雅典娜Athena-signa音频算法源码与麦克风阵列角度定义互换问题

雅典娜Athena-signa音频算法源码与麦克风阵列角度定义互换问题 是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,+群赠送语音信号处理降噪算法,蓝牙耳机音频,DSP音频项目核心开发资料, 1 dios_ssp_doa_api.c 2 公…

【python VS vba】(8) 在python使用matplotlib库来画图

目录 1 matplotlib的基本用法 1.1 需要用到的模块&#xff0c;需要实现安装&#xff0c;且导入 1.2 画布 figure 1.2.1 figure的官方解释 1.2.2 画布语法 1.2.3 必须先获取至少1个figure: 1.2.4 figure的生效范围与多个figure 1.2.5 可以设置多个画布 1.3 设置函数…

创业就做轻资产 低门槛高收益的创业项目

1.在创业之前&#xff0c;首先要找对方向 所谓方向就是根据经济环境和市场分析&#xff0c;哪个行业最赚钱&#xff0c;哪个产品市场需求量大&#xff0c;竞争力下&#xff0c;发展前景好&#xff0c;可以实现长期收益。 2.清晰地思考商业摸式&#xff0c;建立盈利循环 例如&…

排序算法(详解)

排序在日常生活中十分重要&#xff0c;购物平台上商品的排序&#xff0c;各国高校等级的排序......可以说&#xff0c;现代生活中已经离不开排序了&#xff1b;因此学好排序算法至关重要&#xff0c;本篇文章就来讲讲常见的排序算法 排序的种类非常多&#xff0c;按照种类划分&…

AI数字人克隆采集规范分享!

数字人直播的时代已经来临&#xff0c;使用青否数字人SaaS系统数字人源码&#xff1a;zhibo175&#xff09;去生成数字人&#xff0c;那如何能得到自己想要的效果呢&#xff1f;需要注意一下几点&#xff1a; 一.摄影棚灯光方案 中型(15m左右)摄影棚​ 适用于美妆/珠宝等直播&a…

Rust语言抓取在线考试平台的专业试题数据

不管你是学车也好&#xff0c;还是考各类证书&#xff0c;都离不开刷题&#xff0c;有些题库都是需要收费的&#xff0c;而且市面平台那么多&#xff0c;想要刷更多的题只能下载很多不同APP&#xff0c;因此&#xff0c;我写了一个Rust爬取试题的爬虫&#xff0c;将更多的分散的…

从 enable_if 了解模板元编程

前言 在阅读学习 ZLToolKit 源码时&#xff0c;从如下一段代码中了解到 enable_if 和 SFINAE 的概念&#xff0c;从而引入了对模板元编程的了解。 template<class R, class... ArgTypes> class TaskCancelableImp<R(ArgTypes...)> : public TaskCancelable { pub…

PHP基础 - 循环与条件语句

循环语句 1)for循环: 重复执行一个代码块指定的次数。 for ($i = 0; $i < 5; $i++) { // 初始化 $i 为 0,每次循环后将 $i 值增加 1,当 $i 小于 5 时执行循环echo "The number is: $i \n"; // 输出当前 $i 的值并换行 }// 循环输出结果为: // The number …

【一秒梵高】基于OpenCV4实现图像九种风格迁移

风格迁移 图像风格迁移、色彩填充与色彩变换等&#xff0c;严格意义上来说都属于计算机视觉任务中图像处理的分支。它们输入的是图像&#xff0c;输出的也是图像&#xff0c;过程实现图像到图像的内容与风格的转换&#xff0c;深度学习在这类图像处理任务上也取得了良好的效果…

改进了编排控制并增强了推理的可视性,Agents for Amazon Bedrock 现已上市

七月份的时候&#xff0c;我们推出了 Agents for Amazon Bedrock 预览版。如今&#xff0c;Agents for Amazon Bedrock 全面上市。 Agents for Amazon Bedrock 通过编排多步任务&#xff0c;有助于您加速生成人工智能 &#xff08;AI&#xff09; 应用程序的开发。代理使用基础…

【ARM Coresight 系列 2 文章 -- Trace32 对 APBIC 地址的配置 介绍】

请阅读【ARM Coresight SoC-400/SoC-600 专栏导读】 文章目录 APBIC RomtableTrace32 RESBREAKTrace32 ENRESETAPBIC Romtable 图 1 APBIC 网络图 如上图所示,如果想通过Trace32/DS-5 去访问 AP, 这个时候需要怎么做呢?可以看到 APBIC 中ROMTABLE 中 APB-AP 的偏移是0x002000…

2023 re:Invent|Amazon Q与Amazon CodeWhisperer面向企业开发者提效利器

本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 2023年&#xff0c;以GPT为代表的生成式AI引爆了新一轮技术热潮&#xff0c;短短一年的时…