web-dev-qa-db-ja.com

ターミナルコマンド以外の方法で閉じないXウィンドウを作成する方法

X11で始まり、グラフィカルで、自分のユーザーが殺せないプロセスを作成しようとしています。

具体的には、起動時に開始し、すぐにtmuxセッションを実行するurxvtドロップダウンターミナルがあります。私を悩ませているのは、私が時々それを殺すということです Alt+F4 ドロップダウン端末であることを忘れて、代わりに非表示にすることになっているとき。

確かに、別の端末からtmuxセッションに再接続できるため、tmuxセッションが失われることはありませんが、ドロップダウン端末を(正確な構成で)再起動して再接続する必要があり、面倒です。

私がやりたいのは、できないことです Alt+F4 この特定のプロセスを強制終了します

これを読んだ後: Linuxでプロセスを強制終了できないようにする

私は、別のユーザーに属するものとしてプロセスを起動する必要があることを理解しましたが、自分のXサーバー内で次のようにしてそれを実行できたとしても。

Sudo xhost +local:
Sudo runuser -l my-secondary-user -c urxvt

私は2つの望ましくない行動に直面しています。

  1. プロセスは私のメインユーザー(Xセッションを所有しているユーザー)によって強制終了できます
  2. 仮想端末がmy-secondary-userとしてログインを開始します(もちろん)

(2)は修正可能かもしれません-代わりにメインユーザーとしてログインするコマンドを実行するだけです-しかし、(1)を修正する方法がわかりません。

これを機能させる方法、または私がやりたいことを行う別の方法はありますか?可能であれば、カーネルモジュールの作成に煩わされることは避けたいと思います。

OpenboxでArchLinuxを実行する。

[〜#〜]編集[〜#〜]

この特定のウィンドウでAlt + F4を機能させないようにできるかもしれないと思いました。これが見つかりました: Openbox:アプリケーションごとにAlt-F4を無効にします

そして私のrc.xmlを次のように変更しました:

<keybind key="A-F4">
 <action name="If">
  <application class="URxvt"
    title="tmux-session">
  </application>
  <then><!-- Do nothing for urxvt-tmux-session --></then>
  <else>
   <action name="Close" />
  </else>
 </action>
</keybind>

これは以前よりもわずかにうまく機能します:私はできません Alt+F4 その端末だけでなく、できません Alt+F4 現在、任意のurxvtウィンドウがあります(これは、新しいurxvtウィンドウがすべて同じクラス名で実行されているためだと思いますか?)

それに加えて、メニューバーから、または色合いパネルを右クリックして、あるいはもちろんコマンドによって、必要なものをすべて削除できます。しかし、このアプローチは次のことを意味します。

  1. Tint2パネルを右クリックすることで、ドロップダウンターミナルを強制終了できます(ドロップダウンターミナルをパネルのアイコンとして表示しないようにすると修正できる可能性があります-いくつかの調査で可能になるはずです)
  2. 私はできない Alt+F4 他のターミナルウィンドウ(あまり好きではありませんが、おそらく受け入れられます)

何か案は?

[〜#〜]ソリューション[〜#〜]

Dmitryの回答と上記の編集に基づいて、自分に合った解決策を見つけました。

1)カスタムタイトルをurxvtに設定しました:

urxvt -title urxvt-drop-down

カスタム名は使用しなかったのは、

urxvt -name urxvt-drop-down

コマンドは、現在使用している.Xresourcesファイルを無視しますが、-titleはそれを使用します。

2)私は Alt+F4 urxvt-drop-downというタイトルの端末を無視するためのkeybind。 rc.xml:

<keybind key="A-F4"> <action name="If"> <title>urxvt-drop-down</title> <then><!-- Do nothing for urxvt-drop-down --></then> <else> <action name="Close" /> </else> </action> </keybind>

3)犯人がタスクバーに表示されないようにしましたが、skip_taskbarもウィンドウのフォーカスを解除したため、再度フォーカスしました。 rc.xml:

<application title="urxvt-drop-down"> <skip_taskbar>yes</skip_taskbar> <focus>yes</focus> </application>

これで問題は解決しますが、基本的には回避策です。したがって、ステファンの答えがこの質問の正しい答えであるかどうかはまだわかりません。

何が行われているのかを理解するために、提示されたコマンドについて少し調査する必要があります。

偽の透明性とドロップダウン機能が必要なため、xtermは使用しません(xtermでも何らかのドロップダウンが可能かもしれませんが、透明性は確かにコンポジターなしではありません-そして私はそうします」 tコンポジターを使用)

xtermに切り替えることがオプションである場合は、以下のハックを使用できます。ただし、いくつかの注意点があります。それらのほとんどに対処すると、ソリューションは非常に複雑になります。最後の最後のスクリプトを参照してください。

_xterm -e 'trap "" HUP; your-application'
_

ウィンドウマネージャーから閉じる命令を受け取ると、xtermはSIGHUPをアプリケーションのプロセスグループに送信し、プロセスが戻ったときにのみ終了します。

これは、アプリケーションがSIGHUPのハンドラーをリセットせず、アプリケーションの子に望ましくない副作用をもたらす可能性があることを前提としています。

アプリケーションがtmuxの場合、どちらも問題のようです。

これらを回避するには、次のようにします。

