From a9ec27edd74ecac1334cefd31740b6c6adc3ede6 Mon Sep 17 00:00:00 2001 From: Luflosi Date: Wed, 4 Dec 2019 00:04:52 +0100 Subject: [PATCH] Fix macOS keyboard shortcut encoding `glfwGetCocoaKeyEquivalent()` in `glfw/cocoa_window.m` expects the returned characters to be of type `unichar`, which won't work for all unicode characters because it is defined as `unsigned short` according to https://developer.apple.com/documentation/foundation/unichar?language=objc, which is only guaranteed to be at least 16 bits in size. The code calling this function also expects the encoding to be UTF-16. When I added the various keys in https://github.com/kovidgoyal/kitty/pull/1928, I missed these facts. This means, that `glfwGetCocoaKeyEquivalent()` will behave unexpectedly when called with any of the new-ish keys. Luckily this function is currently only used for determining the macOS shortcut for `new_os_window` but I plan on using it more in the future. Some of the constants, e.g. `NSBackspaceCharacter` are UTF-16 constants, so we can't just use UTF-8 everywhere. I fixed the problem by using either UTF-8 characters packed into a `uint32_t` or UTF-16 characters in a `unichar` and then converting them to a UTF-8 encoded char string. `NSEventModifierFlagNumericPad` isn't guaranteed to fit in a `unichar`, which made this undefined behaviour. It also didn't work. I tried to make it work using `NSEventModifierFlagNumericPad` as a modifier instead, as can be seen in this commit, but couldn't get it to work either because the constants used are native key codes and not unicode characters. Therefore the numpad keys will be removed in the next commit. --- glfw/cocoa_window.m | 301 +++++++++++++++++++++++-------------------- glfw/glfw.py | 2 +- kitty/cocoa_window.m | 6 +- kitty/glfw-wrapper.h | 2 +- kitty/glfw.c | 2 +- kitty/state.h | 2 +- 6 files changed, 171 insertions(+), 144 deletions(-) diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 63fd6ee2655..33b74e30cec 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -2179,8 +2179,7 @@ GLFWAPI void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun requestRenderFrame((_GLFWwindow*)w, callback); } -GLFWAPI void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, unsigned short *cocoa_key, int *cocoa_mods) { - *cocoa_key = 0; +GLFWAPI void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, char **cocoa_key, int *cocoa_mods) { *cocoa_mods = 0; if (glfw_mods & GLFW_MOD_SHIFT) @@ -2194,148 +2193,174 @@ GLFWAPI void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, unsigned sho if (glfw_mods & GLFW_MOD_CAPS_LOCK) *cocoa_mods |= NSEventModifierFlagCapsLock; + uint32_t utf_8_key = 0; + unichar utf_16_key = 0; + START_ALLOW_CASE_RANGE switch(glfw_key) { -#define K(ch, name) case GLFW_KEY_##name: *cocoa_key = ch; break; - K('!', EXCLAM); - K('"', DOUBLE_QUOTE); - K('#', NUMBER_SIGN); - K('$', DOLLAR); - K('&', AMPERSAND); - K('\'', APOSTROPHE); - K('(', PARENTHESIS_LEFT); - K(')', PARENTHESIS_RIGHT); - K('+', PLUS); - K(',', COMMA); - K('-', MINUS); - K('.', PERIOD); - K('/', SLASH); - K('0', 0); - K('1', 1); - K('2', 2); - K('3', 3); - K('5', 5); - K('6', 6); - K('7', 7); - K('8', 8); - K('9', 9); - K(':', COLON); - K(';', SEMICOLON); - K('<', LESS); - K('=', EQUAL); - K('>', GREATER); - K('@', AT); - K('[', LEFT_BRACKET); - K('\\', BACKSLASH); - K(']', RIGHT_BRACKET); - K('^', CIRCUMFLEX); - K('_', UNDERSCORE); - K('`', GRAVE_ACCENT); - K('a', A); - K('b', B); - K('c', C); - K('d', D); - K('e', E); - K('f', F); - K('g', G); - K('h', H); - K('i', I); - K('j', J); - K('k', K); - K('l', L); - K('m', M); - K('n', N); - K('o', O); - K('p', P); - K('q', Q); - K('r', R); - K('s', S); - K('t', T); - K('u', U); - K('v', V); - K('w', W); - K('x', X); - K('y', Y); - K('z', Z); - K(PARAGRAPH_UTF_8, PARAGRAPH); - K(MASCULINE_UTF_8, MASCULINE); - K(S_SHARP_UTF_8, S_SHARP); - K(A_GRAVE_LOWER_CASE_UTF_8, A_GRAVE); - K(A_DIAERESIS_LOWER_CASE_UTF_8, A_DIAERESIS); - K(A_RING_LOWER_CASE_UTF_8, A_RING); - K(AE_LOWER_CASE_UTF_8, AE); - K(C_CEDILLA_LOWER_CASE_UTF_8, C_CEDILLA); - K(E_GRAVE_LOWER_CASE_UTF_8, E_GRAVE); - K(E_ACUTE_LOWER_CASE_UTF_8, E_ACUTE); - K(I_GRAVE_LOWER_CASE_UTF_8, I_GRAVE); - K(N_TILDE_LOWER_CASE_UTF_8, N_TILDE); - K(O_GRAVE_LOWER_CASE_UTF_8, O_GRAVE); - K(O_DIAERESIS_LOWER_CASE_UTF_8, O_DIAERESIS); - K(O_SLASH_LOWER_CASE_UTF_8, O_SLASH); - K(U_GRAVE_LOWER_CASE_UTF_8, U_GRAVE); - K(U_DIAERESIS_LOWER_CASE_UTF_8, U_DIAERESIS); - K(CYRILLIC_A_LOWER_CASE_UTF_8, CYRILLIC_A); - K(CYRILLIC_BE_LOWER_CASE_UTF_8, CYRILLIC_BE); - K(CYRILLIC_VE_LOWER_CASE_UTF_8, CYRILLIC_VE); - K(CYRILLIC_GHE_LOWER_CASE_UTF_8, CYRILLIC_GHE); - K(CYRILLIC_DE_LOWER_CASE_UTF_8, CYRILLIC_DE); - K(CYRILLIC_IE_LOWER_CASE_UTF_8, CYRILLIC_IE); - K(CYRILLIC_ZHE_LOWER_CASE_UTF_8, CYRILLIC_ZHE); - K(CYRILLIC_ZE_LOWER_CASE_UTF_8, CYRILLIC_ZE); - K(CYRILLIC_I_LOWER_CASE_UTF_8, CYRILLIC_I); - K(CYRILLIC_SHORT_I_LOWER_CASE_UTF_8, CYRILLIC_SHORT_I); - K(CYRILLIC_KA_LOWER_CASE_UTF_8, CYRILLIC_KA); - K(CYRILLIC_EL_LOWER_CASE_UTF_8, CYRILLIC_EL); - K(CYRILLIC_EM_LOWER_CASE_UTF_8, CYRILLIC_EM); - K(CYRILLIC_EN_LOWER_CASE_UTF_8, CYRILLIC_EN); - K(CYRILLIC_O_LOWER_CASE_UTF_8, CYRILLIC_O); - K(CYRILLIC_PE_LOWER_CASE_UTF_8, CYRILLIC_PE); - K(CYRILLIC_ER_LOWER_CASE_UTF_8, CYRILLIC_ER); - K(CYRILLIC_ES_LOWER_CASE_UTF_8, CYRILLIC_ES); - K(CYRILLIC_TE_LOWER_CASE_UTF_8, CYRILLIC_TE); - K(CYRILLIC_U_LOWER_CASE_UTF_8, CYRILLIC_U); - K(CYRILLIC_EF_LOWER_CASE_UTF_8, CYRILLIC_EF); - K(CYRILLIC_HA_LOWER_CASE_UTF_8, CYRILLIC_HA); - K(CYRILLIC_TSE_LOWER_CASE_UTF_8, CYRILLIC_TSE); - K(CYRILLIC_CHE_LOWER_CASE_UTF_8, CYRILLIC_CHE); - K(CYRILLIC_SHA_LOWER_CASE_UTF_8, CYRILLIC_SHA); - K(CYRILLIC_SHCHA_LOWER_CASE_UTF_8, CYRILLIC_SHCHA); - K(CYRILLIC_HARD_SIGN_LOWER_CASE_UTF_8, CYRILLIC_HARD_SIGN); - K(CYRILLIC_YERU_LOWER_CASE_UTF_8, CYRILLIC_YERU); - K(CYRILLIC_SOFT_SIGN_LOWER_CASE_UTF_8, CYRILLIC_SOFT_SIGN); - K(CYRILLIC_E_LOWER_CASE_UTF_8, CYRILLIC_E); - K(CYRILLIC_YU_LOWER_CASE_UTF_8, CYRILLIC_YU); - K(CYRILLIC_YA_LOWER_CASE_UTF_8, CYRILLIC_YA); - K(CYRILLIC_IO_LOWER_CASE_UTF_8, CYRILLIC_IO); - - K(0x35, ESCAPE); - K('\r', ENTER); - K('\t', TAB); - K(NSBackspaceCharacter, BACKSPACE); - K(NSInsertFunctionKey, INSERT); - K(NSDeleteCharacter, DELETE); - K(NSLeftArrowFunctionKey, LEFT); - K(NSRightArrowFunctionKey, RIGHT); - K(NSUpArrowFunctionKey, UP); - K(NSDownArrowFunctionKey, DOWN); - K(NSPageUpFunctionKey, PAGE_UP); - K(NSPageDownFunctionKey, PAGE_DOWN); - K(NSHomeFunctionKey, HOME); - K(NSEndFunctionKey, END); - K(NSPrintFunctionKey, PRINT_SCREEN); +#define K8(ch, name) case GLFW_KEY_##name: utf_8_key = ch; break; +#define K16(ch, name) case GLFW_KEY_##name: utf_16_key = ch; break; +#define K16_numpad(ch, mods, name) case GLFW_KEY_##name: utf_16_key = ch; *cocoa_mods |= mods; break; + K8('!', EXCLAM); + K8('"', DOUBLE_QUOTE); + K8('#', NUMBER_SIGN); + K8('$', DOLLAR); + K8('&', AMPERSAND); + K8('\'', APOSTROPHE); + K8('(', PARENTHESIS_LEFT); + K8(')', PARENTHESIS_RIGHT); + K8('+', PLUS); + K8(',', COMMA); + K8('-', MINUS); + K8('.', PERIOD); + K8('/', SLASH); + K8('0', 0); + K8('1', 1); + K8('2', 2); + K8('3', 3); + K8('5', 5); + K8('6', 6); + K8('7', 7); + K8('8', 8); + K8('9', 9); + K8(':', COLON); + K8(';', SEMICOLON); + K8('<', LESS); + K8('=', EQUAL); + K8('>', GREATER); + K8('@', AT); + K8('[', LEFT_BRACKET); + K8('\\', BACKSLASH); + K8(']', RIGHT_BRACKET); + K8('^', CIRCUMFLEX); + K8('_', UNDERSCORE); + K8('`', GRAVE_ACCENT); + K8('a', A); + K8('b', B); + K8('c', C); + K8('d', D); + K8('e', E); + K8('f', F); + K8('g', G); + K8('h', H); + K8('i', I); + K8('j', J); + K8('k', K); + K8('l', L); + K8('m', M); + K8('n', N); + K8('o', O); + K8('p', P); + K8('q', Q); + K8('r', R); + K8('s', S); + K8('t', T); + K8('u', U); + K8('v', V); + K8('w', W); + K8('x', X); + K8('y', Y); + K8('z', Z); + K8(PARAGRAPH_UTF_8, PARAGRAPH); + K8(MASCULINE_UTF_8, MASCULINE); + K8(S_SHARP_UTF_8, S_SHARP); + K8(A_GRAVE_LOWER_CASE_UTF_8, A_GRAVE); + K8(A_DIAERESIS_LOWER_CASE_UTF_8, A_DIAERESIS); + K8(A_RING_LOWER_CASE_UTF_8, A_RING); + K8(AE_LOWER_CASE_UTF_8, AE); + K8(C_CEDILLA_LOWER_CASE_UTF_8, C_CEDILLA); + K8(E_GRAVE_LOWER_CASE_UTF_8, E_GRAVE); + K8(E_ACUTE_LOWER_CASE_UTF_8, E_ACUTE); + K8(I_GRAVE_LOWER_CASE_UTF_8, I_GRAVE); + K8(N_TILDE_LOWER_CASE_UTF_8, N_TILDE); + K8(O_GRAVE_LOWER_CASE_UTF_8, O_GRAVE); + K8(O_DIAERESIS_LOWER_CASE_UTF_8, O_DIAERESIS); + K8(O_SLASH_LOWER_CASE_UTF_8, O_SLASH); + K8(U_GRAVE_LOWER_CASE_UTF_8, U_GRAVE); + K8(U_DIAERESIS_LOWER_CASE_UTF_8, U_DIAERESIS); + K8(CYRILLIC_A_LOWER_CASE_UTF_8, CYRILLIC_A); + K8(CYRILLIC_BE_LOWER_CASE_UTF_8, CYRILLIC_BE); + K8(CYRILLIC_VE_LOWER_CASE_UTF_8, CYRILLIC_VE); + K8(CYRILLIC_GHE_LOWER_CASE_UTF_8, CYRILLIC_GHE); + K8(CYRILLIC_DE_LOWER_CASE_UTF_8, CYRILLIC_DE); + K8(CYRILLIC_IE_LOWER_CASE_UTF_8, CYRILLIC_IE); + K8(CYRILLIC_ZHE_LOWER_CASE_UTF_8, CYRILLIC_ZHE); + K8(CYRILLIC_ZE_LOWER_CASE_UTF_8, CYRILLIC_ZE); + K8(CYRILLIC_I_LOWER_CASE_UTF_8, CYRILLIC_I); + K8(CYRILLIC_SHORT_I_LOWER_CASE_UTF_8, CYRILLIC_SHORT_I); + K8(CYRILLIC_KA_LOWER_CASE_UTF_8, CYRILLIC_KA); + K8(CYRILLIC_EL_LOWER_CASE_UTF_8, CYRILLIC_EL); + K8(CYRILLIC_EM_LOWER_CASE_UTF_8, CYRILLIC_EM); + K8(CYRILLIC_EN_LOWER_CASE_UTF_8, CYRILLIC_EN); + K8(CYRILLIC_O_LOWER_CASE_UTF_8, CYRILLIC_O); + K8(CYRILLIC_PE_LOWER_CASE_UTF_8, CYRILLIC_PE); + K8(CYRILLIC_ER_LOWER_CASE_UTF_8, CYRILLIC_ER); + K8(CYRILLIC_ES_LOWER_CASE_UTF_8, CYRILLIC_ES); + K8(CYRILLIC_TE_LOWER_CASE_UTF_8, CYRILLIC_TE); + K8(CYRILLIC_U_LOWER_CASE_UTF_8, CYRILLIC_U); + K8(CYRILLIC_EF_LOWER_CASE_UTF_8, CYRILLIC_EF); + K8(CYRILLIC_HA_LOWER_CASE_UTF_8, CYRILLIC_HA); + K8(CYRILLIC_TSE_LOWER_CASE_UTF_8, CYRILLIC_TSE); + K8(CYRILLIC_CHE_LOWER_CASE_UTF_8, CYRILLIC_CHE); + K8(CYRILLIC_SHA_LOWER_CASE_UTF_8, CYRILLIC_SHA); + K8(CYRILLIC_SHCHA_LOWER_CASE_UTF_8, CYRILLIC_SHCHA); + K8(CYRILLIC_HARD_SIGN_LOWER_CASE_UTF_8, CYRILLIC_HARD_SIGN); + K8(CYRILLIC_YERU_LOWER_CASE_UTF_8, CYRILLIC_YERU); + K8(CYRILLIC_SOFT_SIGN_LOWER_CASE_UTF_8, CYRILLIC_SOFT_SIGN); + K8(CYRILLIC_E_LOWER_CASE_UTF_8, CYRILLIC_E); + K8(CYRILLIC_YU_LOWER_CASE_UTF_8, CYRILLIC_YU); + K8(CYRILLIC_YA_LOWER_CASE_UTF_8, CYRILLIC_YA); + K8(CYRILLIC_IO_LOWER_CASE_UTF_8, CYRILLIC_IO); + + K8(0x35, ESCAPE); + K8('\r', ENTER); + K8('\t', TAB); + K16(NSBackspaceCharacter, BACKSPACE); + K16(NSInsertFunctionKey, INSERT); + K16(NSDeleteCharacter, DELETE); + K16(NSLeftArrowFunctionKey, LEFT); + K16(NSRightArrowFunctionKey, RIGHT); + K16(NSUpArrowFunctionKey, UP); + K16(NSDownArrowFunctionKey, DOWN); + K16(NSPageUpFunctionKey, PAGE_UP); + K16(NSPageDownFunctionKey, PAGE_DOWN); + K16(NSHomeFunctionKey, HOME); + K16(NSEndFunctionKey, END); + K16(NSPrintFunctionKey, PRINT_SCREEN); case GLFW_KEY_F1 ... GLFW_KEY_F24: - *cocoa_key = NSF1FunctionKey + (glfw_key - GLFW_KEY_F1); break; + utf_16_key = NSF1FunctionKey + (glfw_key - GLFW_KEY_F1); break; case GLFW_KEY_KP_0 ... GLFW_KEY_KP_9: - *cocoa_key = NSEventModifierFlagNumericPad | (0x52 + (glfw_key - GLFW_KEY_KP_0)); break; - K((unichar)(0x41|NSEventModifierFlagNumericPad), KP_DECIMAL); - K((unichar)(0x43|NSEventModifierFlagNumericPad), KP_MULTIPLY); - K((unichar)(0x45|NSEventModifierFlagNumericPad), KP_ADD); - K((unichar)(0x4B|NSEventModifierFlagNumericPad), KP_DIVIDE); - K((unichar)(0x4E|NSEventModifierFlagNumericPad), KP_SUBTRACT); - K((unichar)(0x51|NSEventModifierFlagNumericPad), KP_EQUAL); -#undef K + utf_16_key = 0x52 + (glfw_key - GLFW_KEY_KP_0); *cocoa_mods |= NSEventModifierFlagNumericPad; break; + K16_numpad(0x41, NSEventModifierFlagNumericPad, KP_DECIMAL); + K16_numpad(0x43, NSEventModifierFlagNumericPad, KP_MULTIPLY); + K16_numpad(0x45, NSEventModifierFlagNumericPad, KP_ADD); + K16_numpad(0x4B, NSEventModifierFlagNumericPad, KP_DIVIDE); + K16_numpad(0x4E, NSEventModifierFlagNumericPad, KP_SUBTRACT); + K16_numpad(0x51, NSEventModifierFlagNumericPad, KP_EQUAL); +#undef K8 +#undef K16 +#undef K16_numpad END_ALLOW_CASE_RANGE } + if (utf_16_key != 0) { + NSString *tmp_cocoa_key = [NSString stringWithCharacters:&utf_16_key length:1]; + *cocoa_key = _glfw_strdup([tmp_cocoa_key UTF8String]); + } else { + // 5 chars for one UTF-8 character plus a null byte should be enough + // Use 4 * 4 + 1 chars to allow returning at least four unicode characters in the future, should the need arise + char tmp_cocoa_key[4 * 4 + 1]; + int str_pos = 0; + for (int i = 0; i < 4; i++) { + uint8_t byte = (utf_8_key >> 24) & 0xff; + utf_8_key <<= 8; + if (byte != 0) { + tmp_cocoa_key[str_pos] = byte; + str_pos++; + } + } + tmp_cocoa_key[str_pos] = 0; + *cocoa_key = _glfw_strdup(tmp_cocoa_key); + } } diff --git a/glfw/glfw.py b/glfw/glfw.py index f6d699d27fb..663c505c374 100755 --- a/glfw/glfw.py +++ b/glfw/glfw.py @@ -166,7 +166,7 @@ def generate_wrappers(glfw_header): GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWwindow *window, GLFWcocoatogglefullscreenfun callback) GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback) GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunching(GLFWapplicationwillfinishlaunchingfun callback) - void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, void* cocoa_key, int* cocoa_mods) + void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, char **cocoa_key, int* cocoa_mods) void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback) void* glfwGetX11Display(void) int32_t glfwGetX11Window(GLFWwindow* window) diff --git a/kitty/cocoa_window.m b/kitty/cocoa_window.m index cb167328a6d..b910bb04fd7 100644 --- a/kitty/cocoa_window.m +++ b/kitty/cocoa_window.m @@ -97,7 +97,7 @@ + (GlobalMenuTarget *) shared_instance @end -static unichar new_window_key = 0; +static char* new_window_key = NULL; static NSEventModifierFlags new_window_mods = 0; static PyObject* @@ -253,7 +253,7 @@ - (void)openFilesFromPasteboard:(NSPasteboard *)pasteboard type:(int)type { [preferences_menu_item setTarget:global_menu_target]; [appMenu addItem:preferences_menu_item]; if (new_window_key) { - NSString *s = [NSString stringWithCharacters:&new_window_key length:1]; + NSString *s = @(new_window_key); new_os_window_menu_item = [[NSMenuItem alloc] initWithTitle:@"New OS window" action:@selector(new_os_window:) keyEquivalent:s]; [new_os_window_menu_item setKeyEquivalentModifierMask:new_window_mods]; [new_os_window_menu_item setTarget:global_menu_target]; @@ -474,6 +474,8 @@ - (void)openFilesFromPasteboard:(NSPasteboard *)pasteboard type:(int)type { dockMenu = nil; if (notification_activated_callback) Py_DECREF(notification_activated_callback); notification_activated_callback = NULL; + free(new_window_key); + new_window_key = NULL; } // autoreleasepool } diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 420fbf8fac7..20257cebec9 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -2083,7 +2083,7 @@ typedef GLFWapplicationwillfinishlaunchingfun (*glfwSetApplicationWillFinishLaun glfwSetApplicationWillFinishLaunching_func glfwSetApplicationWillFinishLaunching_impl; #define glfwSetApplicationWillFinishLaunching glfwSetApplicationWillFinishLaunching_impl -typedef void (*glfwGetCocoaKeyEquivalent_func)(int, int, void*, int*); +typedef void (*glfwGetCocoaKeyEquivalent_func)(int, int, char**, int*); glfwGetCocoaKeyEquivalent_func glfwGetCocoaKeyEquivalent_impl; #define glfwGetCocoaKeyEquivalent glfwGetCocoaKeyEquivalent_impl diff --git a/kitty/glfw.c b/kitty/glfw.c index 5737d65867d..cb808c015a7 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1079,7 +1079,7 @@ set_custom_cursor(PyObject *self UNUSED, PyObject *args) { #ifdef __APPLE__ void -get_cocoa_key_equivalent(int key, int mods, unsigned short *cocoa_key, int *cocoa_mods) { +get_cocoa_key_equivalent(int key, int mods, char **cocoa_key, int *cocoa_mods) { glfwGetCocoaKeyEquivalent(key, mods, cocoa_key, cocoa_mods); } diff --git a/kitty/state.h b/kitty/state.h index 96b253b275c..8886e5eb26d 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -225,7 +225,7 @@ void set_titlebar_color(OSWindow *w, color_type color); FONTS_DATA_HANDLE load_fonts_data(double, double, double); void send_prerendered_sprites_for_window(OSWindow *w); #ifdef __APPLE__ -void get_cocoa_key_equivalent(int, int, unsigned short*, int*); +void get_cocoa_key_equivalent(int, int, char**, int*); typedef enum { PREFERENCES_WINDOW = 1, NEW_OS_WINDOW = 2,