Emacs on WSL로 시작할 때 최대화하고 싶습니다.

16020 단어 WSLEmacs

개요



WSL 환경 (xserver에는 vcxsrv 사용)에서 Emacs를 극대화하는 방법을 찾을 때까지 로그

문제점



최대화 시작을 위해 (set-frame-parameter nil 'fullscreen 'maximized) 있지만 위치가 이상합니다.

프레임 위치를 (0,0)으로 설정해도 이상합니다.


윈도우의 타이틀 바 등은 시스템(window manager)이 그려져 있는 것인가? (wayland에서 그런 일을 한 것 같지 않아..)
원래 "최대화"또는 "원본 크기로 되돌리기"버튼을 클릭해도 frame-parameterfullscreen에 변화 없음
x의 window manager가 아니기 때문에 Emacs에 최대화의 이벤트 날고 있지 않나?사이즈의 설정만 되고 있다고 예상
(vcxsrv가 나쁜가?)

Emacs에서 제공하는 극대화 방법을 여러 가지 시도



xwindow 사용하고 있기 때문에
시도
(when (eq system-type 'gnu/linux)
  (defun x11-maximize-frame ()
    "Maximize the current frame (to full screen)"
    (interactive)
    (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 '(2 "_NET_WM_STATE_MAXIMIZED_HORZ" 0))
    (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 '(2 "_NET_WM_STATE_MAXIMIZED_VERT" 0)))
  (run-with-idle-timer 0.01 nil 'x11-maximize-frame)
  )

(when (eq system-type 'windows-nt)
  (w32-send-sys-command 61488)
  )

x server 메시지로 최대화



vcxsrv의 로그 보는 한, 아무것도 x11의 메시지 보내기 잘 말하지 않은 것 같습니다.
x window manager를 사용하지 않습니까?
windows에서 다른 앱과 같은 모양으로 사용하고 싶기 때문에 windows의 window manager로 이동하고 싶습니다.

windows의 window manager에게 메시지 보내기


w32-send-sys-command는 Windows 용 빌드에서만 사용할 수 있습니다.
github에서 리포지토리 내 grep (부끄러워하면서 이런 일을 처음 알았습니다)하면 C의 함수 호출하는 것밖에 모른다
win32api wm_syscommand sc_maximize를 부르는 것 같습니다.

win32api의 SendMessage() 사용



바이너리보다 스크립트가 더 좋을까 powershell를 사용해 보았습니다.

powershell 스크립트 시작까지


powershell에서 win32api SendMessage() 할 수 있음을 알았지 만 보안 관련으로 귀찮은 것으로 나타났습니다.
해결 방법은 두 가지. 표준 입력에서 제공
cat path\to\w32_wm_syscmd.ps1 | powershell.exe -command -
(WSL環境なのでLinuxコマンドとWindowsコマンドをpipeできる)

또는, 일시적으로 policy를 변경해 로컬의 파일의 실행을 허가한다
참조 소스: PowerShell 스크립트를 쉽게 실행
powershell.exe -ExecutionPolicy RemoteSigned -File path\to\w32_wm_syscmd.ps1
(-Fileでスクリプトファイル指定)

이번에는 아래를 사용했습니다.

SendMessage()까지



스크립트 설명은 접히지만 C# 코드를 powershell에서 호출 할 수있는 것을 이용하고 C#에서 win32api dll을로드하고 사용합니다.
자세한 내용은 powershell에서 Win32 API 사용(powershell 2.0 이상)

w32_wm_syscmd.ps1
# file : w32_wm_syscmd.ps1 [Windows PowerShell script]
# usage: w32_wm_syscmd.ps1 {"maximize","minimize","restore"} [process-name="vcxsrv"]
# execute win32api::SendMessage(WM_SYSCOMMAND) to Maximize/Minimize/Restore window.
# arg1 selects Maximize, Minimize, Restore. mandatory.
# arg2 specify process-name. optionary.

Param(
    [ValidateSet("maximize","minimize","restore")][String]$cmd,
    [String]$procName = "vcxsrv"
)

# Import win32api by C# syntax
$Win32 = &{
    $cscode = @"
[DllImport("user32.dll")]
public static extern long SendMessage(
    IntPtr hWnd,
    UInt32 Msg,
    int wParam,
    long lParam
);
"@
    return (add-type -memberDefinition $cscode -name "Win32ApiFunctions" -passthru)
}

# Set win32api defines
$WM_SYSCOMMAND = 0x0112
$SC_MAXIMIZE   = 0xF030
$SC_MINIMIZE   = 0xF020
$SC_RESTORE    = 0xF120

switch($cmd){
    "maximize" { $scCmd = $SC_MAXIMIZE; }
    "minimize" { $scCmd = $SC_MINIMIZE; }
    "restore"  { $scCmd = $SC_RESTORE;  }
    default    { $scCmd = $SC_MAXIMIZE; }
}

# Get processes list
$psArray = [System.Diagnostics.Process]::GetProcesses()

# Search SendMessage tartget 
foreach ($ps in $psArray) {
    $hWnd = $ps.MainWindowHandle.ToInt32()
    $name = $ps.Name

    if ( $name -eq $procName ) {
        $retval = $Win32::SendMessage( $hWnd, $WM_SYSCOMMAND, $scCmd, 0)
    return "($name $hWnd $retval)"
    }
}
return "()"

시도해 보았던 것은 wsl에서 시작한 x11 window window handle은 각 프로세스가 없으며 vcxsrv 프로세스가 있고 마지막으로 포커스되었지만 handle을 가지고 있습니다.
(다른 xserver는 어떻게되고 있는지는 모르겠지만)
Emacs에 초점을 맞추고 있다고 가정하여 vcxsrv에 최대화 메시지 보내기
Emacs를 시작하는 동안 다른 x11 프로세스를 시작하지 않으면 문제가되지 않습니다.

Emacs에서 호출



비동기로 명령을 호출하고 싶기 때문에 start-process 시도했지만 작동하지 않습니다.
우선 shell-command에서 잘 작동했기 때문에 여기를 사용하십시오.
(프로세스 일람을 취해 찾는 처리가 있으므로 시간이 걸려 버리지만 어쩔 수 없다)

그런 다음 기존 toggle-frame-maximized을 덮어 쓰기 위해 advice :around

frame-maximize.el
(defvar frame-wsl-powershell-path nil)
(defvar frame-wsl-w32-sys-cmd-path "path\\\\to\\\\w32_wm_syscmd.ps1")
(defvar frame-wsl-wm-name "vcxsrv")

;; Toggle flag. Do not touch this.
(setq frame-wsl-maximize nil)

(defun frame-maximized-wsl (maximize)
  "If MAXIMIZE is not nil, frame maximize, or frame restore
This function works only with the Windows Subsystem for Linux.
And, use powershell script for win32api::SendMessage().

You can customize these variables for your enviroment.
`frame-wsl-powershell-path' Path to powershell.exe. Maybe not need.
`frame-wsl-w32-sys-cmd-path' Path to powershell script (w32_wm_syscmd.ps1).
`frame-wsl-wm-name' Process name (e.g. vcxsrv) to get window handle.
"
  (let ((powershell (or frame-wsl-powershell-path "powershell.exe"))
    (powershell-opt "-ExecutionPolicy RemoteSigned -File")
    (w32-wm-syscmd (or frame-wsl-w32-sys-cmd-path "w32_wm_syscmd.ps1"))
    (w32-wm-syscmd-arg1 (if maximize "maximize" "restore"))
    (w32-wm-syscmd-arg2 (or frame-wsl-wm-name "")))
    (setq frame-wsl-maximize maximize)
    (shell-command
     (format "%s %s %s %s %s"
         powershell powershell-opt
         w32-wm-syscmd w32-wm-syscmd-arg1 w32-wm-syscmd-arg2))
    )
  )

(defun toggle-frame-maximized-advice (orig-func &rest args)
  (if frame-wsl-maximize
      (frame-maximized-wsl nil)
      (frame-maximized-wsl t) ) )

;; override toggle-frame-maximized
(advice-add 'toggle-frame-maximized :around 'toggle-frame-maximized-advice)

그래서, 프레임의 조작 (툴바 지우기, 스크롤 바 지우기 등) 끝난 최종 단계에서 (toggle-frame-maximized)적어도 내 환경에서 갈 수 있었던

마지막으로



더 쉬운 방법이 있으면 알려주세요.
그리고 emacs-lisp의 깨끗한 쓰기를 알고 싶습니다.

추가



재부팅 후 또는 잠자기에서 복귀 한 후 새로 이맥스를 시작하면 작동하지 않았습니다.
구체적으로는, 타이틀 바의 상태적으로는 최대화 상태인데 윈도우 사이즈가 중반(toggle-frame-maximized) 전에 (set-frame-parameter nil 'fullscreen 'maximized) 잘 작동했습니다.
아무래도 vcxsrv가 가지는 상태에 의해 잘 안되는 것 같습니다.
외부 (Windows 창 관리자)에서 최대화 만 해도
내 (xwindow)의 상태에 영향을받는 것 같습니다.
자세한 내용은 모르겠지만 ...

좋은 웹페이지 즐겨찾기