本文档主要介绍了两种方法实现国产操作系统UOS20的文件资源管理器dde-file-manager添加徽标(角标)。由于dfm的版本众多且不同版本之间的接口差异较大,因此本文所谈及的接口于dfm的版本密切相关,更多实时接口信息还请关注dfm官方文档和源码。
Intro
值得说明的是,在本文中,角标、徽标、emblem、emblemicon表示的意思是一致的。与本文相关的关键字有:
emblem 徽标 角标 metadata::emblems overlayicons 图标覆盖 SVN角标
文件资源管理器 文管 file manager
caja nautilus nemo peony dde-file-manager explorer.exe
我想,但凡你用过SVN就应该清楚上述的关键字在描述些什么,是的,我最近在研究在各个系统下实现SVN图标效果的方案。虽是在不同的系统实现徽标效果,但一般而言实现方案大体上是类似的:
Interface
本文在此叙述了两个接口以实现徽标的添加功能(因不同的版本接口也不一样)。
DFMGenericPlugin
dde-file-manager ~ (此接口虽说会被删减,但在持续更新的版本中均发现仍然是保留的)
depends: libdde-file-manager-dev
此接口为我在调研期间,浏览开发者论坛查阅得于此链接link:不来体验体验深度文件管理器的坚果云插件么?-论坛-深度科技 ,遂找到了项目linuxdeepin/dde-file-manager-integration并结合dde-file-manager源码以理解此接口。
在dde-file-manager源码DFileViewHelperPrivate::init()
中可见初始化了插件DFMGenericFactory::createAll(QStringLiteral("fileinfo/additionalIcon"))
.
在源码DFileViewHelperPrivate::getAdditionalIconByPlugins
中可以看到
invokeMethod(object, "fileAdditionalIcon"...
槽函数。结合具体实现章节的代码,此接口并不难理解。
DFMExtEmblemIconPlugin
dde-file-manager >= 5.5.10 (10 Dec 2021)
depends: libdfm-extension-dev
👀 关于此接口何时开始被支持,可以结合项目的tag和commit以及系统的发布日志,发现此接口从5.5.10开始支持。
https://github.com/linuxdeepin/dde-file-manager/commits/5.5.10/src/dde-file-manager-extension
此部分详细信息可参与github项目
DFMExtEmblemIconPlugin类是第三方开发者应该继承并实现的接口类,并且在元接口
dfm_extesion_emblem中返回派生的类对象,接口定义在头文件
dfmextemblemiconplugin.h` 中。需要特别注意的是,需要提前将角标资源图片文件安装到系统主题中,规则遵循 freedesktop 规范。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
extern "C" void dfm_extension_initialize();
extern "C" void dfm_extension_shutdown();
extern "C" DFMExtEmblemIconPlugin *dfm_extension_emblem();
/////////////////////////////////////////////////////////////
class DFMExtEmblemIconPluginPrivate;
class DFMExtEmblemIconPlugin
{
DFM_DISABLE_COPY(DFMExtEmblemIconPlugin)
public:
using IconsType = std::vector<std::string>;
using EmblemIcons = std::function<IconsType(const std::string &)>;
using LocationEmblemIcons = std::function<DFMExtEmblem(const std::string &, int)>;
public:
DFMExtEmblemIconPlugin();
~DFMExtEmblemIconPlugin();
// Note: If the corner mark set by emblemIcons conflicts with the corner mark position set by locationEmblemIcons,
// the conflict position will only display the corner mark set by locationEmblemIcons
DFM_FAKE_VIRTUAL IconsType emblemIcons(const std::string &fileUrl) const;
void registerEmblemIcons(const EmblemIcons &func);
DFM_FAKE_VIRTUAL DFMExtEmblem locationEmblemIcons(const std::string &fileUrl, int systemIconCount) const;
void registerLocationEmblemIcons(const LocationEmblemIcons &func);
private:
DFMExtEmblemIconPluginPrivate *d { nullptr };
};
|
dfm_extension_initialize | 插件初始化入口函数,插件被加载后将首先调用它 |
dfm_extension_shutdown | 插件释放的函数,当插件被卸载前将会调用它 |
dfm_extesion_menu | 返回右键菜单扩展对象的函数,该对象的类由第三方开发者实现 |
dfm_extesion_emblem | 返回角标对象的函数,该对象的类由第三方开发者实现 |
名称 | 简介 |
emblemIcons | 文管主动调用,传入文件路径,返回被安装的角标图片名称列表 |
registerEmblemIcons | emblemIcons 接口的注册函数,第三方开发者主动注册 |
locationEmblemIcons | 文管主动调用,传入文件路径和这个文件的现有系统角标数量,如果这个值达到了4,那么就位置绘制扩展角标了 |
registerLocationEmblemIcons | locationEmblemIcons 接口的注册函数,第三方开发者主动注册 |
Dev & Impl
OS: UOS20-1050-PRO
dde-file-manage:5.6.12
github: GitHub - pinkkmin/dfm-examples
Project
DFMGenericPlugin
⚠️ 我在浏览论坛时,发现有人提到此接口在某些版本的dfm可能引起崩溃(见上述链接内容),但我在实践的UOS20版本中并未发现,因此具体在不同版本的dfm实践时还需多多测试。
1
2
3
4
5
6
7
|
dfm-emblem-example-plugin.pro
dfmgenericpluginobject.cpp
dfmgenericpluginobject.h
emblem-default.png
generic.json
main.cpp
res.qrc
|
DFMExtEmblemIconPlugin
👊 我实践此接口时(2022-09-02)并没有找到可参考的文档或示例,所以我邮件请教了dfm的开发者。他提供了一份有用的文档(见docs/dfm-extension-doc(answerofdeveloper).md)可以参考。
⚠️应当小心此文档的时效性,还是以官方的最新文档以及github仓库信息优先。
1
2
3
4
5
|
emblems
+ basketball.png
ext-emblem-example.pro
ext-emblem-impl.cpp
res.qrc
|
Coding
DFMGenericPlugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
// dfmgenericpluginobject.h
#include <QObject>
#include <QIcon>
#include <QQueue>
#include <dabstractfileinfo.h>
#include "dde-file-manager-extension/emblemicon/dfmextemblemiconplugin.h"
QT_BEGIN_NAMESPACE
class QTcpSocket;
class QUdpSocket;
QT_END_NAMESPACE
class DFMGenericPluginObject : public QObject
{
Q_OBJECT
public:
explicit DFMGenericPluginObject(QObject *parent = 0);
public slots:
QList<QIcon> fileAdditionalIcon(const DAbstractFileInfoPointer &fileInfo);
};
#endif // DFMGENERICPLUGINOBJECT_H
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// dfmgenericpluginobject.h
#include "dfmgenericpluginobject.h"
#include <QWidget>
DFMGenericPluginObject::DFMGenericPluginObject(QObject *parent)
: QObject(parent)
{
}
QList<QIcon> DFMGenericPluginObject::fileAdditionalIcon(const DAbstractFileInfoPointer &fileInfo)
{
QList<QIcon> list;
list << QIcon("://emblem-default.png");
return list;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// dfmgenericpluginobject.cpp
#include <dfmgenericplugin.h>
#include "dfmgenericpluginobject.h"
DFM_USE_NAMESPACE
class PluginMain : public DFMGenericPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID DFMGenericFactoryInterface_iid FILE "generic.json")
public:
QObject *create(const QString &key)
{
if (key != "fileinfo/additionalIcon")
return Q_NULLPTR;
return new DFMGenericPluginObject();
}
};
#include "main.moc"
|
DFMExtEmblemIconPlugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
#include <QMessageLogger>
#include <QDebug>
#include <QString>
#include <iostream>
#include "dfm-extension.h"
#include "emblemicon/dfmextemblem.h"
#include "emblemicon/dfmextemblemiconplugin.h"
#include "emblemicon/dfmextemblemiconlayout.h"
USING_DFMEXT_NAMESPACE
// 全局徽标插件单例
static DFMExtEmblemIconPlugin *kEmblemPlugin = nullptr;
// bind functions
DFMExtEmblemIconPlugin::EmblemIcons emblemIconFunc;
DFMExtEmblemIconPlugin::LocationEmblemIcons localEmblemFunc;
std::vector<std::string> demo_emblemIcons(const std::string &fileUrl)
{
std::vector<std::string> icons;
std::cout<<"########################## emblem-example: fileUrl: "<<fileUrl<<std::endl;
if(fileUrl.empty()) return icons;
// demo 使用qrc资源
icons.push_back("://emblems/basketball.png");
// demo 系统主题默认的emblem
// /usr/lib/icons/xxx/48x48/emblems/emblem-default.png
icons.push_back("emblem-default");
return icons;
}
DFMExtEmblem demo_locationEmblemIcons(const std::string &fileUrl, int systemIconCount)
{
std::string emblempath="://emblems/basketball.png";
DFMExtEmblemIconLayout dsmemblem(DFMExtEmblemIconLayout::LocationType::BottomRight,emblempath);
std::vector<DFMExtEmblemIconLayout> iconPaths;
iconPaths.push_back(dsmemblem);
DFMExtEmblem emblems;
emblems.setEmblem(iconPaths);
return emblems;
}
extern "C" void dfm_extension_initiliaze()
{
qInfo()<<"########################## emblem-example: dfm_extension_initiliaze.....";
if (!kEmblemPlugin)
{
kEmblemPlugin = new DFMExtEmblemIconPlugin;
// 方式一:据悉,此接口为旧接口。但实际效果比localEmblem要好很多
emblemIconFunc = demo_emblemIcons;
kEmblemPlugin->registerEmblemIcons(emblemIconFunc);
// 方式二:此接口指定了位置,当位置冲突时,徽标可能会不显示
// localEmblemFunc = demo_locationEmblemIcons;
// kEmblemPlugin->registerLocationEmblemIcons(localEmblemFunc);
}
}
extern "C" void dfm_extension_shutdown()
{
qInfo()<<"########################## emblem-example: dfm_extension_shutdown.....";
if (kEmblemPlugin)
{
delete kEmblemPlugin;
kEmblemPlugin = nullptr;
}
}
extern "C" DFMExtEmblemIconPlugin *dfm_extension_emblem()
{
qInfo()<<"################# dfm_extension_emblem.......";
return kEmblemPlugin;
}
|
如上,这只是一份示例代码。建议使用C++继承对应的基类实现该功能,见官方文档。
Demo
将编译的动态库放置于以下目录:
对于DFMGenericPlugin接口,该目录为/usr/lib/x86_64-linux-gnu/dde-file-manager/plugins/generics/
对于DFMExtEmblemIconPlugin接口,改目录为/usr/lib/x86_64-linux-gnu/dde-file-manager/plugins/extensions/
然后,重启dde-file-manager
.由于dfm有守护进程的存在,因而直接执行sudo kill -9 dde-file-manager
可能并不会重新加载插件动态库,徽标也就无法奏效。因而,需要先杀死dfm的守护进程然后在重启之。
1
2
3
4
5
6
7
8
|
# install DFMGenericPlugin
mkdir -p /usr/lib/x86_64-linux-gnu/dde-file-manager/plugins/generics/
cp libemblem-example-plugin.so /usr/lib/x86_64-linux-gnu/dde-file-manager/plugins/generics/
# install DFMExtEmblemIconPlugin
mkdir -p /usr/lib/x86_64-linux-gnu/dde-file-manager/plugins/extensions/
cp ./out/libext-menu-example.so /usr/lib/x86_64-linux-gnu/dde-file-manager/plugins/extensions/
cp libext-emblem-demo.so /usr/lib/x86_64-linux-gnu/dde-file-manager/plugins/extensions/
|
DFMGenericPlugin
dde-file-manager
desktop
DFMExtEmblemIconPlugin
desktop
dde-file-manager
Finally
有一个特别无语的事情…..UOS提供的dfm-extension-dev包里面的头文件是错误的…如下,如果不仔细看的话…..插件就永远起不来….
看看最后两个函数的定义…..wtf?单词拼错了…..
1
2
3
4
|
extern "C" void dfm_extension_initiliaze();
extern "C" void dfm_extension_shutdown();
extern "C" DFMExtMenuPlugin *dfm_extesion_menu();
extern "C" DFMExtEmblemIconPlugin *dfm_extesion_emblem();
|
Reference
不来体验体验深度文件管理器的坚果云插件么?-论坛-深度科技 (deepin.org)
linuxdeepin/dde-file-manager-integration