Skip to content

Commit 4166e9a

Browse files
committed
add icons
1 parent 304cb8f commit 4166e9a

28 files changed

Lines changed: 222 additions & 115 deletions

.github/workflows/release.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,24 @@ jobs:
114114
chmod +x "${APP}/Contents/MacOS/screenmcp-mac"
115115
echo "APPLscmc" > "${APP}/Contents/PkgInfo"
116116
117+
# Build .icns from pre-made PNGs
118+
ICON_DIR="mac/assets/icon-pngs"
119+
if [ -d "$ICON_DIR" ]; then
120+
mkdir -p /tmp/screenmcp.iconset
121+
cp "$ICON_DIR/16.png" /tmp/screenmcp.iconset/icon_16x16.png
122+
cp "$ICON_DIR/32.png" /tmp/screenmcp.iconset/icon_16x16@2x.png
123+
cp "$ICON_DIR/32.png" /tmp/screenmcp.iconset/icon_32x32.png
124+
cp "$ICON_DIR/64.png" /tmp/screenmcp.iconset/icon_32x32@2x.png
125+
cp "$ICON_DIR/128.png" /tmp/screenmcp.iconset/icon_128x128.png
126+
cp "$ICON_DIR/256.png" /tmp/screenmcp.iconset/icon_128x128@2x.png
127+
cp "$ICON_DIR/256.png" /tmp/screenmcp.iconset/icon_256x256.png
128+
cp "$ICON_DIR/512.png" /tmp/screenmcp.iconset/icon_256x256@2x.png
129+
cp "$ICON_DIR/512.png" /tmp/screenmcp.iconset/icon_512x512.png
130+
cp "$ICON_DIR/1024.png" /tmp/screenmcp.iconset/icon_512x512@2x.png
131+
iconutil -c icns /tmp/screenmcp.iconset -o "${APP}/Contents/Resources/AppIcon.icns"
132+
rm -rf /tmp/screenmcp.iconset
133+
fi
134+
117135
# Ad-hoc sign (no developer cert needed, satisfies basic integrity checks)
118136
codesign --force --deep -s - "${APP}"
119137

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,20 @@ worker_url = "ws://localhost:8080"
8080
- Enable Accessibility Service in Android Settings
8181
- In the app: enable "Open Source Server", enter your server URL and `user.id` token
8282