_xterm -e sh -c 'bash -mc tmux <&1 & trap "" HUP; wait'
_

そうすれば、tmuxは別のプロセスグループで開始されるため、shのみがSIGHUPを受け取ります(無視します)。

さて、それはとにかくそれらのシグナルのハンドラーをリセットするtmuxには当てはまりませんが、一般的なケースでは、shの実装に応じて、SIGINT、SIGQUITシグナル、そして一般的に両方がbashは非対話型のshから非同期コマンドとして開始されるため、アプリケーションでは無視してください。つまり、アプリケーションを中断することはできませんでした Ctrl+C または Ctrl+\

これはPOSIXの要件です。 mkshのようないくつかのシェルはそれを尊重しません(少なくとも現在のバージョンではありません)、またはSIGINTではそれを行うがSIGQUITではないdashのような部分だけです。したがって、mkshが利用可能な場合は、次のことができます。

_xterm -e mksh -c 'bash -mc your-application <&1 & trap "" HUP; wait'
_

(ただし、mkshの将来のバージョンでは、その不適合を修正することを決定した場合、それは機能しない可能性があります)。

または、mkshまたはbashが使用可能になることを保証できない場合、または将来変更される可能性のある動作に依存したくない場合は、Perlたとえば、次のような_unclosable-xterm_ラッパースクリプトを記述します。

_#! /bin/sh -
[ "$#" -gt 0 ] || set -- "${Shell:-/bin/sh}"
exec xterm -e Perl -MPOSIX -e '
  $pid = fork;
  if ($pid == 0) {
    setpgrp or die "setpgrp: $!";
    tcsetpgrp(0,getpid) or die "tcsetpgrp: $!";
    exec @ARGV;
    die "exec: $!";
  }
  die "fork: $!" if $pid < 0;
  $SIG{HUP} = "IGNORE";
  waitpid(-1,WUNTRACED)' "$@"
_

(_unclosable-xterm your-application and its args_と呼ばれます)。

さて、もう1つの副作用は、作成してフォアグラウンドに配置している新しいプロセスグループ(上記の_bash -m_またはsetpgrp + tcsetpgrp)がセッションリーダープロセスグループではなくなったことです。 、したがって、もはや孤立したプロセスグループではありません(おそらく今それを気にかけている親がいます(shまたはPerl))。

それが意味するのは、押すと Ctrl+Z、そのプロセスは中断されます。ここでは、不注意な親が終了するだけです。つまり、プロセスグループはSIGHUPを取得します(そしてうまくいけば死にます)。

これを回避するには、子プロセスでSIGTSTPを無視することもできますが、アプリケーションがインタラクティブシェルの場合、mkshyashrcなどの実装では、 Ctrl-Z 彼らが実行するジョブに対しても機能しません。

または、次のように、停止するたびに子を再開する、より注意深い親を実装することもできます。

_#! /bin/sh -
[ "$#" -gt 0 ] || set -- "${Shell:-/bin/sh}"
exec xterm -e Perl -MPOSIX -e '
  $pid = fork;
  if ($pid == 0) {
    setpgrp or die "setpgrp: $!";
    tcsetpgrp(0,getpid) or die "tcsetpgrp: $!";
    exec @ARGV;
    die "exec: $!";
  }
  die "fork: $!" if $pid < 0;
  $SIG{HUP} = "IGNORE";
  while (waitpid(-1,WUNTRACED) > 0 && WIFSTOPPED(${^CHILD_ERROR_NATIVE})) {
    kill "CONT", -$pid;
  }' "$@"
_

もう1つの問題は、ウィンドウマネージャーからclose以外の理由でxtermがなくなった場合、たとえばxtermが強制終了されたり、Xサーバーへの接続が失われたりした場合です。 (xkill、ウィンドウマネージャーのdestroyアクション、またはXサーバーのクラッシュなどのため)、これらの場合はSIGHUPも使用されるため、これらのプロセスは停止しません。それらを終了します。これを回避するには、端末デバイスでpoll()を使用できます(xtermが実行されると破棄されます)。

_#! /bin/sh -
[ "$#" -gt 0 ] || set -- "${Shell:-/bin/sh}"
exec xterm -e Perl -w -MPOSIX -MIO::Poll -e '
  $pid = fork; # start the command in a child process
  if ($pid == 0) {
    setpgrp or die "setpgrp: $!"; # new process group
    tcsetpgrp(0,getpid) or die "tcsetpgrp: $!"; # in foreground
    exec @ARGV;
    die "exec: $!";
  }
  die "fork: $!" if $pid < 0;
  $SIG{HUP} = "IGNORE"; # ignore SIGHUP in the parent
  $SIG{CHLD} = sub {
    if (waitpid(-1,WUNTRACED) == $pid) {
      if (WIFSTOPPED(${^CHILD_ERROR_NATIVE})) {
        # resume the process when stopped
        # we may want to do that only for SIGTSTP though
        kill "CONT", -$pid;
      } else {
        # exit when the process dies
        exit;
      }
    }
  };

  # watch for terminal hang-up
  $p = IO::Poll->new;
  $p->mask(STDIN, POLLERR);
  while ($p->poll <= 0 || $p->events(STDIN) & POLLHUP == 0) {};
  kill "HUP", -$pid;
  ' "$@"
_
5