开发环境搭建
- Ubuntu 14 Desktop
- Lib GTK3
- Lib Appindicator3
GTK3开发环境安装:
sudo apt-get install libgtk-3-dev make gcc pkg-config
托盘图标开发包安装:
sudo apt-get install -y libappindicator3-dev
GTK Hello World!
首先我们来尝试一下由GTK程序的Hello World,创建一个标题为"Window" 的GTK窗口
#include <gtk/gtk.h>
int main (int argc, char *argv[]){
GtkWidget *window;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Window");
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show (window);
gtk_main ();
return 0;
}
程序编译
sudo gcc `pkg-config --cflags gtk+-3.0` hello.c -o hello `pkg-config --libs gtk+-3.0`
普通用户编译可能会造成
(.text+0x18):对‘main’未定义的引用
错误
到这里我们已经证明了我们的开发环境已经可用。
托盘程序
我们需要创建一个如下的状态栏图标程序:
托盘程序使用GTK和appindicator3 API实现,使用GTK创建UI主程序和提供菜单,使用libappindicator
创建状态栏的图标。
main.c 示例代码如下:
#include <stdio.h>
#include <gtk/gtk.h>
#include <libappindicator/app-indicator.h>
#include <string.h>
#define APPINDICATOR_ID "MyFirstTrayApp"
#define ICON "/tmp/tmp.MV7CyDttpW/cmake-build-debug/icon.ico"
/**
* 创建菜单
* @return 菜单
*/
GtkMenuShell *create_menu();
int main() {
AppIndicator *indicator = NULL;
GtkMenuShell *indicator_menu = NULL;
// 1. 初始化GTK
if (gtk_init_check(0, NULL) == FALSE) {
return -1;
}
// 2. app-indicator 创建应用程序状态栏的图标
// 注意:图标文件名必须是绝对路径否则会出现无法显示问题。
indicator = app_indicator_new(APPINDICATOR_ID, ICON,
APP_INDICATOR_CATEGORY_APPLICATION_STATUS);
app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE);
// 设置图标
app_indicator_set_icon(indicator, ICON);
// 3. 初始化菜单项
indicator_menu = create_menu();
// 4. 关联到状态栏
app_indicator_set_menu(indicator, GTK_MENU (indicator_menu));
// 5. 启动GTK程序,并阻塞进程。
gtk_main();
return 0;
}
/**
* 按钮回调函数
*/
void hello_cb(GtkMenuItem *item, gpointer data) {
printf(">> Hello world!\n");
}
GtkMenuShell *create_menu() {
GtkWidget *hello_item;
GtkWidget *quit_item;
GtkMenuShell *indicator_menu;
indicator_menu = (GtkMenuShell *) gtk_menu_new();
hello_item = gtk_check_menu_item_new_with_label("你好!");
// 菜单项定义
// gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(hello_item), FALSE);
// 表示可交互
// gtk_widget_set_sensitive(hello_item, TRUE);
// 设置点击事件回调函数
g_signal_connect(hello_item, "activate", G_CALLBACK(hello_cb), NULL);
quit_item = gtk_check_menu_item_new_with_label("退出");
// gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(quit_item), FALSE);
// gtk_widget_set_sensitive(quit_item, TRUE);
g_signal_connect(quit_item, "activate", G_CALLBACK(gtk_main_quit), NULL);
// 显示菜单项目,并添加到菜单中。
gtk_widget_show(hello_item);
gtk_widget_show(quit_item);
gtk_menu_shell_append(indicator_menu, hello_item);
gtk_menu_shell_append(indicator_menu, quit_item);
return indicator_menu;
}
注意:图标文件名必须要是绝对路径,否则图标无法显示!
- 初始GTK。
- 使用Appindicator3 API 创建并初始化Appindicator。
- 使用GTK创建菜单,并把菜单关联到Appindicator,菜单包含两个功能,控制台打印字符串、退出程序。
- 启动程序。
编译程序
sudo gcc `pkg-config --cflags gtk+-3.0 appindicator3-0.1` main.c -o main `pkg-config --libs gtk+-3.0 appindicator3-0.1`
运行程序
CMake进行项目管理
CMake可以非常方便的对C/C++工程进行管理,减少编译连接对开发者的负担,使用上面程序作为工程文件,创建一个CMake项目。
首先,安装CMake:
sudo apt-get install cmake
- 创建目录
UbuntuTray
- 把刚才创建的
main.c
和icon.ico
文件复制到目录中。 - 创建
CMakeLists.txt
如下所示:
CMakeLists.txt内容:
cmake_minimum_required(VERSION 2.8)
project(UbuntuTray C)
set(CMAKE_C_STANDARD 99)
add_executable(main main.c)
如果是一个普通程序,那么上面内容表示生成编译生成一个名为main
的可执行程序。
由于我们的程序使用到了gtk+-3.0
、appindicator3
两个库,编译时使用需要指明头文件位置,连接时需要指明需要连接的动态库。
之前gcc编译命令中,我们使用pkg-config
程序来查找这2个库的头文件(pkg-config --cflags
参数)和动态库(pkg-config --libs
参数)。
在CMake中我们需要使用下面语法来进行查找和使用
完整的CMakeLists.txt内容:
cmake_minimum_required(VERSION 2.8)
project(UbuntuTray C)
set(CMAKE_C_STANDARD 99)
# pkg-config --cflags gtk+-3.0 appindicator3-0.1
# pkg-config --libs gtk+-3.0 appindicator3-0.1
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
pkg_check_modules(AppI3 REQUIRED appindicator3-0.1)
# 添加头文件目录
include_directories(${GTK3_INCLUDE_DIRS} ${AppI3_INCLUDE_DIRS})
# 添加链接库目录
link_directories(${GTK3_LINK_LIBRARIES} ${AppI3_LINK_LIBRARIES})
add_executable(main main.c)
# 可执行程序链接库
target_link_libraries(main ${GTK3_LIBRARIES} ${AppI3_LIBRARIES})
- 首先使用
find_package(PkgConfig REQUIRED)
引入pkg-config
,请确保已经在系统中安装pkg-config
。 - 使用
pkg_check_modules(变量名 REQUIRED 包名称)
查找相关的模块,如果模块存在那么会以变量名
作为前缀设置一些列的变量,如:头文件路径_INCLUDE_DIRS
、依赖包_LIBRARIES
。 - 接下来添加使用之前设置变量来添加头文件和链接库的目录。
- 最后为可执行程序链接冬天库。
创建用于构建的目录,并运行cmake构建Makefile等相关文件
mkdir build
cd build/
cmake ..
运行后会在build目录生成构建相关的文件
可以看到已经生成了Makefile,我们接下来我们使用make命令编译程序即可:
make
可以看到我们的main
可执行程序已经编译完成
运行程序可以看到与我们之前使用gcc命令编译的程序一样效果。
参考文献
[1]. ubuntu . ApplicationIndicators . https://wiki.ubuntu.com/DesktopExperienceTeam/ApplicationIndicators
[2]. gtk . gtk3 . https://docs.gtk.org/gtk3/
[3]. 博客园 . 用cmake构建gtk程序 . ChrisZZ . 2019.06 . https://www.cnblogs.com/zjutzz/p/10959211.html
[4]. 空心菜 . cmake使用pkg-config配置工程依赖 . 2021.03 . https://kxcblog.com/post/dev/cmake-pkg-config/
[5]. github . Serge Zaitsev . zserge/tray . https://github.com/zserge/tray
[6]. github getlantern . getlantern/systray . https://github.com/getlantern/systray