mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 21:21:06 +01:00 
			
		
		
		
	Backends: Win32, SDL, GLFW: only honor io.WantSetMousePos when focused + fix GLFW uninstalling handler + tweaks to reduce branch drift with docking. (#787, #2445, #2696, #3751, #4377)
This commit is contained in:
		| @@ -55,7 +55,7 @@ | ||||
| #define GLFW_HAS_WINDOW_ALPHA         (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity | ||||
| #define GLFW_HAS_PER_MONITOR_DPI      (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale | ||||
| #define GLFW_HAS_VULKAN               (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface | ||||
| #ifdef GLFW_RESIZE_NESW_CURSOR  // let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? | ||||
| #ifdef GLFW_RESIZE_NESW_CURSOR        // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? | ||||
| #define GLFW_HAS_NEW_CURSORS          (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR | ||||
| #else | ||||
| #define GLFW_HAS_NEW_CURSORS          (0) | ||||
| @@ -116,7 +116,7 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) | ||||
| void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) | ||||
| { | ||||
|     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | ||||
|     if (bd->PrevUserCallbackMousebutton != NULL) | ||||
|     if (bd->PrevUserCallbackMousebutton != NULL && window == bd->Window) | ||||
|         bd->PrevUserCallbackMousebutton(window, button, action, mods); | ||||
|  | ||||
|     if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(bd->MouseJustPressed)) | ||||
| @@ -126,7 +126,7 @@ void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int acti | ||||
| void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) | ||||
| { | ||||
|     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | ||||
|     if (bd->PrevUserCallbackScroll != NULL) | ||||
|     if (bd->PrevUserCallbackScroll != NULL && window == bd->Window) | ||||
|         bd->PrevUserCallbackScroll(window, xoffset, yoffset); | ||||
|  | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
| @@ -137,7 +137,7 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo | ||||
| void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) | ||||
| { | ||||
|     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | ||||
|     if (bd->PrevUserCallbackKey != NULL) | ||||
|     if (bd->PrevUserCallbackKey != NULL && window == bd->Window) | ||||
|         bd->PrevUserCallbackKey(window, key, scancode, action, mods); | ||||
|  | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
| @@ -174,7 +174,7 @@ void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered) | ||||
| void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) | ||||
| { | ||||
|     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | ||||
|     if (bd->PrevUserCallbackChar != NULL) | ||||
|     if (bd->PrevUserCallbackChar != NULL && window == bd->Window) | ||||
|         bd->PrevUserCallbackChar(window, c); | ||||
|  | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
| @@ -298,6 +298,7 @@ void ImGui_ImplGlfw_Shutdown() | ||||
|  | ||||
|     if (bd->InstalledCallbacks) | ||||
|     { | ||||
|         glfwSetCursorEnterCallback(bd->Window, bd->PrevUserCallbackCursorEnter); | ||||
|         glfwSetMouseButtonCallback(bd->Window, bd->PrevUserCallbackMousebutton); | ||||
|         glfwSetScrollCallback(bd->Window, bd->PrevUserCallbackScroll); | ||||
|         glfwSetKeyCallback(bd->Window, bd->PrevUserCallbackKey); | ||||
| @@ -316,32 +317,32 @@ void ImGui_ImplGlfw_Shutdown() | ||||
| static void ImGui_ImplGlfw_UpdateMousePosAndButtons() | ||||
| { | ||||
|     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | ||||
|  | ||||
|     // Update buttons | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|  | ||||
|     const ImVec2 mouse_pos_prev = io.MousePos; | ||||
|     io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); | ||||
|  | ||||
|     // Update mouse buttons | ||||
|     // (if a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame) | ||||
|     for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) | ||||
|     { | ||||
|         // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. | ||||
|         io.MouseDown[i] = bd->MouseJustPressed[i] || glfwGetMouseButton(bd->Window, i) != 0; | ||||
|         bd->MouseJustPressed[i] = false; | ||||
|     } | ||||
|  | ||||
| #ifdef __EMSCRIPTEN__ | ||||
|     const bool focused = true; // Emscripten | ||||
|     const bool focused = true; | ||||
| #else | ||||
|     const bool focused = glfwGetWindowAttrib(bd->Window, GLFW_FOCUSED) != 0; | ||||
| #endif | ||||
|     GLFWwindow* mouse_window = (bd->MouseWindow == bd->Window || focused) ? bd->Window : NULL; | ||||
|  | ||||
|     // Update mouse position | ||||
|     const ImVec2 mouse_pos_backup = io.MousePos; | ||||
|     io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); | ||||
|     if (io.WantSetMousePos) | ||||
|     { | ||||
|         if (focused) | ||||
|             glfwSetCursorPos(bd->Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y); | ||||
|     } | ||||
|     else if (mouse_window != NULL) | ||||
|     // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) | ||||
|     if (io.WantSetMousePos && focused) | ||||
|         glfwSetCursorPos(bd->Window, (double)mouse_pos_prev.x, (double)mouse_pos_prev.y); | ||||
|  | ||||
|     // Set Dear ImGui mouse position from OS position | ||||
|     if (mouse_window != NULL) | ||||
|     { | ||||
|         double mouse_x, mouse_y; | ||||
|         glfwGetCursorPos(mouse_window, &mouse_x, &mouse_y); | ||||
|   | ||||
| @@ -59,10 +59,11 @@ | ||||
| #include "TargetConditionals.h" | ||||
| #endif | ||||
|  | ||||
| #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE    SDL_VERSION_ATLEAST(2,0,4) | ||||
| #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE    (SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)) | ||||
| #define SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH    SDL_VERSION_ATLEAST(2,0,5) | ||||
| #define SDL_HAS_VULKAN                      SDL_VERSION_ATLEAST(2,0,6) | ||||
|  | ||||
| // SDL Data | ||||
| struct ImGui_ImplSDL2_Data | ||||
| { | ||||
|     SDL_Window* Window; | ||||
| @@ -156,6 +157,17 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window) | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|     IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!"); | ||||
|  | ||||
|     // Check and store if we are on a SDL backend that supports global mouse position | ||||
|     // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list) | ||||
|     const char* sdl_backend = SDL_GetCurrentVideoDriver(); | ||||
|     const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" }; | ||||
|     bool mouse_can_use_global_state = false; | ||||
| #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE | ||||
|     for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++) | ||||
|         if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0) | ||||
|             mouse_can_use_global_state = true; | ||||
| #endif | ||||
|  | ||||
|     // Setup backend capabilities flags | ||||
|     ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)(); | ||||
|     io.BackendPlatformUserData = (void*)bd; | ||||
| @@ -164,6 +176,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window) | ||||
|     io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;        // We can honor io.WantSetMousePos requests (optional, rarely used) | ||||
|  | ||||
|     bd->Window = window; | ||||
|     bd->MouseCanUseGlobalState = mouse_can_use_global_state; | ||||
|  | ||||
|     // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array. | ||||
|     io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB; | ||||
| @@ -204,20 +217,11 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window) | ||||
|     bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); | ||||
|     bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO); | ||||
|  | ||||
|     // Check and store if we are on a SDL backend that supports global mouse position | ||||
|     // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list) | ||||
|     const char* sdl_backend = SDL_GetCurrentVideoDriver(); | ||||
|     const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" }; | ||||
|     bd->MouseCanUseGlobalState = false; | ||||
|     for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++) | ||||
|         if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0) | ||||
|             bd->MouseCanUseGlobalState = true; | ||||
|  | ||||
| #ifdef _WIN32 | ||||
|     SDL_SysWMinfo wmInfo; | ||||
|     SDL_VERSION(&wmInfo.version); | ||||
|     SDL_GetWindowWMInfo(window, &wmInfo); | ||||
|     io.ImeWindowHandle = wmInfo.info.win.window; | ||||
|     SDL_SysWMinfo info; | ||||
|     SDL_VERSION(&info.version); | ||||
|     if (SDL_GetWindowWMInfo(window, &info)) | ||||
|         io.ImeWindowHandle = info.info.win.window; | ||||
| #else | ||||
|     (void)window; | ||||
| #endif | ||||
| @@ -278,55 +282,59 @@ void ImGui_ImplSDL2_Shutdown() | ||||
|  | ||||
| static void ImGui_ImplSDL2_UpdateMousePosAndButtons() | ||||
| { | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|     ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|  | ||||
|     // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) | ||||
|     if (io.WantSetMousePos) | ||||
|         SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y); | ||||
|     else | ||||
|     ImVec2 mouse_pos_prev = io.MousePos; | ||||
|     io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); | ||||
|  | ||||
|     int mx, my; | ||||
|     Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my); | ||||
|     // Update mouse buttons | ||||
|     int mouse_x_local, mouse_y_local; | ||||
|     Uint32 mouse_buttons = SDL_GetMouseState(&mouse_x_local, &mouse_y_local); | ||||
|     io.MouseDown[0] = bd->MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;  // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. | ||||
|     io.MouseDown[1] = bd->MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; | ||||
|     io.MouseDown[2] = bd->MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; | ||||
|     bd->MousePressed[0] = bd->MousePressed[1] = bd->MousePressed[2] = false; | ||||
|  | ||||
| #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) | ||||
|     SDL_Window* focused_window = SDL_GetKeyboardFocus(); // Mouse position won't be reported unless window is focused. | ||||
| #if SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH | ||||
|     SDL_Window* hovered_window = SDL_GetMouseFocus();    // This is better but is only reliably useful with SDL 2.0.5+ and SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH enabled. | ||||
|     SDL_Window* mouse_window = (bd->Window == focused_window || bd->Window == hovered_window) ? bd->Window : NULL; | ||||
|     // Obtain focused and hovered window. We forward mouse input when focused or when hovered (and no other window is capturing) | ||||
| #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE | ||||
|     SDL_Window* focused_window = SDL_GetKeyboardFocus(); | ||||
|     SDL_Window* hovered_window = SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH ? SDL_GetMouseFocus() : NULL; // This is better but is only reliably useful with SDL 2.0.5+ and SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH. | ||||
|     SDL_Window* mouse_window = NULL; | ||||
|     if (hovered_window && bd->Window == hovered_window) | ||||
|         mouse_window = hovered_window; | ||||
|     else if (focused_window && bd->Window == focused_window) | ||||
|         mouse_window = focused_window; | ||||
|  | ||||
|     // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside | ||||
|     SDL_CaptureMouse(ImGui::IsAnyMouseDown() ? SDL_TRUE : SDL_FALSE); | ||||
| #else | ||||
|     SDL_Window* mouse_window = (bd->Window == focused_window) ? bd->Window : NULL; | ||||
|     // SDL 2.0.3 and non-windowed systems: single-viewport only | ||||
|     SDL_Window* mouse_window = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) ? bd->Window : NULL; | ||||
| #endif | ||||
|     if (mouse_window != NULL) | ||||
|     { | ||||
|  | ||||
|     if (mouse_window == NULL) | ||||
|        return; | ||||
|  | ||||
|     // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) | ||||
|     if (io.WantSetMousePos) | ||||
|         SDL_WarpMouseInWindow(bd->Window, (int)mouse_pos_prev.x, (int)mouse_pos_prev.y); | ||||
|  | ||||
|     // Set Dear ImGui mouse position from OS position + get buttons. (this is the common behavior) | ||||
|     if (bd->MouseCanUseGlobalState) | ||||
|     { | ||||
|             // SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?) | ||||
|             // The creation of a new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally. | ||||
|             // Won't use this workaround on SDL backends that have no global mouse position, like Wayland or RPI | ||||
|             int wx, wy; | ||||
|             SDL_GetWindowPosition(mouse_window, &wx, &wy); | ||||
|             SDL_GetGlobalMouseState(&mx, &my); | ||||
|             mx -= wx; | ||||
|             my -= wy; | ||||
|         // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) | ||||
|         // Unlike local position obtained earlier this will be valid when straying out of bounds. | ||||
|         int mouse_x_global, mouse_y_global; | ||||
|         SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global); | ||||
|         int window_x, window_y; | ||||
|         SDL_GetWindowPosition(mouse_window, &window_x, &window_y); | ||||
|         io.MousePos = ImVec2((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y)); | ||||
|     } | ||||
|         io.MousePos = ImVec2((float)mx, (float)my); | ||||
|     else | ||||
|     { | ||||
|         io.MousePos = ImVec2((float)mouse_x_local, (float)mouse_y_local); | ||||
|     } | ||||
|  | ||||
|     // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor. | ||||
|     // The function is only supported from SDL 2.0.4 (released Jan 2016) | ||||
|     bool any_mouse_button_down = ImGui::IsAnyMouseDown(); | ||||
|     SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE); | ||||
| #else | ||||
|     // SDL 2.0.3 and non-windowed systems | ||||
|     if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) | ||||
|         io.MousePos = ImVec2((float)mx, (float)my); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static void ImGui_ImplSDL2_UpdateMouseCursor() | ||||
| @@ -393,9 +401,9 @@ static void ImGui_ImplSDL2_UpdateGamepads() | ||||
|  | ||||
| void ImGui_ImplSDL2_NewFrame() | ||||
| { | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|     ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); | ||||
|     IM_ASSERT(bd != NULL && "Did you call ImGui_ImplSDL2_Init()?"); | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|  | ||||
|     // Setup display size (every frame to accommodate for window resizing) | ||||
|     int w, h; | ||||
|   | ||||
| @@ -219,29 +219,34 @@ static bool ImGui_ImplWin32_UpdateMouseCursor() | ||||
|  | ||||
| static void ImGui_ImplWin32_UpdateMousePos() | ||||
| { | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|     ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|     IM_ASSERT(bd->hWnd != 0); | ||||
|  | ||||
|     // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) | ||||
|     const ImVec2 mouse_pos_prev = io.MousePos; | ||||
|     io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); | ||||
|  | ||||
|     // Obtain focused and hovered window. We forward mouse input when focused or when hovered (and no other window is capturing) | ||||
|     HWND focused_window = ::GetForegroundWindow(); | ||||
|     HWND hovered_window = bd->MouseHwnd; | ||||
|     HWND mouse_window = NULL; | ||||
|     if (hovered_window && (hovered_window == bd->hWnd || ::IsChild(hovered_window, bd->hWnd))) | ||||
|         mouse_window = hovered_window; | ||||
|     else if (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd))) | ||||
|         mouse_window = focused_window; | ||||
|     if (mouse_window == NULL) | ||||
|         return; | ||||
|  | ||||
|     // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) | ||||
|     if (io.WantSetMousePos) | ||||
|     { | ||||
|         POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; | ||||
|         POINT pos = { (int)mouse_pos_prev.x, (int)mouse_pos_prev.y }; | ||||
|         if (::ClientToScreen(bd->hWnd, &pos)) | ||||
|             ::SetCursorPos(pos.x, pos.y); | ||||
|     } | ||||
|  | ||||
|     // Set mouse position | ||||
|     io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); | ||||
|     HWND focused_window = ::GetForegroundWindow(); | ||||
|     HWND hovered_window = bd->MouseHwnd; | ||||
|     HWND mouse_window = NULL; | ||||
|     if (hovered_window && (hovered_window == bd->hWnd) || ::IsChild(hovered_window, bd->hWnd)) | ||||
|         mouse_window = hovered_window; | ||||
|     else if (focused_window && (focused_window == bd->hWnd) || ::IsChild(focused_window, bd->hWnd)) | ||||
|         mouse_window = focused_window; | ||||
|     // Set Dear ImGui mouse position from OS position | ||||
|     POINT pos; | ||||
|     if (mouse_window) | ||||
|     if (::GetCursorPos(&pos) && ::ScreenToClient(mouse_window, &pos)) | ||||
|         io.MousePos = ImVec2((float)pos.x, (float)pos.y); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user