-
Notifications
You must be signed in to change notification settings - Fork 175
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: [example] add example for dfm-extension
add example for dfm-extension Log: add example for dfm-extension
- Loading branch information
1 parent
9cad874
commit e4b6222
Showing
8 changed files
with
386 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
cmake_minimum_required(VERSION 2.8) | ||
|
||
# 设置项目名称 | ||
project(dfm-extension-example) | ||
|
||
set(CMAKE_CXX_STANDARD 17) | ||
|
||
# 只需要依赖 dfm-extension | ||
find_package(dfm-extension REQUIRED) | ||
|
||
|
||
# 扩展插件源码 | ||
file(GLOB_RECURSE SRCS CONFIGURE_DEPENDS | ||
"./*.h" | ||
"./*.cpp" | ||
) | ||
|
||
# 生成共享库 | ||
add_library(${PROJECT_NAME} SHARED ${SRCS}) | ||
|
||
# 链接 dfm-extension | ||
target_link_libraries(${PROJECT_NAME} | ||
PUBLIC ${dfm-extension_LIBRARIES} | ||
) | ||
|
||
# 安裝配置 | ||
include(GNUInstallDirs) | ||
if(NOT DEFINED LIB_INSTALL_DIR) | ||
set(LIB_INSTALL_DIR ${CMAKE_INSTALL_FULL_LIBDIR}) | ||
endif() | ||
|
||
if(NOT DEFINED DFM_EXT_PLUGIN_DIR) | ||
set(DFM_EXT_PLUGIN_DIR ${LIB_INSTALL_DIR}/dde-file-manager/plugins/extensions) | ||
endif() | ||
|
||
# 安裝插件 | ||
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${DFM_EXT_PLUGIN_DIR}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# dfm-extension-example | ||
|
||
一个基于文件管理器(dde-file-manager)的扩展开发库(dfm-extension)的示例程序。 | ||
|
||
## 依赖 | ||
|
||
```shell | ||
$ sudo apt install libdfm-extension-dev | ||
``` | ||
|
||
## 安装 | ||
|
||
```shell | ||
$ cmake -B build -DCMAKE_INSTALL_PREFIX=/usr | ||
$ cmake --build build | ||
$ sudo cmake --build build --target install | ||
``` | ||
|
||
安装后,重启生效。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#include <dfm-extension/dfm-extension.h> | ||
|
||
#include "mymenuplugin.h" | ||
#include "myemblemiconplugin.h" | ||
|
||
// 右键菜单的扩展 | ||
static DFMEXT::DFMExtMenuPlugin *myMenu { nullptr }; | ||
// 角标的扩展 | ||
static DFMEXT::DFMExtEmblemIconPlugin *myEmblemIcon { nullptr }; | ||
|
||
extern "C" void dfm_extension_initiliaze() | ||
{ | ||
myMenu = new Exapmle::MyMenuPlugin; | ||
myEmblemIcon = new Exapmle::MyEmblemIconPlugin; | ||
} | ||
|
||
extern "C" void dfm_extension_shutdown() | ||
{ | ||
delete myMenu; | ||
delete myEmblemIcon; | ||
} | ||
|
||
extern "C" DFMEXT::DFMExtMenuPlugin *dfm_extension_menu() | ||
{ | ||
return myMenu; | ||
} | ||
|
||
extern "C" DFMEXT::DFMExtEmblemIconPlugin *dfm_extension_emblem() | ||
{ | ||
return myEmblemIcon; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. | ||
// | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include "myemblemiconplugin.h" | ||
|
||
#include <sys/types.h> | ||
#include <sys/xattr.h> | ||
#include <ulimit.h> | ||
|
||
namespace Exapmle { | ||
|
||
USING_DFMEXT_NAMESPACE | ||
|
||
MyEmblemIconPlugin::MyEmblemIconPlugin() | ||
: DFMEXT::DFMExtEmblemIconPlugin() | ||
{ | ||
registerLocationEmblemIcons([this](const std::string &filePath, int systemIconCount) { | ||
return locationEmblemIcons(filePath, systemIconCount); | ||
}); | ||
} | ||
|
||
MyEmblemIconPlugin::~MyEmblemIconPlugin() | ||
{ | ||
} | ||
|
||
DFMExtEmblem MyEmblemIconPlugin::locationEmblemIcons(const std::string &filePath, int systemIconCount) const | ||
{ | ||
DFMExtEmblem emblem; | ||
|
||
// 一个文件的角标最多只有 4 个,当系统角标的数量已经达到 4 个时则无法添加扩展角标了 | ||
// 此外,如果扩展角标添加的位置被系统角标占用,那么扩展角标将无法被显示 | ||
if (systemIconCount >= 4) | ||
return emblem; | ||
|
||
// 从文件扩展属性中获取右键菜单扩展添加的角标属性 | ||
char buffer[FILENAME_MAX] { 0 }; | ||
ssize_t result = getxattr(filePath.c_str(), "user.icon", buffer, FILENAME_MAX); | ||
if (result == -1) | ||
return emblem; | ||
|
||
// 添加角标 icon 到文件图标的左下角 | ||
std::string strBuffer { buffer }; | ||
if (!strBuffer.empty()) { | ||
std::vector<DFMExtEmblemIconLayout> layouts; | ||
DFMExtEmblemIconLayout iconLayout { DFMExtEmblemIconLayout::LocationType::BottomLeft, strBuffer }; | ||
layouts.push_back(iconLayout); | ||
emblem.setEmblem(layouts); | ||
} | ||
|
||
return emblem; | ||
} | ||
|
||
} // namespace Exapmle |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. | ||
// | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#ifndef MYEMBLEMICONPLUGIN_H | ||
#define MYEMBLEMICONPLUGIN_H | ||
|
||
#include <dfm-extension/emblemicon/dfmextemblemiconplugin.h> | ||
|
||
namespace Exapmle { | ||
|
||
class MyEmblemIconPlugin : public DFMEXT::DFMExtEmblemIconPlugin | ||
{ | ||
public: | ||
MyEmblemIconPlugin(); | ||
~MyEmblemIconPlugin(); | ||
|
||
DFMEXT::DFMExtEmblem locationEmblemIcons(const std::string &filePath, int systemIconCount) const DFM_FAKE_OVERRIDE; | ||
}; | ||
|
||
} // namespace Exapmle | ||
|
||
#endif // MYEMBLEMICONPLUGIN_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. | ||
// | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include "mymenuplugin.h" | ||
|
||
#include <sys/types.h> | ||
#include <sys/xattr.h> | ||
#include <sys/wait.h> | ||
#include <unistd.h> | ||
#include <cassert> | ||
#include <iostream> | ||
|
||
#include <dfm-extension/menu/dfmextmenu.h> | ||
#include <dfm-extension/menu/dfmextmenuproxy.h> | ||
#include <dfm-extension/menu/dfmextaction.h> | ||
|
||
namespace Exapmle { | ||
USING_DFMEXT_NAMESPACE | ||
|
||
MyMenuPlugin::MyMenuPlugin() | ||
: DFMEXT::DFMExtMenuPlugin() | ||
{ | ||
registerInitialize([this](DFMEXT::DFMExtMenuProxy *proxy) { | ||
initialize(proxy); | ||
}); | ||
registerBuildNormalMenu([this](DFMExtMenu *main, const std::string ¤tPath, | ||
const std::string &focusPath, const std::list<std::string> &pathList, | ||
bool onDesktop) { | ||
return buildNormalMenu(main, currentPath, focusPath, pathList, onDesktop); | ||
}); | ||
registerBuildEmptyAreaMenu([this](DFMExtMenu *main, const std::string ¤tPath, bool onDesktop) { | ||
return buildEmptyAreaMenu(main, currentPath, onDesktop); | ||
}); | ||
} | ||
|
||
MyMenuPlugin::~MyMenuPlugin() | ||
{ | ||
} | ||
|
||
void MyMenuPlugin::initialize(DFMExtMenuProxy *proxy) | ||
{ | ||
m_proxy = proxy; | ||
} | ||
|
||
bool MyMenuPlugin::buildNormalMenu(DFMExtMenu *main, const std::string ¤tPath, | ||
const std::string &focusPath, const std::list<std::string> &pathList, | ||
bool onDesktop) | ||
{ | ||
// 可使用此方法管理自己开辟的内存,菜单关闭时被调用 | ||
// 但是并不需要使用代理 m_proxy->deleteMenu / delteAction | ||
// 因为只要创建的 menu 和 action 被加入了菜单 main,那么 | ||
// 它们的内存会被自动释放 | ||
auto memTest { new int }; | ||
main->registerDeleted([memTest](DFMExtMenu *self) { | ||
delete memTest; | ||
}); | ||
|
||
(void)onDesktop; | ||
(void)currentPath; | ||
(void)focusPath; | ||
|
||
// 通过代理创建 action,此 action 在堆区分配,不自行释放将内存泄露! | ||
auto rootAction { m_proxy->createAction() }; | ||
rootAction->setText("角标管理"); | ||
|
||
// 通过代理创建 menu,此 menu 在堆区分配,不自行释放将内存泄露! | ||
auto menu { m_proxy->createMenu() }; | ||
|
||
// 二级菜单在 Hover 中创建,以减少一级菜单显示的性能开销 | ||
rootAction->setMenu(menu); | ||
rootAction->registerHovered([this, pathList](DFMExtAction *action) { | ||
if (!action->menu()->actions().empty()) | ||
return; | ||
auto favoriteEmblemAct { m_proxy->createAction() }; | ||
favoriteEmblemAct->setText("角标设置为favorite"); | ||
favoriteEmblemAct->setIcon("emblem-favorite"); | ||
favoriteEmblemAct->registerTriggered([this, pathList](DFMExtAction *, bool) { | ||
std::for_each(pathList.begin(), pathList.end(), [this](const std::string &path) { | ||
setEmblemIcon(path, "emblem-favorite"); | ||
}); | ||
}); | ||
|
||
auto defaultEmblemAct { m_proxy->createAction() }; | ||
defaultEmblemAct->setIcon("emblem-default"); | ||
defaultEmblemAct->setText("角标设置为default"); | ||
defaultEmblemAct->registerTriggered([this, pathList](DFMExtAction *, bool) { | ||
std::for_each(pathList.begin(), pathList.end(), [this](const std::string &path) { | ||
setEmblemIcon(path, "emblem-default"); | ||
}); | ||
}); | ||
|
||
auto clearEmbelmAct { m_proxy->createAction() }; | ||
clearEmbelmAct->setIcon("emblem-important"); | ||
clearEmbelmAct->setText("清除角标"); | ||
clearEmbelmAct->registerTriggered([this, pathList](DFMExtAction *, bool) { | ||
std::for_each(pathList.begin(), pathList.end(), [this](const std::string &path) { | ||
clearEmblemIcon(path); | ||
}); | ||
}); | ||
|
||
action->menu()->addAction(favoriteEmblemAct); | ||
action->menu()->addAction(defaultEmblemAct); | ||
action->menu()->addAction(clearEmbelmAct); | ||
}); | ||
|
||
main->addAction(rootAction); | ||
return true; | ||
} | ||
|
||
bool MyMenuPlugin::buildEmptyAreaMenu(DFMExtMenu *main, const std::string ¤tPath, bool onDesktop) | ||
{ | ||
assert(main); | ||
|
||
// 通过代理创建 action,此 action 在堆区分配,不自行释放将内存泄露! | ||
auto action { m_proxy->createAction() }; | ||
|
||
// 通过 onDesktop 区分业务在桌面还是文管 | ||
if (onDesktop) | ||
action->setText("从文件管理器打开桌面"); | ||
else | ||
action->setText("打开当前路径"); | ||
// 添加图标,也支持图片的文件绝对路径 | ||
// 例如:/usr/share/icons/Adwaita/16x16/emblems/emblem-generic.png | ||
action->setIcon("emblem-generic"); | ||
|
||
// action 被点击触发的业务处理 | ||
action->registerTriggered([currentPath](DFMExtAction *self, bool checked) { | ||
(void)self; | ||
(void)checked; | ||
pid_t pid = fork(); | ||
if (pid == 0) { | ||
// 子进程中调用 execvp 函数来执行 dde-file-manager 进程,并传递参数 | ||
char *argv[] { "/usr/bin/dde-file-manager", "-n", const_cast<char *>(currentPath.c_str()), NULL }; | ||
execvp(argv[0], argv); | ||
} else if (pid > 0) { | ||
// 父进程等待子进程结束 | ||
int status; | ||
waitpid(-1, &status, WNOHANG); | ||
} else { | ||
perror("fork failed"); | ||
} | ||
}); | ||
|
||
main->addAction(action); | ||
return true; | ||
} | ||
|
||
void MyMenuPlugin::setEmblemIcon(const std::string &filePath, const std::string &iconName) | ||
{ | ||
std::cout << "set emblem icon " << iconName << " for " << filePath << std::endl; | ||
const std::string path { removeScheme(filePath) }; | ||
int result = setxattr(path.c_str(), "user.icon", iconName.c_str(), iconName.size(), 0); | ||
if (result == -1) | ||
perror("setxattr"); | ||
} | ||
|
||
void MyMenuPlugin::clearEmblemIcon(const std::string &filePath) | ||
{ | ||
std::cout << "clear emblem icon for " << filePath; | ||
const std::string path { removeScheme(filePath) }; | ||
int result = removexattr(path.c_str(), "user.icon"); | ||
if (result == -1) | ||
perror("removexattr"); | ||
} | ||
|
||
// 在 V5 版本的文管中,menu 接收到的是文件 url 的字符串,而 V6 则直接是文件路径 | ||
std::string MyMenuPlugin::removeScheme(const std::string &url) | ||
{ | ||
std::string result = url; | ||
|
||
// 查找第一个冒号后的斜杠位置 | ||
size_t startPos = result.find("://"); | ||
if (startPos != std::string::npos) { | ||
startPos = result.find('/', startPos + 3); // 跳过冒号和两个斜杠 | ||
if (startPos != std::string::npos) { | ||
result = result.substr(startPos); | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
|
||
} // namespace Exapmle |
Oops, something went wrong.