Raspberry Pi Application Menuとdevilspie

アプリケーションを起動する方法はメインメニューやファイルマネージャーの関連付けなどいろいろありますが自作のスクリプトや自前でコンパイルしたアプリケーションを含めて使いやすいと思うものはあまり見当たりません。

以前ZEROで作成したpythonクリプトのアプリケーションランチャを利用します。

devilspieはX Window Systemのウインドウを検出してマッチしたときウインドウサイスや位置など一連のアクションを実行することができます。

Application Menu

アプリケーションランチャ(ZERO)

これまでデイスクトップやLXPanelに置いていたものなどを適当に登録してみました。
アイコンファイルは32×32サイズを使っています。

サンプル ~/bin/app_menu.py

#!/usr/bin/python3

from tkinter import *
from tkinter import ttk 
import subprocess
import time

root = Tk()
root.title('Application Menu')
style = ttk.Style()
style.theme_use('default') #('clam', 'alt', 'default', 'classic')

# Frame as Widget Container
frame1 = ttk.Frame(
    root,
    padding=5)
frame1.grid()

# Button arduino
def app06():
    subprocess.run("~/Applications/arduino/arduino &", shell=True)
    time.sleep(5)
    subprocess.run("killall devilspie && devilspie -a &", shell=True)
icon6 = PhotoImage(file='~/.icons/32x32/arduino.png')
button6 = ttk.Button(
    frame1,
    image=icon6,
    command=app06)
button6.grid(row=2,column=1)

# Button loop_remove
def app15():
    subprocess.run("~/bin/loop_remove.py &", shell=True)
    time.sleep(1)
    subprocess.run("killall devilspie && devilspie -a &", shell=True)
icon15 = PhotoImage(file='~/.icons/32x32/folder_loop.png')
button15 = ttk.Button(
    frame1,
    image=icon15,
    command=app15)
button15.grid(row=3,column=5)

root.mainloop()

~/.iconsはサイズ別に整理しています。
subprocess.runでdevilspieを再起動しています。(後述)
ボタンの並びはrowとcolumnを入れ替えることで変更できます。

devilspie

アプリケーションを起動するとopenboxは空いているスペースから配置します。devilspieから特定のアプリケーションを使いやすい場所に配置するようにします。

# apt install gdevilspie

gDevilspieはdevilspieのGUIフロントエンドです。devilspieは依存関係でインストールされます。
Xのパラメータは少々わかりにくい項目もありますが今回の用途ではgDevilspieから比較的簡単に設定することができます。

メニュー アクセサリ gDevilspie 起動
追加をクリック


Matchingタブ
一番上の枠にルールネームを記入(適当に)
window_nameまたはapplication_nameにチェック


Actionsタブ
とりあえずgeometryにチェック
ほか
pin 全ワークスペースに配置
shade タイトルバー巻き上げ
set_workspace ワークスペースナンバー指定
maximize 最大化
minimize 最小化
などなど


Application Menuを配置したい場所に移動
Getボタンクリック
Window SelectorでApplication Menu選択 適用をクリック


ウインドウサイズ、位置取得


Rawタブで確認(このタブからは直接編集不可)
保存をクリック
( window_name ) “Application Menu” はapp_menu.pyのroot.title(‘Application Menu’)で設定した値です。タイトルを変更するとdevilspieからはmatchしなくなります。


app_menuが登録された
ここでApplication Menuのウインドウ位置をずらしてStartボタンをクリックすると設定が正しければ(matchしたら)ヒョイと移動します。


MatchやActionの追加、変更は編集ボタンから実行します。
設定したファイルは~/.devilspie以下に保存されます。
ウインドウサイズは必ずしも期待通りの値を取得しません。
細かい調整は直接~/.devilspie/app_menu.dsを編集したほうが早い。

正しい値はターミナルから

$ xwininfo

を実行してApplication Menuウインドウをクリックすると取得できます。編集しながらStop,Startで確認できます。

