mieki256's diary



2022/08/04(木) [n年前の日記]

#1 [windows] Windows10からPowerToysをアンインストールした

昨晩、Windows10 x64 21H2 上で PowerToys 0.57.0 を 0.61.1 にアップデートしようとしたら Windows10 がブルースクリーン(BSOD)になってしまう不具合に遭遇した。アンインストールしようとしても必ずブルースクリーンになる。ブルースクリーンには、thread がどうとか、Ntfs.sys がどうとか表示されている。

そんなわけで、どうにか PowerToys をアンインストールしようと四苦八苦していた。

ハードウェア環境は、CPU が AMD Ryzen 5 5600X。CドライブがSSD、DドライブがHDD。

以下、参考ページ。

_PowerToys のインストール | Microsoft Docs
_I can't delete PowerToys or Uninstall it - Issue #1490 - microsoft/PowerToys
_Cant uninstall Microsoft Power Toys. - Microsoft Community

試したこと。 :

まず、PowerToys の設定画面を表示して、全機能をオフにしてみた。PowerToys はエクスプローラに色々な機能を追加するので、そのあたりで問題が発生してそうだよなと…。設定を変更したらOS再起動。

PowerToys 0.57.0 のセットアップファイル、PowerToysSetup-0.57.0-x64.exe を github から入手。管理者権限で PowerShell を開いて、以下を打ってみた。

.\PowerToysSetup-0.57.0-x64.exe --extract_msi

セットアップファイルは .exe で提供されているけれど、アンインストール処理時は .msi が必要になる、という話をどこかで見かけた。--extract_msi とつけると、おそらくはどこかしらに .msi を解凍して、そちらから処理をするのではないか。たぶん。

アンインストール画面が出てきたので、「Uninstall」をクリック。ブルースクリーンにならないでくれと祈りながら処理が終わるのを数十秒ほど待った。幸い、ブルースクリーンにはならず、アンインストールも成功した。助かった。

またこんな目にあったら嫌なので、今後、PowerToys のインストールは避けよう…。機能が豊富な分、Windowsの奥深いところに関わってそうでもあるし…。

#2 [ruby][xscreensaver] ruby-gtk2を使ってxscreensaver用スクリーンセーバを作る

Ruby + ruby-gtk2 を使って、xscreensaver用スクリーンセーバを作れそうか試してみた。

一応ざっくり説明しておくと…。
環境は、Ubuntu Linux 20.04 LTS + Ruby 2.7.0 p0 + ruby-gtk2 3.4.1-2build1 + xscreensaver 6.04。ちなみに、Ubuntu Linux は Windows10 x64 21H2 + VMware Player上で動かしてる。

実行結果は以下のような感じ。

参考にしたスクリプト。 :

今回参考にさせてもらった Rubyスクリプトは以下。お天気情報を表示してくれる、Ruby製の xscreensaver用スクリーンセーバらしい。

_zhum/rubysaver: Xscreensaver module, displaying weather, forecast, clock and now playing song title and author.
_rubysaver/rs.rb at master - zhum/rubysaver

必要なパッケージのインストール。 :

端末を開いて、以下を打ってインストール。

sudo apt install ruby-gtk2

ちなみに、Ubuntu Linux 20.04 LTS の場合、デフォルトで Ruby 2.7.0 がインストールされているっぽい。

ソース。 :

前述のスクリプトから、xscreensaver に絡んでいる部分だけを抜き出して、簡単なサンプルにしてみた。処理内容としては、赤い円がウインドウ内を跳ね回るだけのスクリプト。

_04_xscrsav.rb
#!/usr/bin/ruby
# encoding: UTF-8

require "gtk2"
require "logger"

# for gtk2
SIGNAL_DRAW = "expose_event"

# for gtk3
# SIGNAL_DRAW = "draw"

TMOUT = 16

$drawing_area = nil
$logger = Logger.new("/tmp/rubysaver-#{ENV["USER"]}.log", "monthly")

class RubyXscrApp < Gtk::Window
  def initialize
    super

    set_title "xscreensaver module"

    signal_connect "destroy" do
      $logger.warn "EXIT by destroy"
      Gtk.main_quit
    end

    signal_connect "delete-event" do
      $logger.warn "EXIT by delete-event"
      Gtk.main_quit
      false
    end

    signal_connect "delete_event" do
      $logger.warn "EXIT by delete_event"
      Gtk.main_quit
      false
    end

    realize

    ident = ENV["XSCREENSAVER_WINDOW"]
    if not ident.nil?
      $logger.warn "XSCREENSAVER_WINDOW = #{ident}"
      self.window = Gdk::Window.foreign_new(ident.to_i(16))
      self.window.set_events(Gdk::Event::EXPOSURE_MASK | Gdk::Event::STRUCTURE_MASK)

      x, y, width, height, depth = self.window.geometry
      # puts "window = #{self.window}, (x,y,w,h) = #{x}, #{y}, #{width}, #{height}"
      $logger.warn "window = #{self.window}, (x,y,w,h) = #{x}, #{y}, #{width}, #{height}"

      set_default_size width, height
      move(x, y)
      # set_window_position :center
    else
      x, y, width, height, depth = self.window.geometry
      width, height = 640, 360
      set_default_size width, height
      set_window_position :center
      puts "window = #{self.window}, (w,h) = #{width}, #{height}"
    end

    @x = width / 2
    @y = height / 2
    @dx = width.to_f / (60 * 1)
    @dy = height.to_f / (60 * 1.5)

    $drawing_area = @darea = Gtk::DrawingArea.new
    @bgcol = Gdk::Color.new(0x2000, 0x4000, 0xa000)
    @darea.modify_bg(:normal, @bgcol)
    @darea.set_size_request(width, height)

    @darea.signal_connect SIGNAL_DRAW do |widget, event|
      on_draw widget
    end

    @fixed = Gtk::Fixed.new
    @fixed.put(@darea, 0, 0)
    add(@fixed)

    show_all
  end

  def on_draw(widget)
    cr = widget.window.create_cairo_context
    x, y, width, height, depth = widget.window.geometry

    # update position
    r = 24
    @x += @dx
    @y += @dy
    @dx *= -1 if (@x <= r or @x >= width - r)
    @dy *= -1 if (@y <= r or @y >= height - r)

    # clear bg
    cr.set_source_rgb(0.1, 0.3, 0.5)
    cr.paint

    # draw circle
    cr.set_source_rgb(1.0, 0.0, 0.0)
    cr.arc(@x, @y, r, 0, 2 * Math::PI)
    cr.fill

    cr.destroy
  end
end

Gtk.init
window = RubyXscrApp.new

# animation
GLib::Timeout.add(TMOUT) do
  $drawing_area.queue_draw if (not $drawing_area.nil?)
  true
end

Gtk.main

chmod +x 04_xscrsav.rb で実行権限をつけて、端末上で ./04_xscrsav.rb としてテスト実行。ウインドウが開いて、赤い円が跳ね回った。これでひとまず、xscreensaver を経由しなくても、アニメーション部分の動作テストや調整はできそうだなと…。

xscreensaver から呼び出せるように、設定ファイル ~/.xscreensaver を編集。
programs:                                                                     \
                   "RUBYSAVER"                                                \
                                  /home/USERNAME/prg/ruby/ruby-gtk2/04_xscrsav.rb \n\
                                maze -root                                  \n\
  • TAB幅は8文字、TAB文字有効で編集を行う。
  • 「programs:」以下に、追加するスクリーンセーバの名前と、Rubyスクリプトのパスを記述。
  • 行の最後が「\」なら継続行、「\n\」ならスクリーンセーバ1つ分の記述が終わったことを示す、のだと思う。

xscreensaverの設定画面を表示して、上記で追加した「RUBYSAVER」を選んでみると、プレビュー画面の中でも赤い円が跳ね回ってくれた。「プレビュー」ボタンをクリックしたら、フルスクリーンでテスト表示された。

これで、ハードルの高い C/C++ で書かなくても、Ruby + ruby-gtk2 で xscreensaver用スクリーンセーバを書くことができそうだと分かった。

問題点。 :

上記のサンプルは、少々問題が残ってる。xscreensaverの設定画面でスクリーンセーバ種類を切り替えた際に、以下のメッセージが表示されてしまう。

