From 01c17723fa4f91c40ac946e9d02bd55be85c1f75 Mon Sep 17 00:00:00 2001
From: yangxianzhao <yangxianzhao@uniontech.com>
Date: Thu, 6 Apr 2023 10:06:18 +0800
Subject: [PATCH] Fix-the-system-monitor-displaying-a-scene

---
 dock/dock_manager_entries.go |  3 +-
 dock/dock_manager_xevent.go  | 13 ++++---
 dock/identify_window.go      | 70 ++++++++++++++++++++++++------------
 3 files changed, 58 insertions(+), 28 deletions(-)

diff --git a/dock/dock_manager_entries.go b/dock/dock_manager_entries.go
index ad758c8..bf4c1d5 100644
--- a/dock/dock_manager_entries.go
+++ b/dock/dock_manager_entries.go
@@ -83,6 +83,7 @@ func (m *Manager) attachOrDetachWindow(winInfo *WindowInfo) {
 	} else {
 
 		if winInfo.entryInnerId == "" {
+			logger.Debugf("winInfo.entryInnerId is empty, call identifyWindow, win: %d", winInfo.window)
 			winInfo.entryInnerId, winInfo.appInfo = m.identifyWindow(winInfo)
 			m.markAppLaunched(winInfo.appInfo)
 		} else {
@@ -173,7 +174,7 @@ func (m *Manager) attachWindow(winInfo *WindowInfo) {
 func (m *Manager) detachWindow(winInfo *WindowInfo) {
 	entry := m.Entries.getByWindowId(winInfo.window)
 	if entry == nil {
-		logger.Warningf("entry of window '%x' is nil", winInfo.window)
+		logger.Warningf("entry of window %d is nil", winInfo.window)
 		return
 	}
 	needRemove := entry.detachWindow(winInfo)
diff --git a/dock/dock_manager_xevent.go b/dock/dock_manager_xevent.go
index 17468bf..c67a776 100644
--- a/dock/dock_manager_xevent.go
+++ b/dock/dock_manager_xevent.go
@@ -21,6 +21,7 @@ package dock
 
 import (
 	"sort"
+	"strings"
 	"time"
 
 	x "github.com/linuxdeepin/go-x11-client"
@@ -76,12 +77,13 @@ func (m *Manager) handleClientListChanged() {
 		for _, win := range add {
 			window0 := win
 			addFunc := func() {
-				logger.Debugf("client list add: %x", window0)
+				logger.Debugf("client list add: %d", window0)
 				winInfo := m.registerWindow(window0)
 				logger.Infof("%v", m.windowInfoMap)
 				repeatCount := 0
 				for {
 					if repeatCount > 10 {
+						logger.Debugf("give up identify window %d", window0)
 						return
 					}
 					good := isGoodWindow(window0)
@@ -90,7 +92,9 @@ func (m *Manager) handleClientListChanged() {
 					}
 					pid := getWmPid(window0)
 					wmClass, _ := getWmClass(window0)
-					if pid != 0 || wmClass != nil {
+					wmName := getWmName(window0)
+					wmCmd, _ := getWmCommand(window0)
+					if pid != 0 || wmClass != nil || wmName != "" || strings.Join(wmCmd, "") != "" {
 						m.attachOrDetachWindow(winInfo)
 						return
 					}
@@ -106,7 +110,7 @@ func (m *Manager) handleClientListChanged() {
 		for _, win := range remove {
 			window0 := win
 			removeFunc := func() {
-				logger.Debugf("client list remove: %x", window0)
+				logger.Debugf("client list remove: %d", window0)
 				m.windowInfoMapMutex.RLock()
 				logger.Infof("%v", m.windowInfoMap)
 				winInfo := m.windowInfoMap[window0]
@@ -115,7 +119,7 @@ func (m *Manager) handleClientListChanged() {
 					m.detachWindow(winInfo)
 					winInfo.entryInnerId = ""
 				} else {
-					logger.Warningf("window info of '%x' is nil", window0)
+					logger.Warningf("window info of %d is nil", window0)
 					entry := m.Entries.getByWindowId(window0)
 					m.removeAppEntry(entry)
 				}
@@ -198,6 +202,7 @@ func (m *Manager) handleMapNotifyEvent(ev *x.MapNotifyEvent) {
 	logger.Debug("MapNotifyEvent window:", ev.Window)
 	winInfo := m.registerWindow(ev.Window)
 	time.AfterFunc(2*time.Second, func() {
+		logger.Warningf("mapNotifyEvent after 2s, call identifyWindow, win: %d", winInfo.window)
 		_, appInfo := m.identifyWindow(winInfo)
 		m.markAppLaunched(appInfo)
 	})
diff --git a/dock/identify_window.go b/dock/identify_window.go
index 9b433ed..e4f178e 100644
--- a/dock/identify_window.go
+++ b/dock/identify_window.go
@@ -20,9 +20,11 @@
 package dock
 
 import (
+	"fmt"
 	"path/filepath"
 	"strconv"
 	"strings"
+	"time"
 
 	"pkg.deepin.io/lib/procfs"
 )
@@ -59,18 +61,18 @@ func (m *Manager) identifyWindow(winInfo *WindowInfo) (innerId string, appInfo *
 	logger.Debugf("identifyWindow: window id: %v, window innerId: %q",
 		winInfo.window, winInfo.innerId)
 	if winInfo.innerId == "" {
-		logger.Debug("identifyWindow: winInfo.innerId is empty")
+		logger.Debugf("identifyWindow: win %d winInfo.innerId is empty", winInfo.window)
 		return
 	}
 
 	for idx, item := range m.identifyWindowFuns {
 		name := item.Name
-		logger.Debugf("identifyWindow: try %s:%d", name, idx)
+		logger.Debugf("identifyWindow %d try %s:%d", winInfo.window, name, idx)
 		innerId, appInfo = item.Fn(m, winInfo)
 		if innerId != "" {
 			// success
-			logger.Debugf("identifyWindow by %s success, innerId: %q, appInfo: %v",
-				name, innerId, appInfo)
+			logger.Debugf("identifyWindow %d by %s success, innerId: %q, appInfo: %v",
+				winInfo.window, name, innerId, appInfo)
 			// NOTE: if name == "Pid", appInfo may be nil
 			if appInfo != nil {
 				fixedAppInfo := fixAutostartAppInfo(appInfo)
@@ -101,8 +103,9 @@ func fixAutostartAppInfo(appInfo *AppInfo) *AppInfo {
 }
 
 func identifyWindowByScratch(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
+	msgPrefix := fmt.Sprintf("identifyWindowByScratch win: %d ", winInfo.window)
 	desktopFile := filepath.Join(scratchDir, addDesktopExt(winInfo.innerId))
-	logger.Debugf("try scratch desktop file: %q", desktopFile)
+	logger.Debugf("%s try scratch desktop file: %q", msgPrefix, desktopFile)
 	appInfo := NewAppInfoFromFile(desktopFile)
 	if appInfo != nil {
 		// success
@@ -113,8 +116,9 @@ func identifyWindowByScratch(m *Manager, winInfo *WindowInfo) (string, *AppInfo)
 }
 
 func identifyWindowByPid(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
+	msgPrefix := fmt.Sprintf("identifyWindowByPid win: %d ", winInfo.window)
 	if winInfo.pid > 10 {
-		logger.Debugf("identifyWindowByPid: pid: %d", winInfo.pid)
+		logger.Debugf("%s pid: %d", msgPrefix, winInfo.pid)
 		entry := m.Entries.GetByWindowPid(winInfo.pid)
 		if entry != nil {
 			// success
@@ -126,8 +130,9 @@ func identifyWindowByPid(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
 }
 
 func identifyWindowByGtkAppId(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
+	msgPrefix := fmt.Sprintf("identifyWindowByGtkAppId win: %d ", winInfo.window)
 	gtkAppId := winInfo.gtkAppId
-	logger.Debugf("identifyWindowByGtkAppId: gtkAppId: %q", gtkAppId)
+	logger.Debugf("%s gtkAppId: %q", msgPrefix, gtkAppId)
 	if gtkAppId != "" {
 		appInfo := NewAppInfo(gtkAppId)
 		if appInfo != nil {
@@ -140,8 +145,9 @@ func identifyWindowByGtkAppId(m *Manager, winInfo *WindowInfo) (string, *AppInfo
 }
 
 func identifyWindowByFlatpakAppID(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
+	msgPrefix := fmt.Sprintf("identifyWindowByFlatpakAppID win: %d ", winInfo.window)
 	flatpakRef := winInfo.flatpakAppID
-	logger.Debugf("identifyWindowByFlatpakAppID: flatpak ref is %q", flatpakRef)
+	logger.Debugf("%s flatpak ref is %q", msgPrefix, flatpakRef)
 	if strings.HasPrefix(flatpakRef, "app/") {
 		parts := strings.Split(flatpakRef, "/")
 		if len(parts) > 1 {
@@ -204,12 +210,13 @@ var crxAppIdMap = map[string]string{
 }
 
 func identifyWindowByCrxId(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
+	msgPrefix := fmt.Sprintf("identifyWindowByCrxId win: %d ", winInfo.window)
 	if winInfo.wmClass != nil &&
 		strings.EqualFold(winInfo.wmClass.Class, "chromium-browser") &&
 		strings.HasPrefix(winInfo.wmClass.Instance, "crx_") {
 
 		appId, ok := crxAppIdMap[winInfo.wmClass.Instance]
-		logger.Debug("identifyWindowByCrxId", appId)
+		logger.Debug(msgPrefix, "appId:", appId)
 		if ok {
 			appInfo := NewAppInfo(appId)
 			if appInfo != nil {
@@ -223,6 +230,7 @@ func identifyWindowByCrxId(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
 }
 
 func identifyWindowByCmdlineTurboBooster(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
+	msgPrefix := fmt.Sprintf("identifyWindowByCmdlineTurboBooster win: %d ", winInfo.window)
 	pid := winInfo.pid
 	process := winInfo.process
 	if process != nil && pid != 0 {
@@ -233,7 +241,7 @@ func identifyWindowByCmdlineTurboBooster(m *Manager, winInfo *WindowInfo) (strin
 			} else if strings.Contains(process.cmdline[0], "/applications/") {
 				matches, err := filepath.Glob(process.cmdline[0] + "*")
 				if err != nil {
-					logger.Warning("filepath.Glob err:", err)
+					logger.Warning(msgPrefix, "filepath.Glob err:", err)
 					return "", nil
 				}
 				if len(matches) > 0 && strings.HasSuffix(matches[0], desktopExt) {
@@ -242,7 +250,7 @@ func identifyWindowByCmdlineTurboBooster(m *Manager, winInfo *WindowInfo) (strin
 			}
 
 			if desktopFile != "" {
-				logger.Debugf("identifyWindowByCmdlineTurboBooster: desktopFile: %s", desktopFile)
+				logger.Debugf("%s desktopFile: %s", msgPrefix, desktopFile)
 				appInfo := NewAppInfoFromFile(desktopFile)
 				if appInfo != nil {
 					// success
@@ -257,6 +265,7 @@ func identifyWindowByCmdlineTurboBooster(m *Manager, winInfo *WindowInfo) (strin
 }
 
 func identifyWindowByPidEnv(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
+	msgPrefix := fmt.Sprintf("identifyWindowByPidEnv win: %d ", winInfo.window)
 	pid := winInfo.pid
 	process := winInfo.process
 	if process != nil && pid != 0 {
@@ -264,18 +273,22 @@ func identifyWindowByPidEnv(m *Manager, winInfo *WindowInfo) (string, *AppInfo)
 		launchedDesktopFilePid, _ := strconv.ParseUint(
 			process.environ.Get("GIO_LAUNCHED_DESKTOP_FILE_PID"), 10, 32)
 
-		logger.Debugf("identifyWindowByPidEnv: launchedDesktopFile: %q, pid: %d",
-			launchedDesktopFile, launchedDesktopFilePid)
+		logger.Debugf("%s launchedDesktopFile: %q, pid: %d",
+			msgPrefix, launchedDesktopFile, launchedDesktopFilePid)
 
+		// 以下 2 种情况下，才能信任环境变量 GIO_LAUNCHED_DESKTOP_FILE。
+		// 1. 当窗口 pid 和 launchedDesktopFilePid 相同时；
+		// 2. 当窗口的进程的父进程 id（即 ppid）和 launchedDesktopFilePid 相同，
+		// 并且该父进程是 sh 或 bash 时。
 		var try bool
-		if uint(launchedDesktopFilePid) == pid  || process.ppid == 1 { // launchedDesktopFilePid可能被销毁，process变成孤儿进程
+		if uint(launchedDesktopFilePid) == pid {
 			try = true
 		} else if uint(launchedDesktopFilePid) == process.ppid && process.ppid != 0 {
-			logger.Debug("ppid equal")
+			logger.Debug(msgPrefix, "ppid equal")
 			parentProcess := procfs.Process(process.ppid)
 			cmdline, err := parentProcess.Cmdline()
 			if err == nil && len(cmdline) > 0 {
-				logger.Debugf("parent process cmdline: %#v", cmdline)
+				logger.Debugf("%s parent process cmdline: %#v", msgPrefix, cmdline)
 				base := filepath.Base(cmdline[0])
 				if base == "sh" || base == "bash" {
 					try = true
@@ -296,11 +309,12 @@ func identifyWindowByPidEnv(m *Manager, winInfo *WindowInfo) (string, *AppInfo)
 }
 
 func identifyWindowByRule(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
+	msgPrefix := fmt.Sprintf("identifyWindowByRule win: %d ", winInfo.window)
 	ret := m.windowPatterns.Match(winInfo)
 	if ret == "" {
 		return "", nil
 	}
-	logger.Debug("identifyWindowByRule ret:", ret)
+	logger.Debug(msgPrefix, "patterns match result:", ret)
 	// parse ret
 	// id=$appId or env
 	var appInfo *AppInfo
@@ -356,12 +370,21 @@ func identifyWindowByWmClass(m *Manager, winInfo *WindowInfo) (string, *AppInfo)
 }
 
 func identifyWindowByBamf(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
-	// bamf
+	msgPrefix := fmt.Sprintf("identifyWindowByBamf win: %d ", winInfo.window)
 	win := winInfo.window
-	desktop, err := getDesktopFromWindowByBamf(win)
-	if err != nil {
-		logger.Warning(err)
-		return "", nil
+	desktop := ""
+	// 重试 bamf 识别，yozo office 的窗口经常要第二次时才能识别到。
+	for i := 0; i < 3; i++ {
+		var err error
+		desktop, err = getDesktopFromWindowByBamf(win)
+		logger.Debugf("%s get desktop i: %d, desktop: %q", msgPrefix, i, desktop)
+		if err != nil {
+			logger.Warning(msgPrefix, "get desktop failed:", err)
+		}
+		if desktop != "" {
+			break
+		}
+		time.Sleep(100 * time.Millisecond)
 	}
 
 	if desktop != "" {
@@ -375,6 +398,7 @@ func identifyWindowByBamf(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
 }
 
 func identifyWindowByCmdlineXWalk(m *Manager, winInfo *WindowInfo) (string, *AppInfo) {
+	msgPrefix := fmt.Sprintf("identifyWindowByCmdlineXWalk win: %d ", winInfo.window)
 	process := winInfo.process
 	if process == nil || winInfo.pid == 0 {
 		return "", nil
@@ -386,7 +410,7 @@ func identifyWindowByCmdlineXWalk(m *Manager, winInfo *WindowInfo) (string, *App
 		return "", nil
 	}
 	lastArg := args[len(args)-1]
-	logger.Debugf("lastArg: %q", lastArg)
+	logger.Debugf("%s lastArg: %q", msgPrefix, lastArg)
 
 	if filepath.Base(lastArg) == "manifest.json" {
 		appId := filepath.Base(filepath.Dir(lastArg))
-- 
2.18.4

