mirror of
https://github.com/nickrunning/wechat-selkies.git
synced 2026-05-09 00:24:09 +00:00
feat: auto-refresh menu on app install/uninstall and add third-party app docs
- Extract menu generation logic into standalone refresh-menu.sh script - Use inotifywait to watch ~/Desktop/ for .desktop file changes and auto-refresh the openbox right-click menu on app install/uninstall - Add inotify-tools to Dockerfile dependencies - Add 'Installing Third-Party Applications' section to both READMEs documenting how to install apps like Telegram via sidebar panel
This commit is contained in:
@@ -27,7 +27,7 @@ RUN apt-get update && \
|
|||||||
libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 \
|
libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 \
|
||||||
libxcomposite1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 \
|
libxcomposite1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 \
|
||||||
libxss1 libxtst6 libatomic1 libxcomposite1 libxrender1 libxrandr2 libxkbcommon-x11-0 \
|
libxss1 libxtst6 libatomic1 libxcomposite1 libxrender1 libxrandr2 libxkbcommon-x11-0 \
|
||||||
libfontconfig1 libdbus-1-3 libnss3 libx11-xcb1 python3-tk stalonetray
|
libfontconfig1 libdbus-1-3 libnss3 libx11-xcb1 python3-tk stalonetray inotify-tools
|
||||||
|
|
||||||
RUN pip install --no-cache-dir python-xlib
|
RUN pip install --no-cache-dir python-xlib
|
||||||
|
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -160,6 +160,19 @@ docker run -it -p 3001:3001 -v ./config:/config --device /dev/dri:/dev/dri nickr
|
|||||||
|
|
||||||
> **注意:** 如果升级后右键菜单缺少 `WeChat` 相关选项,请先清空本地挂载目录下的openbox目录(如`./config/.config/openbox`)。
|
> **注意:** 如果升级后右键菜单缺少 `WeChat` 相关选项,请先清空本地挂载目录下的openbox目录(如`./config/.config/openbox`)。
|
||||||
|
|
||||||
|
## 安装第三方应用(如 Telegram)
|
||||||
|
|
||||||
|
本项目支持通过 [proot-apps](https://github.com/linuxserver/proot-apps) 安装第三方 Linux 应用。以 Telegram 为例:
|
||||||
|
|
||||||
|
1. 在浏览器中打开容器桌面
|
||||||
|
2. 点击左侧 **侧边栏** → **应用程序**(Applications)
|
||||||
|
3. 在应用列表中找到 **Telegram**
|
||||||
|
4. 点击 **安装**(Install)按钮,等待安装完成
|
||||||
|
|
||||||
|
安装完成后,应用快捷方式会自动出现在 `~/Desktop/` 目录下,**右键菜单会自动刷新**,无需重启容器即可从菜单中启动该应用。
|
||||||
|
|
||||||
|
> **提示:** 如需卸载应用,同样通过侧边栏 → 应用程序,选中对应应用后点击 **卸载**(Uninstall)即可,右键菜单会自动更新。
|
||||||
|
|
||||||
## 高级配置
|
## 高级配置
|
||||||
|
|
||||||
### 硬件加速
|
### 硬件加速
|
||||||
|
|||||||
13
README_en.md
13
README_en.md
@@ -158,6 +158,19 @@ Configure the following environment variables in `docker-compose.yml`:
|
|||||||
|
|
||||||
> **Note:** If the right-click menu lacks `WeChat` related options after an upgrade, please clear the `openbox` directory in the local mounted directory (e.g., `./config/.config/openbox`).
|
> **Note:** If the right-click menu lacks `WeChat` related options after an upgrade, please clear the `openbox` directory in the local mounted directory (e.g., `./config/.config/openbox`).
|
||||||
|
|
||||||
|
## Installing Third-Party Applications (e.g., Telegram)
|
||||||
|
|
||||||
|
This project supports installing third-party Linux applications via [proot-apps](https://github.com/linuxserver/proot-apps). Here's how to install Telegram as an example:
|
||||||
|
|
||||||
|
1. Open the container desktop in your browser
|
||||||
|
2. Click the **Sidebar** on the left → **Applications**
|
||||||
|
3. Find **Telegram** in the application list
|
||||||
|
4. Click the **Install** button and wait for the installation to complete
|
||||||
|
|
||||||
|
Once installed, the application shortcut will automatically appear in the `~/Desktop/` directory, and the **right-click menu will auto-refresh** — no container restart needed to launch the app from the menu.
|
||||||
|
|
||||||
|
> **Tip:** To uninstall an application, go to Sidebar → Applications, select the app, and click **Uninstall**. The right-click menu will update automatically.
|
||||||
|
|
||||||
## Advanced Configuration
|
## Advanced Configuration
|
||||||
|
|
||||||
### Hardware Acceleration
|
### Hardware Acceleration
|
||||||
|
|||||||
57
root/scripts/refresh-menu.sh
Executable file
57
root/scripts/refresh-menu.sh
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Regenerate openbox right-click menu from defaults + ~/Desktop/*.desktop files
|
||||||
|
|
||||||
|
MENU_DEFAULT="/defaults/menu.xml"
|
||||||
|
MENU_TARGET="/config/.config/openbox/menu.xml"
|
||||||
|
MENU_TMP="/tmp/menu.xml"
|
||||||
|
|
||||||
|
mkdir -p /config/.config/openbox
|
||||||
|
cp "$MENU_DEFAULT" "$MENU_TMP"
|
||||||
|
|
||||||
|
if ls "$HOME/Desktop/"*.desktop >/dev/null 2>&1; then
|
||||||
|
for desktop_file in "$HOME/Desktop/"*.desktop; do
|
||||||
|
name=$(grep -E "^Name=" "$desktop_file" | head -n 1 | cut -d "=" -f 2-)
|
||||||
|
exec_cmd=$(grep -E "^Exec=" "$desktop_file" | head -n 1 | cut -d "=" -f 2-)
|
||||||
|
icon=$(grep -E "^Icon=" "$desktop_file" | head -n 1 | cut -d "=" -f 2-)
|
||||||
|
|
||||||
|
# skip entries without a name or exec command
|
||||||
|
[ -z "$name" ] || [ -z "$exec_cmd" ] && continue
|
||||||
|
|
||||||
|
# strip %U, %u, %F, %f field codes
|
||||||
|
exec_cmd=$(echo "$exec_cmd" | sed 's/ %[fFuU]//g')
|
||||||
|
|
||||||
|
# resolve icon path if it's just a name (not an absolute path)
|
||||||
|
if [ -n "$icon" ] && [ "${icon#/}" = "$icon" ]; then
|
||||||
|
icon_resolved=""
|
||||||
|
# search in proot-apps icons (prefer 256x256)
|
||||||
|
for size in 256x256 512x512 128x128 64x64 48x48 scalable; do
|
||||||
|
found=$(find /config/proot-apps/*/usr/share/icons/hicolor/"$size"/apps/"$icon".* 2>/dev/null | head -n 1)
|
||||||
|
if [ -n "$found" ]; then
|
||||||
|
icon_resolved="$found"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# fallback: search system icons
|
||||||
|
if [ -z "$icon_resolved" ]; then
|
||||||
|
found=$(find /usr/share/icons/hicolor/*/apps/"$icon".* 2>/dev/null | head -n 1)
|
||||||
|
[ -n "$found" ] && icon_resolved="$found"
|
||||||
|
fi
|
||||||
|
[ -n "$icon_resolved" ] && icon="$icon_resolved"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# handle missing icon
|
||||||
|
[ -z "$icon" ] && icon="/usr/share/pixmaps/xterm-color_48x48.xpm"
|
||||||
|
|
||||||
|
# escape XML entities
|
||||||
|
exec_cmd=$(echo "$exec_cmd" | sed 's/&/\&/g; s/</\</g; s/>/\>/g')
|
||||||
|
name=$(echo "$name" | sed 's/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g')
|
||||||
|
icon=$(echo "$icon" | sed 's/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g')
|
||||||
|
|
||||||
|
sed -i "/<menu id=\"root-menu\" label=\"MENU\">/a \\<item label=\"${name}\" icon=\"${icon}\"><action name=\"Execute\"><command>${exec_cmd}</command></action></item>" "$MENU_TMP"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$MENU_TARGET" ] || ! cmp -s "$MENU_TMP" "$MENU_TARGET"; then
|
||||||
|
cp "$MENU_TMP" "$MENU_TARGET"
|
||||||
|
openbox --reconfigure 2>/dev/null || true
|
||||||
|
fi
|
||||||
@@ -8,53 +8,16 @@ if [ ! -f /config/.config/openbox/rc.xml ] || grep -A20 "<dock>" /config/.config
|
|||||||
openbox --reconfigure
|
openbox --reconfigure
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# generate openbox menu
|
# generate openbox menu from defaults + ~/Desktop/*.desktop files
|
||||||
mkdir -p /config/.config/openbox
|
/scripts/refresh-menu.sh
|
||||||
cp /defaults/menu.xml /tmp/menu.xml
|
|
||||||
|
|
||||||
if ls "$HOME/Desktop/"*.desktop >/dev/null 2>&1; then
|
# watch ~/Desktop/ for .desktop file changes and auto-refresh menu
|
||||||
for desktop_file in "$HOME/Desktop/"*.desktop; do
|
mkdir -p "$HOME/Desktop"
|
||||||
name=$(grep -E "^Name=" "$desktop_file" | head -n 1 | cut -d "=" -f 2-)
|
if command -v inotifywait >/dev/null 2>&1; then
|
||||||
exec_cmd=$(grep -E "^Exec=" "$desktop_file" | head -n 1 | cut -d "=" -f 2-)
|
(while inotifywait -q -e create -e delete -e modify "$HOME/Desktop/" --include '\.desktop$'; do
|
||||||
icon=$(grep -E "^Icon=" "$desktop_file" | head -n 1 | cut -d "=" -f 2-)
|
sleep 1
|
||||||
|
/scripts/refresh-menu.sh
|
||||||
# strip %U, %u, %F, %f
|
done) >/dev/null 2>&1 &
|
||||||
exec_cmd=$(echo "$exec_cmd" | sed 's/ %[fFuU]//g')
|
|
||||||
|
|
||||||
# resolve icon path if it's just a name (not an absolute path)
|
|
||||||
if [ -n "$icon" ] && [ "${icon#/}" = "$icon" ]; then
|
|
||||||
icon_resolved=""
|
|
||||||
# search in proot-apps icons (prefer 256x256)
|
|
||||||
for size in 256x256 512x512 128x128 64x64 48x48 scalable; do
|
|
||||||
found=$(find /config/proot-apps/*/usr/share/icons/hicolor/"$size"/apps/"$icon".* 2>/dev/null | head -n 1)
|
|
||||||
if [ -n "$found" ]; then
|
|
||||||
icon_resolved="$found"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
# fallback: search system icons
|
|
||||||
if [ -z "$icon_resolved" ]; then
|
|
||||||
found=$(find /usr/share/icons/hicolor/*/apps/"$icon".* 2>/dev/null | head -n 1)
|
|
||||||
[ -n "$found" ] && icon_resolved="$found"
|
|
||||||
fi
|
|
||||||
[ -n "$icon_resolved" ] && icon="$icon_resolved"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# handle missing icon
|
|
||||||
[ -z "$icon" ] && icon="/usr/share/pixmaps/xterm-color_48x48.xpm"
|
|
||||||
|
|
||||||
# escape XML entities
|
|
||||||
exec_cmd=$(echo "$exec_cmd" | sed 's/&/\&/g; s/</\</g; s/>/\>/g')
|
|
||||||
name=$(echo "$name" | sed 's/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g')
|
|
||||||
icon=$(echo "$icon" | sed 's/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g')
|
|
||||||
|
|
||||||
sed -i "/<menu id=\"root-menu\" label=\"MENU\">/a \\<item label=\"${name}\" icon=\"${icon}\"><action name=\"Execute\"><command>${exec_cmd}</command></action></item>" /tmp/menu.xml
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f /config/.config/openbox/menu.xml ] || ! cmp /tmp/menu.xml /config/.config/openbox/menu.xml; then
|
|
||||||
cp /tmp/menu.xml /config/.config/openbox/menu.xml
|
|
||||||
openbox --reconfigure
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
nohup stalonetray --dockapp-mode simple > /dev/null 2>&1 &
|
nohup stalonetray --dockapp-mode simple > /dev/null 2>&1 &
|
||||||
|
|||||||
Reference in New Issue
Block a user