Skip to content

Commit 8cfc14c

Browse files
authored
Merge pull request #28 from powellnorma/aw-instance
x11: include wm_instance
2 parents 16942ea + d719c54 commit 8cfc14c

File tree

3 files changed

+65
-15
lines changed

3 files changed

+65
-15
lines changed

watchers/src/report_client.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use anyhow::Context;
44
use aw_client_rust::{AwClient, Event as AwEvent};
55
use chrono::{DateTime, TimeDelta, Utc};
66
use serde_json::{Map, Value};
7+
use std::collections::HashMap;
78
use std::error::Error;
89
use std::future::Future;
910

@@ -93,6 +94,16 @@ impl ReportClient {
9394
}
9495

9596
pub async fn send_active_window(&self, app_id: &str, title: &str) -> anyhow::Result<()> {
97+
self.send_active_window_with_extra(app_id, title, None)
98+
.await
99+
}
100+
101+
pub async fn send_active_window_with_extra(
102+
&self,
103+
app_id: &str,
104+
title: &str,
105+
extra_data: Option<HashMap<String, String>>,
106+
) -> anyhow::Result<()> {
96107
let mut data = Map::new();
97108

98109
if let Some((inserted_app_id, inserted_title)) = self.get_filtered_data(app_id, title) {
@@ -104,6 +115,12 @@ impl ReportClient {
104115

105116
data.insert("app".to_string(), Value::String(inserted_app_id));
106117
data.insert("title".to_string(), Value::String(inserted_title));
118+
119+
if let Some(extra) = extra_data {
120+
for (key, value) in extra {
121+
data.insert(key, Value::String(value));
122+
}
123+
}
107124
} else {
108125
return Ok(());
109126
}

watchers/src/watchers/x11_connection.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use x11rb::rust_connection::RustConnection;
99
pub struct WindowData {
1010
pub title: String,
1111
pub app_id: String,
12+
pub wm_instance: String,
1213
}
1314

1415
pub struct X11Client {
@@ -86,10 +87,12 @@ impl X11Client {
8687
)?;
8788

8889
let title = str::from_utf8(&name.value).with_context(|| "Invalid title UTF")?;
90+
let (instance, class) = parse_wm_class(&class)?;
8991

9092
Ok(WindowData {
9193
title: title.to_string(),
92-
app_id: parse_wm_class(&class)?.to_string(),
94+
app_id: class,
95+
wm_instance: instance,
9396
})
9497
})
9598
}
@@ -149,21 +152,26 @@ impl X11Client {
149152
}
150153
}
151154

152-
fn parse_wm_class(property: &GetPropertyReply) -> anyhow::Result<&str> {
155+
fn parse_wm_class(property: &GetPropertyReply) -> anyhow::Result<(String, String)> {
153156
if property.format != 8 {
154157
bail!("Malformed property: wrong format");
155158
}
156159
let value = &property.value;
157160
// The property should contain two null-terminated strings. Find them.
158161
if let Some(middle) = value.iter().position(|&b| b == 0) {
159-
let (_, class) = value.split_at(middle);
160-
// Skip the null byte at the beginning
162+
let (instance, class) = value.split_at(middle);
163+
// Remove the null byte at the end of the instance
164+
let instance = &instance[..instance.len()];
165+
// Skip the null byte at the beginning of the class
161166
let mut class = &class[1..];
162167
// Remove the last null byte from the class, if it is there.
163168
if class.last() == Some(&0) {
164169
class = &class[..class.len() - 1];
165170
}
166-
Ok(std::str::from_utf8(class)?)
171+
Ok((
172+
std::str::from_utf8(instance)?.to_string(),
173+
std::str::from_utf8(class)?.to_string(),
174+
))
167175
} else {
168176
bail!("Missing null byte")
169177
}

watchers/src/watchers/x11_window.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,55 @@ use super::{x11_connection::X11Client, Watcher};
22
use crate::report_client::ReportClient;
33
use anyhow::Context;
44
use async_trait::async_trait;
5+
use std::collections::HashMap;
56
use std::sync::Arc;
67

78
pub struct WindowWatcher {
89
client: X11Client,
9-
last_title: String,
1010
last_app_id: String,
11+
last_title: String,
12+
last_wm_instance: String,
1113
}
1214

1315
impl WindowWatcher {
16+
pub async fn send_active_window_with_instance(
17+
&self,
18+
client: &ReportClient,
19+
app_id: &str,
20+
title: &str,
21+
wm_instance: &str,
22+
) -> anyhow::Result<()> {
23+
let mut extra_data = HashMap::new();
24+
extra_data.insert("wm_instance".to_string(), wm_instance.to_string());
25+
client
26+
.send_active_window_with_extra(app_id, title, Some(extra_data))
27+
.await
28+
}
29+
1430
async fn send_active_window(&mut self, client: &ReportClient) -> anyhow::Result<()> {
1531
let data = self.client.active_window_data()?;
1632

17-
if data.app_id != self.last_app_id || data.title != self.last_title {
33+
if data.app_id != self.last_app_id
34+
|| data.title != self.last_title
35+
|| data.wm_instance != self.last_wm_instance
36+
{
1837
debug!(
19-
r#"Changed window app_id="{}", title="{}""#,
20-
data.app_id, data.title
38+
r#"Changed window app_id="{}", title="{}", wm_instance="{}""#,
39+
data.app_id, data.title, data.wm_instance
2140
);
22-
self.last_app_id = data.app_id;
23-
self.last_title = data.title;
41+
self.last_app_id = data.app_id.clone();
42+
self.last_title = data.title.clone();
43+
self.last_wm_instance = data.wm_instance.clone();
2444
}
2545

26-
client
27-
.send_active_window(&self.last_app_id, &self.last_title)
28-
.await
29-
.with_context(|| "Failed to send heartbeat for active window")
46+
self.send_active_window_with_instance(
47+
client,
48+
&self.last_app_id,
49+
&self.last_title,
50+
&self.last_wm_instance,
51+
)
52+
.await
53+
.with_context(|| "Failed to send heartbeat for active window")
3054
}
3155
}
3256

@@ -40,6 +64,7 @@ impl Watcher for WindowWatcher {
4064
client,
4165
last_title: String::new(),
4266
last_app_id: String::new(),
67+
last_wm_instance: String::new(),
4368
})
4469
}
4570

0 commit comments

Comments
 (0)