也许经常会有人提问,这个东西究竟是什么?它的意义何在?你怎么去实现?在我看来这三个问题其实综合起来就是对一个事物从未知到了解的过程。如果你明白了这三个问题,那么就完全足够了,毕竟可能你只是想参观一下。
简单的说就是文件管理器,这太过简单和宽泛了,我们可能需要从更多的细节去分析它的内容。
我们一提到文件管理器,首先想到的就是一个具有侧边栏工具栏和菜单栏的交互式文件视图窗口,确实这一点太过于鲜明了,鲜明的以至于我们认为它就是理所当然的——文件管理器的本质就是操作文件的图形界面。
但是,不是所有的东西都是没有外包装的,除了本质之外,确实会有很多其它相关但并非撼动本质的东西存在。打个比方来说,如果你用过UKUI2.0的文件管理器Peony,你是否注意到当你刻意杀死文件管理器Peony后,整个系统的桌面也会闪退呢?没错,对于Peony来说,它既是文件管理器,同时也是桌面,但实际上我们可能不会认为它们是一个东西。
不光是Peony,很多桌面环境的文件管理器同时也是桌面,比如Mate的Caja。这种文件管理器身兼多职的情况并不罕见,因为在早期Linux图形界面还不发达的时候,整个桌面都是一摸黑,调试工具基本上是人脑,届时我们如果既要有文件管理器,也要有桌面,那么没有比把二者代码重用更加高效的开发方案了。
正因为如此,现在的许多文件管理器,或多或少的承担了一些额外的责任,其中有硬性的需求,比如Freedesktop的规则(dbus接口,我们在浏览器中打开文件夹其实是实现了这个接口),也有根据需要衍生出来的一些附加功能,比如拉起桌面,提供菜单栏插件(打开终端,管理员身份运行等,压缩文件等)。
我们在对一个文件管理器进行分析的时候,首先需要的就是对它涉及范围的一个界定,方法就是通过本质来判断——一个功能究竟是不是文件操作所必须的功能?认清了这一点,我们才能在设计上有方向的去规划如何去实现一个文件管理器,如果没有分清楚这一点,那么我们就会觉得这个好像也要做,这个好像又不是我要做的,这样杂糅出来的一个产品绝对会给后人挖一个大坑。
我认为,就算不能分清楚这些,哪怕有往这方面分析的想法也是极好的。这能够很好的协调大家的工作——设计师能够把设计内容准确的定位下来,开发者能够迅速的根据设计师的需求进行重构,而不是设计和开发处于各自为战的状态;设计师辛苦设计出来的东西不是开发者目前能够控制的东西,这样可能到最后都不能尽如人意。
那么回到正题,我们的Peony又是什么样的一个文件管理器呢?
从命名上其实就可以看出一二来,UKUI3.0的Peony首先还是继承了Peony的名字,但已不再是Gtk项目,其实说白了就是基于旧版Peony的设计结合Qt进行的一次重构,既然它的本质还是文件操作的GUI,我们需要重构的范围和思路也很明确了。
首先,Peony的文件系统是基于GVfs的,那么Peony中依然如此;其次,我们文件操作的交互过程中可能会有一些UI,那么最直接的办法就是替换这些UI,不过这是及其困难并且未必是最好的,所以我们需要重构这一部分,形成一个新的文件操作集;再者,前端界面的重构也是一件繁琐的工作,文件管理器的前端需要底层的支持,所以难免得进行一次自底向上的重构;最后,为了能够在保持代码健壮和可读的情况下丰富文件管理器的功能,额外功能和插件机制的重构也是不可或缺的。关于这些的具体细节,我会在之后再细化的分析,这里我们先进入下一个点。
这又是一个很多人会质疑的问题,其实对于我来说,一个最直接的想法就是为了脱离现有Peony的窘境,我身为社区组的开发人员,全职进行文件管理器方面的工作,应该是体会最为深刻的了。那么我下面就自问自答一波,讲述一下我的心路历程,顺便让大家了解一下Why。
首先,Peony不好吗?这要从用户和开发者的角度,并且每个角度从多面去分析,我想这样才能让大家勉强接受我的观点。对于用户来说,一个文件管理器就像是空气一样,哪怕空气再怎么新鲜,可能迟钝如我都不会觉得怎么样,但是要是空气没了,或者是有毒,那么问题就大条了。至少现在来看,Peony虽然有许多用户吐槽界面不美观,有小bug,但是还不至于有毒。从开发者来看呢?毕竟是从caja fork出来的,虽然整体的架构和功能还是十分完善的,稳定性也暂时可以保证,但是我们可以计算一下整个peony项目的代码行数,10万为单位的代码量不是一个或者几个一般的程序员能够hold住的。我们fork出来以后已经和上游产生了巨大的断层,当我接手这个项目的时候我就明确了一点——我们已经不能跟的住上游的变化了。我花了半年多的时间去研究文件管理器,对Peony可谓是恨得深刻,虽然我做了一些有小特色的新功能,修了几个bug,但就如我在上一章所说的,我根本撼动不了Poeny的本质,所以我认为我做的这些工作说白了其实可有可无,改来改去最后可能越来越不稳定。也许一个特色功能获得用户的认同会让我心里稍微有点慰藉,但是我更关心的是大家对整个文件管理器,甚至对整个UKUI的评价,现在看来,根本没有可以能够沾沾自喜的时间了。
那么为什么要做新版Peony呢?书面版本——未雨绸缪,Gtk接口变动太频繁,考虑到确保社区文件管理器今后的稳定性,以及整个UKUI3.0的设计难度,在无法跟进上游和保持新特性的情况下,使用稳定可靠的Qt快速重构是最优选择;内心版本——我XXX的C+Gtk,XXw的代码,只要不让我干这个干什么都好。
不论如何,在Peony乃至UKUI3.0已经拍板的现在,其实Why都不算重要了,再说的直白一点,连How都不重要,因为必须是要做出来的。对于非开发者而言,过程永远是没有意义的,一切只看结果,但是不管怎么样,哪怕是走了一条新路,也只是减少了心里的苦而已,干的活肯定不会比之前少的。
这个问题涉及到我的工作任务和工作计划,相信领导会对这一块特别关注,一些同样工作的同僚们可能也会特别关注,但是我可能会让大家失望了。说白了讲,如果等我真的把所有的坑都摸了个遍,那我还写这本书干什么呢?直接给一个deadline然后给出成品不就完了吗?并不是技术水平有多高,我可能只是在这一块比大家的思路更清晰一点而已,毕竟我从接手的时刻开始就想着要干一波大事了。那么现在我来理一理自己的思路,同时也会结合我目前的工作进度,进行阶段性的总结,并对将来的工作做出一个暂时的计划。
我们UKUI3.0已经开过很多次会了,单论技术交流会也不少,但是大多还是从整体的方向入手,很难做到因地制宜。就拿技术选型路线来说,虽然确定了使用Qt,但是哪怕是Qt也会有诸多选型,比如到底是基于KF5或者其它框架,又或者自己重构SDK,之前在这个问题上也产生过不少分歧的。我认为这个问题的解决办法就是怎么简单怎么来,相信大家也是这么做的。框架是把双刃剑,这个坑我已经在Peony上趟过无数遍了,再多一遍我都不想去趟;虽然我还是迫于压力和指示去趟了一下基于别人框架进行开发的路子,花了半个月的时间,也算是有所收获,但是实际上也没有办法继续走下去了。一个框架的设计理念是不可重用的,不管是KF5还是libfm-qt,最终都回不到UKUI的设计理念上,如果强行糅合二者,那么我能断言新版Peony依然是一个和UKUI2.0中的旧版Peony一样性质的项目。
不过请各位不要误会,我不是说拒绝框架,之前我也说过因地制宜,怎么方便怎么来是第一步,如果有合适的轮子,我绝对就用了,我没有一定要自己造轮子的情结,奈何实在这些框架都是不可尽用的。最后一圈下来发现,对我而言glib和qt足矣,而且谁敢说这不是框架不是轮子呢?它们的好处在于理念的层级不同,不相互冲突,所以开发起来能够得心应手,至于那些被我抛弃的框架,我也会吸取其中的亮点以及思路,甚至非常好的我花精力重用都是可以的。也许对于其它的UKUI项目而言,选用基于Qt的更高级框架也说不定,但是这也不是我关心的问题,我只能给大家提出我的一点建议——要选的明白,不要再次进同样的坑。想要做到这一点其实很不容易,我想关键点还是需要有从零构建的思路,这样才能够有针对性的判断和选择最适合自己的开发环境。
那么在这个大前提作为铺垫下,我讲一下实现peony的思路,所有的坑肯定是不可能完全覆盖得到的,我的目标就是保持一个可持续推进的开发计划,不论是前期成型还是后期维护、定制与转型,所有的工作都能够被衔接起来,哪怕我不再负责文件管理器的开发,它也依然能够较的好持续下去。
我前面也提到了使用glib+qt作为开发环境,那么第一个问题就是如何将gvfs和qt结合起来;最直接的一点,我已经能够获取gvfs的数据,怎么样将它们以一个比较完美的方式展现在窗口中呢?我认为这是文件管理器迁移的第一个难题,我对这个难题的解答也很简单,就是实现gvfs的qt model,qt的model/view编程非常适合用在文件管理器这一类的项目上,我在之后会专门起一节阐述这方面与文件管理器结合的过程,目前而言,这方面的进展已经完成了可以“看”的部分,比如登录特定的uri,或者在终端的操作能够映射到我的model中去,或者进行简单的筛选和排序;而为了实现可以“改”,我们还需要文件操作的支持;为了使得视图更加美观或者达到一些特殊的效果以及功能,我们还需要对view以及delegate进行继承和重写。
model的可写性最直观的在于图标在视图间的拖拽,qt和gtk其实都提供了dnd的接口,我们需要做的其实是结合文件操作的代码实现这些接口,同时,这些文件操作的接口也可以复用在其它诸如菜单、工具栏之类的地方。关于这一块的工作,我目前只是完成了文件移动的实现,至于与model的dnd以及其它功能的结合,还得等文件操作部分的代码稳定下来之后再进行推进。
有了model以及文件操作之后,我们可以构造一个仅有文件视图的文件管理器窗口了,当然这还远远不够,至少我们还需要提供一个侧边栏。其实侧边栏的本质也是一个model,只是它不光是显示一个目录中的文件了,它还可能包括设备以及收藏夹,这一块在我对qt model/view编程有了一定的造诣之后也不是一个特别棘手的问题,我之前使用libfm-qt快速开发时也构造了一个窗体,只能说qt在这方面的优势还是挺大的,能够快速接近设计者的需求,当然花费大量时间进行微调是难以避免的,这一块的工作我打算放到最后再去做。
关于桌面的拉起其实一直是我心里的一道坎,9012年了,我们还不能让文件管理器变成一个非常驻后台的应用。哪怕是再成熟的项目,常驻后台意味着需要承担内存泄漏带来的风险将会随时间增长,连caja这么成熟的一个项目都无法摆脱这个问题,而且谁敢断言glib/gio或者qt自己不会有内存泄漏的问题呢?如果桌面必须常驻,那么至少不要带上文件管理器,这点只要框架足够分离完全是可以做到的。回归正题,桌面要做的事情也有很多,比响应屏幕的改变、壁纸的切换、记录图标的位置等,qt对屏幕事件的封装还是比较完善的,关于图标的记录其实可以看做是对model的二次修改,这些细节的东西同样是放在后面去实现的。我在基于libfm-qt进行快速开发的时候也趟过桌面这一块的坑,也尝试了各个DE的桌面,总之每一个都有每一个的缺陷吧,毕竟这些细节上的东西混在一起要实现一个完美的效果确实挺难的。
我之前也专门行文分析过Peony的插件机制,比起glib那一套,qt的plugin机制算是非常直观和简单的了,实际上我从Peony创立的一开始,趟的第一个坑就是这个,关于整个Peony插件机制的实现,其实上也就是对qt plugin机制的一层封装,插件机制的实现其实并不困难,难的是插件的迁移,就像ukui-panel的迁移一样。这一块可以等到整个文件管理器实现之后再加入都没有问题。
qt的信号槽机制使得各个组件之间能够简单的实现解耦合的效果,所以我不会再像原来Peony一样把各个成员绑的死死的,因为这样对于后期的维护和开发十分不利。我再之后也会花时间梳理和规范前后端的接口,把各个组件模块化,如果想做UI的改动,实现一组接口就可以了,这样的尝试我在文件操作的重构中也进行了实践,比如进行文件操作出错时的处理接口,可以是一个对话框,也可以没有ui。
我对文件管理器重构的计划是3+3个月,前三个月的任务是底层的重构,也就是框架的重构,后3个月则是基于框架进行开发与迭代的过程,如果我前3个月的工作足够好,那么可能之后的日程会推进的更快,我认为在现有条件下这样的计划是最高效并且能够达到UKUI3.0要求的方案了。
以上差不多是我思路的一些要点,没有无中生有,全部都是以实际问题的角度去得出的。现阶段我也不想揣摩一些用户的想法,真要是被这些弄得晕头转向了可一点都不好玩,我的理想情况就是用户的需求能够在我的框架之下由技服快速解决,XD。
接下来的文章会对我认为有必要阐明的思路和技术进行详细的、结合实例的补充,以方便大家了解如何使用libpeony-qt的api,并且摸清我的开发思路,这会有助于开发人员对现有项目进行完善或者二次开发。