*pcmanfmは登録してはいけません。画面全体がずれる。(再起動で直る)
*アプリケーションによってはgeometryが指定できます。(早い確実)
*常用するターミナルなどはopenboxに任せたほうがいい(と思う)
*期待通りの位置にいかないものはxdotoolを使っています。

*devilspieは起動時に自動実行します。
当サイトのApplication Menuはpin,shadeをActionに加えて右上隅に配置しています(ウインドウを巻き上げて全ワークスペースに配置)
OS起動時にApplication Menuを起動しています。
Application Menu内のアプリケーション実行後は
subprocess.run(“killall devilspie && devilspie -a &”, shell=True)
でまたウインドウを巻き上げています。
(起動済みアプリケーションでサイズ、位置変更している場合は設定値に戻る)

app_menu.pyを自動実行する(autostart)
~/.config/autostart/app_menu.desktop

[Desktop Entry]
Type=Application
Name=app_menu
Exec=~/bin/app_menu.py

当サイトのスタートアップはxdotoolと併用しながらスクリプトから起動しています。
ターミナルやpcmanfmはxdotoolでワークスペースを切り替えながら配置。(xdotoolは適切にスリープを入れること)

前回のshutdown.py,changesd.pyも登録、実行時は中央に配置しています。

Raspberry Pi 3 SD起動 + SSD起動

以前よりSDカード(内蔵スロット)とSSDを切り替えて起動する方法は実行していたのですがこのあたりからブートオンリーに変更していました。

以前はSSDへの移行、バックアップ目的で運用していたのですが前回の作業工程をみるとやはり内蔵スロットのSDカードから起動、各種ツールが使えるとなにかと便利と思います。

SDカードに軽量級のraspbianをインストール、最近流行り(?)のpythonランチャから切り替えてみたいと思います。

raspbianのインストール

ベースOSにはraspbian-stretch-liteをインストール、必要な環境を構築します。

$ sudo apt install -y --no-install-recommends xserver-xorg xinit
$ sudo apt install -y raspberrypi-ui-mods lxde-core lightdm
$ sudo apt install -y lxappearance gnome-terminal
$ sudo apt install -y fonts-ipafont fonts-ricty-diminished fcitx-mozc


アプリケーションはほとんど入ってないので必要なツール等をインストールします。
SSDもマウントされています。
SSDのファイルの扱いには注意

shutdown.pyの作成

shutdownメニューを作成します。 shutdown.py

当サイトのPi3はAVRを利用して電源オフしているので独自のメニューを採用しています。
このプログラムにGPIO制御のコマンドなどを追加しています。
オプションボタンをクリックするとSDカード、SSD選択のメニューが起動します。(Shutdown Menuは終了)
下記のchangesd.pyとはそれぞれ単独に起動可能です。

changesd.pyの作成

changesd.py

内蔵スロットにSDカードがある場合SDカードが優先します。
SDカードのcmdline.txtを書き換えることで起動タイプを選択することができます。
デフォルトのLXDE(pcmanfm)は読み込み可能なデバイスをオートマウントします。
SDカードのbootはユーザー所有になるのでpythonから書き換えてみました。

PARTUUIDは自環境に合わせます。

# Button 1(Micro SD)
def sdc():
    with open('/media/boot/cmdline.txt', 'r') as f:
        s = f.read()
        s = s.replace("9950f4f8","b35a28ce")
    with open('/media/boot/cmdline.txt', 'w') as f:
        f.write(s)
    subprocess.run("sudo reboot", shell=True)

*オプションボタンはconfig.txtのオプションを変更する予定ですが現時点ではshutdown menuを呼んでいます。

SDカードで起動

SDカードに切り替えた直後は起動時fsckがかかりますが特に問題なく起動するようです。

SDカードで起動したbootはroot所有になるためpythonからは簡単に書き換えることができません。
こちらはコピーすることで起動デバイスを変更することにしました。
それぞれのPARTUUIDを記載したcmdline.txtをcmdline-SDC.txt,cmdline-SSD.txtとして/bootに保存します。

changesd.py.sd (ファイル名は変更)

