Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix OSX backend threading issues #6528

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 68 additions & 29 deletions backends/imgui_impl_osx.mm
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2023-06-19: Fixed threading issues with io.SetClipboardTextFn(), io.GetClipboardTextFn() and io.SetPlatformImeDataFn().
// 2023-04-09: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_Pen.
// 2023-02-01: Fixed scroll wheel scaling for devices emitting events with hasPreciseScrollingDeltas==false (e.g. non-Apple mices).
// 2022-11-02: Fixed mouse coordinates before clicking the host window.
Expand Down Expand Up @@ -412,30 +413,57 @@ bool ImGui_ImplOSX_Init(NSView* view)
// Note that imgui.cpp also include default OSX clipboard handlers which can be enabled
// by adding '#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS' in imconfig.h and adding '-framework ApplicationServices' to your linker command-line.
// Since we are already in ObjC land here, it is easy for us to add a clipboard handler using the NSPasteboard api.
// The events below may be blocking until dispatched when not invoked from the main thread (usually in the realm of 0.6 to 2ms). See #6527.
io.SetClipboardTextFn = [](void*, const char* str) -> void
{
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
[pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil];
[pasteboard setString:[NSString stringWithUTF8String:str] forType:NSPasteboardTypeString];
void (*setClipboardText)(const char*) = [](const char* str) -> void
{
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
[pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil];
[pasteboard setString:[NSString stringWithUTF8String:str] forType:NSPasteboardTypeString];
};

if ([NSThread isMainThread])
return setClipboardText(str);

dispatch_sync(dispatch_get_main_queue(),
^{
setClipboardText(str);
});
};

io.GetClipboardTextFn = [](void*) -> const char*
{
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
NSString* available = [pasteboard availableTypeFromArray: [NSArray arrayWithObject:NSPasteboardTypeString]];
if (![available isEqualToString:NSPasteboardTypeString])
return nullptr;

NSString* string = [pasteboard stringForType:NSPasteboardTypeString];
if (string == nil)
return nullptr;

const char* string_c = (const char*)[string UTF8String];
size_t string_len = strlen(string_c);
static ImVector<char> s_clipboard;
s_clipboard.resize((int)string_len + 1);
strcpy(s_clipboard.Data, string_c);
return s_clipboard.Data;
const char* (*getClipboardText)(void) = [](void) -> const char*
{
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
NSString* available = [pasteboard availableTypeFromArray: [NSArray arrayWithObject:NSPasteboardTypeString]];
if (![available isEqualToString:NSPasteboardTypeString])
return nullptr;

NSString* string = [pasteboard stringForType:NSPasteboardTypeString];
if (string == nil)
return nullptr;

const char* string_c = (const char*)[string UTF8String];
size_t string_len = strlen(string_c);
static ImVector<char> s_clipboard;
s_clipboard.resize((int)string_len + 1);
strcpy(s_clipboard.Data, string_c);
return s_clipboard.Data;
};

if ([NSThread isMainThread])
return getClipboardText();

__block const char* clipboardText;

dispatch_sync(dispatch_get_main_queue(),
^{
clipboardText = getClipboardText();
});

return clipboardText;
};

[[NSNotificationCenter defaultCenter] addObserver:bd->Observer
Expand All @@ -456,18 +484,29 @@ bool ImGui_ImplOSX_Init(NSView* view)

io.SetPlatformImeDataFn = [](ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void
{
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
if (data->WantVisible)
{
[bd->InputContext activate];
}
else
void (*setPlatformImeData)(ImGuiPlatformImeData*) = [](ImGuiPlatformImeData* data) -> void
{
[bd->InputContext discardMarkedText];
[bd->InputContext invalidateCharacterCoordinates];
[bd->InputContext deactivate];
}
[bd->KeyEventResponder setImePosX:data->InputPos.x imePosY:data->InputPos.y + data->InputLineHeight];
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
if (data->WantVisible)
{
[bd->InputContext activate];
}
else
{
[bd->InputContext discardMarkedText];
[bd->InputContext invalidateCharacterCoordinates];
[bd->InputContext deactivate];
}
[bd->KeyEventResponder setImePosX:data->InputPos.x imePosY:data->InputPos.y + data->InputLineHeight];
};

if ([NSThread isMainThread])
return setPlatformImeData(data);

dispatch_sync(dispatch_get_main_queue(),
^{
setPlatformImeData(data);
});
};

return true;
Expand Down