Skip to content

Commit

Permalink
Merge pull request #28 from powellnorma/aw-instance
Browse files Browse the repository at this point in the history
x11: include wm_instance
  • Loading branch information
2e3s authored Oct 16, 2024
2 parents 16942ea + d719c54 commit 8cfc14c
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 15 deletions.
17 changes: 17 additions & 0 deletions watchers/src/report_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use anyhow::Context;
use aw_client_rust::{AwClient, Event as AwEvent};
use chrono::{DateTime, TimeDelta, Utc};
use serde_json::{Map, Value};
use std::collections::HashMap;
use std::error::Error;
use std::future::Future;

Expand Down Expand Up @@ -93,6 +94,16 @@ impl ReportClient {
}

pub async fn send_active_window(&self, app_id: &str, title: &str) -> anyhow::Result<()> {
self.send_active_window_with_extra(app_id, title, None)
.await
}

pub async fn send_active_window_with_extra(
&self,
app_id: &str,
title: &str,
extra_data: Option<HashMap<String, String>>,
) -> anyhow::Result<()> {
let mut data = Map::new();

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

data.insert("app".to_string(), Value::String(inserted_app_id));
data.insert("title".to_string(), Value::String(inserted_title));

if let Some(extra) = extra_data {
for (key, value) in extra {
data.insert(key, Value::String(value));
}
}
} else {
return Ok(());
}
Expand Down
18 changes: 13 additions & 5 deletions watchers/src/watchers/x11_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use x11rb::rust_connection::RustConnection;
pub struct WindowData {
pub title: String,
pub app_id: String,
pub wm_instance: String,
}

pub struct X11Client {
Expand Down Expand Up @@ -86,10 +87,12 @@ impl X11Client {
)?;

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

Ok(WindowData {
title: title.to_string(),
app_id: parse_wm_class(&class)?.to_string(),
app_id: class,
wm_instance: instance,
})
})
}
Expand Down Expand Up @@ -149,21 +152,26 @@ impl X11Client {
}
}

fn parse_wm_class(property: &GetPropertyReply) -> anyhow::Result<&str> {
fn parse_wm_class(property: &GetPropertyReply) -> anyhow::Result<(String, String)> {
if property.format != 8 {
bail!("Malformed property: wrong format");
}
let value = &property.value;
// The property should contain two null-terminated strings. Find them.
if let Some(middle) = value.iter().position(|&b| b == 0) {
let (_, class) = value.split_at(middle);
// Skip the null byte at the beginning
let (instance, class) = value.split_at(middle);
// Remove the null byte at the end of the instance
let instance = &instance[..instance.len()];
// Skip the null byte at the beginning of the class
let mut class = &class[1..];
// Remove the last null byte from the class, if it is there.
if class.last() == Some(&0) {
class = &class[..class.len() - 1];
}
Ok(std::str::from_utf8(class)?)
Ok((
std::str::from_utf8(instance)?.to_string(),
std::str::from_utf8(class)?.to_string(),
))
} else {
bail!("Missing null byte")
}
Expand Down
45 changes: 35 additions & 10 deletions watchers/src/watchers/x11_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,55 @@ use super::{x11_connection::X11Client, Watcher};
use crate::report_client::ReportClient;
use anyhow::Context;
use async_trait::async_trait;
use std::collections::HashMap;
use std::sync::Arc;

pub struct WindowWatcher {
client: X11Client,
last_title: String,
last_app_id: String,
last_title: String,
last_wm_instance: String,
}

impl WindowWatcher {
pub async fn send_active_window_with_instance(
&self,
client: &ReportClient,
app_id: &str,
title: &str,
wm_instance: &str,
) -> anyhow::Result<()> {
let mut extra_data = HashMap::new();
extra_data.insert("wm_instance".to_string(), wm_instance.to_string());
client
.send_active_window_with_extra(app_id, title, Some(extra_data))
.await
}

async fn send_active_window(&mut self, client: &ReportClient) -> anyhow::Result<()> {
let data = self.client.active_window_data()?;

if data.app_id != self.last_app_id || data.title != self.last_title {
if data.app_id != self.last_app_id
|| data.title != self.last_title
|| data.wm_instance != self.last_wm_instance
{
debug!(
r#"Changed window app_id="{}", title="{}""#,
data.app_id, data.title
r#"Changed window app_id="{}", title="{}", wm_instance="{}""#,
data.app_id, data.title, data.wm_instance
);
self.last_app_id = data.app_id;
self.last_title = data.title;
self.last_app_id = data.app_id.clone();
self.last_title = data.title.clone();
self.last_wm_instance = data.wm_instance.clone();
}

client
.send_active_window(&self.last_app_id, &self.last_title)
.await
.with_context(|| "Failed to send heartbeat for active window")
self.send_active_window_with_instance(
client,
&self.last_app_id,
&self.last_title,
&self.last_wm_instance,
)
.await
.with_context(|| "Failed to send heartbeat for active window")
}
}

Expand All @@ -40,6 +64,7 @@ impl Watcher for WindowWatcher {
client,
last_title: String::new(),
last_app_id: String::new(),
last_wm_instance: String::new(),
})
}

Expand Down

0 comments on commit 8cfc14c

Please sign in to comment.