• 首页
  • 加入
  • RSS
  • Monday, August 14, 2023

    队员:复旦大学 朱元依、沈扬、朱俊杰
    指导老师:张亮、陈辰
    企业导师:王子冲

    本项目为2023年操作系统大赛企业赛道赛题。

    项目链接:DDE 控制中心自启动管理插件 github仓库

    1 摘要

    Deepin(原名Linux Deepin)致力于为全球用户提供美观易用,安全可靠的Linux发行版。该系统由深度科技自主开发,提供了美观易用、极简操作的桌面环境,主要由桌面、启动器、任务栏、控制中心、窗口管理器等组成。其中,控制中心是Deepin桌面环境的核心组件之一,它是用于管理和配置操作系统各种设置的集成工具。然而,在该控制中心中,并未对用户提供自启动项提供的便捷管理界面。在本项目中,我们为Deepin操作系统中自启动项的修改功能编写了简洁易用的控制中心插件,将自启动管理的系统功能集成到了控制中心中。该插件以单独的仓库提供,并能够单独构建,一键植入Deepin控制中心中。

    2 需求分析

    最终用户对自启动权限的管理目前只能通过dde-launcher(启动器/“开始菜单”)的右键菜单进行管理,而控制中心作为控制系统的门户应用反而缺少此功能。

    用户需求

    在官方发布的deepin23-Beta版本中,对于用户程序与系统程序的自启动管理方法为:找到应用的可执行程序(通常为.desktop)类型的文件,通过右键打开功能菜单的方式设置为开机自启动。但由于操作系统自带的应用程序界面中所有程序都会被展示到,所以当操作系统中应用程序过多的时候用户很难统计到那些程序被设置成了开机自启动,同时对于用户不想参与管理的应用也会展示在应用菜单中。因此我们对于本项目开发所面向的需求是在控制中心(deepin-control-center)中在不影响原有插件所提供的设置服务的基础上,为用户提供一个额外的插件用于管理开机自启动软件,同时插件可以满足用户自行选择需要手动维护的自启动程序,对于用户希望自己管理是否自启动的软件显示在面板上可以对是否自启动进行开关,用户不希望管理的软件默认不自启动不显示到面板;面板也可以提供添加和删除的功能让用户挑选出自己想要在面板上操作的应用。

    功能需求

    deepin作为国产开源的深度Linux桌面系统,不仅为用户提供了人性化、个性化以及对于中文等语言有良好支持的操作系统体验,也为Linux的开发者与学习者提供了控制中心(dde-control-center)与任务栏(dde-dock)等桌面控件的开发者接口与插件注入接口。除了可以不断的扩展完善用户需求与用户体验外,deepin深度桌面在操作系统学科的教学与深入理解方面也带来了很多的可能性与创造性。因此作为OS大赛的参与团队,我们不仅是在希望我们的开发会对deepin项目的完整性、deepin用户的体验感上带来一些帮助,同时也想通过我们自己的努力在学生的视角让操作系统的教学与后续学习有一个优秀的案例和一些开发相关的经验总结,使得我们理论层面的操作系统教学可以有更大的实践空间。

    2.1 当前方案

    目前已有的自启动管理方法是在开始菜单中对菜单中所展示应用软件单独进行自启动的设置。具体的方法是对所希望设置自启动项的应用软件选中后右键,点击“设置开机自启动”即可在每次开机时自动打开该应用软件。

    默认自启动设置方式

    然而,这种方法有两大明显的缺陷:(1)无法向用户展示所有的自启动项设置(2)大批量的自启动项修改极其不便。由此,催生了控制中心自启动管理插件的需求。

    2.2 插件需求

    为了完成控制中心插件,我们对需求进行了更细致的刻画。经过总结后,插件的需求主要分为三条:

    1、完成一个控制中心插件,能够展示当前所有开机启动项的列表; 2、能够在插件中,通过用户界面的交互来管理(添加、删除、启用、禁用)开机启动项; 3、插件以单独的仓库提供,并能够单独构建,不需要合并入 dde-control-center 项目。

    其中,第一条需求是该插件的基础。自启动项的列表一方面为用户提供了清晰的展示界面,另一方面也是程序与用户交互,获取修改操作信息的基础。 第二条需求总结了该插件需要支持的功能,即添加、删除、启用、禁用,这些功能需要在前端设计对应的交互界面,同时在后端设计对应的操作接口,调用系统接口以修改自启动设置。 第三条需求与系统发布相关。目前最新的稳定发布版本是Deepin V23 Beta,而官方版本已经在发布,若修改源码统一编译控制中心,会需要对当前已发行的操作系统版本进行修改,较为不便。故需要单独编译该插件,并将其装载到系统中的插件接口中。

    3 相关资料调研

    3.1 Deepin开机自启动系统设置

    Deepin系统通过检测固定的目录,检测自启动项。通过放置应用程序的.desktop文件在其中一个自动启动目录中,系统可以检测到该应用程序的自启动设置。通过修改.desktop文件中的对应字段,可以修改对应应用程序的自启动设置。

    3.1.1 自启动目录

    “desktop base directory specification”中的“Referencing this specification” 部分进行定义了自动启动目录是 $XDG_CONFIG_DIRS/autostart

    如果同一文件名位于多个自动启动目录下,只应使用最重要目录下的文件。

    示例:

    如果未设置$XDG_CONFIG_HOME,用户主目录中的自动启动目录为~/.config/autostart/

    如果未设置$XDG_CONFIG_DIRS,系统范围的自动启动目录为/etc/xdg/autostart/

    如果未设置$XDG_CONFIG_HOME$XDG_CONFIG_DIRS,并且两个文件/etc/xdg/autostart/foo.desktop~/.config/autostart/foo.desktop存在,那么只有文件~/.config/autostart/foo.desktop将被使用,因为~/.config/autostart//etc/xdg/autostart/更重要。

    3.1.2 应用程序的.desktop 文件

    一个应用程序的.desktop文件必须符合"桌面入口规范"中定义的格式。所有关键字应按照定义进行解释,但以下情况除外,以便考虑到位于自动启动目录中的.desktop文件不会显示在菜单中。

    Hidden关键字

    .desktop文件的Hidden关键字设置为true时,该.desktop文件必须被忽略。当多个具有相同名称的.desktop文件存在于多个目录中时,仅应考虑最重要的.desktop文件中的Hidden关键字:如果其设置为true,则其他目录中具有相同名称的所有.desktop文件也必须被忽略。

    OnlyShowInNotShowIn关键字

    OnlyShowIn项可以包含一个字符串列表,用于标识必须自动启动此应用程序的桌面环境,其他桌面环境不得自动启动此应用程序。

    NotShowIn项可以包含一个字符串列表,用于标识不得自动启动此应用程序的桌面环境,其他桌面环境必须自动启动此应用程序。

    这两个关键字中的一个,要么是OnlyShowIn,要么是NotShowIn,可以出现在单个.desktop文件中。

    TryExec关键字

    带有非空TryExec字段的.desktop文件如果TryExec关键字的值与已安装的可执行程序不匹配,则不得自动启动。TryExec字段的值可以是绝对路径,也可以是没有任何路径组件的可执行文件名。如果指定了没有任何路径组件的可执行文件名,则会搜索$PATH环境以找到匹配的可执行程序。

    注意事项

    如果通过在系统范围的自动启动目录中安装.desktop文件来自动启动应用程序,则个人用户可以通过在其个人自动启动目录中放置具有相同名称的.desktop文件来禁用此应用程序的自动启动,并在其中包含Hidden=true关键字。

    3.2 控制中心插件开发

    V23控制中心特性

    1、V23控制中心只负责框架设计,具体功能全部由插件实现; 2、V23控制中心支持多级插件系统,支持插件插入到任意位置中; 3、高度可定制,可定制任意插件是否显示,若插件支持,可定制任意插件内容是否显示。

    V23控制中心插件安装路径说明

    1、控制中心会自动加载翻译,翻译目录需要严格放置在/${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/dde-control-center/translations下,控制中心会自动加载,同时,插件的翻译和名称也有要求,命名为${Plugin_name}_{locale}.tslocale就是多语言的翻译,翻译文件必须控制和插件名称相同; 2、控制中心的so应该放置在/${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTA;LL_LIBDIR}/dde-control-center/modules下,请使用构建系统的提供的gnuinstall路径,上面举的例子是cmakemesonbuild也有自己的逻辑。

    V23控制中心开发接口说明

    1、ModuleObject类用于构建每个页面元素,其是插件的核心; 2、PluginInterface类用于规范插件信息,每个插件必须提供一个`ModuleObject对象。

    标准开发流程示例

    1、继承PluginInterface,实现其虚函数; 2、实例化一个根模块,根模块在初始化时不允许有耗时操作,若有耗时操作,应继承ModuleObject然后实现active方法,将耗时操作放入其中; 3、若根模块的子项是横向菜单列表,则可使用List储存其基础信息,继承或使用HListModule类,然后循环使用appendChild方法将菜单添加到根模块中; 4、若根模块的子项是纵向菜单列表,则可使用List储存其基础信息,继承或使用VListModule类,然后循环使用appendChild方法将菜单添加到根模块中; 5、以此类推,具体的某个子项菜单同样再次添加菜单列表,直到菜单列表的子项为PageModule时为止; 6、准备一个以上的Module继承自ModuleObject,并实现其page()方法,然后添加到PageModule中,注意,page()方法中需返回新的QWidget对象; 7、当某个菜单为PageModule时,使用其appendChild方法将上方的Module添加到其子项中,此时,控制中心会根据page的大小添加滚动条,并将多个page进行垂直排列进行显示。PageModule持支嵌套,并且其有默认边距,如果嵌套使用,嵌套的PageModule边距建议设置为0; 8、若某个VListModulePageModule页面需要附加按钮时,可调其子项ModuleObjectsetExtra,该ModuleObjectpage提供按钮,这样该ModuleObject将显示在VListModulePageModule页面的最下方。

    4 系统框架设计

    4.1 项目组织方式

    类图

    类图

    项目文件组织

    .
    ├── CMakeLists.txt
    ├── include
    │   ├── interface
    │   │   ├── ...
    │   └── widgets
    │       ├── ...
    ├── misc
    │   ├── ...
    ├── shell.sh
    ├── src
    │   ├── frame
    │   │   ├── ...
    │   ├── interface
    │   │   ├── ...
    │   ├── plugin-selfstartup
    │   │   ├── operation
    │   │   │   ├── ...
    │   │   └── window
    │   │       ├── ...
    │   └── widgets
    │       ├── ...
    └── translations
        ├── ...(translation files)
        ├── desktop
            ├──...(desktop translation files)
    

    4.1 总体思路与系统框架

    4.1.1文件框架思路

    通过阅读dde-control-center的源代码,src部分为插件的实现以及实现代码复用所存在的框架代码,代码的插件部分在src/plugin-selfstartup目录,分为operation和window部分,其中windows部分主要负责控制中心自启动项目的界面构成,operation部分负责参与控制中心对系统文件与配置的控制。translation文件夹为控制中心(dde-control-center)提供了不同语言环境下的支持,通过识别系统的语言环境选择展示到面板不同的语言。include与misc为项目注册到控制中心所必须包含的编译依赖文件。

    4.1.2 设计思路

    我们在初赛中已经完成了通过注册到dde-dock实现的自启动插件,对于插件的界面以及界面上按钮对应的功能已经有了一个大致的构想,但由于dde-dock的插件是一个较为独立的结构,而dde-control-center里面的每一个插件都需要往控制中心里注册一个module并且通过rpc方法与dde-application-manager进行远程服务的交流,因此在实现细节上dde-control-center插件和dde-dock插件有着很大的区别。

    用户逻辑方面,我们首先在控制中心实现了管理自启动应用的面板,对于添加到维护列表的应用都会被展示到面板上,对于每一项应用都会提供Enable/Disable的选择按钮和Delete的删除按钮,用于管理是否开机自启动与不希望维护改应用的删除。同时在面板有一个添加按钮,用户点击后会打开文件对话框,用户可以自行从中选择自定义路径的应用程序添加到插件维护的列表中。

    插件运行逻辑方面,分别有添加、删除、开启/关闭(反转)逻辑,分别思路如下:

    • 添加逻辑:用户在点击添加按钮后会获取该文件的路径并读取FileInfoAddButtonWidget发送requestCreateFile信号携带参数Category名称与FileInfoWorker中;Worker/home/user/.config/autostart文件下判断是否存在一个相同的应用信息,如果不存在则创建一个原.desktop文件的副本并且添加一行Hidden=false字段,把应用信息存到App结构体中,同时调用Worker中对应的Category的添加函数传入赋值好的App,Category在内存中同步一份自启动应用信息,最后更新前端页面。
    • 删除逻辑:在用户点击应用对应行的删除按钮后获取到AppID,通过getAppById得到App信息后发送requestDelUserApp信号到WorkerWoker找到autostart文件夹中对应文件并将其删去,同时把App在对应的Category中移除,最后更新前端页面。
    • 反转逻辑:在用户点击对应行的打勾按钮后想获取到AppId,通过getAppById得到App信息后发送反转请求到WorkerWorker读取磁盘中autostart里对应.desktop文件文本找到Hidden字段并将其反转,同时调用Category把内存中App结构体的Hidden成员反转,最后更新前端页面。
    • 启动逻辑:插件启动的时候会调用CategorygetAppItem函数,该函数从autostart文件夹中逐文件读取信息存在App结构体中,封装到m_appList作为初始化时参与维护的应用程序,前端从m_appList中把应用名称以及是否自启动信息列举到页面

    4.2 类功能说明

    operation部分
    ├── defappmodel.cpp
    ├── defappmodel.h
    ├── defappworker.cpp
    ├── defappworker.h
    ├── mimedbusproxy.cpp
    ├── mimedbusproxy.h
    └── qrc
    

    operation部分是插件的后端部分,对于控制中心的每个插件都有ModelWorkerDBusProxy三个部分:

    • ModelModel部分通过继承QObject注册到QT的项目中,私有变量Category实现了自启动信息在内存中的一个副本用于前端的交互。
    • WorkerWorker部分提供了插件对文件系统的操作。由于操作系统对于开机自启动的支持在于把对应的.desktop文件拷贝到/home/user/.config/autostart中并设置Hidden=false,因此对于自启动应用管理的插件必须要对文件的读写提供支持,该支持由Woker部分实现。
    • DBusProxy:由于插件要注册到控制中心并且对应用进行管理,因此需要向运行中的应用程序管理服务(dde-application-manager)进行交互,管理服务提供了rpc的调用接口,插件通过DBusProxy部分向管理服务发起远程请求。
    window部分
    ├── selfstartup.json
    ├── selfstartup.cpp
    ├── selfstartupdetailwidget.h
    ├── selfstartupplugin.cpp
    ├── selfstartupplugin.h
    └── widgets
        ├── addbuttonwidget.cpp
        ├── addbuttonwidget.h
        ├── category.cpp
        └── category.h
    

    window部分是插件的前端部分,由PluginDetailwidgetAddbuttonwidgetCategory四个部分:

    • PluginPlugin部分构造了自启动程序插件。包括插件接口的初始化,一级页面的初始化和二级页面的初始化。
    • DetailwidgetDetailwidget部分构造了自启动程序插件的 app条目。包括app条目的外形、位置,app条目的增删改查操作,以及与workermodel的交互操作(通过信号和槽函数实现)。
    • AddbuttonwidgetAddbuttonwidget部分构造了自启动程序插件的加号按钮。包括加号按钮的外形、位置,新增app的弹窗显示,新增app的路径处理,以及与workermodel的交互操作(通过信号和槽函数实现)。
    • Category: category部分为磁盘中autostart文件夹中重要信息在内存中的拷贝,用于插件的窗口部分直接获取到该文件夹中.desktop类型文件的重要字段展示到界面。

    4.3 实现描述

    4.3.1 DefAppModel

    名称功能
    DefAppModelModel构造函数
    ~DefAppModelModel析构函数
    getModSelfSetUp返回SelfSetUp内存Category

    4.3.2 DefAppWorker

    名称功能
    DefAppWorkerWorker构造函数,连接Worker和Model
    DefaultAppsCategory枚举类,用于实现插件的可扩展性,实现对不同类型软件的分类,默认状态为只有SelfSetUp类
    active向应用程序管理服务发出blockSignal(false)消息
    deactive向应用程序管理服务发出blockSignal(true)消息
    onReverseUserApp对参与维护的自启动应用开关反转处理,把autostart中的.desktop文件Hidden字段反转并同步Category
    onGetListApps与Model处理应用变化信号结束的信息提供的一个空接口,只用于承接信号处理
    onDelUserApp在autostart文件夹中删去用户不希望继续维护是否自启动的应用并同步Category
    onAddUserFile向autostart中添加用户希望维护是否自启动的应用并同步Category
    getCategory返回应用类型的分类

    4.3.3 MimeDBusProxy

    名称功能
    MimeDBusProxyDBusProxy构造函数。
    DeleteApp向应用程序管理服务发送删除App请求。
    AddUserApp向应用程序管理服务发送添加用户App请求。
    ListApps向应用程序管理服务发送展示所有App请求。
    Change向应用程序管理服务发送App变动处理请求。

    4.3.4 SelfStartupDetailWidget

    名称功能
    SelfStartupDetailWidget自启动软件条目窗口构造函数。初始化条目窗口中的文字不可编辑、icon大小、条目形状、条目不可移动,初始化存储软件列表的QStandardItemModel,初始化软件条目的布局。
    ~SelfStartupDetailWidget自启动软件条目窗口析构函数。
    setModel设置自启动软件条目窗口的当前model。根据当前窗口的分类,设置不同的窗口model(由于本插件目前只有一个分类,因此setModel功能相当于直接调用setCategory功能)。
    setCategory设置自启动软件条目窗口的当前分类。将分类的增、删、改的信号和对应的自启动软件条目窗口的槽函数连接,将分类中的软件放入存储软件列表的QStandardItemModel中,并更新自启动软件条目窗口。
    updateListView更新自启动软件条目窗口。依次读取自启动软件条目窗口的当前model中的每一个软件状态,依照软件状态,更新窗口显示(显示是否自启动、软件名称、软件icon、删除按键)。
    getAppIcon获取软件的icon。从系统中获取软件的icon,并统一调整为32*32大小。
    getAppById通过ID获取APP结构体。遍历分类中的app,返回对应的APP结构体。
    appendItemData向model中新增app信息。从APP结构体中获取app信息,向model中新增app,并更新总app数量。
    isDesktopOrBinaryFile判断文件是否属于桌面或二进制文件。
    isValid判断app是否有效。判断app的ID非空。
    reverseItem向category发出app自启动状态转换的信号。
    requestDelUserApp向category发出删除app的信号。
    onListViewClicked自启动软件条目窗口被点击后的槽函数。从自启动软件条目窗口获取app信息,并向category发出app自启动状态转换的信号。
    onDelBtnClicked自启动软件条目窗口删除按钮被点击后的槽函数。从自启动软件条目窗口获取app信息,并向category发出删除app的信号。
    onClearAll清空model中所有的app信息。
    getAppListview返回model中所有的app信息。
    AppsItemChanged重置model中所有的app信息。依次将app_list中的app信息存入model中,并连接激活、点击信号。
    onReverseAppcategory返回app自启动状态转换信号的槽函数。更新对应model中app的自启动状态,并更新窗口。
    addItemcategory返回app新增信号的槽函数。向model中新增对应的app信息,并更新窗口。
    removeItemcategory返回app删减信号的槽函数。向model中删减对应的app信息,并更新窗口。
    showInvalidText设置自启动软件条目窗口的字体、图标的位置、大小。

    4.3.5 SelfStartupPlugin

    名称功能
    SelfStartupPlugin自启动程序插件的构造函数。基于DCC_NAMESPACE::PluginInterface的接口。
    name返回自启动程序插件的名称。
    module自启动程序插件初始化函数。初始化自启动程序插件的一级页面、二级页面和加号按钮。
    location返回自启动程序插件的位置。即,在控制中心插件中的排序。

    4.3.6 SelfStartupModule

    名称功能
    SelfStartupModule自启动程序插件一级页面的构造函数。初始化一级页面的名称,描述,图标,work,model。
    ~SelfStartupModule自启动程序插件一级页面的解构函数。向m_work、m_model发送删除信号。
    work返回m_work。
    model返回m_model。
    active激活m_work。

    4.3.7 SelfStartupDetailModule

    名称功能
    SelfStartupDetailModule自启动程序插件二级页面的构造函数。初始化二级页面的名称,分类,work,model。
    page自启动程序插件二级页面的初始化函数。初始化DetailWidget,并将DetailWidget的app状态修改信号、删除信号与work的槽函数相连接。

    4.3.8 Category

    名称功能
    CategoryCategory类构造函数,继承QObject类,每个Category类里面封装相同类型的应用信息
    getName获取当前Category分类的名称
    setCategory设置当前Category的类型名称
    getappItem获取当前Category封装的应用信息
    clear清空当前Category储存的应用信息
    addUserItem把传入应用信息存到Category中并向前端发送更新信号
    delUserItem把目标应用从Category中删除并向前端发送更新信号
    reverseUserItem设置目标应用Hidden字段反转并向前端发送更新信号

    5 系统测试情况

    5.1前端测试

    完成插件安装后,可在 DDE 控制中心中看到名为“自启动程序”的管理选项:

    前端页面

    5.2 自启动管理功能测试

    点击改图标,可以进入自启动管理界面:

    自启动管理页面

    该界面展示了设置所有的自启动项的软件,如果在软件右边出现了蓝色勾,则说明该软件设置了开机自启动。可以通过点击蓝色的勾取消开机自启动的设置,再次点击则可恢复。由此实现了自启动管理的开启、禁用功能。

    底部的加号用于添加需要进行自启动管理的软件,点击后跳出选择窗口:

    应用选择页面

    进入软件所安装的文件夹,选择该软件,即可将其添加入自启动管理中。在自启动管理界面中,可以点击软件右侧灰色的叉号,以将该软件剔除出自启动管理的界面。由此实现了自启动管理的添加、删除功能。

    6 插件的可扩展性

    本次项目的插件完整的覆盖了OSCOMP-proj223的所有需求,但由于只是一个短期开发的项目,因此有构想到了很多可以对插件进行扩展的方面;同时deepin作为开源社区也为开发者提供了良好的扩展接口,我们考虑了以下几点的扩展路径:

    6.1 语言扩展

    对于translation 板块,我们修改和编译仅仅使用了dde-control-center的zh_CN部分,限于语言广度我们只能提供插件的简体中文和英文模式,对于deepin可以支持的其他语言还有待扩展

    6.2 用户体验扩展

    由于Linux系统贯彻了"everything is a file"这一思想,因此整个操作系统的磁盘布局是文件化的,用户的应用可以安装到磁盘的任意地方,同时考虑到大部分Linux使用者为具有计算机基础能力的开发者,我们在插件中设计的添加应用按钮是让用户自主找到文件路径并添加。但是对于一般用户,这样的操作可能有些许复杂,所以我们考虑一个提高用户体验的方式:deepin中系统应用和从应用商店获取的用户程序分别分布在了两个文件夹中,如果用户没有自定义路径的话,我们的插件可以在用户请求添加的时候扫描这两个文件夹,提前给用户展示出可能用户希望添加的应用程序可供直接点击添加

    6.3 实时性扩展

    我们测试了dde-control-center的大部分插件,我们发现几乎所有都没有实现实时扫描磁盘的功能——即如果我们在dde-control-center外部对插件所管理的磁盘进行了修改的话,前端的界面并不会感受到更新而刷新界面。以自启动为例,我们实现了管理插件,但是用户仍然可以在应用菜单栏从控制中心外部添加到自启动中,此时自启动并不会更新页面,需要放回上一级窗口重新启动插件进行扫描。对于这一项扩展,我们考虑了一种方法为新起一个线程不停的扫描autostart文件夹中的.desktop文件并与Category中的比较,如果出现了不一致则发送(Q_Emit)更新窗口的信号,这样可以实现不返回上一级的情况下更新。但该功能只是作为扩展性的一个构想,实际实现的话首先带来的用户体验收益并不是很大,且已经存在插件的情况下应用场景很小,同时开启一个持续扫描的线程对于内存与插件的效率有较大的开销。

    6.4 并发性扩展

    插件的工作流程包含了修改磁盘与更新内存中的映射同时展示到面板上。对于磁盘的修改会涉及到一定次数的I/O,因此时间开销一定会比内存中信息更新更大的。因此我们思考了可以在此插件的基础上在新起一个进程,用rpc的方式对插件提供服务,服务内容包括对autostart文件夹的增删查改,插件只需要修改内存中的部分并作为rpc客户端向磁盘I/O的服务发送函数调用请求即可

    6.5 一致性的扩展

    因为插件会同时修改内存与磁盘的信息,并且保证二者相同,此时就会存在一定的一致性问题:

    • 磁盘和内存写入不同步,在其中一个进行的过程中发生了崩溃程序退出,此时是否成功写入成为一个一致性问题。我们的解决方式为先写入磁盘再写入内存,同时在重启插件的时候会重新扫描一次磁盘,这样只要写入磁盘的第一阶段成功之后即使崩溃也可以在重启的时候恢复数据
    • 多进程同时操作:如果有多个控制中心进程同时进行了文件的操作,采取的方式为读磁盘,写磁盘,写内存的操作,这样可以使得在读磁盘的时候如果有同名的应用被添加到里面会被正在写入(包括添加与删除操作)的进程阻塞读取,在写入过程结束之后才会触发读磁盘,然后写内存的时候判断是否存在,如果存在则跳过第三步,如果不存在则再写入磁盘

    附录A 插件安装

    1 开发环境配置

    1.1 配置 Deepin 操作系统

    开发环境:Deepin V23Beta版

    系统架构:x86

    镜像下载链接:https://mirrors.ustc.edu.cn/deepin-cd/releases/23-Beta/

    虚拟机平台:WMware Workstation 16Pro

    操作系统环境搭建参考博客:https://blog.csdn.net/qq_44133136/article/details/105887560

    1.2 配置 Deepin 插件环境

    安装依赖包

    sudo apt build-dep .
    sudo apt install -y qt5-default
    sudo apt-get install dde-control-center-dev
    

    1.3 插件安装测试

    安装插件:
    sudo sh install.sh
    

    安装成功后,打开控制中心,会看到以下自启动插件图标,即为安装成功:

    控制中心插件图标

    此时,如果进入/usr/lib/x86_64-linux-gnu/dde-control-center/modules/文件夹,看到编译出的.so文件已经被下载到该文件夹中:

    插件安装位置文件夹

    1.4 插件卸载测试

    卸载插件:
    sudo sh uninstall.sh
    

    重启控制中心,可以看到原本的“自启动管理”图标消失,即为卸载成功。

    附录B 开发过程问题记录

    1 开发环境配置问题

    1.1 Deepin V20 Beta与Deepen V20.9

    在开发环境配置过程中,我们遇到了比较大的问题。

    我们起初顺延初赛的思路进行开发,在Deepin V20Beta版中进行开发。我们完成相关依赖包的安装后可以顺利地编译我们所写的控制中心自启动插件。但我们发现安装插件后的控制中心只剩我们所编译的自启动插件。(如下图中仅剩测试编译的 Default Applications 和 Self Start-up 插件)

    失败编译结果-仅剩插件

    我们推测是因为系统自动配置的控制中心框架与网上的控制中心开源代码版本不同,导致插件安装后框架复写。故我们只需重新编译控制中心的代码重新安装至虚拟机系统中即可完成测试。

    然而,在尝试编译控制中心时各种尝试均失败。报错DTK版本不符,未找出解决方法。在Deepen V20.9中亦未成功。

    1.2 Deepin V23Beta

    在遇到上述问题后,我们加入了Matrix的Deepin开发者社区,在线上与其他开发者讨论我们所遇到的问题。

    经过与其他开发者的讨论,我们得知最新的开源版本的控制中心已不再支持 20 版的Deepin系统。

    于是我们重新安装最新版本的Deepin V23Beta,成功的将我们所编写的插件植入控制中心中。

    2 图标与文字颜色展示问题

    我们初步的demo展示出来的界面所有管理的应用程序都是统一显示的默认应用程序的图标,但我们还是希望要和deepin桌面上.desktop文件相同的图标;与此同时,我们发现发现插件中的应用程序名字都是红色,同时希望这里是一个经典的黑色,这两个都是关于item的展示问题。我们关注到了这一段代码:

    QIcon icon = getAppIcon(iconName, QSize(32, 32));
    act->setIcon(icon);
    act->setTextColorRole(DPalette::TextTitle);
    act->setIconText(name);
    
    • 关于icon问题,我们可以对App结构体进行扩展,增加一条icon字段,通过读取带有图标应用程序.desktop文件中的icon字段存到当中,如果没有icon字段的程序设置为“application-default-icon”,并且在展示的时候调用act->setIcon()传入icon字段
    • 关于颜色问题,上述代码中看到了act->setTextColorRole()字段,里面传入了文字颜色类型的变量,在DPalette中定义了如下常量,初始选择的红色文字为TextWarning,我们只需要替换为TextTitle即可
    TypeName颜色类型
    ItemBackground列表项的背景色
    TextTitle标题型文本的颜色
    TextTips提示性文本的颜色
    TextWarning警告类型的文本颜色
    TextLively活跃式文本颜色(不受活动色影响)
    LightLively活跃式按钮(recommend button)背景色中的亮色(不受活跃色影响)
    DarkLively活跃式按钮(recommend button)背景色中的暗色,会从亮色渐变到暗色(不受活跃色影响)
    FrameBorder控件边框颜色
    NColorTypes无颜色类型

    3 翻译问题

    翻译主要涉及到:插件名的翻译和自启动软件名的翻译。

    对于插件名的翻译。我们学习了DDE-NETWORK-CORE仓库的做法,首先我们编写翻译成不同语言的.ts翻译文件,使用CMakelists中的qt5_add_translation指令获得.qm翻译文件,再将翻译的.qm文件install进入${CMAKE_INSTALL_DATAROOTDIR}/dde-control-center/translations(通常是$/usr/share/dde-control-center/translations),在通过loadTranslator载入系统对应语言的翻译文件。

    对于自启动软件名的翻译。考虑到部分软件缺失官方翻译名称,无法软件的信息中直接获取,我们目前只采用英文格式。

    4 开机启动项处理思路问题

    为了实现插件可视化管理软件的开机自启动,了解Deepin系统开机自启动的功能实现是至关重要的。

    通过查阅资料与实践,我们了解到Deepin系统包含自启动文件夹~/.config/autostart,该文件夹类似于 Windows 下的启动文件夹,系统开机时会执行该文件夹下的每个 desktop 文件 Exec 参数指向的脚本或可执行文件。

    为了确认可行性,小组进行了该方法的验证。首先,通过Deepin系统自带的修改开机自启动设置的方法,修改开机启动项(图中修改终端的自启动项):

    默认自启动设置方式

    随后检查自启动文件夹~/.config/autostart

    yang@yang-PC:~/.config/autostart$ ls
    deepin-terminal.desktop org.deepin.browser.desktop
    

    发现deepin-terminal.desktop文件被添加入了该自启动文件夹中,并且会在开机时自启动。

    而取消终端的自启动时,~/.config/autostart中已有的deepin-terminal.desktop文件并不会被移除,而是其中的Hidden的字段会被修改为false,表示取消开机自启动设置。

    由此,可以通过在插件中检查所有~/.config/autostart文件夹中.desktop文件的Hidden字段来搜索系统所有的自启动软件;也可以通过添加.desktop文件、修改Hidden字段的方式进行开机自启动设置的修改。

    5 rpc远程通信问题

    1. 远程过程调用: RPC允许一个程序调用另一个程序在远程机器或进程上执行的过程(函数或方法),就像本地调用一样。这样,开发者可以透明地在分布式系统中调用远程的功能,无需关注底层网络细节。
    2. 通信协议: RPC通信需要定义一个协议,该协议规定了消息的格式、编码方式、序列化和反序列化方法等。通过确定的request和response协议格式制定规定了客户端和服务器之间如何进行数据交换。
    3. 序列化和反序列化: 在RPC通信中,数据需要在网络上传输,因此需要将数据进行序列化(编码)以便在网络上传输,然后在接收端进行反序列化(解码)以还原数据。序列化和反序列化过程确保数据的正确传输和解释。
    4. 数据传输: RPC通信依赖底层的网络传输协议,如TCP或HTTP。客户端和服务器通过网络传输消息,以实现远程过程调用。
    5. 错误处理: RPC通信中需要处理各种可能的错误情况,例如网络连接中断、超时、服务不可用等。合理的错误处理可以保证系统的可靠性和鲁棒性。
    6. 服务注册与发现: 在dde-application-manager中以字符串命名注册了远程调用函数的服务,dde-control-center中关于对应用的变更可以通过rpc远程调用实现就和
    7. 安全性: RPC通信涉及跨网络的数据传输,因此安全性是一个重要考虑因素。加密、认证和授权等机制可以确保通信的安全性。

    6 插件描述缺失问题

    添加描述前

    在加载插件后,我们发现插件缺失了描述信息,与其他的插件格式明显由很大的不同,通过Matrix上交流发现,是插件缺少了setDescription的代码,因此,正确加入描述后,我们获得了以下结果。

    添加描述后

    附录C 开发计划

    第一步(4/9~4/18)

    • 调研Deepindde-dockQT框架等相关内容
    • 设计项目方案
    • 分工

    第二步(4/19~5/2)

    • 搭建主体插件类的框架
    • 设计启动项管理窗口的前端展示页面

    第三步(5/3~5/13)

    • 开发部件类接口
    • 完善插件类功能

    第四步(5/14~5/21)

    • 插件类右键功能开发
    • 完成配置文件

    第五步(5/22~5/31)

    • Debug
    • 撰写文档

    (以上DDE-Dock自启动插件开发均在初赛完成,项目地址见末尾)

    第六步(6/26~7/8)

    • 调研DDE Control Center框架等相关内容
    • 设计前端界面
    • 分工

    第七步(7/9~7/15)

    • 编译教程中的Hello World控制中心插件
    • 设计插件架构

    第八步(7/16~7/22)

    • 配置环境,编译V20示例插件
    • 设计后端接口
    • 修改windowoperationcategory下的文件

    第九步(7/23~7/29)

    • 配置环境,编译Default-AppSelf Start-up插件
    • Debug

    第十步(7/30~8/10)

    • 修改翻译、文字颜色问题
    • 撰写文档

    附录D 参考资料

    文档

    Qt 插件标准:https://wiki.qt.io/Plugins

    deepin V23 dde-control-center文档:dde-control-center: dde-control-center (linuxdeepin.github.io)

    dde-control-center控制中心插件开发示例:控制中心插件 - deepin开发者平台

    qt-5手册:https://doc.qt.io/qt-5/

    deepin 应用自启动说明:https://specifications.freedesktop.org/autostart-spec/autostart-spec-latest.html

    博客

    关于deepin开机自启动项的讨论:https://bbs.deepin.org/zh/post/169824、https://blog.csdn.net/qq_21137441/article/details/124825726

    仓库

    dde-control-center仓库:https://github.com/linuxdeepin/dde-control-center.git

    其他开发者的插件项目:https://github.com/linuxdeepin/dde-network-core/tree/master

    说明:由于控制中心的插件对于外观的统一性具有较高的要求,因此,我们仓库中的include/interfaceinclude/widgetssrc/interfacesrc/widgetssrc/frame下的文件均来自dde-control-center源代码仓库,以保证插件接口的一致性和外观的统一性。

    编辑的话请把自己的名字加到作者名单里

    DDE v23 首个正式版即将随 deepin v23 发布(你阅读到这个文章的时候可能已经发布了)。为了方便各个其它发行版的包维护者可以更方便的移植 DDE 到对应的发行版,这里提供一篇简要的移植指南,用以描述常见的移植问题和解决方案。

    下面对项目名称的称呼均以 GitHub 对应的原始仓库名为准。 {.note}

    概览

    即便本次从版本号字面来看可能并没有较大变动,但事实上,本次相比 beta3 -> rc 而言仍然是存在比较大的变化的。本次中,dde-shell 加载托盘插件的策略做了大幅调整,转变为通过 dde-tray-loader 加载插件,托盘区域的插件也放弃了原有的插件,转而移植并使用了来自原 UOS 20 专业版的托盘插件。此外,为了为后续的应用权限管控做准备,本次也对包括 dde-launchpad、dde-shell 等在内的项目调整了其 DSG 配置文件 所使用的应用 ID(DSG_APP_ID),故对于移植到其它发行版的情况,若存在相应的 DConfig OEM 配置则也需进行调整。另外,为了解决一些已知的开源合规问题,我们也将原本位于 dtkcore 中的日志部分分离为了一个单独的组件,名为 dtklog。

    由于这些项目的版本间互相影响,我们强烈建议移植人员参照 deepin v23 正式版所使用的包版本进行打包(也务必遵循依赖顺序打包)。下面会对主要的部分进行详细说明。

    需要注意的是,由于此文章编写时间早于版本发布时间,故最终版本镜像中使用的版本可能高于下面列出的版本。我们尽可能确保此文章的准确性,但若您需要获取 ISO 镜像中使用的确切软件版本列表,请挂载 ISO 后参阅 LIVE/FILESYSTEM.MANIFEST (也可能是 LIVE/FILESYS0.MAN)路径对应的文件的内容。

    主要组件

    DTK 与 DTK6

    DTK 是 DDE 组件与应用的基础依赖,适用于 RC 的版本参照如下:

    packageversion
    dtkcommon5.6.32
    dtklog0.0.1
    dtkcore5.6.32
    dtkgui5.6.32
    dtkwidget5.6.32
    dtkdeclarative5.6.32
    qt5integration5.6.32
    qt5platform-plugins5.6.32
    dtk6log0.0.1
    dtk6core6.0.18
    dtk6gui6.0.18
    dtk6widget6.0.18
    dtk6declarative6.0.18
    qt6integration6.0.18
    qt6platform-plugins6.0.18

    除新增的 dtklog 外,本次 DTK 版本号以及相对应的平台插件等版本号均已对齐,可直接参照打包。

    deepin-kwin wayland 功能已经废弃,未来将由 treeland 替代。目前 dwayland 包已经不再使用,依赖此包的应用比如 qt5platform-plugins, 不应该继续编译依赖 dwayland 的功能,可参照 linuxdeepin/developer-center#7217 打对应的 patch 规避。

    dtk6 曾对 Qt 6.2, Qt 6.4 和 Qt 6.6 均进行过适配,我们目前的研发与测试主要使用 Qt 6.6 版本,但当前主干也包含了对 Qt 6.7 的支持。如仍发现有 Qt 版本支持问题可在 DDE 移植群(地址见文末)反馈。

    目前,使用 dtk6 的正式组件有 dde-application-manager,dde-launchpad 与 dde-shell, 需要注意 dde-shell 的托盘组件 dde-tray-loader 仍然需要使用 qt5。

    DDE 主要组件

    下面仅涉及变化较大或影响较广的组件。其余未涉及的组件可正常参照最新 tag 进行打包与移植。

    下面涉及到的组件的版本参照如下:

    packageversion
    deepin-osconfig2024.08.06
    dde-app-services1.0.25
    dde-session1.2.13
    dde-application-manager1.2.15
    dde-tray-loader0.0.8
    dde-shell0.0.40
    dde-launchpad0.8.4
    dde-application-wizard0.1.10
    deepin-wayland-protocols1.10.0.28
    deepin-kwin5.27.2.206
    dde-launcher被 dde-launchpad 取代,不再使用
    dde-dock被 dde-shell 取代,不再使用

    deepin-osconfig

    此仓库存放了适用于 deepin 发行版的“OEM”配置。此配置一般 不需要被其它发行版原样移植,但考虑到本次存在针对 DSG 应用 ID 的变化调整,故将其列在此处,仅供移植人员参考对应的修改内容,以便当自己所移植到的目标发行版存在 OEM 配置时做出相应的调整。

    dde-application-manager

    负责启动和管理 DDE 桌面环境存在的应用程序列表的组件。此组件在 rc 阶段无太大变化(但仍总是建议升级)。

    dde-tray-loader

    这是一个新增的组件,旨在提供 DDE 的任务栏托盘部分的各个托盘插件。此项目提供了 xembed、SNI 托盘的加载支持,以及旧式 dde-dock 托盘插件的加载支持(因为并非直接兼容的旧式插件,故此项目同时也提供了这些插件)。

    此项目需要配合新的 dde-shell 一同使用。

    dde-shell

    dde-shell 旨在将 DDE 桌面环境插件化与模块化,降低开发难度,使各个组件的替换变得更加容易,并且提供更好的桌面环境集成支持。

    相较于 RC 阶段,此组件的变化主要在于任务栏托盘区域的加载逻辑的大幅调整与相关动画的调整,以及 shell 本体功能上的支撑调优。对于托盘区域,请参见新增项目 dde-tray-loader 的描述。另外,RC 阶段内附的一些第三方库(例如 networkmanager-qt)已被移除,故一般无需刻意留意是否存在 vendor libs 的问题。

    dde-launchpad

    dde-launchpad 相较于 RC 阶段变化并不大,调整大多与缺陷修复以及动画调整有关。需要注意的是,此应用的 DConfig DSG 应用 ID 有变化,故对于移植人员,若原有主动提供针对启动器的 OEM 配置,则需注意修改配置文件放置的对应路径的变化(对应文档也已更新)。

    deepin-kwin

    启动器与 shell 均依赖窗管提供一些支持(例如窗口组件的状态、位于的工作区以及层级关系的控制等),故请同时确保 deepin-kwin 使用的版本。

    需要注意的是,截至编写此文档时,GitHub 中 deepin-kwin 仓库的最新 tag 落后于上述所列的 deepin-kwin 版本,我们正在与相关项目组协商,若您阅读至此时仍无法在 GitHub 获取到对应的版本且 GitHub 所获取的最新版本存在较大问题,则请暂时先从 deepin v23 (beige) 的软件仓库获取对应源码。

    dde-session

    此项目在 RC 阶段无缺陷修复之外的较大变动。

    仍需重申,我们已在 beta3 阶段放弃了对 deepin-kwin wayland 的支持,DDE 后续所有 wayland 相关的支持均由 treeland 提供。

    技术预览组件

    为全力确保正式版的版本发布,原本涉及的技术预览组件在 RC 至 release 的这个阶段均无较大进展,故不再于此罗列。

    获取移植帮助

    如果您希望得到移植相关的帮助,请考虑加入我们 DDE 移植小组的在线交流群(下列房间有桥接,任选其一即可),一起展开相关的交流:

    Sunday, June 25, 2023

    KWin 是 KDE 开发的窗口管理器,提供了非常丰富的插件,可以对功能进行大量的定制。

    本篇文章是对窗口特效插件的开发介绍。

    Thursday, June 1, 2023

    在 V23 beta 版本中,DDE 试验性的开启了 Wayland 的支持,允许用户在 Wayland 协议下的桌面工作环境启动 。本篇文章会向大家介绍一下 Wayland 是什么,我们尝试做了什么改变,以及 DDE Wayland 未来会支持哪些新特性。(注:单独提出 Wayland, 通常和 Wayland 合成器、Wayland 服务器、显示服务器被视为同一个内容;X Window System 和 X11 也被视为同一个内容。)

    什么是 Wayland?

    Wayland 是一个通信协议,规定了显示服务器与客户端之间的通信方式,而使用这个协议的显示服务器称为 Wayland Compositor。Wayland 只专注于图形,并希望使用其他库与输入硬件进行通信,以降低自身的复杂度。Wayland 最大的好处也是大家都推崇的原因,那就是 Wayland 在设计上会考虑安全,例如默认不允许窗口获取其他窗口的数据,合成器和窗口管理器的合并也降低了对系统资源的消耗。

    Wayland 与 X Window System 有什么不同?

    Wayland 与 X Window System 的最大不同在于,Wayland 与 X Window System 的最大不同在于,它的窗口管理器和 Wayland Server 在同一个进程,并且客户端能够通过 EGL 以及一些 Wayland 特定的 EGL 扩充组件直接在显示内存中绘制自己的缓冲区。 窗口管理器简化成显示管理服务,专门负责绘制那些屏幕上的程序。 这比 X Window System 中的窗口管理器要更简单、高效。

    Wayland 协议有哪些组成?

    1.协议概述

    Wayland 协议被描述为异步面向对象协议。协议是异步的,这意味着不必等待回复或者响应 ACK,避免了往返时间并提高性能。协议封装为面向对象的设计,则是面向对象的设计方式,能很好的对服务器上不同窗口数据及接口进行封装。

    Wayland 合成器可以定义和公开自己的附加接口,被称为扩展协议,不同的 Wayland 会提供功能完全不同,甚至功能相反的协议,这带来了很大灵活性,但使用客户端时需要自行判断。

    2.协议架构

    Wayland 协议是一种“客户端 —— 服务器”模型,客户端是请求在屏幕上显示画面的图形应用程序,服务器是控制应用程序显示在屏幕上的管理程序。Wayland 参考实现被设计成两层协议,既:

    • 下层协议:处理客户端和服务器之间的进程间通信,以及在内部的数据封装处理。
    • 上层协议:处理客户端和服务器交换的数据,以实现窗口系统的基本功能,这一层被实现为异步面向对象协议。 下层协议是使用 C 语言开发的,而上层协议是根据 XML 格式的协议描述文件自动生成,每当 XML 协议的描述发生变化时,就可以重新生成该协议的源代码,这使得协议非常灵活、可扩展性好且防止出错。

    如下 Wayland 工作原理图:

    wayland.png

    以下对应图中所标编号作说明:

    Linux 内核中的 evdev 模块接收事件并将它们发送到 Wayland 合成器。

    Wayland 合成器查看场景图并确定哪个窗口应接收事件。场景图对应于屏幕上显示的内容,Wayland 合成器显示对应用事件的场景图中元素的转换。因此,Wayland 合成器可以反向变换以找到正确的窗口,并将屏幕上的坐标转换为窗口中的坐标。

    当客户端收到事件时,Wayland 的客户端只需通过 EGL 渲染并向合成器发送请求以通知更新的范围即可。

    Wayland 合成器 从客户端收集更改请求并重新配置屏幕。 然后,合成器直接发出 ioctl 让 KMS 重绘屏幕。

    当了解了 Wayland 相关基本介绍之后,基于它我们在 DDE 上将会作哪些适配功过呢?将从以下几个方面说一下我们在 Wayland 技术预览版里面所做的适配工作。

    DDE 适配 Wayland 都做了哪些工作

    DDE 原本设计为在 X11 协议下工作,很多组件直接或间接依赖 X11 的接口,多数组件依赖的功能并没有在 XWayland 中提供,所以就需要进行一些修改。

    首先在 Qt 插件中实现和 Wayland 特定性相关的功能,Qt 提供了一个 Wayland Shell Integration 的插件,允许我们在这里调用 DDE Wayland 合成器提供的扩展协议。

    Qt 已提供核心协议的适配,所以 DDE 只需要在现有框架下实现扩展协议即可。

    目前 DDE 提供的扩展协议有以下几个方面:

    • 设置圆角窗口
    • 请求获取窗口数据(截图权限)
    • 划分工作区可用区域 DTK 程序可以通过设置窗口的属性,或者使用 DTK 提供的平台接口,即可调用扩展的 Wayland 协议,非 DTK 程序则需要手动使用扩展协议的 XML 文件进行代码生成调用。

    DDE Wayland 未来会支持什么特性?

    1.HDR 支持

    高动态范围(HDR)是比平时更高的动态范围。HDR 的内容过于深入,在这里只简单的进行说明。

    HDR 可以保存更多的内容信息,在支持 HDR 的屏幕上观看 HDR 的内容,可以获得更好的体验,DDE 目前正在准备支持 HDR 内容的输出,这会让 DDE 拥有更好的显示效果。

    2.成体系的窗口动画

    在 X11 下,由于窗口管理和画面合成管理是两个进程,并且在启动速度上存在差异,所以只能采用一些“巧妙”的设计来规避视觉错误。

    但是在 Wayland 下,窗口管理器和窗口合成器被合并成一个进程,那么启动后就可以立即使用动画效果,例如可以设计视觉效果更好的登录动画。

    目前 DDE 的窗口动画支持并不多,且大部分是单调的线性动画,有些情况还需要客户端自己实现虚假动画,例如任务栏发生位置变化时,桌面的图标会进行计算,并自行改变大小,这引入了非必要的依赖。如果使用窗口动画,桌面并不需要关心任何外部因素,只需要设置自己在可用工作区域最大化,当任务栏发生位置改变时,合成器会自动调整桌面的大小,并产生相应的窗口动画。

    未来 DDE 会使用更多窗口动画来减少组件之间的依赖,以及实现更多更好的视觉效果。

    最后总结

    阅读至此,是不是对 Wayland 的概念及工作原理更加清晰啦?如果您有什么疑问也欢迎与我们互动探讨 Wayland。

    坦白说,DDE 的 Wayland 支持还处于初步阶段(技术预览版,请谨慎使用),未来我们会使用更多合成器提供的功能,来为桌面环境降低开发难度,提升性能。提供更好的体验。

    Tuesday, May 30, 2023

    队员:复旦大学 朱元依、沈扬、朱俊杰
    指导老师:张亮、陈辰
    企业导师:王子冲

    本项目为2023年操作系统大赛企业赛道赛题。

    项目链接:DDE 自启动管理插件 github仓库

    一、目标描述

    我们小组的选题为proj223-control-center-startup-management-plugin

    DDE 深度桌面环境的控制中心提供了插件功能,以便第三方开发者可以扩展其功能并额外的功能组件添加到控制中心之中。我们将在本项目中为 DDE 桌面环境的控制中心编写一个自启动管理插件。

    二、比赛题目分析和相关资料调研

    为了明确题目设置的原因与需求,我们请教了了企业导师,得知:目前用户对自启动权限的管理目前只能通过 dde-launcher (启动器/“开始菜单”)的右键菜单进行管理;考虑到此功能本身也并不复杂,所以设置了此课题,旨在解决这样的问题。

    而对于此开发任务的具体实施,主要需要对dde-dock插件运行的原理和deepin开机自启动的设置方式进行调研,以便进行开发。调研的具体内容包括:

    了解了Qt 插件标准(Qt 插件标准

    阅读整理了dde-dock官方仓库中的插件工作原理(插件工作原理

    学习其他开发者的插件项目(CMDU_DDE_DOCK

    阅读整理了各个论坛中关于deepin开机自启动项的讨论(169824124825726

    三、系统框架设计

    1、项目整体结构设计

    符合dde-dock提供的接口与插件开发规范,本项目将分为插件类(SelfStartPlugin)、部件类(MainWidget)和自启动管理窗口(AppletWidget)分别进行功能的实现。其中,项目的结构和各对象所包含的数据结构与方法如下图所示:

    类图

    2、类功能说明

    插件类SelfStartPlugin负责实现插件与dde-dock交互所必须的接口;部件类MainWidget负责在dde-dock中展示该插件的图标;自启动管理窗口AppletWidget负责实现核心功能:读取Deepin系统的开机自启动项、同时对各个软件的开机自启动进行管理(包括添加、删除、启用、禁用)。

    3、实现描述

    (1)插件类

    在插件类中,主要实现了dde-dockPluginItemInterface相关的接口,便于系统加载并实现插件的功能。接口包括以下内容:

    名称功能
    SelfStarupPlugin类的初始化函数
    pluginName返回插件名称,用于在 dde-dock 内部管理插件时使用
    init插件初始化入口函数,参数 proxyInter 可认为是主程序的进程
    pluginDisplayName返回插件名称,用于在界面上显示
    itemWidget返回插件主控件,用于显示在 dde-dock 面板上
    itemPopupApplet返回鼠标左键点击插件主控件后弹出的控件
    flags用于返回插件的属性,例如插件显示的位置,插件占几列,插件是否支持拖动等
    pluginIsAllowDisable返回插件是否允许被禁用(默认不允许被禁用)
    pluginIsDisable返回插件当前是否处于被禁用状态
    pluginStateSwitched当插件的禁用状态被用户改变时此接口被调用
    itemContextMenu返回鼠标左键点击插件主控件后要执行的命令数据
    invokedMenuItem返回鼠标右键点击插件主控件后要显示的菜单数据

    (2)部件类

    名称功能
    MainWidgetMainWidget部件的初始化函数,设置dde-dock图标的基础样式与文字内容
    ~MainWidgetMainWidget部件的析构函数
    sizeHint设置图标大小的函数
    插件图标

    图标

    最左侧的SELF_STARTUP图标为该插件图标。

    (3)自启动管理窗口

    名称功能
    AppletWidgetAppletWidget的初始化函数,负责绘制与用户交互的开机自启动项展示表格与修改设置选项
    ~AppletWidgetAppletWidget部件的析构函数
    searchAll搜索所有可设置开机自启动的软件
    update更新被自启动的软件
    readfiles工具函数,用于读取文件中的内容
    disable禁用开机自启动设置的后端接口
    enable启用开机自启动设置的后端接口
    add添加开机自启动设置的后端接口
    delete删除开机自启动设置的后端接口
    getFileName通过绝对路径找到文件的名字
    getAllFiles递归获取到某目录中所有文件
    globalSearch在所有文件中找到.desktop类型文件
    Manual寻找拟添加软件的函数,给用户在系统中寻找想要添加自启动项的软件
    showAppsDebug工具,在Debug信息中打印软件名称
    showPathsDebug工具,在Debug信息中打印路径名称
    onButtonClicked自启动管理窗口启用/禁用按钮的处理函数
    addButtonClicked自启动管理窗口添加按钮的处理函数
    delButtonClicked自启动管理窗口删除按钮的处理函数
    自启动管理窗口的前端页面

    AppletWidget的构造函数中,我们实现了便于用户查看系统开机自启动设置信息列表、并便于管理的前端展示页面:

    前端界面

    开机自启动管理的后端接口

    该部件中,主要设置了四个函数接口实现与操作系统的交互,分别是searchAll、update、disable、enable

    首先要在MainWidget启动的时候在/home中读到用户名username

    searchAll()

    opt/apps中找到所有用户下载程序的文件夹,读入文件夹名称subdir,再到opts/appp/subdir/entries/application中找到.desktop启动文件,解析文件内容,读入name字段并把name - path存到MainWidge类中,并且返回所有找到的app名称

    update()

    根据启动时读到的username在/data/home/username/.config/autostart里面找到里面所有的.desktop文件,分别读取并获取状态Hidden是否为false,把所有Hidden字段为False的插件(被设置成了开机自启动)在MainWidget的selfSetUp成员中设置为pair<name, true>

    disable()

    功能设计为禁用自启动。通过name_path中对name的索引找到路径path,对设置为自启动的应用path会在/data/home/username/.config/autostart/*.desktop中。读取该.desktop文件修改Hidden字段为True即可

    enable()

    功能设计为启用自启动。对于之前添加过的应用,name_path中得到的路径是在/data/home/username/.config/autostart中,此时与disable()过程相同,把Hidden字段设置成false即可;对于之前没有添加过的应用,name_path中的路径会在opts/appp/subdir/entries/application/appname/entries/application/*.desktop中,并且该文件是只读的。需要读取该文件并写入到/data/home/username/.config/autostart/*.desktop中,并且在文件的第一个分区里面写入一行"Hidden=false"

    Add()

    用户点击后打开文件资源管理器对话框,从中选择希望添加的可执行文件并返回文件路径。如果该文件是一个.desktop类型文件则添加到autostart中,如果不是则会在autostart中创建一个新的.desktop文件,并且把Exec=行设置为该可执行文件的路径

    Delete()

    从管理窗口中删除某应用的管理。传入参数是应用名称,找到该应用的.desktop文件路径并从autostart中删除,并且在数据结构name_pathselfSetUp中删去该部分信息

    四、开发计划

    第一步(4/9~4/18)

    • 调研Deepindde-dockQT框架等相关内容
    • 设计项目方案
    • 分工

    第二步(4/19~5/2)

    • 搭建主体插件类的框架
    • 设计启动项管理窗口的前端展示页面

    第三步(5/3~5/13)

    • 开发部件类接口
    • 完善插件类功能

    第四步(5/14~5/21)

    • 插件类右键功能开发
    • 完成配置文件

    第五步(5/22~5/31)

    • Debug
    • 撰写文档

    五、比赛过程中的重要进展

    日期进展
    4/17完成开发环境配置
    4/27完成插件框架设计
    5/3完成自启动管理界面的实现
    5/8完成自启动管理接口实现的讨论
    5/12完成自启动操作项的接口设计与实现
    5/21完成配置文件,并通过cmake编译
    5/22完成图标的Debug,前端界面展示正常
    5/29完成自启动操作接口Debug

    六、系统测试情况

    1、前端测试

    在项目总路径下运行install.sh脚本,可完成插件的编译与安装:

    sh install.sh
    

    该脚本使用cmake编译代码,并安装到dde-dock插件文件夹中。运行后,可以正常展示自启动管理页面。点击加号后,用户可以在弹窗中选择想要添加自启动项的软件。

    结果

    右键功能展示正常:

    右键

    2、自启动管理功能测试

    以浏览器为例。根据自启动管理窗口的设置,我们尝试添加并启用浏览器的自启动项。关机重启后,浏览器完成自启动。同理,删除、禁用功能均通过测试。

    七、遇到的主要问题和解决方法

    1、开发环境配置

    (1)、配置 Deepin 操作系统

    开发环境:Deepin 20Beta版

    系统架构:x86

    镜像下载链接:Deepin 操作系统下载链接

    虚拟机平台:WMware Workstation 16Pro

    操作系统环境搭建参考博客:环境搭建博客

    (2)、配置 Deepin 插件开发环境

    安装基本开发环境:

    安装包 build-essentialgitg++cmakeddedtk

    sudo apt install build-essential git g++ cmake
    sudo apt install dde-dock-dev libdtkwidget-dev
    
    安装 QT 开发环境:

    安装 qt5-defaultqt5-docqtcreator

    sudo apt install qt5-default qt5-doc qtcreator
    

    依照上述方法,可在虚拟机中运行qtcreator,并在qtcreator中对插件进行测试

    image-20230513155011159

    (3)、插件安装测试

    为了测试所配置的虚拟机环境可用于 DDE 插件的开发,在环境配置中,本小组选取了Github仓库中的插件dde-sys-monitor-plugin(项目地址:dde-sys-monitor-plugin插件仓库)进行试运行。

    根据上述方法配置插件开发环境后,可按照dde-sys-monitor-plugin中的提示信息顺利运行该插件。这表明开发环境配置已完成。

    (4)环境配置中遇到的问题

    安装sudo apt install libdtkwidget-dev libdtkgui-dev libdtkcore-dev出错

    正试图覆盖 /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/dtk_install_dconfig.prf,它同时被包含于软件包 libdtkcommon-dev 5.5.23-1

    在处理时有错误发生:

    /var/cache/apt/archives/libdtkcore-dev_5.6.4-1+rb1_amd64.deb
    E: Sub-process /usr/bin/dpkg returned an error code (1)
    

    解决方法:

    使用sudo apttitude install libdtkwidget-dev libdtkgui-dev libdtkcore-dev 选择第二种解决方式(先卸载nY再重新安装sudo apt install libdtkwidget-dev libdtkgui-dev libdtkcore-dev)

    2、开机启动项处理思路

    为了实现插件可视化管理软件的开机自启动,了解Deepin系统开机自启动的功能实现是至关重要的。

    通过查阅资料与实践,我们了解到Deepin系统包含自启动文件夹~/.config/autostart,该文件夹类似于 Windows 下的启动文件夹,系统开机时会执行该文件夹下的每个 desktop 文件 Exec 参数指向的脚本或可执行文件。

    为了确认可行性,小组进行了该方法的验证。首先,通过Deepin系统自带的修改开机自启动设置的方法,修改开机启动项(图中修改终端的自启动项):

    deepin自启动修改

    随后检查自启动文件夹~/.config/autostart

    yang@yang-PC:~/.config/autostart$ ls
    deepin-terminal.desktop org.deepin.browser.desktop
    

    发现deepin-terminal.desktop文件被添加入了该自启动文件夹中,并且会在开机时自启动。

    而取消终端的自启动时,~/.config/autostart中已有的deepin-terminal.desktop文件并不会被移除,而是其中的Hidden的字段会被修改为false,表示取消开机自启动设置。

    由此,可以通过在插件中检查所有~/.config/autostart文件夹中.desktop文件的Hidden字段来搜索系统所有的自启动软件;也可以通过添加.desktop文件、修改Hidden字段的方式进行开机自启动设置的修改。

    3、与 deepin 接口设计

    (1)、关于开机自启动项

    在查找deepin如何实现开机自启动时,看到了在deepin文件夹中有多个名为autostart的文件夹,其中有一部分包含了系统文件(例如终端、输入法等),但是在我们通过“开始”菜单修改其是否自启动性质时发现并为出现变化,并且我们自行在“应用商店”里面下载的软件并没有在设置为开机自启动后进入到该文件夹。经过在网络上搜索了关于deepin开发的一些讨论资料以及学习了一些关于启动文件.desktop文件功能并通过vscode对是否开机自启动设置后的文件进行比较后,找到了文件路径位于/data/home/username/.config/autostart中,并且在文件中有Hidden字段使得不用每次取消自启动是都要删除文件并且下次设置又重新加入

    (2)、关于查找应用程序

    一开始的想法是在系统目录下整体查找,找到系统中所有的.desktop文件,但显然这样过于繁琐且效率低下。后来在通过打开每个引用的.desktop文件后发现exec项均在/opt/apps中,打开该文件夹可以发现里面有所有用户下载的应用程序及其依赖等文件的文件夹,并在打开每个文件夹后可以找到启动文件均在entries/application中,并且可能有多个.desktop文件,所以把自启动的工作变为了对启动器文件用文本方式打开后的解析与修改

    (3)、关于函数接口设计

    对QT库中的数据类型和class的使用不太熟悉,需要根据官方文档对提供的api和C++模式的代码进行替换。但熟悉使用之后理解到了QT数据类型的多样性以及提供的方法会更加完备,在做开发时避免了很多自己重写方法的复杂流程。

    4、cmake中遇到的问题

    (1)、cmake 出现 dbus、core 找不到

    解决方法:find_package()的REQUIRED后面新增找不到的对应的包

    (2)、cmake 出现 FOUND=FALSE

      /usr/lib/x86_64-linux-gnu/cmake/DtkWidget/DtkWidgetConfig.cmake                                                                                                                   
      but it set DtkWidget_FOUND to FALSE so package "DtkWidget" is considered to                                 
      be NOT FOUND. 
    

    解决方法:使用.pro文件设置cmake需要的相关参数。

    八、分工和协作

    朱元依:插件类框架开发、部件类前端开发

    沈扬:自启动管理功能逻辑设计、插件类右键功能开发

    朱俊杰:自启动管理窗口后端接口开发(添加、删除、启用、禁用)

    九、提交仓库目录和文件描述

    .
    ├── CMakeLists.txt
    ├── README.md
    ├── aboutdialog.cpp    #关于窗口的实现文件
    ├── aboutdialog.h     #关于窗口的头文件
    ├── aboutdialog.ui     #关于窗口的UI文件
    ├── appletwidget.cpp   #自启动管理窗口的实现文件
    ├── appletwidget.h    #自启动管理窗口的头文件
    ├── images        #图片
    │ ├── QT_IDE.png
    │ ├── QT_前端.png
    │ ├── deepin自启动修改.png
    │ ├── 类图.jpg
    │ ├── 右键.png
    │ ├── 图标.png
    │ ├── 结果.png
    │ ├── 中期类图.jpg
    │ ├── 中期测试.png
    │ └── 前端界面.png
    ├── install.sh        #插件安装脚本
    ├── main_aboutdialog_test.cpp #关于窗口的测试文件
    ├── main_test.cpp      #测试文件
    ├── mainwidget.cpp     #插件类的实现文件
    ├── mainwidget.h      #插件类的头文件
    ├── self_startup.json     #插件的元数据文件,指明了当前插件所使用的 dde-dock 的接口版本
    ├── self_startup.pro     #辅助 cmake 的配置文件
    ├── self_startup.qrc     #用于展示插件图片
    ├── selfstartupplugin.cpp   #部件类的实现文件
    ├── selfstartupplugin.h    #部件类的头文件
    ├── uninstall.sh        #插件卸载脚本
    ├── 初赛报告.md
    └── 过程文档.md

    十、比赛收获

    借由为deepindde-dock编写插件的机会,我们小组了解了deepin系统相关的接口、dde-dock插件加载原理、开发逻辑等等操作系统相关的知识;同时我们在合作开发的过程中熟悉了软件工程的开发规范。小组同学在比赛中均受益匪浅。

    十一、与企业导师的沟通情况

    我们已于企业导师(王子冲)通过电子邮件进行联系。王导师向我们推荐了 deepin 开源社区各种公开渠道(如实时聊天渠道 Matrix、开发者社区讨论板等),鼓励我们在开发过程中将所遇到的问题在社区研发话题板块中进行公开探索。

    此外,王导师还耐心的向我们介绍了该课题的设置原因,这对与我们在项目设计的过程中了解用户需求起到了很大的作用。

    Monday, May 29, 2023

    【摘要】arm64架构支持 v23仓库已经支持arm64和amd64架构软件包,arm64架构的基础环境已经具备,现在就差镜像制作工具的支持了,镜像构建工具的目标是构建出标准pc镜像。为此我借来一台紫光 飞腾D2000机器进行arm64的适配工作,这台机器有相对标准的UEFI固件,目前已经支持UEFI安装, 阅读全文

    Sunday, May 14, 2023

    编辑的话请把自己的名字加到作者名单里

    DDE v23 RC 即将随 deepin v23 RC 发布(你阅读到这个文章的时候可能已经发布了)。为了方便各个其它发行版的包维护者可以更方便的移植 DDE 到对应的发行版,这里提供一篇简要的移植指南,用以描述常见的移植问题和解决方案。

    下面对项目名称的称呼均以 GitHub 对应的原始仓库名为准。 {.note}

    概览

    相比 beta2 -> beta3 而言,原本处于技术预览状态的 dde-shell 项目现已开始逐步取代部分旧的 DDE 组件。DDE 此次 beta3 -> RC 的更新中,dde-shell 取代了 dde-dock 项目,dde-launchpad 也开始转为使用 dde-shell 的对应插件版本。同时,由于对 Qt6 与 DTK6 使用的增加,我们也对 DTK 进行了大量的问题修复,这些修复也被对应的组件(dde-launchpad 与 dde-shell)依赖。

    由于这些项目的版本间互相影响,我们建议移植人员参照 deepin v23 RC 所使用的包版本进行打包,下面会对主要的部分进行详细说明。

    需要注意的是,由于此文章编写时间早于版本发布时间,故最终版本镜像中使用的版本可能高于下面列出的版本。我们尽可能确保此文章的准确性,但若您需要获取 ISO 镜像中使用的确切软件版本列表,请挂载 ISO 后参阅 LIVE/FILESYS0.MAN 路径对应的文件的内容。

    主要组件

    DTK 与 DTK6

    DTK 是 DDE 组件与应用的基础依赖,适用于 RC 的版本参照如下:

    packageversion
    dtkcommon5.6.29
    dtkcore5.6.29
    dtkgui5.6.29
    dtkwidget5.6.29
    dtkdeclarative5.6.29
    qt5integration5.6.29
    qt5platform-plugins5.6.29
    dtk6core6.0.16
    dtk6gui6.0.16
    dtk6widget6.0.16
    dtk6declarative6.0.16
    qt6integration6.0.16
    qt6platform-plugins6.0.16

    本次 DTK 版本号以及相对应的平台插件等版本号均已对齐,可直接参照打包。

    关于 qt5platform-plugins,现有的 dwayland 插件可能对非 DDE 环境(例如 KDE)的 wayland 用户存在影响,可参照 linuxdeepin/developer-center#7217 打对应的 patch 规避影响。

    dtk6 曾对 Qt 6.2, Qt 6.4 和 Qt 6.6 均进行过适配,我们目前的研发与测试主要使用 Qt 6.6 版本。对于 Qt 6.7 我们暂未进行主动支持,对于 Qt 6.7 的相关处理请先参照 Arch Linux 目前使用的 qt-6.7.patch

    目前,使用 dtk6 的正式组件有 dde-application-manager,dde-launchpad 与 dde-shell,技术预览组件有 treeland。

    DDE 主要组件

    下面仅涉及变化较大或影响较广的组件。其余未涉及的组件可正常参照最新 tag 进行打包与移植。

    下面涉及到的组件的版本参照如下:

    packageversion
    dde-session1.2.9
    dde-application-manager1.2.12
    dde-shell0.0.23
    dde-launchpad0.6.12
    dde-application-wizard0.1.5
    dde-dock被 dde-shell 取代,不再使用

    dde-application-manager

    本次此组件并不存在如 beta2 -> beta3 阶段时的巨大变化,但由于此组件仍为诸多组件的核心依赖,并且此组件也因其它组件需要而增加了一些新的接口,故建议总是使用最新版本。

    dde-shell

    dde-shell 旨在将 DDE 桌面环境插件化与模块化,降低开发难度,使各个组件的替换变得更加容易,并且提供更好的桌面环境集成支持。RC 阶段,dde-shell 已经可以满足原计划的部分目标。现 DDE 环境下,dde-shell 已取代 dde-dock 来负责管理整个 dock 区域,并且 dde-launchpad 也提供了(且默认使用)对应的 dde-shell 插件,用以展示启动器相关的界面。

    尽管 dde-shell 也包含了一份通知中心插件,但这个插件并不会在 RC 中被启用。

    出于初期快速开发目的,dde-shell 本身内附了诸多其它项目的托盘插件代码以及一些第三方库,这部分的代码会在后续版本迭代中逐渐被调整或移除。对于这些代码,可在移植过程中先行酌情调整或移除。项目内附的 networkmanager-qt 依赖也会在后续移除,转而使用系统版本。由于 RC 版本不会涵盖此变更,若有需要,请参见 linuxdeepin/dde-shell#286

    dde-launchpad

    RC 版本中,dde-launchpad 不再支持 Qt 5 构建,也不再直接支持以独立进程的形式被最终用户使用(事实上仍然支持,但仅供开发调试场景下使用)而仅支持以 dde-shell 插件的形式被最终用户使用。因而,打包 dde-launchpad 现需要先打包 dde-shell,并确保用户最终使用的是 dde-shell。

    dde-session

    在之前的版本中,dde-session 提供的相关 systemd 服务依赖关系会导致进入 KDE 环境时也会拉起 DDE 相关的服务,最终由于拉起失败导致 KDE 环境也无法进入。在 RC 版本的 dde-session 中,此问题应当已被解决。

    另外重申,我们已在 beta3 阶段放弃了对 deepin-kwin wayland 的支持,DDE 后续所有 wayland 相关的支持均由 treeland 提供。

    技术预览组件

    技术预览阶段的组件均可酌情决定是否打包。需要注意的是,这些组件并不一定在 RC 阶段存在改善。

    treeland / ddm

    treeland 目前是技术预览阶段的项目,兼顾 Wayland 窗口合成器和显示管理功能。treeland 除需要 dtk6declarative 外,还依赖新项目包括 waylibqwlroots。需要使用 Qt 版本 >= 6.6.0, wlroots 版本 >= 0.17.0 编译 qwlroots/waylib。

    ddm 的仓库也在 RC 阶段进行了拆分,现在 ddm 与 treeland 已是分别独立的两个仓库进行维护了。

    deepin-im

    treeland 目前是技术预览阶段的项目,提供了输入法的抽象层。目前,deepin-im 仅期望在 treeland 环境下使用。它会设置 QT_IM_MODULE 等环境变量的值来影响实际使用的输入法模块。

    RC 版本中,并未涉及对 deepin-im 组件的改善。

    获取移植帮助

    如果您希望得到移植相关的帮助,请考虑加入我们 DDE 移植小组的在线交流群(下列房间有桥接,任选其一即可),一起展开相关的交流:

    Monday, April 10, 2023

    目前 dde-nixos 已经分叉,mian 分支进行 v23 的维护,目前主要更新了 dtk 和部分 deepin 开头的应用, dde 开头的核心应用移植暂未实现,dbus 接口不兼容,因此目前不可日常使用。

    gomod 分支用于测试使用 buildGoModule 完成构建,仅验证可行性,实际使用还需要调整硬编码相关的 patch。

    日常使用 DDE 需要切换 v20 分支,会优先使用已经提交到上游的应用:

       dde-nixos = {
          url = "github:linuxdeepin/dde-nixos/v20";
          inputs.nixpkgs.follows = "nixpkgs";
        };
    

    在 v20 分支,dtk 使用 5.6.3 不再升级,deepin 应用会保持最新的 v20 版的最新版本(不会上 6.0.0),dde 应用冻结为 1 月份打包时测试可用的版本,一般不再升级:

    既除了 deepin 应用,其他应用只有在 v23 移植完成后再更新。

    目前 NixOS 23.05 — Feature Freeze & Release Blockers 已经开始,进度请关注: https://github.com/NixOS/nixpkgs/issues/224457#issuecomment-1501383113

    向上游贡献的主要调整:

    1. 调整 patch

    在 dde-nixos 中,编写了 getPatchFrom, replaceAll 等函数帮助 patch 硬编码路径,但打包时为上游添加函数是难以接受的,因此所有的 patch 都需要使用 substituteInPlace 重写:

    一个典型的例子是:https://github.com/NixOS/nixpkgs/pull/217806

    1. 改善对交叉编译

    所有 deepin 启用 strictDeps,调整了 nativeBuildInputs 和 buildInputs 不规范的地方,(使用 qmake 的除外,会造成 qtwebengine 找不到,且上游已经不太关心 qmake)

    strictDeps 下无法传播 qtimageformats 问题 ,由 NickCao 解决

    ps:可以使用 nix-build -A pkgsCross.riscv64.deepin.dtkcore 尝试交叉编译。目前 x86_64 和 aarch64 可正常编译。

    Friday, April 7, 2023

    obs 全称 Open Build Service,是一个开放的构建平台。相较于其他构建工具有以下优点:

    • 支持跨平台构建(x86、arm64 等)
    • 支持多种虚拟环境(kvm、lxc、chroot 等)
    • 支持软件包构建(deb、rpm、pkg 等)
    • 支持容器构建(flatpak、appimage、docker 等)
    • 支持发型版镜像构建(debian、windows 等)

    玲珑 是一种新型的独立包管理工具集,致力于治理 Linux 系统下传统软件包格式复杂、交叉的依赖关系导致的各种兼容性问题,以及过于松散的权限管控导致的安全风险。

    本文介绍怎么给 obs 添加玲珑构建支持,供以参考实现你自己的 obs 构建服务。

    Thursday, March 9, 2023

    deepin v23 beta 的发布在即,为了能够使相关的 bug 能够得以更快解决,并促进研发团队的协作变得更高效,我们(开源社区中心)决定在 deepin 员工内部举办小规模的 bug hunting 性质的比赛,并命名该比赛为“小浣熊杯修 bug 大赛”。而首届“小浣熊杯”也于昨天顺利落幕,那么就让我们一起了解一下这个比赛吧!

    比赛介绍

    如上所述,“小浣熊杯“的比赛大致内容即为在比赛时间内对已有缺陷进行修复。我们将所有参赛的员工划分为多个组,每个组除研发外也配备一个测试人员。在比赛时间周期内,研发从指定的缺陷看板中挑选自己”中意“的 BUG 进行修复,并在修复后将修复公布在相关群内,由 其他组 的测试人员进行测试。当修复被测试人员验证没有问题后,即可进行计分。最终,会以本组研发人员所修复的数量与测试人员所完成的测试数量相组合,并计算小组人均得分,最后以小组人均得分的高低决定最终排名。

    小组得分的计算公示为:

    小组得分 = (本组研发修复的缺陷数量 + 本组测试所验证的缺陷数量 / 3) / 小组总人数
    

    比赛会在 https://github.com/linuxdeepin/.bug-game/ 中进行,每次比赛会创建一个看板来跟进整个比赛的实时情况,并创建一个对应的 issue 记录相关进展与结果。

    另外,考虑到比赛过程中对缺陷的修复不需要经过其他研发人员的 code review ,因而可能存在实际的代码质量问题,故相关的 PR 均不要求在比赛结束前合入,相关提交仍需按照正常流程,经过有效 review 获得 approval 后合入。

    首届状况介绍

    比赛过程看板截图

    首届比赛共划分了四个小队参赛,比赛时间从 3 月 7 日开始,为期两天。比赛过程与结果在 这个 Issue 中汇总,最终的缺陷修复情况也可以参见 这个看板。比赛过程中“修 bug”队一度领先,随后被”进击的小浣熊“队反超,最终经过了两天的”激烈比拼“后,本次比赛总计处理了 42 个 Issue,由”进击的小浣熊“队以 18.333 分的总积分获得人均积分第一夺冠。“修 bug”队紧随其后,“呆呆鹅” 与 “bug 收割小分队” 获得随后的名次。

    比赛过程中,各个小组对已有 bug 的挑选与“占坑”以及测试人员对新提交修复的“抢单”是过程中最有趣的事情之一。快速挑选便于修复的 BUG 并进行有效的修复成为了获胜的关键之一,根据表象快速分析推测问题的能力,以及在陌生项目1中快速尝试定位和修复问题的能力也变得至关重要。作为花絮,有的小组也在选择 BUG 的过程中连续发现自己所选择的缺陷实际早已在版本迭代中被修复,耗费了较多时间而造成了相对的失利,但这个过程也对现存 BUG 的有效性验证有很大的帮助2

    赛后,我们进行了比赛的颁奖,获胜队伍获得了比赛限定奖杯与荣誉证书,以及一个 deepin 主题背包。获奖队伍也进行了合影:

    荣誉证书

    颁奖截图

    无论是否获奖,我们都感谢各个参赛队伍的积极参与,也希望各位能在后续的比赛中能够获得优异的成绩。


    1. 注:缺陷的修复不限于自己所维护的项目,研发人员也可以尝试修复由其他项目组所维护的缺陷。 ↩︎

    2. 或许在后续的比赛中应当为此类也算作计分项。 ↩︎