Ken Thomases : winemac: Improve positioning of input method candidate window.

Alexandre Julliard julliard at winehq.org
Fri May 17 14:24:33 CDT 2013


Module: wine
Branch: master
Commit: 939d9a906ff75ac8db68f09d3ccbb6b7e32eec2a
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=939d9a906ff75ac8db68f09d3ccbb6b7e32eec2a

Author: Ken Thomases <ken at codeweavers.com>
Date:   Thu May 16 16:48:39 2013 -0500

winemac: Improve positioning of input method candidate window.

---

 dlls/winemac.drv/cocoa_window.m |   28 +++++++++-
 dlls/winemac.drv/event.c        |    4 +
 dlls/winemac.drv/ime.c          |  123 +++++++++++++++++++++++++++++++++++++++
 dlls/winemac.drv/macdrv.h       |    1 +
 dlls/winemac.drv/macdrv_cocoa.h |    6 ++
 5 files changed, 161 insertions(+), 1 deletions(-)

diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m
index 8ebda3b..daa1e66 100644
--- a/dlls/winemac.drv/cocoa_window.m
+++ b/dlls/winemac.drv/cocoa_window.m
@@ -370,6 +370,8 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
             [[window queue] postEvent:event];
 
             macdrv_release_event(event);
+
+            [[self inputContext] invalidateCharacterCoordinates];
         }
     }
 
@@ -414,10 +416,32 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
 
     - (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 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
         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 cb305d6..51f6723 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 e9f1369..44d5d8b 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 fed1d47..1010ded 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 84dfd87..905738f 100644
--- a/dlls/winemac.drv/macdrv_cocoa.h
+++ b/dlls/winemac.drv/macdrv_cocoa.h
@@ -259,6 +259,7 @@ enum {
     QUERY_DRAG_DROP,
     QUERY_DRAG_EXITED,
     QUERY_DRAG_OPERATION,
+    QUERY_IME_CHAR_RECT,
     QUERY_PASTEBOARD_DATA,
     NUM_QUERY_TYPES
 };
@@ -284,6 +285,11 @@ typedef struct macdrv_query {
             CFTypeRef           pasteboard;
         }                                           drag_operation;
         struct {
+            void   *data;
+            CFRange range;
+            CGRect  rect;
+        }                                           ime_char_rect;
+        struct {
             CFStringRef type;
         }                                           pasteboard_data;
     };




More information about the wine-cvs mailing list