Como criar uma janela X que não feche de outra forma que não seja um comando de terminal

3

Estou tentando criar um processo que comece com X11, seja gráfico e não possa ser martelado pelo meu próprio usuário.

Mais especificamente, eu tenho um terminal suspenso urxvt iniciando na inicialização e executando uma sessão tmux imediatamente. O que me irrita é que às vezes eu mato com Alt + F4 quando eu esqueço que é o terminal drop-down e eu devo escondê-lo.

Claro, eu não estou perdendo a minha sessão tmux, já que eu posso recolocá-la em outro terminal, mas eu teria que reiniciar o terminal drop-down (com a configuração exata) e reconectar e isso é tedioso. / p>

O que eu gostaria de fazer, é não ser capaz de Alt + F4 matar este processo específico .

Depois de ler isto: Tornar um processo inutilizável no Linux

Eu entendi que deveria iniciar o processo como pertencente a outro usuário, mesmo que eu consiga fazer isso dentro do meu próprio servidor X com:

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

Eu enfrento dois comportamentos indesejados:

  1. O processo é eliminável pelo meu usuário principal (aquele que possui a sessão X)
  2. O terminal virtual inicia a sessão como meu usuário secundário (claro)

O (2) pode ser retificável - apenas execute um comando para efetuar login como meu usuário principal - mas não tenho idéia de como corrigir o (1).

Existe uma maneira de fazer isso funcionar ou outra maneira de fazer o que eu quero? Eu prefiro evitar ter que mexer com a criação de módulos do kernel, se possível.

Executando o Arch Linux com o Openbox.

EDITAR

Eu comecei a pensar que eu poderia fazer o Alt + F4 não funcionar nesta janela específica. achei isso: Openbox: desabilite Alt-F4 por aplicativo

e modifiquei meu rc.xml assim:

<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>

Isso funciona um pouco melhor que antes: eu não posso Alt + F4 nesse terminal, mas também não consigo Alt + F4 qualquer janela do urxvt agora (acho que isso acontece porque todas as novas janelas do urxvt são executadas com o mesmo nome de classe?)

Além disso, posso matar tudo o que preciso na barra de menu, ou clicar com o botão direito no meu painel de tonalidade, ou, claro, por comando. Mas essa abordagem significa que:

  1. Eu ainda posso matar meu terminal drop-down clicando com o botão direito do mouse no painel tint2 (talvez consertável se eu fizer o terminal drop-down não aparecer como um ícone no painel - deve ser possível com alguma pesquisa)
  2. Eu não posso Alt + F4 outras janelas de terminal (não gosto muito, mas talvez seja aceitável)

Alguma idéia?

SOLUÇÃO

Eu encontrei uma solução que funciona para mim com base na resposta de Dmitry e na minha edição acima:

1) eu defino um título personalizado para o meu urxvt:

urxvt -title urxvt-drop-down

Eu não usei um nome personalizado porque parece que o

urxvt -name urxvt-drop-down

O comando

ignora o arquivo .Xresources que eu uso atualmente, enquanto o -title o usa.

2) Eu fiz o keybind Alt + F4 para ignorar os terminais intitulados urxvt-drop-down. 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) Eu fiz o culpado nunca aparecer na barra de tarefas, e desde que o skip_taskbar também desfoca a janela, refocused ele. rc.xml:

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

Embora isso resolva o problema para mim, é essencialmente uma solução alternativa. Portanto, ainda não tenho certeza se a resposta de Stephane é a correta para essa pergunta.

Precisa fazer uma pequena pesquisa sobre os comandos apresentados para entender o que está sendo feito.

Eu não usarei o xterm, já que eu quero uma capacidade de transparência e drop-down falsas (algum tipo de drop-down pode ser possível com o xterm também, mas transparência certamente não é sem um compositor - e eu não vou usar um compositor)

    
por John Kontochristopoulos 18.03.2016 / 13:52

2 respostas

2

Se a mudança para xterm for uma opção, você pode usar o hack abaixo. Há algumas ressalvas embora. Depois de abordar a maioria deles, a solução acaba sendo bastante complicada, veja o roteiro final no final.

xterm -e 'trap "" HUP; your-application'

