[gtk+] Bug 694273 - Patch to support NSTextInputClient in text widgets



commit 155caad4267e6e59b9c4859ab448c96875df4404
Author: E. K. Kato <ek kato gmial com>
Date:   Mon May 20 10:48:32 2013 -0700

    Bug 694273 - Patch to support NSTextInputClient in text widgets
    
    Provides an input module for native OSX input methods.
    Based on a patch by Hiroyuki Yamamoto
    (http://www.sraoss.jp/sylpheed/sylpheed/macosx/gtk+-2.24.0-macosx-textinputclient_ja-test1.patch).
    Adjustments for Gtk3 by Matthew Francis <gnomebugs newsheffield co uk>

 configure.ac               |    2 +
 gdk/quartz/GdkQuartzView.c |  529 ++++++++++++++++++++++++++++++++++++++++++--
 gdk/quartz/GdkQuartzView.h |   27 ++-
 modules/input/Makefile.am  |   13 +
 modules/input/imquartz.c   |  393 ++++++++++++++++++++++++++++++++
 5 files changed, 939 insertions(+), 25 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 46b8b6d..4e029da 100644
--- a/configure.ac
+++ b/configure.ac
@@ -362,6 +362,7 @@ DISABLE_ON_QUARTZ=''
 if test "x$enable_quartz_backend" = xyes; then
   cairo_backends="$cairo_backends cairo-quartz"
   GDK_BACKENDS="$GDK_BACKENDS quartz"
+  backend_immodules="$backend_immodules,quartz"
   GDK_WINDOWING="$GDK_WINDOWING
 #define GDK_WINDOWING_QUARTZ"
   GDK_EXTRA_LIBS="$GDK_EXTRA_LIBS -framework Cocoa"
@@ -861,6 +862,7 @@ AM_CONDITIONAL(INCLUDE_IM_IME, [test x"$INCLUDE_ime" = xyes])
 AM_CONDITIONAL(INCLUDE_IM_INUKTITUT, [test x"$INCLUDE_inuktitut" = xyes])
 AM_CONDITIONAL(INCLUDE_IM_IPA, [test x"$INCLUDE_ipa" = xyes])
 AM_CONDITIONAL(INCLUDE_IM_MULTIPRESS, [test x"$INCLUDE_multipress" = xyes])
+AM_CONDITIONAL(INCLUDE_IM_QUARTZ, [test x"$INCLUDE_quartz" = xyes])
 AM_CONDITIONAL(INCLUDE_IM_THAI, [test x"$INCLUDE_thai" = xyes])
 AM_CONDITIONAL(INCLUDE_IM_TI_ER, [test x"$INCLUDE_ti_er" = xyes])
 AM_CONDITIONAL(INCLUDE_IM_TI_ET, [test x"$INCLUDE_ti_et" = xyes])
diff --git a/gdk/quartz/GdkQuartzView.c b/gdk/quartz/GdkQuartzView.c
index 4058474..cd25efc 100644
--- a/gdk/quartz/GdkQuartzView.c
+++ b/gdk/quartz/GdkQuartzView.c
@@ -1,6 +1,7 @@
 /* GdkQuartzView.m
  *
  * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2011 Hiroyuki Yamamoto
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,18 +24,507 @@
 
 @implementation GdkQuartzView
 
+-(id)initWithFrame: (NSRect)frameRect
+{
+  if ((self = [super initWithFrame: frameRect]))
+    {
+      markedRange = NSMakeRange (NSNotFound, 0);
+      selectedRange = NSMakeRange (NSNotFound, 0);
+    }
+
+  return self;
+}
+
+-(BOOL)acceptsFirstResponder
+{
+  GDK_NOTE (EVENTS, g_print ("acceptsFirstResponder\n"));
+  return YES;
+}
+
+-(BOOL)becomeFirstResponder
+{
+  GDK_NOTE (EVENTS, g_print ("becomeFirstResponder\n"));
+  return YES;
+}
+
+-(BOOL)resignFirstResponder
+{
+  GDK_NOTE (EVENTS, g_print ("resignFirstResponder\n"));
+  return YES;
+}
+
+-(void) keyDown: (NSEvent *) theEvent
+{
+  GDK_NOTE (EVENTS, g_print ("keyDown\n"));
+  [self interpretKeyEvents: [NSArray arrayWithObject: theEvent]];
+}
+
+-(void)flagsChanged: (NSEvent *) theEvent
+{
+}
+
+-(NSUInteger)characterIndexForPoint: (NSPoint)aPoint
+{
+  GDK_NOTE (EVENTS, g_print ("characterIndexForPoint\n"));
+  return 0;
+}
+
+-(NSRect)firstRectForCharacterRange: (NSRange)aRange actualRange: (NSRangePointer)actualRange
+{
+  GDK_NOTE (EVENTS, g_print ("firstRectForCharacterRange\n"));
+  gint ns_x, ns_y;
+  GdkRectangle *rect;
+
+  rect = g_object_get_data (G_OBJECT (gdk_window), GIC_CURSOR_RECT);
+  if (rect)
+    {
+      _gdk_quartz_window_gdk_xy_to_xy (rect->x, rect->y + rect->height,
+                                      &ns_x, &ns_y);
+
+      return NSMakeRect (ns_x, ns_y, rect->width, rect->height);
+    }
+  else
+    {
+      return NSMakeRect (0, 0, 0, 0);
+    }
+}
+
+-(NSArray *)validAttributesForMarkedText
+{
+  GDK_NOTE (EVENTS, g_print ("validAttributesForMarkedText\n"));
+  return [NSArray arrayWithObjects: NSUnderlineStyleAttributeName, nil];
+}
+
+-(NSAttributedString *)attributedSubstringForProposedRange: (NSRange)aRange actualRange: 
(NSRangePointer)actualRange
+{
+  GDK_NOTE (EVENTS, g_print ("attributedSubstringForProposedRange\n"));
+  return nil;
+}
+
+-(BOOL)hasMarkedText
+{
+  GDK_NOTE (EVENTS, g_print ("hasMarkedText\n"));
+  return markedRange.location != NSNotFound && markedRange.length != 0;
+}
+
+-(NSRange)markedRange
+{
+  GDK_NOTE (EVENTS, g_print ("markedRange\n"));
+  return markedRange;
+}
+
+-(NSRange)selectedRange
+{
+  GDK_NOTE (EVENTS, g_print ("selectedRange\n"));
+  return selectedRange;
+}
+
+-(void)unmarkText
+{
+  GDK_NOTE (EVENTS, g_print ("unmarkText\n"));
+  markedRange = selectedRange = NSMakeRange (NSNotFound, 0);
+}
+
+-(void)setMarkedText: (id)aString selectedRange: (NSRange)newSelection replacementRange: 
(NSRange)replacementRange
+{
+  GDK_NOTE (EVENTS, g_print ("setMarkedText\n"));
+  const char *str;
+  char *prev_str;
+
+  if (replacementRange.location == NSNotFound)
+    {
+      markedRange = NSMakeRange (newSelection.location, [aString length]);
+      selectedRange = NSMakeRange (newSelection.location, newSelection.length);
+    }
+  else {
+      markedRange = NSMakeRange (replacementRange.location, [aString length]);
+      selectedRange = NSMakeRange (replacementRange.location + newSelection.location, newSelection.length);
+    }
+
+  if ([aString isKindOfClass: [NSAttributedString class]])
+    {
+      str = [[aString string] UTF8String];
+    }
+  else {
+      str = [aString UTF8String];
+    }
+
+  prev_str = g_object_get_data (G_OBJECT (gdk_window), TIC_MARKED_TEXT);
+  if (prev_str)
+    g_free (prev_str);
+  g_object_set_data (G_OBJECT (gdk_window), TIC_MARKED_TEXT, g_strdup (str));
+  g_object_set_data (G_OBJECT (gdk_window), TIC_SELECTED_POS,
+                    GUINT_TO_POINTER (selectedRange.location));
+  g_object_set_data (G_OBJECT (gdk_window), TIC_SELECTED_LEN,
+                    GUINT_TO_POINTER (selectedRange.length));
+
+  GDK_NOTE (EVENTS, g_print ("setMarkedText: set %s (%p, nsview %p): %s\n",
+                            TIC_MARKED_TEXT, gdk_window, self,
+                            str ? str : "(empty)"));
+}
+
+-(void)doCommandBySelector: (SEL)aSelector
+{
+  GDK_NOTE (EVENTS, g_print ("doCommandBySelector\n"));
+  [super doCommandBySelector: aSelector];
+}
+
+-(void)insertText: (id)aString replacementRange: (NSRange)replacementRange
+{
+  GDK_NOTE (EVENTS, g_print ("insertText\n"));
+  const char *str;
+  char *prev_str;
+
+  if ([self hasMarkedText])
+    [self unmarkText];
+
+  if ([aString isKindOfClass: [NSAttributedString class]])
+    {
+      str = [[aString string] UTF8String];
+    }
+  else
+    {
+      str = [aString UTF8String];
+    }
+
+  prev_str = g_object_get_data (G_OBJECT (gdk_window), TIC_INSERT_TEXT);
+  if (prev_str)
+    g_free (prev_str);
+  g_object_set_data (G_OBJECT (gdk_window), TIC_INSERT_TEXT, g_strdup (str));
+  GDK_NOTE (EVENTS, g_print ("insertText: set %s (%p, nsview %p): %s\n",
+                            TIC_INSERT_TEXT, gdk_window, self,
+                            str ? str : "(empty)"));
+
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_FILTERED));
+}
+
+-(void)deleteBackward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("deleteBackward\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteForward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("deleteForward\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteToBeginningOfLine: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("deleteToBeginningOfLine\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteToEndOfLine: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("deleteToEndOfLine\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteWordBackward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("deleteWordBackward\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteWordForward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("deleteWordForward\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)insertBacktab: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("insertBacktab\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)insertNewline: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("insertNewline\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY, GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)insertTab: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("insertTab\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveBackward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveBackward\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveBackwardAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveBackwardAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveDown: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveDown\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveDownAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveDownAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveForward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveForward\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveForwardAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveForwardAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveLeft: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveLeft\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveLeftAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveLeftAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveRight: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveRight\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveRightAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveRightAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfDocument: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveToBeginningOfDocument\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfDocumentAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveToBeginningOfDocumentAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfLine: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveToBeginningOfLine\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfLineAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveToBeginningOfLineAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfDocument: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveToEndOfDocument\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfDocumentAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveToEndOfDocumentAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfLine: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveToEndOfLine\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfLineAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveToEndOfLineAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveUp: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveUp\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveUpAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveUpAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordBackward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveWordBackward\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordBackwardAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveWordBackwardAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordForward: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveWordForward\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordForwardAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveWordForwardAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordLeft: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveWordLeft\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordLeftAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveWordLeftAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordRight: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveWordRight\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordRightAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("moveWordRightAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageDown: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("pageDown\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageDownAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("pageDownAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageUp: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("pageUp\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageUpAndModifySelection: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("pageUpAndModifySelection\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)selectAll: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("selectAll\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)selectLine: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("selectLine\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)selectWord: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("selectWord\n"));
+  g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
+                    GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)noop: (id)sender
+{
+  GDK_NOTE (EVENTS, g_print ("noop\n"));
+}
+
+/* --------------------------------------------------------------- */
+
 -(void)dealloc
 {
   if (trackingRect)
     {
-      [self removeTrackingRect:trackingRect];
+      [self removeTrackingRect: trackingRect];
       trackingRect = 0;
     }
 
   [super dealloc];
 }
 
--(void)setGdkWindow:(GdkWindow *)window
+-(void)setGdkWindow: (GdkWindow *)window
 {
   gdk_window = window;
 }
@@ -60,10 +550,11 @@
     return YES;
 
   /* A view is opaque if its GdkWindow doesn't have the RGBA visual */
-  return gdk_window_get_visual (gdk_window) != gdk_screen_get_rgba_visual (_gdk_screen);
+  return gdk_window_get_visual (gdk_window) !=
+    gdk_screen_get_rgba_visual (_gdk_screen);
 }
 
