From 9c03d2554317147af7ae3588a0a3117e4c6fec2f Mon Sep 17 00:00:00 2001 From: Fredrick Brennan Date: Sun, 28 Nov 2021 16:18:39 -0500 Subject: [PATCH] Add back X11 legacy WM_NAME encodings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #4924. Based on patches of the past, such as this work by James Cloos in July 2010: https://github.com/exg/rxvt-unicode/commit/d7d98751b7385416ad1694b5f1fde6c312ba20d5, as well as code comments in the Perl module X11::Protocol::WM (https://metacpan.org/pod/X11::Protocol::WM) and even the code to Xlib itself, which taught me that we should never have been using `XStoreName`, all it does is call `XChangeProperty`, hardcoded to `XA_STRING`! What can I say, when the task is old school, the sources are too 😂 --- src/video/x11/SDL_x11messagebox.c | 30 ++-------------- src/video/x11/SDL_x11sym.h | 3 ++ src/video/x11/SDL_x11video.c | 8 +++++ src/video/x11/SDL_x11window.c | 60 +++++++++++++++++++------------ src/video/x11/SDL_x11window.h | 2 ++ 5 files changed, 53 insertions(+), 50 deletions(-) diff --git a/src/video/x11/SDL_x11messagebox.c b/src/video/x11/SDL_x11messagebox.c index 8eda7c82c..069a2df58 100644 --- a/src/video/x11/SDL_x11messagebox.c +++ b/src/video/x11/SDL_x11messagebox.c @@ -404,11 +404,10 @@ X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data ) int x, y; XSizeHints *sizehints; XSetWindowAttributes wnd_attr; - Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_NAME; + Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG; Display *display = data->display; SDL_WindowData *windowdata = NULL; const SDL_MessageBoxData *messageboxdata = data->messageboxdata; - char *title_locale = NULL; if ( messageboxdata->window ) { SDL_DisplayData *displaydata = @@ -452,32 +451,7 @@ X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data ) X11_XSetTransientForHint( display, data->window, windowdata->xwindow ); } - X11_XStoreName( display, data->window, messageboxdata->title ); - _NET_WM_NAME = X11_XInternAtom(display, "_NET_WM_NAME", False); - - title_locale = SDL_iconv_utf8_locale(messageboxdata->title); - if (title_locale) { - XTextProperty titleprop; - Status status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop); - SDL_free(title_locale); - if (status) { - X11_XSetTextProperty(display, data->window, &titleprop, XA_WM_NAME); - X11_XFree(titleprop.value); - } - } - -#ifdef X_HAVE_UTF8_STRING - if (SDL_X11_HAVE_UTF8) { - XTextProperty titleprop; - Status status = X11_Xutf8TextListToTextProperty(display, (char **) &messageboxdata->title, 1, - XUTF8StringStyle, &titleprop); - if (status == Success) { - X11_XSetTextProperty(display, data->window, &titleprop, - _NET_WM_NAME); - X11_XFree(titleprop.value); - } - } -#endif + SDL_X11_SetWindowTitle(display, data->window, (char*)messageboxdata->title); /* Let the window manager know this is a dialog box */ _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index db8715ac4..ba08ea9db 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -156,6 +156,9 @@ SDL_X11_SYM(SDL_X11_XESetWireToEventRetType,XESetWireToEvent,(Display* a,int b,S SDL_X11_SYM(SDL_X11_XESetEventToWireRetType,XESetEventToWire,(Display* a,int b,SDL_X11_XESetEventToWireRetType c),(a,b,c),return) SDL_X11_SYM(void,XRefreshKeyboardMapping,(XMappingEvent *a),(a),) SDL_X11_SYM(int,XQueryTree,(Display* a,Window b,Window* c,Window* d,Window** e,unsigned int* f),(a,b,c,d,e,f),return) +SDL_X11_SYM(Bool,XSupportsLocale,(void),(),return) +SDL_X11_SYM(void,XSetWMName,(Display* a,Window b,XTextProperty* c),(a,b,c),return) +SDL_X11_SYM(Status,XmbTextListToTextProperty,(Display* a,char** b,int c,XICCEncodingStyle d,XTextProperty* e),(a,b,c,d,e),return) #if SDL_VIDEO_DRIVER_X11_XFIXES SDL_X11_MODULE(XFIXES) diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index 92eff8318..6d2cd0713 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -460,6 +460,14 @@ X11_VideoInit(_THIS) X11_InitXfixes(_this); #endif /* SDL_VIDEO_DRIVER_X11_XFIXES */ +#ifndef X_HAVE_UTF8_STRING + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "X server doesn't support UTF8_STRING, a feature introduced in 2000! This is likely to become a hard error in a future libSDL2."); +#endif + + if (X11_XSupportsLocale() != True) { + return SDL_SetError("Current locale not supported by X server, cannot continue."); + } + if (X11_InitKeyboard(_this) != 0) { return -1; } diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 8c0d31d38..48f0cc60e 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -716,9 +716,11 @@ X11_GetWindowTitle(_THIS, Window xwindow) 0L, 8192L, False, XA_STRING, &real_type, &real_format, &items_read, &items_left, &propdata); if (status == Success && propdata) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Failed to convert _WM_NAME title expecting UTF8! Title: %s", title); title = SDL_iconv_string("UTF-8", "", SDL_static_cast(char*, propdata), items_read+1); X11_XFree(propdata); } else { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not get any window title response from Xorg, returning empty string!"); title = SDL_strdup(""); } } @@ -729,30 +731,11 @@ void X11_SetWindowTitle(_THIS, SDL_Window * window) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + Window xwindow = data->xwindow; Display *display = data->videodata->display; - Status status; - const char *title = window->title ? window->title : ""; + char *title = window->title ? window->title : ""; - Atom UTF8_STRING = data->videodata->UTF8_STRING; - Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME; - Atom WM_NAME = data->videodata->WM_NAME; - - X11_XChangeProperty(display, data->xwindow, WM_NAME, UTF8_STRING, 8, 0, (const unsigned char *) title, SDL_strlen(title)); - - status = X11_XChangeProperty(display, data->xwindow, _NET_WM_NAME, UTF8_STRING, 8, 0, (const unsigned char *) title, SDL_strlen(title)); - - if (status != 1) { - char *x11_error = NULL; - char x11_error_locale[256]; - if (X11_XGetErrorText(display, status, x11_error_locale, sizeof(x11_error_locale)) == Success) - { - x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale)+1); - SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "Error when setting X11 window title to %s: %s\n", title, x11_error); - SDL_free(x11_error); - } - } - - X11_XFlush(display); + SDL_X11_SetWindowTitle(display, xwindow, title); } void @@ -1888,6 +1871,39 @@ X11_FlashWindow(_THIS, SDL_Window * window, SDL_FlashOperation operation) return 0; } +bool SDL_X11_SetWindowTitle(Display* display, Window xwindow, char* title) { + Atom _NET_WM_NAME = X11_XInternAtom(display, "_NET_WM_NAME", False); + XTextProperty titleprop; + int conv = X11_XmbTextListToTextProperty(display, (char**) &title, 1, XStdICCTextStyle, &titleprop); + Status status; + + if (conv == 0) { + X11_XSetTextProperty(display, xwindow, &titleprop, XA_WM_NAME); + X11_XFree(titleprop.value); + // we know this can't be a locale error as we checked X locale validity in X11_VideoInit + } else if (conv <= 0) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "X11 reporting it's out of memory"); + return EXIT_FAILURE; + } else { // conv >= 0 + SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "%d characters were not convertable to the current locale!", conv); + return EXIT_FAILURE; + } + +#ifdef X_HAVE_UTF8_STRING + status = X11_Xutf8TextListToTextProperty(display, (char **) &title, 1, XUTF8StringStyle, &titleprop); + if (status == Success) { + X11_XSetTextProperty(display, xwindow, &titleprop, _NET_WM_NAME); + X11_XFree(titleprop.value); + } else { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Failed to convert title to UTF8! Bad encoding, or bad Xorg encoding? Window title: «%s»", title); + return EXIT_FAILURE; + } +#endif + + X11_XFlush(display); + return EXIT_SUCCESS; +} + #endif /* SDL_VIDEO_DRIVER_X11 */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index bf01e1a2a..dd66af795 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -117,6 +117,8 @@ extern int X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled); extern void X11_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept); extern int X11_FlashWindow(_THIS, SDL_Window * window, SDL_FlashOperation operation); +bool SDL_X11_SetWindowTitle(Display* display, Window xwindow, char* string); + #endif /* SDL_x11window_h_ */ /* vi: set ts=4 sw=4 expandtab: */