Ao receber a instrução para fechar a partir do gerenciador de janelas, xterm enviará um SIGHUP para o grupo de processos do seu aplicativo e só sairá quando o processo retornar.

Isso pressupõe que o seu aplicativo não redefine o manipulador de SIGHUP e possa ter efeitos colaterais indesejados para os filhos do seu aplicativo.

Ambos parecem ser um problema se o seu aplicativo for tmux .

Para contornar isso, você poderia fazer:

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

Dessa forma, tmux seria iniciado em um grupo de processos diferente, portanto, somente o sh receberia o SIGHUP (e o ignoraria).

Agora, isso não se aplica a tmux que redefine o manipulador para esses sinais de qualquer maneira, mas no caso geral, dependendo da implementação de sh , os sinais SIGINT, SIGQUIT e geralmente ambos serão ignorados seu aplicativo como bash é iniciado como um comando assíncrono de um sh não interativo. Isso significa que você não pode interromper seu aplicativo com Ctrl + C ou Ctrl + \ .

Esse é um requisito POSIX. Alguns shells como mksh não o honram (pelo menos não as versões atuais), ou apenas parcialmente como dash que faz isso para o SIGINT, mas não o SIGQUIT. Então, se mksh estiver disponível, você poderia fazer:

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

(embora isso possa não funcionar em versões futuras de mksh se eles decidirem corrigir essa não conformidade).

Ou, se você não pode garantir que mksh ou bash estarão disponíveis ou preferiria não depender de um comportamento que possa mudar no futuro, você pode fazer seu trabalho manualmente com perl e, por exemplo, escrever um script% wrapper unclosable-xterm como:

#! /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)' "$@"

(a ser chamado como unclosable-xterm your-application and its args ).

Agora, outro efeito colateral é que o novo grupo de processos que estamos criando e colocando em primeiro plano (com bash -m ou setpgrp + tcsetpgrp acima) não é mais o grupo de processos líder da sessão. Grupo de processos órfão (há um pai supostamente cuidando dele agora ( sh ou perl )).

O que isto significa é que ao pressionar Ctrl + Z , esse processo será suspenso. Aqui, nosso pai descuidado simplesmente sairá, o que significa que o grupo de processos receberá um SIGHUP (e esperamos que morra).

Para evitar isso, poderíamos simplesmente ignorar o SIGTSTP no processo filho, mas se o seu-aplicativo for um shell interativo, para algumas implementações como mksh , yash ou rc , Ctrl- Z não funciona nem para as tarefas que executam.

Ou podemos implementar um pai mais cuidadoso que recomeça o filho toda vez que ele for interrompido, como:

#! /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;
  }' "$@"

Outro problema é que se xterm desaparecer por outro motivo que o fechar do gerenciador de janelas, por exemplo, se xterm for eliminado ou perder a conexão com o servidor X (por causa de xkill , a ação destruir do gerenciador de janelas, ou o servidor X trava por exemplo), então esses processos não morrerão como SIGHUP também seria usado nesses casos para terminá-los. Para contornar isso, você poderia usar poll() no dispositivo terminal (que seria demolido quando xterm fosse):

#! /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;
  ' "$@"
    
por 18.03.2016 / 14:38
4

Sua pergunta tem um título um pouco enganador, levando sua pesquisa na direção errada. Quando você fecha uma janela em X , o servidor não mata seu processo . Em vez disso, ele envia uma mensagem WM_DELETE_WINDOW para o processo, que por sua vez termina. Esse fato doa sua primeira abordagem: mesmo que você defina o SIGNAL_UNKILLABLE , ainda será possível fechá-lo.

Sua segunda abordagem parece útil, tudo que você precisa fazer é discriminar uma única janela de terminal contra todas as outras. Uma maneira de conseguir isso é iniciar urxvt com um título específico, por exemplo urxvt -name urxvt-iddqd , e criar uma regra para seu nome:

<keybind key="A-F4">
 <action name="If">
  <application title="urxvt-iddqd"
    title="tmux-session">
  </application>
  <then><!-- Do nothing for urxvt-tmux-session --></then>
  <else>
   <action name="Close" />
  </else>
 </action>
</keybind>
    
por 18.03.2016 / 14:38