$ xscreensaver-settings: 06:27:44: XScreenSaver-debug: Name com.canonical.AppMenu.Registrar does not exist on the session bus
Gdk-WARNING **: GdkWindow 0x5000023 unexpectedly destroyed
        from /home/USERNAME/prg/ruby/ruby-gtk2/04_xscrsav.rb:125:in `<main>'

「GdkWindow 0xXXXX が予期せず破壊された」的な警告が出ている。おそらく、xscreensaver が強制的にスクリーンセーバを殺してしまうことで、こういう警告が出ているのかなと…。何か正しい終了手順があるなら、対策したいものだけど…。

少し解説。 :

xscreensaver は、スクリーンセーバを呼び出す際、「このウインドウを使ってスクリーンセーバの描画処理をするべし」的に、環境変数 XSCREENSAVER_WINDOW に16進数文字列でウインドウハンドルを設定してくれる。

_XScreenSaver Manual
_XScreenSaver FAQ

つまり、
  • 「環境変数 XSCREENSAVER_WINDOW があるかどうかを調べることができて」
  • 「XSCREENSAVER_WINDOW で指定されたウインドウハンドルを使って描画できる」
そんな言語/フレームワーク/プログラムなら、xscreensaver用スクリーンセーバが作れますよ、ということになっている。

実際、xscreensaver のFAQページには、mpv という動画再生ソフトを呼び出して動画を再生するサンプルが載っているけど、それは環境変数 XSCREENSAVER_WINDOW を mpv のコマンドラインオプションに渡すことで目的を果たしている。

Q. How do I make XScreenSaver play a video clip?

A. Install mpv and add something like the following to the "programs" preference in your .xscreensaver file:

"Movies" mpv --really-quiet --no-audio --fs --loop=inf \
--no-stop-screensaver --shuffle \
--wid=$XSCREENSAVER_WINDOW \
$HOME/Videos/poop.mp4 \n\

Or, point it at an .m3u file instead: a text file listing your video files, one per line.

XScreenSaver FAQ より


まあ、xscreensaver のドキュメントには、「ウインドウハンドルを渡して処理できる言語やフレームワークはそれほど多くないから、実際にはC/C++で書くことになるだろうね」と書いてあったりするのだけど…。

_README.hacking.edit.txt

幸い、Ruby は環境変数の有無を調べることができるし、ruby-gtk2 は指定されたウインドウハンドルを自身のウインドウとして再設定する機能があるっぽいので、こうして xscreensaver用スクリーンセーバを書けそう、という話になるわけで。

一応、そのあたりの処理を以下に抜き出してみる。

    ident = ENV["XSCREENSAVER_WINDOW"]
    if not ident.nil?
      # xscreensaver

      self.window = Gdk::Window.foreign_new(ident.to_i(16))
      self.window.set_events(Gdk::Event::EXPOSURE_MASK | Gdk::Event::STRUCTURE_MASK)
      x, y, width, height, depth = self.window.geometry
      set_default_size width, height
      move(x, y)
    else
      # not xscreensaver

      x, y, width, height, depth = self.window.geometry
      width, height = 640, 360
      set_default_size width, height
      set_window_position :center
    end

ちょっとハマったのは、ウインドウの表示位置の指定方法。参考にしたスクリプトは、set_window_position :center を呼んで表示位置を決めていたっぽいのだけど、それだと xscreensaver設定画面のプレビュー窓に位置が合ってくれなかった。move(x, y) にしてみたら上手くいった。

さておき。今回、描画処理は、RubyXscrAppクラス内の on_draw() の中でやっている。件のメソッドの中を魔改造すれば違う描画処理になってくれるはず。

アニメーションさせるためには、一定の周期で描画処理を呼び出す指定が必要だけど、ruby-gtk2 の場合、GLib::Timeout.add(ミリ秒) do - end で指定ができるらしい。以前は Gtk.timeout_add(ミリ秒) で指定してたらしいけど、その指定は非推奨になったそうで。

GLib::Timeout.add(TMOUT) do
  $drawing_area.queue_draw if (not $drawing_area.nil?)
  true
end

描画は、Cairo::Context を使う方法と、Gdk::Drawable を使う方法の2種類があるそうだけど、今回は前者を使ってみた。ただ、Mac上で動かしたときは、Cairo::Context を毎回破棄しないとおかしくなるらしいので、一応 .destroy を呼んで破棄するようにしておいた。 *1

最初、DrawingArea をどこに登録すればいいのか分からなかったけど、どうやら gtk2 のウインドウに登録してやればいいようだなと…。

    $drawing_area = @darea = Gtk::DrawingArea.new
    @bgcol = Gdk::Color.new(0x2000, 0x4000, 0xa000)
    @darea.modify_bg(:normal, @bgcol)
    @darea.set_size_request(width, height)
...
    @fixed = Gtk::Fixed.new
    @fixed.put(@darea, 0, 0)
    add(@fixed)

Gtk::Fixed は、座標指定で配置するためのWidgetらしい。

懸念事項。 :

Debian Linux において、ruby-gtk2 パッケージは、Debian 11 bullseye の時点までは公式に用意されている。故に、Debian系である Ubuntu Linux 20.04 LTS でもインストールして利用することができたのだけど。この ruby-gtk2 パッケージは、将来的にどうなるかちょっと分からないなと…。

_Debian -- bullseye の ruby-gtk2 パッケージに関する詳細

上記ページを見ると、Debian 9 stretch、Debian 10 buster、Debian 11 bullseye の時点までは公式パッケージとして ruby-gtk2 が用意されていた。ただ、おそらくは Debian 12 になるのであろう bookworm にはパッケージが用意されてないっぽい。sid には用意されているみたいだけど…。

例えば、ここで python3-pygame パッケージ情報を眺めると、こちらは Debian 12 bookworm 用パッケージも用意されているように見える。ruby-gtk2 とは扱いが違う。

_Debian -- bookworm の python3-pygame パッケージに関する詳細

そんなわけで、ひょっとすると次期バージョンの Debian系では、ruby-gtk2 を使って xscreensaver用スクリーンセーバを作成するのは難しくなるのかもしれない。ruby-gtk2 パッケージが無くなっているかもしれないので…。

ruby-gtk3 で書き直せたら、しばらくは安心(?)なのかもしれない。自分は知識が無いのでちょっと無理だけど…。

参考ページ。 :


*1: でも、Mac なら JavaScript でスクリーンセーバが書けるという話も見かけたのだよな…。だったらフツーは JavaScript で書くよな…。

#3 [xscreensaver][pygame] pygameでxscreensaver用スクリーンセーバを作れないものか

Python + pygame で、xscreensaver用スクリーンセーバを作れないものだろうか。ちょっと気になったので、少し調べてみた。

pygameに求められる条件。 :

SDL1.x を使っていた頃の pygame は ―― おそらく pygame 1.9.x の頃は、環境変数 SDL_VIDEO_DRIVER と SDL_WINDOWID を利用することで、指定されたウインドウハンドルに対して描画することができていたらしい。

_pygameでスクリーンセーバを作りたいのだけど - mieki256's diary

そういうことができるなら、xscreensaver が指定してきたウインドウハンドルを使って描画することもできそうな気がする。

ただ、最近の pygame 2.x.x は SDL2 を使うようになったそうで、SDL1.x 時代に利用できたその手の技(?)が使えなくなっている模様。

つまり、「xscreensaver用スクリーンセーバを pygame を使って作りたい」なら、「pygame 1.9.x が動く環境が必要」ということになる。たぶん。

OS側の事情。 :

それを踏まえて。Ubuntu Linux 20.04 LTS (focal) の場合、python-pygame (Python 2.7.x用) や python3-pygame (Python 3.x用) といったパッケージをインストールすることで pygame 1.9.6 が利用できる。

_Ubuntu - focal の python-pygame パッケージに関する詳細
_Ubuntu - focal の python3-pygame パッケージに関する詳細

であれば、Ubuntu 20.04 LTS 環境なら、pygame を使って xscreensaver用スクリーンセーバを作ることも不可能ではないのかもしれない。

しかし、Ubuntu 22.04 LTS (jammy) の場合、python3-pygame (Python 3.x用) でインストールされるのは、pygame 2.1.2 らしい…。

_Ubuntu - jammy の python3-pygame パッケージに関する詳細

ちなみに、Ubuntu 22.04 LTS (jammy) において、python-pygame (Python 2.7.x用) は削除された模様。Ubuntu は積極的に Python 2.7系を殺しにかかってきているディストリビューションなので、まあ、仕方ない。

ということで、pygame で xscreensaver用スクリーンセーバを作成できたとしても、Ubuntu 20.04 LTS なら動くけど、Ubuntu 22.04 LTS では動かない、ということになってしまいそうだなと。

Windowsは条件が緩い。 :

ちなみに、Windows と Linux の場合、このあたりちょっと事情が違う気がする。

Windowsの場合、ローカルで pygame 1.9.x をインストールして何かしらを作って、ソレを最終的に .exe に変換すれば、どのPCにソレを持って行っても、pygame 1.9.x を使って動かせる、ということができそうな気がする。

しかし、Linux の場合、OSにインストールされたSDL関連ライブラリを利用して pygame が動くはずで…。おそらく Linux上では、バージョンが事なる pygame を共存させて使い分けるのは少々難しいのではなかろうか。分からんけど。

そんなわけで、もしかすると以下のような状況かもしれないなと。

  • Windows用スクリーンセーバを pygame を使って作成するのは、まだどうにか可能なのかもしれない。
  • Linux + xscreensaver用スクリーンセーバを pygame を使って作成するのは、OSのバージョンが古ければできるけど、最新バージョンのOSではちょっと難しいかもしれない。

何か抜け道は無いものか…。例えば AppImage を利用したりはできないものかな…。

_Linux Mint Tips : SNAP、FLATPAK、APPIMAGE 違い比較 | 221B Baker Street

以上、1 日分です。

過去ログ表示

Prev - 2022/08 - Next
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project