# Button 2 (SSD)
def ssd():
    subprocess.run("sudo cp /boot/cmdline-SSD.txt /boot/cmdline.txt", shell=True)
    time.sleep(1)
    subprocess.run("sudo reboot", shell=True)

アイコンはサイズ別に~/.icons以下に置いています。

*SSDが起動する条件はSDカードとカーネルバージョンが同じである必要があります。カーネルに更新があった場合はそれぞれ単独にupdate && upgradeします。
*インタプリタのpythonはZEROでは少々もたつきますがPi3ではほぼ軽快に動きますね。

Raspberry Pi 3 2019-04-08-raspbian-stretch インストール(SSD)

前回はマイクロSDカードへ2019-04-08-raspbian-stretchを編集したものをインストールしました。今回は同様にSSDにインストールしてみたいと思います。

SSDは敢えてクリーンインストールする必要は無いのですが今後の展開を踏まえて実験してしてみることにします。

基本のイメージ

基本のイメージは前回作成したものを用いますがSSDのパーティション構成は変更しないこととして/boot/cmdline.txtと/etc/fstabのPARTUUIDを現状に合わせます。

$ sudo blkid /dev/sdb
/dev/sdb: PTUUID="9950f4f8" PTTYPE="dos"


/dev/sdbで認識しています。

/boot/cmdline.txt

dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=9950f4f8-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles

/etc/fstab

proc                  /proc           proc    defaults          0       0
PARTUUID=9950f4f8-01  /boot           vfat    defaults          0       2
PARTUUID=9950f4f8-02  /               ext4    defaults,noatime  0       1

config.txtではOpenGLを有効にしています。(追記)
/boot/config.txt

# OpenGL enable
dtoverlay=vc4-kms-v3d
gpu_mem=128

SSDのbootとrootfsを消去

Pi3はSDカードから起動して最低限の環境を構築しています。

現在のbootとrootfsをフォーマットしたのですがラベル情報も消去されてしまいます。
これが原因かどうか不明ですがSSDから起動できませんでした。
デフォルトのgpartedはfatのラベル編集は不可ですがmtoolsをインストールすることで編集可能になります。

# apt install mtools


再読込、アンマウントでLabel File Systemを選択
bootはfat32フラグlbaを確認
bootは単純にファイル削除したほうが簡単ですね。
rootfsも同様にファイル削除してもいい。

SSDに書き込み

ddからの実行ではすべて真っさらになってしまうためloopデバイスからコピーをします。
SSDは/media/pi/boot,/media/pi/rootfsにマウント
loopデバイスをマウントしたイメージは/home/data/stretch/loop0p1,/home/data/stretch/loop0p2にあるものとします。

# cp -r /home/data/stretch/loop0p1/* /media/pi/boot
# cp -Rp /home/data/stretch/loop0p2/* /media/pi/rootfs

SSDから起動

SDカードはひっこ抜いてSSD単体で起動します。
約10秒ほどで起動開始、PiWizardが走ります。
インストール自体の作業は前回のSDカードの時と全く同じになります。
そうそう忘れていました。現在のデスクトップ環境ではswap fileの拡張は必須ですね。
chromium browserなど起動するとハングアップしてしまいます。
/etc/dphys-swapfile 1Gに拡張します

CONF_SWAPSIZE=1024
# systemctl restart dphys-swapfile

ユーザーpiのデフォルト環境で一通り確認、問題が無ければ最低限のtool(vimなど)や当サイト固有の日本語環境をインストール、設定をします。
初期インストールするアプリケーションはほぼ決まっているのでリストを作成して一気にインストールしてしまいます。