--(void)drawRect:(NSRect)rect 
+-(void)drawRect: (NSRect)rect
 {
   GdkRectangle gdk_rect;
   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (gdk_window->impl);
@@ -75,7 +566,7 @@
   if (GDK_WINDOW_DESTROYED (gdk_window))
     return;
 
-  if (!(gdk_window->event_mask & GDK_EXPOSURE_MASK))
+  if (! (gdk_window->event_mask & GDK_EXPOSURE_MASK))
     return;
 
   if (NSEqualRects (rect, NSZeroRect))
@@ -93,7 +584,7 @@
       [NSGraphicsContext saveGraphicsState];
 
       [[NSColor windowBackgroundColor] setFill];
-      [NSBezierPath fillRect:rect];
+      [NSBezierPath fillRect: rect];
 
       [NSGraphicsContext restoreGraphicsState];
 
@@ -107,9 +598,9 @@
       impl->needs_display_region = NULL;
     }
 
-  [self getRectsBeingDrawn:&drawn_rects count:&count];
+  [self getRectsBeingDrawn: &drawn_rects count: &count];
   region = cairo_region_create ();
-  
+
   for (i = 0; i < count; i++)
     {
       gdk_rect.x = drawn_rects[i].origin.x;
@@ -133,7 +624,7 @@
     }
 }
 
