From c28400434f0093552f4a51732f76a1353e26d03a Mon Sep 17 00:00:00 2001 From: Michael Jelly <53475252+michaeljelly@users.noreply.github.com> Date: Mon, 7 Feb 2022 20:36:00 +0000 Subject: [PATCH 1/6] Fixes "unknown" being returned when some apps open I've been developing an electron application, and noticed that ActivityWatch regularly logged the window as unknown. From research, it seems that some applications aren't "scriptable" according to JXA/applescript, and so you can't get their attributes or properties, which was leading the original script to fail at executing both when setting mainWindow and later when setting title. This meant that everything for that window was recorded as unknown. To fix this, I first try to get the window the old way, and if this fails then to get the name of the frontmost window as the title. This works very well, it seems to get appName and title accurately, and avoids failing to execute and getting Unknown app names. --- aw_watcher_window/printAppStatus.jxa | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/aw_watcher_window/printAppStatus.jxa b/aw_watcher_window/printAppStatus.jxa index 757d43c..2ee432e 100755 --- a/aw_watcher_window/printAppStatus.jxa +++ b/aw_watcher_window/printAppStatus.jxa @@ -24,9 +24,9 @@ switch(appName) { case "Safari": // incognito is not available via safari applescript url = Application(appName).documents[0].url(); - title = Application(appName).documents[0].name(); + title = Application(appName).documents[0].name(); break; - case "Google Chrome": + case "Google Chrome": case "Google Chrome Canary": case "Chromium": case "Brave Browser": @@ -37,23 +37,25 @@ switch(appName) { title = activeTab.name(); incognito = activeWindow.mode() === 'incognito'; break; - case "Firefox": - case "Firefox Developer Edition": - title = Application(appName).windows[0].name(); - break; default: - mainWindow = oProcess. - windows(). - find(w => w.attributes.byName("AXMain").value() === true) + try { + mainWindow = oProcess.windows().find((w, i) => w && w.attributes && w.attributes() && w.attributes.byName("AXMain") && w.attributes.byName("AXMain").value() === true) + } catch { + mainWindow = oProcess.windows()[0] + }; + // in some cases, the primary window of an application may not be found // this occurs rarely and seems to be triggered by switching to a different application - if(mainWindow) { - title = mainWindow. - attributes. + try { + title = mainWindow && mainWindow. + attributes && mainWindow.attributes. byName("AXTitle"). value() - } + } catch { + title = oProcess.windows[0].name() + }; + } // key names must match expected names in lib.py From 3d242ae1d13c70403e513729e43e632cd28ac6e9 Mon Sep 17 00:00:00 2001 From: Michael Jelly <53475252+michaeljelly@users.noreply.github.com> Date: Mon, 7 Feb 2022 20:39:18 +0000 Subject: [PATCH 2/6] re-add Firefox and remove accidental changes --- aw_watcher_window/printAppStatus.jxa | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/aw_watcher_window/printAppStatus.jxa b/aw_watcher_window/printAppStatus.jxa index 2ee432e..24d1abe 100755 --- a/aw_watcher_window/printAppStatus.jxa +++ b/aw_watcher_window/printAppStatus.jxa @@ -24,7 +24,7 @@ switch(appName) { case "Safari": // incognito is not available via safari applescript url = Application(appName).documents[0].url(); - title = Application(appName).documents[0].name(); + title = Application(appName).documents[0].name(); break; case "Google Chrome": case "Google Chrome Canary": @@ -37,6 +37,10 @@ switch(appName) { title = activeTab.name(); incognito = activeWindow.mode() === 'incognito'; break; + case "Firefox": + case "Firefox Developer Edition": + title = Application(appName).windows[0].name(); + break; default: try { mainWindow = oProcess.windows().find((w, i) => w && w.attributes && w.attributes() && w.attributes.byName("AXMain") && w.attributes.byName("AXMain").value() === true) From 2ebfbbff4fe2c0bf47c4829c7f1801f496d5380d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Bj=C3=A4reholt?= Date: Tue, 8 Feb 2022 12:54:00 +0100 Subject: [PATCH 3/6] Apply suggestions from code review --- aw_watcher_window/printAppStatus.jxa | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aw_watcher_window/printAppStatus.jxa b/aw_watcher_window/printAppStatus.jxa index 24d1abe..d617c12 100755 --- a/aw_watcher_window/printAppStatus.jxa +++ b/aw_watcher_window/printAppStatus.jxa @@ -26,7 +26,7 @@ switch(appName) { url = Application(appName).documents[0].url(); title = Application(appName).documents[0].name(); break; - case "Google Chrome": + case "Google Chrome": case "Google Chrome Canary": case "Chromium": case "Brave Browser": @@ -46,7 +46,7 @@ switch(appName) { mainWindow = oProcess.windows().find((w, i) => w && w.attributes && w.attributes() && w.attributes.byName("AXMain") && w.attributes.byName("AXMain").value() === true) } catch { mainWindow = oProcess.windows()[0] - }; + }; // in some cases, the primary window of an application may not be found @@ -58,7 +58,7 @@ switch(appName) { value() } catch { title = oProcess.windows[0].name() - }; + }; } From f4119400c7a1391a4a986e09d8dd97560ff13597 Mon Sep 17 00:00:00 2001 From: Michael Jelly <53475252+michaeljelly@users.noreply.github.com> Date: Tue, 8 Feb 2022 15:32:40 +0000 Subject: [PATCH 4/6] Commenting fixed title code for unscriptable apps. --- aw_watcher_window/printAppStatus.jxa | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aw_watcher_window/printAppStatus.jxa b/aw_watcher_window/printAppStatus.jxa index d617c12..ccf3564 100755 --- a/aw_watcher_window/printAppStatus.jxa +++ b/aw_watcher_window/printAppStatus.jxa @@ -42,6 +42,11 @@ switch(appName) { title = Application(appName).windows[0].name(); break; default: + // Some applications aren't "scriptable" according to JXA/applescript, and so you can't get their attributes or properties. + // This was leading the original script to fail at executing, both when setting mainWindow and later when setting title. + // This meant that everything for that window was recorded as unknown. + // To fix this, I first try to get the window the old way, and if this fails then to get the name of the frontmost window as the title. + // This works very well, it seems to get appName and title accurately, and avoids failing to execute and getting Unknown app names. try { mainWindow = oProcess.windows().find((w, i) => w && w.attributes && w.attributes() && w.attributes.byName("AXMain") && w.attributes.byName("AXMain").value() === true) } catch { @@ -51,6 +56,7 @@ switch(appName) { // in some cases, the primary window of an application may not be found // this occurs rarely and seems to be triggered by switching to a different application + // NEW: I believe the above issue is fixed by the new try-catch structure below which falls back to the name of the frontmost window as the title. try { title = mainWindow && mainWindow. attributes && mainWindow.attributes. From 32bfd200dd9c0a78061ccf86d909b67b27cc470a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Bj=C3=A4reholt?= Date: Tue, 8 Feb 2022 17:00:06 +0100 Subject: [PATCH 5/6] Apply suggestions from code review --- aw_watcher_window/printAppStatus.jxa | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aw_watcher_window/printAppStatus.jxa b/aw_watcher_window/printAppStatus.jxa index ccf3564..310c49c 100755 --- a/aw_watcher_window/printAppStatus.jxa +++ b/aw_watcher_window/printAppStatus.jxa @@ -50,7 +50,7 @@ switch(appName) { try { mainWindow = oProcess.windows().find((w, i) => w && w.attributes && w.attributes() && w.attributes.byName("AXMain") && w.attributes.byName("AXMain").value() === true) } catch { - mainWindow = oProcess.windows()[0] + mainWindow = oProcess.windows()[0] }; @@ -63,7 +63,7 @@ switch(appName) { byName("AXTitle"). value() } catch { - title = oProcess.windows[0].name() + title = oProcess.windows[0].name() }; } From a4b343e6f30c29b8d8212019a000e582ae973402 Mon Sep 17 00:00:00 2001 From: Michael Jelly <53475252+michaeljelly@users.noreply.github.com> Date: Wed, 9 Feb 2022 00:18:57 +0000 Subject: [PATCH 6/6] Fix errors for Application with no open windows On Mac, you can have an application open without a window. This edge-case previously caused an error meaning time wasn't tracked. I'm not 100% that a title of "No window" is the right approach, but it is the clearest description of what's happening I can see right now. --- aw_watcher_window/printAppStatus.jxa | 40 ++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/aw_watcher_window/printAppStatus.jxa b/aw_watcher_window/printAppStatus.jxa index 310c49c..9a97012 100755 --- a/aw_watcher_window/printAppStatus.jxa +++ b/aw_watcher_window/printAppStatus.jxa @@ -23,19 +23,35 @@ var url = undefined, incognito = undefined, title = undefined; switch(appName) { case "Safari": // incognito is not available via safari applescript + try { // see catch for details url = Application(appName).documents[0].url(); - title = Application(appName).documents[0].name(); + title = Application(appName).documents[0].name(); + } catch { + // On Mac, you can have an application open without a window. + // You can also have safari open with just a Devtools window, meaning no documents + // This edge-case previously caused an error meaning time wasn't tracked. + // I'm not 100% that a title of "No window" is the right approach, but it is the clearest description of what's happening I can see right now. + title = "No window" + }; break; - case "Google Chrome": + case "Google Chrome": case "Google Chrome Canary": case "Chromium": case "Brave Browser": - const activeWindow = Application(appName).windows[0]; - const activeTab = activeWindow.activeTab(); + try { // see catch for details + + const activeWindow = Application(appName).windows[0]; + const activeTab = activeWindow.activeTab(); - url = activeTab.url(); - title = activeTab.name(); - incognito = activeWindow.mode() === 'incognito'; + url = activeTab.url(); + title = activeTab.name(); + incognito = activeWindow.mode() === 'incognito'; + } catch { + // On Mac, you can have an application open without a window. + // This edge-case previously caused an error meaning time wasn't tracked. + // I'm not 100% that a title of "No window" is the right approach, but it is the clearest description of what's happening I can see right now. + title = "No window" + }; break; case "Firefox": case "Firefox Developer Edition": @@ -50,7 +66,15 @@ switch(appName) { try { mainWindow = oProcess.windows().find((w, i) => w && w.attributes && w.attributes() && w.attributes.byName("AXMain") && w.attributes.byName("AXMain").value() === true) } catch { - mainWindow = oProcess.windows()[0] + try { // see catch for details + mainWindow = oProcess.windows()[0] + } catch { + // On Mac, you can have an application open without a window. + // This edge-case previously caused an error meaning time wasn't tracked. + // I'm not 100% that a title of "No window" is the right approach, but it is the clearest description of what's happening I can see right now. + title = "No window"; + break; + } };