Qt顯示Linux desktop natification氣泡提示框


在現代Linux桌面環境上我們時常可以看到類似的消息框:

這些消息框常用在如下場景:

  • 即時聊天軟件的新消息
  • 鬧鍾定時提示
  • 電池電量提示
  • 郵件消息
  • 長耗時操作的完成提示

在freedesktop.org的規范中這種消息框被稱為Desktop Notification,中文名我們形象得稱其為“氣泡框”。通過調用D-BUS服務org.freedesktop.Notifications提供的接口即可顯示在桌面上。

所以我們先了解一下這個D-BUS服務。

org.freedesktop.Notifications概覽

一個氣泡框消息通常會包含如下的屬性:

名稱 說明
Application Name 標示發送消息的程序,最好使用程序全名
Replaces ID 可選的消息ID,服務器通過id控制消息框的渲染,通常不用關注
Icon 顯示在氣泡框上的圖標
Summary 標題,只能顯示一行,叫title應該更合適
Body 消息體,支持部分HTML標簽;<b></b><i></i><u></u><a></a><img src=... alt=...>
Actions 顯示一些按鈕或者菜單(QAction),不過這一功能通常未被實現
Hints 為消息體提供的額外數據,比如顯示在屏幕的位置(x,y坐標)
Expiration Timeout 氣泡框顯示的時長,單位毫秒;指定為-1時行為取決於實現;為0時氣泡框將一直顯示在桌面上直到用戶點擊

其中Icon和Hints中的image_path必須為本地絕對路徑或者file://開頭的文件URL。另外使用桌面環境預定義圖標的名字也是可以的。

氣泡框還有三個緊急程度可供選擇:

名稱 說明
Low 0 默認值,可以設置如何顯示,應該設置一個合理的顯示時間以便氣泡框可以隱藏退出
Normal 1 同low
Critical 2 代表重要通知,不應該自動過期隱藏

所有的氣泡框消息請求都是異步的,通常構造請求並發送后用戶就可以不再關心后續的信息,如果有特殊需要則可以自定義處理org.freedesktop.Notifications發送的信號。

得益於freedesktop.org的標准規范,包括KDE,GNOME,XFCE4在內的許多桌面環境都提供了對Desktop Notification的支持,雖然外觀上可能存在一些差異但是創建氣泡框的方法是一樣的。

不過不用擔心,我們不會直接去使用D-BUS,因為已經有簡化的現成方案可供選擇了。下面就讓我們一起看看這些方案。

方案一:調用外部命令

可能你已經知道了,我要介紹的命令就是notify-send

notify-send幾乎被所有的桌面環境和發行版支持,它依賴於后面會介紹的libnotify和glib,如果你的系統上沒有安裝可以使用如下命令進行安裝:

debian/Ubuntu:

sudo apt install libnotify-bin

Arch Linux:

sudo pacman -S libnotify

安裝后可以用如下命令顯示氣泡框:

# notify-send title body [options]
notify-send test 'This is a desktop Notification test.' -t 10000

-t參數設置超時時間。效果如下:

具體的參數可以參考這里:https://ss64.com/bash/notify-send.html

方案二:通過編程方式實現

在Qt代碼中調用外部命令就可以顯示氣泡框,然而這種方式不夠靈活,所以我們需要使用前面提到的libnotify在我們的代碼里生成並顯示氣泡框。

libnotify對各個語言都提供了binding,可以參考這里
這里我們選擇使用golang的binding:

package main
import ("github.com/mqu/go-notify")

func main() {
	notify.Init("Hello world")
	hello := notify.NotificationNew("Hello World!", "This is an example notification.","dialog-information")
	hello.SetTimeout(5000)
	hello.Show()
}

上面的代碼將會顯示一個可以在桌面停留5s的氣泡框:

不過如果每次都要使用一大串代碼才能顯示消息的話必然是低效的,而且需要換算時間至毫秒,所以我寫了一個幫助函數在notify.go:

// ShowNotification 顯示org.freedesktop.Notifications氣泡消息框
// duration == -1時使用默認delay
// duration == 0表示不設置超時,desktop notification將會一直顯示
func ShowNotification(title, text, image string, delay time.Duration) {
	var notifyDelay int32
	if delay == -1 {
		notifyDelay = duration2millisecond(defaultNotifyDelay)
	} else {
		notifyDelay = duration2millisecond(delay)
		// 不合法值(包括duration不足1ms),使用默認值進行替換
		if notifyDelay == -1 {
			notifyDelay = duration2millisecond(defaultNotifyDelay)
		}
	}

	libnotify.Init(applicationName)

	notify := libnotify.NotificationNew(title, text, image)
	if notify == nil {
		fmt.Fprintf(os.Stderr, "Unable to create a new notification\n")
		return
	}
	notify.SetTimeout(notifyDelay)

	notify.Show()
}

// duration2millisecond 將time.Duration轉換成millisecond
// duration不足1ms將返回-1
func duration2millisecond(duration time.Duration) int32 {
	res := int32(duration / time.Millisecond)
	if res < 0 {
		return -1
	}

	return res
}

首先將時間值轉換成毫秒數,如果太小或者不合法就使用默認的停留時間。applicationName是程序的完整名稱。
因為氣泡框消息是異步的,所以在調用了Show()之后函數就會返回,后續操作xwindows都會幫我們處理,所以這個函數調用之后是立刻返回的,不會阻塞Qt的gui事件循環,可以放心的使用:

// download something success
ShowNotification("下載", "文件下載完成", "dialog-information", 5*time.Second)

這樣我們也可以輕松地在我們的Qt程序中使用氣泡消息框了。

參考:

https://developer.gnome.org/notification-spec/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM