读项目NeteaseCloudMusicGtk4
netease-cloud-music-gtk4 是基于 GTK4 + Libadwaita 构造的网易云音乐播放器,专为 Linux 系统打造,已在 openSUSE Tumbleweed + GNOME 环境下测试。
如何将项目运行起来
我们要读一个程序的代码,不管它怎么样,先跑起来再说。这个程序使用的是 GTK4 + Libadwaita,是 Linux 桌面常用的 GUI 库。这个程序没有在 Window 上构建的说明,并且可能是只能在 Linux 上正常编译,因此我将在 Ubuntu 上尝试运行这个程序。
运行一个使用 GTK 的项目我尝试了两种方法:
- 使用 IDE(GNOME Builder)
- 使用文本编辑器(VS Code)
On GNOME Builder
通过 flatpak 安装 GNOME Builder.
flatpak install flathub org.gnome.Builder
启动后选择克隆仓库(Clone Repository)即可下载并打开项目。
这个项目中已经有了 flatpak 的描述文件,GNOME Builder 能够通过com.gitee.gmg137.NeteaseCloudMusicGtk4.json
文件自动安装需要的依赖。
要启用调试信息需要在 meson.build
中指定 buildtype=debug
,这样 GNOME Builder 才会在编译的时候加上调试信息,打的断点才会有效。
GNOME Builder 用起来不是很习惯,很多使用 GTK 的人可能是使用 Vim 或者 VSCode.
On VSCode
尽管 VSCode 也有 flatpak 的插件,但是我尝试了没有成功。那不使用 GNOME Builder,也可以不使用 flatpak。不使用 flatpak 需要自己安装依赖:
sudo apt install -y libssl-dev libgtk-4-dev libdbus-glib-1-dev libadwaita-1-dev libgstreamer-plugins-bad1.0-dev gettext
这个项目使用 Rust 语言开发,对于 rustc 我推荐使用 Rust 官网提供的 rustup 安装。项目使用了 meson 作为构建工具,通过 pip 安装最新的 meson 和 ninja。
下载源码,编译,安装。
git clone https://github.com/gmg137/netease-cloud-music-gtk.git
cd netease-cloud-music-gtk
meson setup build
cd build
ninja install
现在通过 VSCode 打开 netease-cloud-music-gtk 就可以通过 VSCode 的 Rust 插件来运行和调试代码了。
为什么需要安装?因为 GTK 程序使用的资源和 UI 文件必须被编译被安装才能被程序访问到,换言之,修改 ui 文件后就要重新安装。
也可以不安装,但是需要修改现在的加载资源的方式,参考GUI development with Rust and GTK 4
程序的初始化
在 VSCode 中配置好后,就可以点击 main 函数上的 run 或者 debug 来启动程序了。一定要通过 meson 安装资源才能在不改动原来的代码的情况下正常启动程序。
整个程序都被封装在 NeteaseCloudMusicGtk4Application
内,main() 函数只做了各种初始化。程序激活后程序才会创建应用的主窗口,所有的其他的页面和组件都在主窗口内去创建和处理。整个应用程序的 activate() 只将窗口创建出来,然后设置一个循环等待消息。
fn activate(&self) {
let obj = self.obj();
let app = obj
.downcast_ref::<super::NeteaseCloudMusicGtk4Application>()
.unwrap();
if let Some(weak_window) = self.window.get() {
weak_window.upgrade().unwrap().present();
return;
}
let window = app.create_window();
let _ = self.window.set(window.downgrade());
// Setup action channel
let receiver = self.receiver.borrow_mut().take().unwrap();
MAINCONTEXT.spawn_local_with_priority(
Priority::HIGH,
clone!(@strong app => async move {
while let Ok(action) = receiver.recv().await {
app.process_action(action);
}
}),
);
// Ask the window manager/compositor to present the window
window.present();
}
在 Rust and GTK4 那本书中介绍了异步函数之间的通信使用的是 async_channel。要在普通的代码中使用异步函数就要有一个 runtime 来 spawn 异步块,MAINCONTEXT 也是 Glib 提供的用来 spawn 异步块的。
整个程序在创建窗口后就一直等待其他的 Action 的发起,这里的 Action 不是 GTK 库的 Action, 相当于传递消息。process_action() 就是收到传递来的消息,然后做对应的事情。
如何响应用户的操作
GNOME 有一个调试用的工具,提供 Ctrl+Shift+I
可以调出一个类似于 Chrome 里面的开发者工具的 Inspector。这样可以找到对应的组件的名字和id,顺着id搜索代码就能找到注册的回调函数。顺着名字就能找到对应的 ui 文件查看组件的结构。
以下一曲按钮(next_button)为例,因为下一曲按钮放置在一个名为 player_controls 的组件里面,在 palyer_controls.ui 中我们找到下面的代码:
<object class="GtkButton" id="next_button">
<property name="halign">fill</property>
<property name="valign">center</property>
<property name="icon-name">media-skip-forward-symbolic</property>
<signal name="clicked" handler="next_button_clicked_cb" swapped="true" />
<style>
<class name="circular" />
<class name="flat" />
</style>
</object>
这个按钮声明了一个信号处理函数,根据这个 handler 的名字就可以在Rust代码中找到回调函数的定义。
#[template_callback]
fn next_button_clicked_cb(&self) {
let sender = self.sender.get().unwrap().clone();
if let Ok(mut playlist) = self.playlist.lock() {
if let Some(song_info) = playlist.next_song() {
let song_info = song_info.to_owned();
sender
.send_blocking(Action::Play(song_info.to_owned()))
.unwrap();
sender
.send_blocking(Action::UpdateLyrics(song_info))
.unwrap();
sender
.send_blocking(
Action::UpdatePlayListStatus(playlist.get_position()))
.unwrap();
return;
}
}
sender
.send_blocking(Action::AddToast(gettext("No more songs!")))
.unwrap();
}
尽管这看起来有一点复杂,但是其实就是拿到下一首歌曲的信息然后发送3个消息:
- 播放歌曲
- 更新歌词
- 更新播放列表的状态
所有发送的消息最终被 process_action() 接收,process_action 函数内部相当于一个巨大的 switch-case.
按照这样的思路,去调试代码就能找到自己感兴趣的部分了。
总结
读一个项目大概就是这样,运行起来,可以调试。
此前我并没有写过什么 GUI 程序,即便是写过的通常也就是只有一个页面,所以对图形界面程序的页面路由和复杂的状态管理没有什么经验。这个程序当然也没有做的特别复杂。
GTK 这个图形库的学习资料比较少,也有类似 Qt 中的属性、信号的概念,只不过这些都是原生的 C 语言做的,因为 Rust 不支持继承,尽管实际上做同样的事情,但是代码的组织方式却不一样。
从项目的代码来看,能看到作者从 GNOME Builder 生成的 Hello World 模板逐步迭代开发的痕迹,代码当中有多处是代码重复的(很明显的拷贝粘贴),有时候作者采用的方法和 Rust GTK4 书上的例子的做法不一样,当然没有孰优孰劣之分,只是喜好不同。尽管代码在实现上还有一些缺点,但是作为一个可以正常使用且使用 GTK 开发的应用已经很棒了。
读项目NeteaseCloudMusicGtk4的更多相关文章
- my-Life项目开发流程
一:新建java web项目 (懂得使用gradle哦!) 1.http://www.cnblogs.com/xylle/p/5234380.html 2.新建项目后,然后新建module, 如果甲 ...
- [转] 学习React Native必看的几个开源项目
http://www.lcode.org/study-react-native-opensource-one/ http://gold.xitu.io/entry/575f498c128fe10057 ...
- 【转】react-native开发混合App-github开源项目
http://www.lcode.org/study-react-native-opensource-one/ http://gold.xitu.io/entry/575f498c128fe10057 ...
- GitHub 热点速览 Vol.13:近 40k star 计算机论文项目再霸 GitHub Trending 榜
作者:HelloGitHub-小鱼干 摘要:"潮流是个轮回",这句话用来形容上周的 GitHub Trending 最贴切不过.无论是已经获得近 40k 的高星项目 Papers ...
- 读 Linux 像读小说「GitHub 热点速览 v.22.03」
本周特推选取了一个画风有点意思的 Linux 代码带读项目 flash-linux0.11-talk,希望有趣的文风能带你读完 Linux 代码.当然画风可以增加阅读体验,彩色标记也是一种学习方法-- ...
- 如何阅读android framework源码
但如果想深入的了解Android系统, 那么可以看下我的一些简单的总结. 知识 Java Java是AOSP的主要语言之一. 没得说, 必需熟练掌握. 熟练的Android App开发 Linux A ...
- 刨根问底U3D---如何退出Play模式后保留数据更改
实际中遇到的需求 在做一款对抗类游戏,目前正在调整游戏的平衡性 所以就产生了一个需求 希望可以在Play模式时候对数据源做的更改可以在退出时候被保存下来. 举个Case, 比如 有一个炮塔 可以发射子 ...
- 转:微博"收藏/赞/转发"技术资料汇总
书籍 HTTP权威指南 <- @Fenng Introduction to Information Retrieval <- @陈利人 Lua 源码欣赏 <- @简悦云风 The A ...
- Angular v6 正式发布
Angular 6 正式发布 Angular 6 已经正式发布了!这个主要版本并不关注于底层的框架,更多地关注于工具链,以及使 Angular 在未来更容易快速推进. 作为发布的一部分,我们同步了主要 ...
- Angular6.0发布
Angular v6 新版本重点关注工具链以及工具链在 Angular 中的运行速度问题. Angular v6 是统一整体框架.Material 和 CLI 三大 Angular 组件的第一个版本, ...
随机推荐
- StarUML画流程图
一.新建流程图 1.1 新建流程图 1.2 左侧操作符介绍 Flow:顾名思义就是流,用来从一个操作流向下一个操作. Process: 过程 Terminator:用在结束的时候. Dicision: ...
- vue-element-template实现顶部菜单栏
一.框架侧边栏改为顶部导航栏 1.复制src/layout/componets/Sidebar所有文件至同级目录,改名为Headbar 2.src/layout/components/index.js ...
- DexExpress Wpf BackstageItemWithImage
参考链接: https://docs.devexpress.com/WPF/DevExpress.Xpf.Ribbon.BackstageItemWithImage.GlyphStyle 设置 Bac ...
- [Ynoi2015] 盼君勿忘 题解
CSP 前学习珂学,祝自己 \(while(1)\ rp++\). 考虑求解出每种数对答案的贡献. 设 \(t=r-l+1,k_x=\sum\limits_{i=l}^r [a_i=x]\),由容斥得 ...
- 克鲁斯焊机GL 270引弧困难维修
克鲁斯焊机维修: 对于客户而言,其受益之处在于所有的机械手系统部件,从机械手控制.工件.定位器.传感器到电源和焊枪,都是由一家供应商开发和制造的.而诸如熔化极惰性气体/活性气体保护双丝焊接技术.等离子 ...
- 使用 SK 进行向量操作
先祝大家 2025 新年好. 在 2024 年落地的 LLM 应用来看,基本上都是结合 RAG 技术来使用的.因为绝大多数人跟公司是没有 fine-turning 的能力的.不管是在难度还是成本的角度 ...
- PHP对表单提交特殊字符的过滤和处理方法汇总
http://www.jb51.net/article/46921.htm PHP关于表单提交特殊字符的处理方法做个汇总,主要涉及htmlspecialchars/addslashes/stripsl ...
- 什么是CPU?
当你用手机刷短视频.用电脑玩游戏,或是使用智能手表查看健康数据时,这些设备的核心"大脑"--CPU(中央处理器)正在默默工作.它是现代计算设备的核心,但很多人对它一知半解.今天我们 ...
- 云服务器下如何部署Flask项目详细操作步骤
参考网上各种方案,再结合之前学过的Django部署方案,最后确定Flask总体部署是基于:centos7+nginx+uwsgi+python3+Flask之上做的. 本地windows开发测试好了我 ...
- Ubuntu 下查看当前用户
博客地址:https://www.cnblogs.com/zylyehuo/ 在终端执行以下命令 whoami