Problema con EXWM + ELISP per scriptare la creazione di custom layouts

In questi ultimi mesi sto cercando di automatizzare tutta una serie di tasks che tipicamente faccio manualmente tramite l’utilizzo di Emacs-lisp.

È da novembre del 2023 oramai che utilizzo EXWM, un pacchetto che trasforma Emacs in un Window Tiling Manager (WM) tipo i3, dwm, e via dicendo.

Ora, in questi giorni stavo provando a risolvere un determinato problema. Non sono però riuscito a trovare una soluzione per adesso. Posto qui quindi per vedere se qualcuno di voi mi può aiutare nello specifico problema. Richiede competenze molto verticali sulla combinazione Emacs + EXWM.


Il problema che sto cercando di risolvere è il seguente: voglio creare una funzione custom-layout, che mi organizza i buffer e le finestre di Emacs in un modo specifico a seconda dei mei requisiti.

Per esempio potrei volere due buffer mostrati in due finestre, una in alto e una in basso, con uno split verticale, come mostra lo screenshot a seguire

Ora, questo problema in realtà lo avrei già risolto, se non fosse per EXWM. Nel senso che so già scriptare qualsiasi tipo di layout che ha a che fare con buffer puramente di Emacs. Ad esempio il layout di prima lo potrei ottenere con la seguente funzione

(defun custom-layout ()
  (interactive)
  (delete-other-windows)
  (with-current-buffer (get-buffer-create "buffer1")
    (erase-buffer)
    (insert "Questo è il primo buffer")
    )
  (switch-to-buffer "buffer1")
  (split-window-vertically)
  (other-window 1)
  (with-current-buffer (get-buffer-create "buffer2")
    (erase-buffer)
    (insert "Questo è il secondo buffer")
    )
  (switch-to-buffer "buffer2")
  )

Ho dei problemi invece quando devo scriptare delle operazioni tra buffer di emacs ed applicazioni fuori di emacs gestite tramite X11 e EXWM. Nello specifico, non ho capito bene come sincronizzare il timing di queste operazioni.

Un piccolo esempio è: voglio aprire una instanza di chromium, e poi splittare la window, e poi aprire un altra instanza di chromium. Se provo a scriptare questa roba non mi funziona più, perché il codice che lancia chromium non è sincrono, ed Emacs continua ad eseguire il restante codice elisp, quindi si crea una incosistenza tra lo stato delle finestre in Emacs e le applicazioni che vengono lanciate.

Nello specifico, il codice che mi lancia chromium è

(start-process "" nil "/usr/bin/chromium")

Se a mano eseguo le operazioni

  1. Lancia chromium
  2. Split Window
  3. Lancia chromium

Allora mi funziona (latenza estremamente alta effettuando le cose in modo lineare a mano) ed ottengo

Se però provo a scriptarlo, tipo come segue

(defun custom-layout ()
  (interactive)
  (split-window-horizontally)
  (start-process "" nil "/usr/bin/chromium")
  (other-window 1)
  (start-process "" nil "/usr/bin/chromium")
  )

Mi apre entrambe le istanze di chromium nella stessa finestra, perché sicuramente lo start-process è un processo asincrono e quindi Emacs finisce l’esecuzione della funzione prima ancora che la prima istanza di Chromium sia stata spawnata.

Mi chiedo se esista un hook o un qualche modo per ottenere questo behavior, che sarebbe estremamente comodo per creare complessi layout tra buffer di emacs e applicazioni.

Toccherebbe capire se sia possibile dire ad Emacs: bloccati fino a quando l’applicazione parte, e continua ad eseguire il resto solo dopo che è partita. Una cosa del genere insomma.

Se qualcuno ne capisce qualcosa mi faccia sapere!


P.S.

Ho anche provato ad utilizzare l’hook exwm-manage-finish-hook, che dovrebbe essere eseguito dopo che il buffer viene caricato, ma sembra cadere nella stessa problematica.

Anche questa risorsa non aiuta, Optimizing Window Placement in EXWM - System Crafters, descrive varie cose che si possono fare dopo aver creato la finestra con EXWM, tipo cambiare il nome del buffer e via dicendo.

A me interessa proprio manipolare il layout di Emacs subito dopo aver creato l’applicazione, non tanto modificare le proprietà del buffer in cui si trova l’appliazione.

Un qualcosa che sembra ogni tanto funzionare, anche se è abbastanza orribile come soluzione, è mettere un time-delay tra l’invocazione di un processo e l’invocazione del processo successivo.

(defun custom-layout ()
  (interactive)
  (split-window-horizontally)
  (start-process "" nil "/usr/bin/chromium")
  (sleep-for 1.5)
  (other-window 1)
  (start-process "" nil "/usr/bin/chromium") 
  )

Questa soluzione però dipende molto dalle performance del momento, quindi sarebbe utile qualcosa di più strutturato.

1 Like

Purtroppo non so aiutarti in quanto non uso EXWM, ancora, come WM ma, sempre che non l’abbia gia visto, c’e’ questo video di Prot che descrive come disporre in automatico le fnestre, vedi se ti puo’ tornare utile.