# sh applications
# applications
# terminal
apt -y install gnome-terminal xterm guake
# mail
apt -y install sylpheed
# ranger dmenu
apt -y install ranger highlight poppler-utils atool mediainfo
apt -y install suckless-tools
# X-tool
apt -y install xbindkeys xdotool devilspie gdevilspie
# system tool
apt -y install cpufrequtils kpartx numlockx eject
apt -y install gparted libparted-i18n mtools tmux dconf-editor
# tool
apt -y install nemo gnome-calculator xpad
apt -y install manpages-ja
# net
apt -y install samba
apt -y install tigervnc-viewer rdesktop
apt -y install nmap dnsutils whois telnet
# multmedia
apt -y install pavucontrol ffmpeg mplayer mpv flac
apt -y remove youtube-dl
apt -y install audacious smplayer easytag kid3
apt -y install libqt5webkit5 libqt5script5
# graphic
apt -y install gimp imagemagick mupdf xsane
apt -y install gnome-screenshot gcolor2
# print
apt -y install cups system-config-printer
# www
apt -y install firefox-esr-l10n-ja
# japanese
apt -y install convmv
# cad
apt -y install kicad

メインのユーザーディレクトリはSSDの/dev/sdb3にあります。
これを/home/dataにマウント、/homeからリンクを張ります。
ユーザーディレクトリからは更にnfsマウントしてあるディレクトリにリンクを張ってarduino IDEなど大きなアプリケーションを起動しています。(少々起動は遅くなる)

# ln -s /home/data/USER

122行目 piから変更(raspi-configからも可)
/etc/lightdm/lightdm.conf

autologin-user=USER

リブート
passwdはイメージの段階でコピーしているので面倒な作業なしに復元することができます。
LXDE関連(libfm,pcmanfmなど)に更新があると一部再設定する必要があるかもしれません。
アプリケーションのユーザー固有の設定はすべてユーザーディレクトリにあります。
ここまで下準備ができていれば実質1時間くらいで作業が完了します。(なかなかそううまくいかないこともある)
今回はSSDブートで躓きましたがそれ以外は順調にいっています。
*usb2.0経由のSSDですがやはりマイクロSDと比べるとファイルの読み書きは明らかに早い。
*usb3.0仕様のPiを期待しているのですがなかなか登場しないですね。
Orange Pi 3という製品も出てるのでRaspberry Pi期待しています。

Raspberry Pi 3 2019-04-08-raspbian-stretch インストール(SDカード)

2019-04-08-raspbian-stretchがリリースされています。
Raspbian Stretch with desktop and recommended software
Raspbian Stretch with desktop
Raspbian Stretch Lite

recommended software版がfullイメージになります。raspbian独自に含まれるアプリケーション(Scratchなど)は設定から簡単に導入できるのでRaspbian Stretch with desktop版が使いやすいと思います。

今回は2019-04-08 Raspbian Stretch with desktop版のイメージを少々編集してPi3のSDカードを作成、インストールしてみたいと思います。

作業環境

作業はraspberry pi3で実行します。
作業ディレクトリは/home/data/stretch/desktop
Raspbian Stretch with desktopをダウンロード、展開します。

$ unzip 2019-04-08-raspbian-stretch.zip
$ mv 2019-04-08-raspbian-stretch.img 2019-04-08-raspbian-stretch-pi3.img

展開したイメージはkpartxを使ってマウントしておきます。
コマンドラインやpcmanfmからも可。
作業に当たってバックアップは必須(基本)ですね。
以降はあくまで参考程度に願います。(自己責任でね)

イメージの編集

下記は当サイトの例です。適当なファイル名でテキストファイルを作成してマウントしたloopデバイス(rootfs)の”/”にコピーします。(2019-04-08-raspbian-stretch-pi3)

pcmanfmから2019-04-08-raspbian-stretch-pi3.imgをマウント

2019-04-08-raspbian-stretch-pi3
記述は相対パスで指定しています。(実行はこのディレクトリから)