--(void)setNeedsInvalidateShadow:(BOOL)invalidate
+-(void)setNeedsInvalidateShadow: (BOOL)invalidate
 {
   needsInvalidateShadow = invalidate;
 }
@@ -151,7 +642,7 @@
 
   if (trackingRect)
     {
-      [self removeTrackingRect:trackingRect];
+      [self removeTrackingRect: trackingRect];
       trackingRect = 0;
     }
 
@@ -163,32 +654,32 @@
    */
 
   rect = [self bounds];
-  trackingRect = [self addTrackingRect:rect
-                                 owner:self
-                              userData:nil
-                          assumeInside:NO];
+  trackingRect = [self addTrackingRect: rect
+                 owner: self
+                 userData: nil
+                 assumeInside: NO];
 }
 
 -(void)viewDidMoveToWindow
 {
   if (![self window]) /* We are destroyed already */
-      return;
+    return;
 
   [self updateTrackingRect];
 }
 
--(void)viewWillMoveToWindow:(NSWindow *)newWindow
+-(void)viewWillMoveToWindow: (NSWindow *)newWindow
 {
   if (newWindow == nil && trackingRect)
     {
-      [self removeTrackingRect:trackingRect];
+      [self removeTrackingRect: trackingRect];
       trackingRect = 0;
     }
 }
 
--(void)setFrame:(NSRect)frame
+-(void)setFrame: (NSRect)frame
 {
-  [super setFrame:frame];
+  [super setFrame: frame];
 
   if ([self window])
     [self updateTrackingRect];
diff --git a/gdk/quartz/GdkQuartzView.h b/gdk/quartz/GdkQuartzView.h
index 346b64d..83455c3 100644
--- a/gdk/quartz/GdkQuartzView.h
+++ b/gdk/quartz/GdkQuartzView.h
@@ -17,17 +17,32 @@
  */
 
 #import <AppKit/AppKit.h>
-#include "gdkwindow.h"
+#include "gdk/gdk.h"
 
- interface GdkQuartzView : NSView {
+/* Text Input Client */
+#define TIC_MARKED_TEXT "tic-marked-text"
+#define TIC_SELECTED_POS  "tic-selected-pos"
+#define TIC_SELECTED_LEN  "tic-selected-len"
+#define TIC_INSERT_TEXT "tic-insert-text"
+
+/* GtkIMContext */
+#define GIC_CURSOR_RECT  "gic-cursor-rect"
+#define GIC_FILTER_KEY   "gic-filter-key"
+#define GIC_FILTER_PASSTHRU    0
+#define GIC_FILTER_FILTERED    1
+
+ interface GdkQuartzView : NSView <NSTextInputClient>
+{
   GdkWindow *gdk_window;
   NSTrackingRectTag trackingRect;
   BOOL needsInvalidateShadow;
+  NSRange markedRange;
+  NSRange selectedRange;
 }
 
--(void)setGdkWindow:(GdkWindow *)window;
--(GdkWindow *)gdkWindow;
--(NSTrackingRectTag)trackingRect;
--(void)setNeedsInvalidateShadow:(BOOL)invalidate;
+- (void)setGdkWindow: (GdkWindow *)window;
+- (GdkWindow *)gdkWindow;
+- (NSTrackingRectTag)trackingRect;
+- (void)setNeedsInvalidateShadow: (BOOL)invalidate;
 
 @end
diff --git a/modules/input/Makefile.am b/modules/input/Makefile.am
index d52b61d..902bad3 100644
--- a/modules/input/Makefile.am
+++ b/modules/input/Makefile.am
@@ -151,6 +151,17 @@ IME_MODULE=im-ime.la
 endif
 endif
 
+im_quartz_la_CPPFLAGS = $(AM_CPPFLAGS) -xobjective-c
+im_quartz_la_LDFLAGS = -rpath $(moduledir) -avoid-version -module $(no_undefined)
+im_quartz_la_SOURCES = imquartz.c
+libstatic_im_quartz_la_SOURCES = $(im_quartz_la_SOURCES)
+im_quartz_la_LIBADD = $(LDADDS)
+if INCLUDE_IM_QUARTZ
+STATIC_QUARTZ_MODULE = libstatic-im-quartz.la
+else
+QUARTZ_MODULE = im-quartz.la
+endif
+
 multipress_defs = -DMULTIPRESS_LOCALEDIR=\""$(mplocaledir)"\" 
-DMULTIPRESS_CONFDIR=\""$(sysconfdir)/gtk-2.0"\"
 im_multipress_la_CPPFLAGS = $(AM_CPPFLAGS) $(multipress_defs)
 libstatic_im_multipress_la_CPPFLAGS = $(im_multipress_la_CPPFLAGS)
@@ -210,6 +221,7 @@ module_LTLIBRARIES =                        \
        $(INUKTITUT_MODULE)             \
        $(IPA_MODULE)                   \
        $(MULTIPRESS_MODULE)            \
+       $(QUARTZ_MODULE)                \
        $(THAI_MODULE)                  \
        $(TI_ER_MODULE)                 \
        $(TI_ET_MODULE)                 \
@@ -226,6 +238,7 @@ noinst_LTLIBRARIES =                                \
        $(STATIC_INUKTITUT_MODULE)              \
        $(STATIC_IPA_MODULE)                    \
        $(STATIC_MULTIPRESS_MODULE)             \
+       $(STATIC_QUARTZ_MODULE)                 \
        $(STATIC_THAI_MODULE)                   \
        $(STATIC_TI_ER_MODULE)                  \
        $(STATIC_TI_ET_MODULE)                  \
diff --git a/modules/input/imquartz.c b/modules/input/imquartz.c
new file mode 100644
index 0000000..9788ad3
--- /dev/null
+++ b/modules/input/imquartz.c
@@ -0,0 +1,393 @@
+/*
+ * gtkimmodulequartz
+ * Copyright (C) 2011 Hiroyuki Yamamoto
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * $Id:$
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include "gtk/gtkintl.h"
+#include "gtk/gtkimmodule.h"
+
+#include "gdk/quartz/gdkquartz.h"
+#include "gdk/quartz/GdkQuartzView.h"
+
+#define GTK_IM_CONTEXT_TYPE_QUARTZ (type_quartz)
+#define GTK_IM_CONTEXT_QUARTZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_IM_CONTEXT_TYPE_QUARTZ, 
GtkIMContextQuartz))
+#define GTK_IM_CONTEXT_QUARTZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_IM_CONTEXT_TYPE_QUARTZ, 
GtkIMContextQuartzClass))
+
+typedef struct _GtkIMContextQuartz
+{
+  GtkIMContext parent;
+  GtkIMContext *slave;
+  GdkWindow *client_window;
+  gchar *preedit_str;
+  unsigned int cursor_index;
+  unsigned int selected_len;
+  GdkRectangle *cursor_rect;
+  gboolean focused;
+} GtkIMContextQuartz;
+
+typedef struct _GtkIMContextQuartzClass
+{
+  GtkIMContextClass parent_class;
+} GtkIMContextQuartzClass;
+
+GType type_quartz = 0;
+static GObjectClass *parent_class;
+
+static const GtkIMContextInfo imquartz_info =
+{
+  "quartz",
+  "Mac OS X Quartz",
+  GETTEXT_PACKAGE,
+  GTK_LOCALEDIR,
+  "ja:ko:zh:*",
+};
+
+static const GtkIMContextInfo *info_list[] =
+{
+  &imquartz_info,
+};
+
+#ifndef INCLUDE_IM_quartz
+#define MODULE_ENTRY(type,function) G_MODULE_EXPORT type im_module_ ## function
+#else
+#define MODULE_ENTRY(type, function) type _gtk_immodule_quartz_ ## function
+#endif
+
+static void
+quartz_get_preedit_string (GtkIMContext *context,
+                           gchar **str,
+                           PangoAttrList **attrs,
+                           gint *cursor_pos)
+{
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+
+  GTK_NOTE (MISC, g_print ("quartz_get_preedit_string\n"));
+
+  if (str)
+    *str = qc->preedit_str ? g_strdup (qc->preedit_str) : g_strdup ("");
+
+  if (attrs)
+    {
+      *attrs = pango_attr_list_new ();
+      int len = g_utf8_strlen (*str, -1);
+      gchar *ch = *str;
+      if (len > 0)
+        {
+          PangoAttribute *attr;
+          int i = 0;
+          for (;;)
+            {
+              gchar *s = ch;
+              ch = g_utf8_next_char (ch);
+
+              if (i >= qc->cursor_index &&
+                 i < qc->cursor_index + qc->selected_len)
+                attr = pango_attr_underline_new (PANGO_UNDERLINE_DOUBLE);
+              else
+                attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
+
+              attr->start_index = s - *str;
+              if (!*ch)
+                attr->end_index = attr->start_index + strlen (s);
+              else
+                attr->end_index = ch - *str;
+
+              pango_attr_list_change (*attrs, attr);
+
+              if (!*ch)
+                break;
+              i++;
+            }
+        }
+    }
+  if (cursor_pos)
+    *cursor_pos = qc->cursor_index;
+}
+
+static gboolean
+quartz_filter_keypress (GtkIMContext *context,
+                        GdkEventKey *event)
+{
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+  gboolean retval = FALSE;
+  NSView *nsview;
+  GdkWindow *win;
+  gchar *fixed_str, *marked_str;
+
+  GTK_NOTE (MISC, g_print ("quartz_filter_keypress\n"));
+
+  if (event->type == GDK_KEY_RELEASE)
+    return FALSE;
+
+  if (!qc->client_window)
+    return FALSE;
+
+  nsview = gdk_quartz_window_get_nsview (qc->client_window);
+  if (GDK_IS_WINDOW (nsview))
+       /* it gets GDK_WINDOW in some cases */
+    return gtk_im_context_filter_keypress (qc->slave, event);
+  else
+    win = (GdkWindow *)[ (GdkQuartzView *)nsview gdkWindow];
+  GTK_NOTE (MISC, g_print ("client_window: %p, win: %p, nsview: %p\n",
+                          qc->client_window, win, nsview));
+
+  if (event->hardware_keycode == 55)   /* Command */
+    return FALSE;
+
+  NSEvent *nsevent = gdk_quartz_event_get_nsevent ((GdkEvent *)event);
+  NSEventType etype = [nsevent type];
+  if (etype == NSKeyDown)
+       [nsview keyDown: nsevent];
+  /* JIS_Eisu || JIS_Kana */
+  if (event->hardware_keycode == 102 || event->hardware_keycode == 104)
+    return FALSE;
+
+  GTK_NOTE (MISC,
+           g_print ("quartz_filter_keypress: getting tic-insert-text\n"));
+  fixed_str = g_object_get_data (G_OBJECT (win), TIC_INSERT_TEXT);
+  marked_str = g_object_get_data (G_OBJECT (win), TIC_MARKED_TEXT);
+  if (fixed_str)
+    {
+      GTK_NOTE (MISC, g_print ("tic-insert-text: %s\n", fixed_str));
+      g_free (qc->preedit_str);
+      qc->preedit_str = NULL;
+      g_object_set_data (G_OBJECT (win), TIC_INSERT_TEXT, NULL);
+      g_signal_emit_by_name (context, "commit", fixed_str);
+      g_signal_emit_by_name (context, "preedit_changed");
+
+      unsigned int filtered =
+          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
+                                               GIC_FILTER_KEY));
+      GTK_NOTE (MISC, g_print ("filtered, %d\n", filtered));
+      if (filtered)
+        retval = TRUE;
+      else
+        retval = FALSE;
+    }
+  if (marked_str)
+    {
+      GTK_NOTE (MISC, g_print ("tic-marked-text: %s\n", marked_str));
+      qc->cursor_index =
+          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
+                                               TIC_SELECTED_POS));
+      qc->selected_len =
+          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
+                                               TIC_SELECTED_LEN));
+      g_free (qc->preedit_str);
+      qc->preedit_str = g_strdup (marked_str);
+      g_object_set_data (G_OBJECT (win), TIC_MARKED_TEXT, NULL);
+      g_signal_emit_by_name (context, "preedit_changed");
+      retval = TRUE;
+    }
+  g_free (fixed_str);
+  g_free (marked_str);
+
+  GTK_NOTE (MISC, g_print ("quartz_filter_keypress done\n"));
+  return retval;
+}
+
+static void
+quartz_reset (GtkIMContext *context)
+{
+  GTK_NOTE (MISC, g_print ("quartz_reset\n"));
+}
+
+static void
+quartz_set_client_window (GtkIMContext *context, GdkWindow *window)
+{
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+
+  GTK_NOTE (MISC, g_print ("quartz_set_client_window: %p\n", window));
+
+  qc->client_window = window;
+}
+
+static void
+quartz_focus_in (GtkIMContext *context)
+{
+  GTK_NOTE (MISC, g_print ("quartz_focus_in\n"));
+
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+  qc->focused = TRUE;
+}
+
+static void
+quartz_focus_out (GtkIMContext *context)
+{
+  GTK_NOTE (MISC, g_print ("quartz_focus_out\n"));
+
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+  qc->focused = FALSE;
+}
+
+static void
+quartz_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
+{
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+  gint x, y;
+  NSView *nsview;
+  GdkWindow *win;
+
+  GTK_NOTE (MISC, g_print ("quartz_set_cursor_location\n"));
+
+  if (!qc->client_window)
+    return;
+
+  if (!qc->focused)
+    return;
+
+  qc->cursor_rect->x = area->x;
+  qc->cursor_rect->y = area->y;
+  qc->cursor_rect->width = area->width;
+  qc->cursor_rect->height = area->height;
+
+  gdk_window_get_origin (qc->client_window, &x, &y);
+
+  qc->cursor_rect->x = area->x + x;
+  qc->cursor_rect->y = area->y + y;
+
+  nsview = gdk_quartz_window_get_nsview (qc->client_window);
+  if (GDK_IS_WINDOW (nsview))
+    /* it returns GDK_WINDOW in some cases */
+    return;
+
+  win = (GdkWindow *)[ (GdkQuartzView*)nsview gdkWindow];
+  g_object_set_data (G_OBJECT (win), GIC_CURSOR_RECT, qc->cursor_rect);
+}
+
+static void
+quartz_set_use_preedit (GtkIMContext *context, gboolean use_preedit)
+{
+  GTK_NOTE (MISC, g_print ("quartz_set_use_preedit: %d\n", use_preedit));
+}
+
+static void
+commit_cb (GtkIMContext *context, const gchar *str, GtkIMContextQuartz *qc)
+{
+  g_signal_emit_by_name (qc, "commit", str);
+}
+
+static void
+imquartz_finalize (GObject *obj)
+{
+  GTK_NOTE (MISC, g_print ("imquartz_finalize\n"));
+
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (obj);
+  g_free (qc->preedit_str);
+  qc->preedit_str = NULL;
+  g_free (qc->cursor_rect);
+  qc->cursor_rect = NULL;
+
+  g_signal_handlers_disconnect_by_func (qc->slave, (gpointer)commit_cb, qc);
+  g_object_unref (qc->slave);
+
+  parent_class->finalize (obj);
+}
+
+static void
+gtk_im_context_quartz_class_init (GtkIMContextClass *klass)
+{
+  GTK_NOTE (MISC, g_print ("gtk_im_context_quartz_class_init\n"));
+
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  parent_class = g_type_class_peek_parent (klass);
+
+  klass->get_preedit_string = quartz_get_preedit_string;
+  klass->filter_keypress = quartz_filter_keypress;
+  klass->reset = quartz_reset;
+  klass->set_client_window = quartz_set_client_window;
+  klass->focus_in = quartz_focus_in;
+  klass->focus_out = quartz_focus_out;
+  klass->set_cursor_location = quartz_set_cursor_location;
+  klass->set_use_preedit = quartz_set_use_preedit;
+
+  object_class->finalize = imquartz_finalize;
+}
+
+static void
+gtk_im_context_quartz_init (GtkIMContext *im_context)
+{
+  GTK_NOTE (MISC, g_print ("gtk_im_context_quartz_init\n"));
+
+  GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (im_context);
+  qc->preedit_str = g_strdup ("");
+  qc->cursor_index = 0;
+  qc->selected_len = 0;
+  qc->cursor_rect = g_malloc (sizeof (GdkRectangle));
+  qc->focused = FALSE;
+
+  qc->slave = g_object_new (GTK_TYPE_IM_CONTEXT_SIMPLE, NULL);
+  g_signal_connect (G_OBJECT (qc->slave), "commit", G_CALLBACK (commit_cb), qc);
+}
+
+static void
+gtk_im_context_quartz_register_type (GTypeModule *module)
+{
+  const GTypeInfo object_info =
+  {
+    sizeof (GtkIMContextQuartzClass),
+    (GBaseInitFunc) NULL,
+    (GBaseFinalizeFunc) NULL,
+    (GClassInitFunc) gtk_im_context_quartz_class_init,
+    NULL,           /* class_finalize */
+    NULL,           /* class_data */
+    sizeof (GtkIMContextQuartz),
+    0,
+    (GInstanceInitFunc) gtk_im_context_quartz_init,
+  };
+
+  type_quartz =
+    g_type_module_register_type (module,
+                                 GTK_TYPE_IM_CONTEXT,
+                                 "GtkIMContextQuartz",
+                                 &object_info, 0);
+}
+
+MODULE_ENTRY (void, init) (GTypeModule * module)
+{
+  gtk_im_context_quartz_register_type (module);
+}
+
+MODULE_ENTRY (void, exit) (void)
+{
+}
+
+MODULE_ENTRY (void, list) (const GtkIMContextInfo *** contexts, int *n_contexts)
+{
+  *contexts = info_list;
+  *n_contexts = G_N_ELEMENTS (info_list);
+}
+
+MODULE_ENTRY (GtkIMContext *, create) (const gchar * context_id)
+{
+  g_return_val_if_fail (context_id, NULL);
+
+  if (!strcmp (context_id, "quartz"))
+    {
+      GTK_NOTE (MISC, g_print ("immodule_quartz create\n"));
+      return g_object_new (type_quartz, NULL);
+    }
+  else
+    return NULL;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]