Emacs 29 pgtk woes

Emacs on my systems has had an issue where IME inputs would pass through to Emacs instead of going to the IME. For instance, 「新鮮」 is typed as vupvu0 RET; some characters would slip through into Emacs. I'm not sure if it's just my configuration or not.

In Emacs 29, when not using pgtk, the issue persists, no change here. But if I use x-gtk-use-native-input, the problem goes away — mostly. Now Shift no longer registers for the IME. For example, I use Kana input in Mozc to type Japanese on my US-layout keyboard, and there を is typed as Shift-0, while 0 on its own types わ. With this issue, that's no longer possible.

When using pgtk, on the other hand, it appears to be fixed entirely. Except, Emacs pops a gigantic irregular warning that pgtk should not be used under X because it causes sporadic crashes (I don't care) and “various issues with keyboard input” (such as with C-; and C-S-u as the NEWS mentions) (but it literally fixes a major issue for me).

This thing is implemented in pgtk_display_x_warning as a normal GTK dialog instead of using literally any other warning mechanisms available in Emacs.

/* If the PGTK port is being used under X, complain very loudly, as
   that isn't supported.  */
pgtk_display_x_warning (dpy);
src/pgtkterm.c, line 6802

At least give me the option to disable it!

As things stand, I'm not seeing a good justification for this use case to be declared unsupported to this extent. An irregular warning like this would be justified if things would be extremely broken, but you still want the user to at least have the option to try. Pgtk isn't that broken, and if the point is to tell users you're on your own this is the wrong way to do it.

Update 2023-09-01: here's my workaround:

  (when (and (display-graphic-p)
             (executable-find "xdotool"))
    (when-let (window-id (ignore-errors
                             "xdotool" "search"
                             "--pid" (format "%s" (emacs-pid))
                             "--name" "^Warning$")))
        "xdotool" "windowclose" window-id))))

Where k/once-after-make-frame adds a self-removing hook to server-after-make-frame-hook:

(defmacro k/once-after-make-frame (&rest body)
  "Eval BODY on `server-after-make-frame-hook' just once."
  (declare (indent 0))
  `(let (func)
     ;; Using `setq' allows the function itself to see the variable.
     ;; I learned this trick from deferred.el.
     (setq func (lambda ()
                  (remove-hook 'server-after-make-frame-hook func)))
     (add-hook 'server-after-make-frame-hook func)))

And k/call-process-to-string is a call-process wrapper:

(defun k/call-process-to-string (command &rest args)
  "Call COMMAND with ARGS; return stdout.

If COMMAND returns with a non-zero exit code, signal an error."
  (declare (indent 0))
    (let ((code (apply #'call-process command nil '(t nil) nil args)))
      (unless (= 0 code)
        (error "%s exited with exit code %s" command code)))
    (string-trim (buffer-string))))