83-
- **Windows / Linux / macOS:** Download from [Releases](https://github.com/shimondoodkin/screenmcp/releases)
83+
- **Windows:** Download the `.exe` from [Releases](https://github.com/shimondoodkin/screenmcp/releases)
84+
- In the app settings: enable "Open Source Server", enter your server URL and token
85+
86+
- **Linux:** Download the `.deb` from [Releases](https://github.com/shimondoodkin/screenmcp/releases)
87+
```bash
88+
sudo dpkg -i screenmcp-linux_0.1.0_amd64.deb
89+
```
90+
- Launch ScreenMCP from your app launcher or run `screenmcp-linux`
91+
- In the app settings: enable "Open Source Server", enter your server URL and token
92+
93+
- **macOS:** Download the `.dmg` from [Releases](https://github.com/shimondoodkin/screenmcp/releases)
94+
- Drag ScreenMCP to `/Applications`
95+
- Remove quarantine: `xattr -cr /Applications/ScreenMCP.app`
96+
- Grant Screen Recording and Accessibility permissions in System Settings
8497
- In the app settings: enable "Open Source Server", enter your server URL and token
8598

8699
### 4. Add to your AI client

linux/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ regex = "1"
1515
screenshots = "0.8"
1616
enigo = { version = "0.2", features = ["serde"] }
1717
base64 = "0.22"
18-
image = { version = "0.25", features = ["png", "webp"] }
18+
image = { version = "0.25", features = ["png", "webp", "ico"] }
1919
arboard = "3"
2020
dirs = "5"
2121
toml = "0.8"

linux/assets/icon-app.png

12.9 KB
Loading

linux/assets/icon-connected.ico

14.7 KB
Binary file not shown.

linux/assets/icon-disconnected.ico

14.7 KB
Binary file not shown.

linux/build.sh

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5+
cd "$SCRIPT_DIR"
6+
7+
APP_NAME="ScreenMCP"
8+
BINARY_NAME="screenmcp-linux"
9+
VERSION="0.1.0"
10+
ARCH="amd64"
11+
DEB_NAME="${BINARY_NAME}_${VERSION}_${ARCH}"
12+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
13+
14+
echo "=== ScreenMCP Linux Build + Package ==="
15+
16+
# --- Step 1: Build release binary ---
17+
echo ""
18+
echo "[1/3] Building release binary..."
19+
cargo build --release
20+
BINARY="target/release/${BINARY_NAME}"
21+
if [ ! -f "$BINARY" ]; then
22+
echo "ERROR: Binary not found at $BINARY"
23+
exit 1
24+
fi
25+
echo "Binary: $(file "$BINARY") ($(du -h "$BINARY" | cut -f1))"
26+
27+
# --- Step 2: Build .deb package ---
28+
echo ""
29+
echo "[2/3] Creating .deb package..."
30+
DEB_DIR="/tmp/${DEB_NAME}"
31+
rm -rf "$DEB_DIR"
32+
33+
# Binary
34+
mkdir -p "$DEB_DIR/usr/bin"
35+
cp "$BINARY" "$DEB_DIR/usr/bin/${BINARY_NAME}"
36+
chmod 755 "$DEB_DIR/usr/bin/${BINARY_NAME}"
37+
strip "$DEB_DIR/usr/bin/${BINARY_NAME}" 2>/dev/null || true
38+
39+
# Desktop entry
40+
mkdir -p "$DEB_DIR/usr/share/applications"
41+
cp screenmcp.desktop "$DEB_DIR/usr/share/applications/"
42+
43+
# Icon
44+
mkdir -p "$DEB_DIR/usr/share/icons/hicolor/512x512/apps"
45+
cp assets/icon-app.png "$DEB_DIR/usr/share/icons/hicolor/512x512/apps/screenmcp.png"
46+
47+
# Calculate installed size in KB
48+
INSTALLED_SIZE=$(du -sk "$DEB_DIR" | cut -f1)
49+
50+
# DEBIAN control file
51+
mkdir -p "$DEB_DIR/DEBIAN"
52+
cat > "$DEB_DIR/DEBIAN/control" <<EOF
53+
Package: screenmcp
54+
Version: ${VERSION}
55+
Section: utils
56+
Priority: optional
57+
Architecture: ${ARCH}
58+
Installed-Size: ${INSTALLED_SIZE}
59+
Depends: libgtk-3-0, libssl3 | libssl1.1, libxdo3, wmctrl
60+
Maintainer: ScreenMCP <support@screenmcp.com>
61+
Homepage: https://screenmcp.com
62+
Description: AI desktop control via MCP
63+
ScreenMCP gives AI assistants real-time vision and control
64+
over desktop computers via the Model Context Protocol.
65+
System tray app that connects to a ScreenMCP worker.
66+
EOF
67+
68+
# Post-install: update icon cache
69+
cat > "$DEB_DIR/DEBIAN/postinst" <<'EOF'
70+
#!/bin/sh
71+
set -e
72+
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
73+
gtk-update-icon-cache -f -t /usr/share/icons/hicolor 2>/dev/null || true
74+
fi
75+
if command -v update-desktop-database >/dev/null 2>&1; then
76+
update-desktop-database /usr/share/applications 2>/dev/null || true
77+
fi
78+
EOF
79+
chmod 755 "$DEB_DIR/DEBIAN/postinst"
80+
81+
# Post-remove: refresh caches
82+
cat > "$DEB_DIR/DEBIAN/postrm" <<'EOF'
83+
#!/bin/sh
84+
set -e
85+
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
86+
gtk-update-icon-cache -f -t /usr/share/icons/hicolor 2>/dev/null || true
87+
fi
88+
if command -v update-desktop-database >/dev/null 2>&1; then
89+
update-desktop-database /usr/share/applications 2>/dev/null || true
90+
fi
91+
EOF
92+
chmod 755 "$DEB_DIR/DEBIAN/postrm"
93+
94+
# Build the .deb
95+
dpkg-deb --build --root-owner-group "$DEB_DIR" "${SCRIPT_DIR}/${DEB_NAME}.deb"
96+
rm -rf "$DEB_DIR"
97+
98+
# --- Step 3: Verify ---
99+
echo ""
100+
echo "[3/3] Verifying package..."
101+
dpkg-deb --info "${DEB_NAME}.deb"
102+
echo ""
103+
echo "Contents:"
104+
dpkg-deb --contents "${DEB_NAME}.deb"
105+
106+
echo ""
107+
echo "=== Build complete ==="
108+
echo "Package: ${SCRIPT_DIR}/${DEB_NAME}.deb ($(du -h "${DEB_NAME}.deb" | cut -f1))"
109+
echo "Install: sudo dpkg -i ${DEB_NAME}.deb"

linux/screenmcp.desktop

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[Desktop Entry]
2+
Name=ScreenMCP
3+
Comment=AI desktop control via MCP
4+
Exec=/usr/bin/screenmcp-linux
5+
Icon=screenmcp
6+
Type=Application
7+
Categories=Utility;RemoteAccess;
8+
Terminal=false
9+
StartupNotify=false

linux/src/tray.rs

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -31,43 +31,18 @@ struct MenuItems {
3131
quit: MenuItem,
3232
}
3333

34-
fn create_icon_rgba(connected: bool) -> Vec<u8> {
35-
let size = 32u32;
36-
let mut rgba = Vec::with_capacity((size * size * 4) as usize);
37-
38-
let (r, g, b) = if connected {
39-
(0x00u8, 0xC8u8, 0x00u8)
40-
} else {
41-
(0xC8u8, 0x00u8, 0x00u8)
42-
};
43-
44-
for y in 0..size {
45-
for x in 0..size {
46-
let dx = x as f32 - size as f32 / 2.0;
47-
let dy = y as f32 - size as f32 / 2.0;
48-
let dist = (dx * dx + dy * dy).sqrt();
49-
let radius = size as f32 / 2.0 - 1.0;
50-
51-
if dist <= radius {
52-
rgba.push(r);
53-
rgba.push(g);
54-
rgba.push(b);
55-
rgba.push(0xFF);
56-
} else {
57-
rgba.push(0);
58-
rgba.push(0);
59-
rgba.push(0);
60-
rgba.push(0);
61-
}
62-
}
63-
}
64-
65-
rgba
34+
const ICON_GREEN: &[u8] = include_bytes!("../assets/icon-connected.ico");
35+
const ICON_RED: &[u8] = include_bytes!("../assets/icon-disconnected.ico");
36+
37+
fn load_icon_from_ico(data: &[u8]) -> Icon {
38+
let img = image::load_from_memory(data).expect("failed to decode ico");
39+
let rgba = img.to_rgba8();
40+
let (w, h) = rgba.dimensions();
41+
Icon::from_rgba(rgba.into_raw(), w, h).expect("failed to create icon")
6642
}
6743

6844
fn create_icon(connected: bool) -> Icon {
69-
let rgba = create_icon_rgba(connected);
70-
Icon::from_rgba(rgba, 32, 32).expect("failed to create icon")
45+
load_icon_from_ico(if connected { ICON_GREEN } else { ICON_RED })
7146
}
7247

7348
/// Update sign-in and registration menu items based on current config and registration state.
@@ -308,9 +283,7 @@ impl TrayApp {
308283
fn update_tray_for_status(&self, status: &ConnectionStatus) {
309284
if let Some(ref tray) = self._tray {
310285
let connected = matches!(status, ConnectionStatus::Connected);
311-
if let Ok(icon) = Icon::from_rgba(create_icon_rgba(connected), 32, 32) {
312-
let _ = tray.set_icon(Some(icon));
313-
}
286+
let _ = tray.set_icon(Some(create_icon(connected)));
314287
let _ = tray.set_tooltip(Some(&format!("ScreenMCP Linux - {status}")));
315288
}
316289
if let Some(ref items) = self.menu_items {

mac/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ regex = "1"
1515
screenshots = "0.8"
1616
enigo = { version = "0.2", features = ["serde"] }
1717
base64 = "0.22"
18-
image = { version = "0.25", features = ["png", "webp"] }
18+
image = { version = "0.25", features = ["png", "webp", "ico"] }
1919
arboard = "3"
2020
dirs = "5"
2121
toml = "0.8"

0 commit comments

Comments
 (0)