# rootfs
# root shellを変更していたらbashに戻す
chsh -s /bin/bash
# 基本設定
cp /etc/hostname ./etc
cp /etc/hosts ./etc
cp /etc/dhcpcd.conf ./etc
cp /etc/wpa_supplicant/wpa_supplicant.conf ./etc/wpa_supplicant
# ユーザー情報
cp /etc/passwd ./etc
cp /etc/shadow ./etc
cp /etc/group ./etc
cp /etc/gshadow ./etc
cp /etc/sudoers ./etc
rm -r ./etc/ssh
cp -r /etc/ssh ./etc
# その他
cp -r /var/lib/bluetooth ./var/lib
cp /usr/local/bin/* ./usr/local/bin
cp /etc/rc.local ./etc

基本設定
固定IP wifi接続情報 ホストネームなど
ユーザー情報
root shellを変更している場合はbashに戻してからコピーするようにします。
piユーザー以外に通常は別IDで運用しています。
sshも今までの情報をそのまま利用します。imgにある/etc/sshを削除またはリネームして同様にコピー
その他
/var/lib/bluetooth ペアリング情報(bluetoothマウスなど起動時に有効になります)
/usr/local/bin コンパイルしたsurfなど
/etc/rc.local GPIO制御(当サイトのPiはshutdownにGPIOを利用)
ユーザーディレクトリ
ユーザーディレクトリは容量の関係から起動後パーティションを拡張してからコピーします。

編集したファイルを実行
マウントしたディレクトリから実行します。

# sudo su
# cd /media/rootfs
# sh 2019-04-08-raspbian-stretch-pi3


実行はほぼ瞬時に完了、エラーも特にないようです。
内容を確認してアンマウント

カードへ書き込み

編集した内容は2019-04-08-raspbian-stretch-pi3.imgに反映されています。
ddで書き込みます。(デバイス名は適宜)

# cd /home/data/stretch/desktop
# dd if=2019-04-08-raspbian-stretch-pi3.img of=/dev/sda bs=1M

カードを差し替えて起動


起動するとPiWizardが走ります。(/usr/bin/piwiz)
WiFI,BluetoothもOK

*スクショはPiWizard終了後に撮ったものです


設定はこの画面からJapanを選択するだけ
パスワードも変更済みなので空のままNext


多分このダイアログは今回のバージョンからと思いますが直訳すると

”デスクトップは画面全体に表示されます
画面の端に黒い枠がある場合は、下のボックスをクリックしてください。”

ということなのでディスプレーによってはオプションを指定するようです。

あとは日本語入力環境やupdateはPiWizardが良きに計らってくれます。
ユーザーディレクトリをバックアップからコピーして問題が無ければ必要なアプリケーションをインストールする手順になります。

Raspberry Pi ZERO Ranger + kpartx

Raspbian imgをマウントするためZEROにkpartxを導入しました。今回はRangerから利用してみたいと思います。
新規にインストールするカードは基本ZEROから作成する予定ですがRaspbian imgを直接編集することでいろいろ応用することができます。
以前pcmanfmに設定した記事と基本同じです。

kpartx

# apt install kpartx

kpartxの基本操作は以下のとおり

# kpartx -va 2018-11-13-raspbian-stretch-lite.img
add map loop0p1 (254:0): 0 89854 linear 7:0 8192
add map loop0p2 (254:1): 0 3547136 linear 7:0 98304
# ls /dev/mapper
control  loop0p1  loop0p2
# mount /dev/mapper/loop0p2 /mnt
---
# umount /mnt
# kpartx -d 2018-11-13-raspbian-stretch-lite.img
loop deleted : /dev/loop0
# ls /dev/mapper
control

loop deviceの取り外しはこんな方法もあります。
参考 https://seesaawiki.jp/w/kou1okada/d/Linux%20-%20loop%20device

# dmsetup remove loop0p2
# losetup -d /dev/loop0

マウント
ダウンロードしたRaspbian imgは/home以下に適当にディレクトリを作成、展開しました。

# mkdir loop0p1 boot用
# mkdir loop0p2 rootfs用
2018-11-13-raspbian-stretch.imgをコピーした2018-11-13-stretch-pi3.imgを編集します。

ranger
rangerのインストールについては以前の記事を参照
kpartxの実行、マウントはrangerのrifle.confを利用して実行します。
~/.config/ranger/rifle.conf

ext img = sudo kpartx -va "$@" && sleep 1 && sudo mount /dev/mapper/loop0p1 /home/data/stretch/loop0p1 && sleep 1 && sudo mount /dev/mapper/loop0p2 /home/data/stretch/loop0p2 && loop_info.py


rifle.confの最初の方に記載しておきます。
rangerからはloop0の決め打ちにしているのでloop0デバイスだけがマウント可能になります。

loop_info.pyの作成

python(tkinter)を利用してメッセージボックスを作成します。
~/bin/loop_info.py

#!/usr/bin/python3
import subprocess
from tkinter import messagebox

command = ("df -h | grep loop | cut -c 1-20 && ls /dev/mapper")
proc = (subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()[0]).decode('utf-8')
messagebox.showinfo('loop_info', proc)
$ chmod 755 ~/bin/loop_info.py

上記rangerのrifle.confに追記した最後にloop_info.pyの起動を記載しています。
参考 [備忘録]Pythonでシェルコマンドを動かす
コマンドからの出力(取得)はバイト文字列になっているようです。decodeで日本語表示も可能です。
rangerを再起動して2018-11-13-stretch-pi3.imgを選択

マウントが成功すると画像のようにメッセージを表示します。
loop0p1にboot、loop0p2にrootfsがそれぞれマウントされます。


マウントしたファイルはOSのイメージそのものなのでOSを壊さない範囲で自由に編集可能ですがraspbianは適当な時期で変更になるため特に事情が無い限りあまり凝った編集をしても意味がありません。WiFi接続情報やインストール後の作業が楽になるような設定を加えるのがいいと思います。

loop_remove.pyの作成

loop deviceのアンマウント、片付けは前回作成したランチャを使用します。
シェルコマンドの実行はos.systemからsubprocessに(推奨)代わっているようですね。
python3.5以降から使えます。
~/bin/loop_dev.py

#!/usr/bin/python3

from tkinter import *
from tkinter import ttk 
import subprocess

root = Tk()
root.title('loop_device')
style = ttk.Style()
style.theme_use('default') #('clam', 'alt', 'default', 'classic')

# Frame as Widget Container
frame1 = ttk.Frame(
    root,
    padding=5)
frame1.grid()

# Button 1
def remove0():
    subprocess.run("sudo umount /home/data/stretch/loop0p1", shell=True)
    subprocess.run("sudo umount /home/data/stretch/loop0p2", shell=True)
    subprocess.run("sudo dmsetup remove loop0p1", shell=True)
    subprocess.run("sudo dmsetup remove loop0p2", shell=True)
    subprocess.run("sudo losetup -d /dev/loop0", shell=True)
    subprocess.run("loop_info.py")
icon1 = PhotoImage(file='~/.icons/folder-loop.png')
button1 = ttk.Button(
    frame1,
    image=icon1,
    command=remove0)
button1.grid(row=1,column=1)

# Button 2
def loop_dev():
    subprocess.run("loop_info.py")
icon2 = PhotoImage(file='~/.icons/text-info.png')
button2 = ttk.Button(
    frame1,
    image=icon2,
    command=loop_dev)
button2.grid(row=1,column=2)

# Button 3
def shutdown():
    subprocess.run("sudo reboot", shell=True)
icon3 = PhotoImage(file='~/.icons/reboot100x48.png')
button3 = ttk.Button(
    frame1,
    image=icon3,
    command=shutdown)
button3.grid(row=2,column=1)

# Button 4
def cancel():
    root.quit()
icon4 = PhotoImage(file='~/.icons/exit100x48.png')
button4 = ttk.Button(
    frame1,
    image=icon4,
    command=cancel)
button4.grid(row=2,column=2)

root.mainloop()
$ chmod 755 ~/bin/loop_remove.py

loop_remove.pyを実行します。

infoボタンで現在の状態を確認できます。
左はrebootボタン
exitボタンはなにもしないで終了します。


loop0ボタンでアンマウント、loop0デバイスの解除を実行します。
rangerなどからloop0デバイスへアクセスがあるとアンマウントに失敗するのでディレクトリから離れておきます。
成功するとcontrolのみを表示します。


現状のプログラムではloop0マウント後にほかのimgを実行するとloop1が作成されてしまいます。削除するにはコマンドラインから外すかまたはrebootを実行します。


次回はこの編集したimgを使用してPi3のディスクを作成、インストールしてみたいと思います。

Top