MC's journal

Pungenday, the 31 day of The Aftermath in the YOLD 3176

Emacsclient flyttar Emacs-fönster!

Jag upptäckte för ett tag sedan en mystisk sak med Emacs beteende under X tillsammans med emacsclient.

Säg att du har en Emacs igång med Emacs-fönster på en annan workspace och att du har server-raise-frame satt som icke-nil (det är default-värdet). Säg att du nu startar nu emacsclient. Då flyttas plötsligt ett av dina Emacs-fönster, vilket som helst, till den workspace du är på! Den flyttar också muspekaren till det flyttade fönstret.

Jag upplevde detta först under min egen fönsterhanterare, mcwm, men verifierade beteendet också under ctwm, evilwm och openbox.

Jag tvingade Emacs att sluta göra så genom att helt enkelt i mcwm förbjuda fönster som redan finns i en annan workspace-lista att dyka upp på den aktuella workspacen (om det nu inte är mcwm själv som bestämt det, förstås). Det löste problemet, åtminstone delvis. Kvar är problemet med en flyttande markör. Emacs flyttar fortfarande markören dit den tror att den just flyttat fönstret.

Ett annat sätt att lösa problemet är förstås

(setq server-raise-frame nil)

och det löser ju också muspekarens förflyttning. Däremot löser det ju inte det generella fallet med X-klienter som själva försöker smita från workspaces. Det vill jag inte tillåta i mcwm.

Om man skall lösa problemet ordentligt, inklusive muspekarens flytt, så kanske man kan ändra i select-frame-set-input-focus i frame.el. Den innehåller:

  "Select FRAME, raise it, and set input focus, if possible.
If `mouse-autoselect-window' is non-nil, also move mouse pointer
to FRAME's selected window.  Otherwise, if `focus-follows-mouse'
is non-nil, move mouse cursor to FRAME."
  (select-frame frame)
  (raise-frame frame)
  ;; Ensure, if possible, that FRAME gets input focus.
  (when (memq (window-system frame) '(x w32 ns))
(x-focus-frame frame))
  ;; Move mouse cursor if necessary.
  (cond
   (mouse-autoselect-window
(let ((edges (window-inside-edges (frame-selected-window frame))))
  ;; Move mouse cursor into FRAME's selected window to avoid that
  ;; Emacs mouse-autoselects another window.
  (set-mouse-position frame (nth 2 edges) (nth 1 edges))))
   (focus-follows-mouse
;; Move mouse cursor into FRAME to avoid that another frame gets
;; selected by the window manager.
(set-mouse-position frame (1- (frame-width frame)) 0))))

Här ser vi att koden antar att raise-frame fungerade. Vad händer om fönstret inte är mappat? Då flyttas alltså muspekaren i alla fall.

I Emacs-koden finns raise-frame som C-funktion i frame.c. Den kallar på make_frame_visible() som sedan kallar på xterm.c:x_make_frame_visible(). Den ser ut att göra så rätt den kan, tycker jag, men den returnerar inga hints om att den kanske gett upp ifall fönsterhanteraren vägrade mappa fönstret.

Tillbaka till elispkoden i select-frame-set-input-focus som jag citerade ovan: Om man skulle peta in en koll med frame-visible-p efter raise-frame för att se om operationen att göra Emacs-fönstret synlig misslyckades så kan man ge upp. Det skulle lösa allas problem, vad jag vet. Jag vet ännu inte vad Emacs-utvecklare tycker om det, men kanske skall försöka nämna det någonstans.


Written by MC using Emacs and friends.