diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 8ebda3b766e..daa1e660246 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -370,6 +370,8 @@ - (void) setMarkedText:(id)string selectedRange:(NSRange)selectedRange replaceme [[window queue] postEvent:event]; macdrv_release_event(event); + + [[self inputContext] invalidateCharacterCoordinates]; } } @@ -414,10 +416,32 @@ - (NSArray*) validAttributesForMarkedText - (NSRect) firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange { + macdrv_query* query; + WineWindow* window = (WineWindow*)[self window]; + NSRect ret; + aRange = NSIntersectionRange(aRange, NSMakeRange(0, [markedText length])); + + query = macdrv_create_query(); + query->type = QUERY_IME_CHAR_RECT; + query->window = (macdrv_window)[window retain]; + query->ime_char_rect.data = [window imeData]; + query->ime_char_rect.range = CFRangeMake(aRange.location, aRange.length); + + if ([window.queue query:query timeout:1]) + { + aRange = NSMakeRange(query->ime_char_rect.range.location, query->ime_char_rect.range.length); + ret = NSRectFromCGRect(query->ime_char_rect.rect); + [[WineApplicationController sharedController] flipRect:&ret]; + } + else + ret = NSMakeRect(100, 100, aRange.length ? 1 : 0, 12); + + macdrv_release_query(query); + if (actualRange) *actualRange = aRange; - return NSMakeRect(100, 100, aRange.length ? 1 : 0, 12); + return ret; } - (NSUInteger) characterIndexForPoint:(NSPoint)aPoint @@ -1211,6 +1235,8 @@ - (void)windowDidResize:(NSNotification *)notification event->window_frame_changed.frame = NSRectToCGRect(frame); [queue postEvent:event]; macdrv_release_event(event); + + [[[self contentView] inputContext] invalidateCharacterCoordinates]; } - (BOOL)windowShouldClose:(id)sender diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index cb305d64a16..51f6723894f 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -136,6 +136,10 @@ static void macdrv_query_event(HWND hwnd, const macdrv_event *event) TRACE("QUERY_DRAG_OPERATION\n"); success = query_drag_operation(query); break; + case QUERY_IME_CHAR_RECT: + TRACE("QUERY_IME_CHAR_RECT\n"); + success = query_ime_char_rect(query); + break; case QUERY_PASTEBOARD_DATA: TRACE("QUERY_PASTEBOARD_DATA\n"); success = query_pasteboard_data(hwnd, query->pasteboard_data.type); diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index e9f13693fce..44d5d8b1d91 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -1509,3 +1509,126 @@ void macdrv_im_set_text(const macdrv_event *event) if (event->im_set_text.complete) IME_NotifyComplete(himc); } + + +/************************************************************************** + * query_ime_char_rect + */ +BOOL query_ime_char_rect(macdrv_query* query) +{ + HWND hwnd = macdrv_get_window_hwnd(query->window); + void *himc = query->ime_char_rect.data; + CFRange* range = &query->ime_char_rect.range; + CGRect* rect = &query->ime_char_rect.rect; + IMECHARPOSITION charpos; + BOOL ret = FALSE; + + TRACE("win %p/%p himc %p range %ld-%ld\n", hwnd, query->window, himc, range->location, + range->length); + + if (!himc) himc = RealIMC(FROM_MACDRV); + + charpos.dwSize = sizeof(charpos); + charpos.dwCharPos = range->location; + if (ImmRequestMessageW(himc, IMR_QUERYCHARPOSITION, (ULONG_PTR)&charpos)) + { + int i; + + *rect = CGRectMake(charpos.pt.x, charpos.pt.y, 0, charpos.cLineHeight); + + /* iterate over rest of length to extend rect */ + for (i = 1; i <= range->length; i++) + { + charpos.dwSize = sizeof(charpos); + charpos.dwCharPos = range->location + i; + if (!ImmRequestMessageW(himc, IMR_QUERYCHARPOSITION, (ULONG_PTR)&charpos) || + charpos.pt.y != rect->origin.y) + { + range->length = i; + break; + } + + rect->size.width = charpos.pt.x - rect->origin.x; + } + + ret = TRUE; + } + + if (!ret) + { + LPINPUTCONTEXT ic = ImmLockIMC(himc); + + if (ic) + { + LPIMEPRIVATE private = ImmLockIMCC(ic->hPrivate); + LPBYTE compdata = ImmLockIMCC(ic->hCompStr); + LPCOMPOSITIONSTRING compstr = (LPCOMPOSITIONSTRING)compdata; + LPWSTR str = (LPWSTR)(compdata + compstr->dwCompStrOffset); + + if (private->hwndDefault && compstr->dwCompStrOffset && + IsWindowVisible(private->hwndDefault)) + { + HDC dc = GetDC(private->hwndDefault); + HFONT oldfont = NULL; + SIZE size; + + if (private->textfont) + oldfont = SelectObject(dc, private->textfont); + + if (range->location > compstr->dwCompStrLen) + range->location = compstr->dwCompStrLen; + if (range->location + range->length > compstr->dwCompStrLen) + range->length = compstr->dwCompStrLen - range->location; + + GetTextExtentPoint32W(dc, str, range->location, &size); + charpos.rcDocument.left = size.cx; + charpos.rcDocument.top = 0; + GetTextExtentPoint32W(dc, str, range->location + range->length, &size); + charpos.rcDocument.right = size.cx; + charpos.rcDocument.bottom = size.cy; + + if (ic->cfCompForm.dwStyle == CFS_DEFAULT) + OffsetRect(&charpos.rcDocument, 10, 10); + + LPtoDP(dc, (POINT*)&charpos.rcDocument, 2); + MapWindowPoints(private->hwndDefault, 0, (POINT*)&charpos.rcDocument, 2); + *rect = cgrect_from_rect(charpos.rcDocument); + ret = TRUE; + + if (oldfont) + SelectObject(dc, oldfont); + ReleaseDC(private->hwndDefault, dc); + } + + ImmUnlockIMCC(ic->hCompStr); + ImmUnlockIMCC(ic->hPrivate); + } + + ImmUnlockIMC(himc); + } + + if (!ret) + { + HWND focus = GetFocus(); + if (focus && (focus == hwnd || IsChild(hwnd, focus)) && + GetClientRect(focus, &charpos.rcDocument)) + { + if (!GetCaretPos((POINT*)&charpos.rcDocument)) + charpos.rcDocument.left = charpos.rcDocument.top = 0; + + charpos.rcDocument.right = charpos.rcDocument.left + 1; + MapWindowPoints(focus, 0, (POINT*)&charpos.rcDocument, 2); + + *rect = cgrect_from_rect(charpos.rcDocument); + ret = TRUE; + } + } + + if (ret && range->length && !rect->size.width) + rect->size.width = 1; + + TRACE(" -> %s range %ld-%ld rect %s\n", ret ? "TRUE" : "FALSE", range->location, + range->length, wine_dbgstr_cgrect(*rect)); + + return ret; +} diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index fed1d475bab..1010ded01e6 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -204,5 +204,6 @@ extern BOOL macdrv_process_text_input(UINT vkey, UINT scan, UINT repeat, const B extern void macdrv_im_set_cursor_pos(const macdrv_event *event) DECLSPEC_HIDDEN; extern void macdrv_im_set_text(const macdrv_event *event) DECLSPEC_HIDDEN; +extern BOOL query_ime_char_rect(macdrv_query* query) DECLSPEC_HIDDEN; #endif /* __WINE_MACDRV_H */ diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 84dfd8732ad..905738fdbf3 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -259,6 +259,7 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display, QUERY_DRAG_DROP, QUERY_DRAG_EXITED, QUERY_DRAG_OPERATION, + QUERY_IME_CHAR_RECT, QUERY_PASTEBOARD_DATA, NUM_QUERY_TYPES }; @@ -283,6 +284,11 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display, uint32_t accepted_op; CFTypeRef pasteboard; } drag_operation; + struct { + void *data; + CFRange range; + CGRect rect; + } ime_char_rect; struct { CFStringRef type; } pasteboard_data;