[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Extension to XIM support (2)
From: |
Kazunobu Kuriyama |
Subject: |
Extension to XIM support (2) |
Date: |
Sun, 13 Jul 2003 22:32:06 +0900 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.0.0) Gecko/20020614 |
Hi all,
The attached are a modified version of the patches I previously sent.
At user level, the following is an only change:
The input method style specification which was done through the
environmental
variable GNUSTEP_INPUT_METHOD_STYLE are now done through the user default
GSXIMInputMethodStyle.
You can use it in a usual manner:
$ defaults write NSGlobalDomain GSXIMInputMethodStyle <val>
where <val> is RootWindow, OffTheSpot, or OverTheSpot.
Thanks to Alexander Malmberg who very recently added some new internal
methods to
NSTextView for the XIM support, the code is fairly improved in view of
OO design,
without loss of any functionality the patches offer.
Because the modified implementation makes use of the new interface of
NSTextView
as mentioned, the patches are expected to work properly with -gui in the
CVS as of
July 12 (around 18:00 GMT).
Any feedback is welcome.
- KK
2003-07-13 Kazunobu Kuriyama <kazunobu.kuriyama@nifty.com>
* Header/x11/XGInputServer.h: Add the new category InputMethod.
* Header/x11/XGServer.h: Add the new category InputMethod.
* Source/x11/XIMInputServer.m:
([XIMInputServer (XIMPrivate) -ximStyleInit]): Cover the input
method styles RootWindow, OffTheSpot, OverTheSpot, and OnTheSpot.
([XIMInputServer (XIMPrivate) -ximCreateIC:]): Implement OffTheSpot
and OverTheSpot. Implement the category InputMethod.
* Source/x11/XGServer.m: Implement the category InputMethod. Add
overriding methods to NSTextView (NSView (InputMethod)).
--- XGInputServer.h.orig 2003-07-13 06:13:36.000000000 +0900
+++ XGInputServer.h 2003-07-13 20:10:49.000000000 +0900
@@ -59,6 +59,22 @@
name: (NSString *)name;
- (void) ximFocusICWindow: (gswindow_device_t *)windev;
- (void) ximCloseIC: (XIC)xic;
+
@end
+// Public interface for the input methods
+@interface XIMInputServer (InputMethod)
+- (NSString *) inputMethodStyle;
+- (NSString *) fontSize: (int *)size;
+- (BOOL) clientWindowRect: (NSRect *)rect;
+
+- (BOOL) statusArea: (NSRect *)rect;
+- (BOOL) preeditArea: (NSRect *)rect;
+- (BOOL) preeditSpot: (NSPoint *)p;
+
+- (BOOL) setStatusArea: (NSRect *)rect;
+- (BOOL) setPreeditArea: (NSRect *)rect;
+- (BOOL) setPreeditSpot: (NSPoint *)p;
+@end // XIMInputServer (InputMethod)
+
#endif
--- XGServer.h.orig 2003-07-13 06:13:36.000000000 +0900
+++ XGServer.h 2003-07-13 20:11:45.000000000 +0900
@@ -81,4 +81,19 @@
- (NSRect) _XFrameToOSFrame: (NSRect)x for: (void*)window;
@end
+// Public interface for the input methods.
+@interface XGServer (InputMethod)
+- (NSString *) inputMethodStyle;
+- (NSString *) fontSize: (int *)size;
+- (BOOL) clientWindowRect: (NSRect *)rect;
+
+- (BOOL) statusArea: (NSRect *)rect;
+- (BOOL) preeditArea: (NSRect *)rect;
+- (BOOL) preeditSpot: (NSPoint *)p;
+
+- (BOOL) setStatusArea: (NSRect *)rect;
+- (BOOL) setPreeditArea: (NSRect *)rect;
+- (BOOL) setPreeditSpot: (NSPoint *)p;
+@end
+
#endif /* _XGServer_h_INCLUDE */
--- XGServer.m.orig 2003-07-13 06:13:37.000000000 +0900
+++ XGServer.m 2003-07-13 21:35:16.000000000 +0900
@@ -550,3 +550,187 @@
@end
+
+@implementation XGServer (InputMethod)
+- (NSString *) inputMethodStyle
+{
+ return inputServer ? [(XIMInputServer *)inputServer inputMethodStyle] : nil;
+}
+
+- (NSString *) fontSize: (int *)size
+{
+ return inputServer ? [(XIMInputServer *)inputServer fontSize: size] : nil;
+}
+
+- (BOOL) clientWindowRect: (NSRect *)rect
+{
+ return inputServer
+ ? [(XIMInputServer *)inputServer clientWindowRect: rect] : NO;
+}
+
+- (BOOL) statusArea: (NSRect *)rect
+{
+ return inputServer ? [(XIMInputServer *)inputServer statusArea: rect] : NO;
+}
+
+- (BOOL) preeditArea: (NSRect *)rect
+{
+ return inputServer ? [(XIMInputServer *)inputServer preeditArea: rect] : NO;
+}
+
+- (BOOL) preeditSpot: (NSPoint *)p
+{
+ return inputServer ? [(XIMInputServer *)inputServer preeditSpot: p] : NO;
+}
+
+- (BOOL) setStatusArea: (NSRect *)rect
+{
+ return inputServer
+ ? [(XIMInputServer *)inputServer setStatusArea: rect] : NO;
+}
+
+- (BOOL) setPreeditArea: (NSRect *)rect
+{
+ return inputServer
+ ? [(XIMInputServer *)inputServer setPreeditArea: rect] : NO;
+}
+
+- (BOOL) setPreeditSpot: (NSPoint *)p
+{
+ return inputServer
+ ? [(XIMInputServer *)inputServer setPreeditSpot: p] : NO;
+}
+
+@end // XGServer (InputMethod)
+
+
+//==== Additional code for NSTextView =========================================
+//
+// WARNING This section is not genuine part of the XGServer implementation.
+// -------
+//
+// The methods implemented in this section override some of the internal
+// methods defined in NSTextView so that the class can support input methods
+// (XIM) in cooperation with XGServer.
+//
+// Note that the orverriding is done by defining the methods in a category,
+// the name of which is not explicitly mentioned in NSTextView.h; the
+// category is called 'InputMethod'.
+//
+
+#include <AppKit/NSClipView.h>
+#include <AppKit/NSTextView.h>
+
+@implementation NSTextView (InputMethod)
+
+- (void) _updateInputMethodState
+{
+ NSRect frame;
+ int font_size;
+ NSRect status_area;
+ NSRect preedit_area;
+ id displayServer = (XGServer *)GSCurrentServer();
+
+ if (![displayServer respondsToSelector: @selector(inputMethodStyle)])
+ return;
+
+ if (![displayServer fontSize: &font_size])
+ return;
+
+ if ([[self superview] isKindOfClass: [NSClipView class]])
+ frame = [[self superview] frame];
+ else
+ frame = [self frame];
+
+ status_area.size.width = 2 * font_size;
+ status_area.size.height = font_size + 2;
+ status_area.origin.x = 0;
+ status_area.origin.y = frame.size.height - status_area.size.height;
+
+ if ([[displayServer inputMethodStyle] isEqual: @"OverTheSpot"])
+ {
+ preedit_area.origin.x = 0;
+ preedit_area.origin.y = 0;
+ preedit_area.size.width = frame.size.width;
+ preedit_area.size.height = status_area.size.height;
+
+ [displayServer setStatusArea: &status_area];
+ [displayServer setPreeditArea: &preedit_area];
+ }
+ else if ([[displayServer inputMethodStyle] isEqual: @"OffTheSpot"])
+ {
+ preedit_area.origin.x = status_area.size.width + 2;
+ preedit_area.origin.y = status_area.origin.y;
+ preedit_area.size.width = frame.origin.x + frame.size.width
+ - preedit_area.origin.x;
+ preedit_area.size.height = status_area.size.height;
+
+ [displayServer setStatusArea: &status_area];
+ [displayServer setPreeditArea: &preedit_area];
+ }
+ else
+ {
+ // Do nothing for the RootWindow style.
+ }
+}
+
+- (void) _updateInputMethodWithInsertionPoint: (NSPoint)insertionPoint
+{
+ id displayServer = (XGServer *)GSCurrentServer();
+
+ if (![displayServer respondsToSelector: @selector(inputMethodStyle)])
+ return;
+
+ if ([[displayServer inputMethodStyle] isEqual: @"OverTheSpot"])
+ {
+ id view;
+ NSRect frame;
+ NSPoint p;
+ NSRect client_win_rect;
+ NSPoint screenXY_of_frame;
+ double x_offset;
+ double y_offset;
+ int font_size;
+ NSRect doc_rect;
+ NSRect doc_visible_rect;
+ BOOL cond;
+ float x = insertionPoint.x;
+ float y = insertionPoint.y;
+
+ [displayServer clientWindowRect: &client_win_rect];
+ [displayServer fontSize: &font_size];
+
+ cond = [[self superview] isKindOfClass: [NSClipView class]];
+ if (cond)
+ view = [self superview];
+ else
+ view = self;
+
+ frame = [view frame];
+ screenXY_of_frame = [[view window] convertBaseToScreen: frame.origin];
+
+ // N.B. The window of NSTextView isn't necessarily the same as the input
+ // method's client window.
+ x_offset = screenXY_of_frame.x - client_win_rect.origin.x;
+ y_offset = (client_win_rect.origin.y + client_win_rect.size.height)
+ - (screenXY_of_frame.y + frame.size.height) + font_size;
+
+ x += x_offset;
+ y += y_offset;
+ if (cond) // If 'view' is of NSClipView, then
+ {
+ // N.B. Remember, (x, y) are the values with respect to NSTextView.
+ // We need to know the corresponding insertion position with respect
+ // to NSClipView.
+ doc_rect = [(NSClipView *)view documentRect];
+ doc_visible_rect = [view documentVisibleRect];
+ y -= doc_visible_rect.origin.y - doc_rect.origin.y;
+ }
+
+ p = NSMakePoint(x, y);
+ [displayServer setPreeditSpot: &p];
+ }
+}
+
+@end // NSTextView
+//==== End: Additional Code for NSTextView ====================================
--- XIMInputServer.m.orig 2003-07-13 06:13:37.000000000 +0900
+++ XIMInputServer.m 2003-07-13 06:37:13.000000000 +0900
@@ -27,6 +27,7 @@
#include "config.h"
+#include <Foundation/NSUserDefaults.h>
#include <Foundation/NSData.h>
#include <Foundation/NSDebug.h>
#include <Foundation/NSException.h>
@@ -37,6 +38,11 @@
#include "x11/XGInputServer.h"
#include <X11/Xlocale.h>
+#define RootWindowStyle (XIMPreeditNothing | XIMStatusNothing)
+#define OffTheSpotStyle (XIMPreeditArea | XIMStatusArea)
+#define OverTheSpotStyle (XIMPreeditPosition | XIMStatusArea)
+#define OnTheSpotStyle (XIMPreeditCallbacks| XIMStatusCallbacks)
+
@interface XIMInputServer (XIMPrivate)
- (BOOL) ximInit: (Display *)dpy;
@@ -240,31 +246,59 @@
- (int) ximStyleInit
{
- /* FIXME: Right now we only support this style *but*
- this is only temporary */
- XIMStyle xim_supported_style=XIMPreeditNothing|XIMStatusNothing;
- XIMStyles *styles;
- char *failed_arg;
- int i;
+ NSUserDefaults *uds;
+ NSString *request;
+ XIMStyle xim_requested_style;
+ XIMStyles *styles;
+ char *failed_arg;
+ int i;
+
+ uds = [NSUserDefaults standardUserDefaults];
+ if ((request = [uds stringForKey: @"GSXIMInputMethodStyle"]) == nil)
+ {
+ xim_requested_style = RootWindowStyle;
+ }
+ else if ([request isEqual: @"RootWindow"])
+ {
+ xim_requested_style = RootWindowStyle;
+ }
+ else if ([request isEqual: @"OffTheSpot"])
+ {
+ xim_requested_style = OffTheSpotStyle;
+ }
+ else if ([request isEqual: @"OverTheSpot"])
+ {
+ xim_requested_style = OverTheSpotStyle;
+ }
+ else if ([request isEqual: @"OnTheSpot"])
+ {
+ xim_requested_style = OnTheSpotStyle;
+ }
+ else
+ {
+ NSLog(@"XIM: Unknown style '%s'.\n"
+ @"Fallback to RootWindow style.", [request cString]);
+ xim_requested_style = RootWindowStyle;
+ }
- failed_arg = XGetIMValues(xim,XNQueryInputStyle,&styles,NULL);
- if (failed_arg!=NULL)
+ failed_arg = XGetIMValues(xim, XNQueryInputStyle, &styles, NULL);
+ if (failed_arg != NULL)
{
NSDebugLLog(@"XIM", @"Can't getting the following IM value :%s",
failed_arg);
return 0;
}
- for (i=0;i<styles->count_styles;i++)
+ for (i = 0; i < styles->count_styles; i++)
{
- if (styles->supported_styles[i]==xim_supported_style)
+ if (styles->supported_styles[i] == xim_requested_style)
{
- xim_style=xim_supported_style;
+ xim_style = xim_requested_style;
XFree(styles);
return 1;
}
}
-
+ NSLog(@"XIM: '%s' is not supported", request);
XFree(styles);
return 0;
}
@@ -315,10 +349,111 @@
- (XIC) ximCreateIC: (Window)w
{
- XIC xic;
- xic = XCreateIC(xim, XNClientWindow, w, XNInputStyle,
- xim_style, NULL);
- if (xic==NULL)
+ XIC xic = NULL;
+
+ if (xim_style == RootWindowStyle)
+ {
+ xic = XCreateIC(xim,
+ XNInputStyle, xim_style,
+ XNClientWindow, w,
+ NULL);
+ }
+ else if (xim_style == OffTheSpotStyle || xim_style == OverTheSpotStyle)
+ {
+ Display *dpy = [XGServer currentXDisplay];
+ XFontSet font_set;
+ char **missing_charset;
+ int num_missing_charset;
+ int dummy = 0;
+ XVaNestedList preedit_args = NULL;
+ XVaNestedList status_args = NULL;
+ XRectangle status_area;
+ XRectangle preedit_area;
+ XPoint preedit_spot;
+ NSString *ns_font_size;
+ int font_size;
+ char base_font_name[64];
+
+ //
+ // Create a FontSet
+ //
+
+ // N.B. Because some input methods fail to provide a default font set,
+ // we have to do it by ourselves.
+ ns_font_size = [self fontSize: &font_size];
+ sprintf(base_font_name, "*medium-r-normal--%s*", [ns_font_size cString]);
+ font_set = XCreateFontSet(dpy,
+ base_font_name,
+ &missing_charset,
+ &num_missing_charset,
+ NULL);
+ if (!font_set)
+ {
+ goto finish;
+ }
+ if (missing_charset)
+ {
+ int i;
+ NSLog(@"XIM: missing charset: ");
+ for (i = 0; i < num_missing_charset; ++i)
+ NSLog(@"%s", missing_charset[i]);
+ XFreeStringList(missing_charset);
+ }
+
+ //
+ // Create XIC.
+ //
+ // At least, XNFontSet and XNPreeditSpotLocation must be specified
+ // at initialization time.
+ //
+ status_area.width = font_size * 2;
+ status_area.height = font_size + 2;
+ status_area.x = 0;
+ status_area.y = 0;
+
+ status_args = XVaCreateNestedList(dummy,
+ XNArea, &status_area,
+ XNFontSet, font_set,
+ NULL);
+
+ preedit_area.width = 120;
+ preedit_area.height = status_area.height;
+ preedit_area.x = 0;
+ preedit_area.y = 0;
+
+ preedit_spot.x = 0;
+ preedit_spot.y = 0;
+
+ preedit_args = XVaCreateNestedList(dummy,
+ XNArea, &preedit_area,
+ XNSpotLocation, &preedit_spot,
+ XNFontSet, font_set,
+ NULL);
+
+ xic = XCreateIC(xim,
+ XNInputStyle, xim_style,
+ XNClientWindow, w,
+ XNPreeditAttributes, preedit_args,
+ XNStatusAttributes, status_args,
+ NULL);
+
+ if (preedit_args) { XFree(preedit_args); preedit_args = NULL; }
+ if (status_args) { XFree(status_args); status_args = NULL; }
+ if (font_set) XFreeFontSet(dpy, font_set);
+ }
+ else if (xim_style == OnTheSpotStyle)
+ {
+ NSLog(@"XIM: GNUstep doesn't support 'OnTheSpot'.\n"
+ @"Fallback to RootWindow style.");
+ xim_style = RootWindowStyle;
+ xic = XCreateIC(xim,
+ XNInputStyle, xim_style,
+ XNClientWindow, w,
+ NULL);
+ }
+
+finish:
+ if (xic == NULL)
NSDebugLLog(@"XIM", @"Can't create the input context.\n");
xics = realloc(xics, sizeof(XIC) * (num_xics + 1));
@@ -356,3 +491,218 @@
}
@end
+
+@implementation XIMInputServer (InputMethod)
+- (NSString *) inputMethodStyle
+{
+ if (num_xics > 0)
+ {
+ if (xim_style == RootWindowStyle)
+ return @"RootWindow";
+ else if (xim_style == OffTheSpotStyle)
+ return @"OffTheSpot";
+ else if (xim_style == OverTheSpotStyle)
+ return @"OverTheSpot";
+ else if (xim_style == OnTheSpotStyle)
+ return @"OnTheSpot";
+ }
+ return nil;
+}
+
+- (NSString *) fontSize: (int *)size
+{
+ NSString *str;
+
+ str = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSFontSize"];
+ if (!str)
+ str = @"12";
+ *size = (int)strtol([str cString], NULL, 10);
+ return str;
+}
+
+- (BOOL) clientWindowRect: (NSRect *)rect
+{
+ Window win;
+ Window dummy;
+ Display *dpy;
+ int abs_x, abs_y;
+ int x, y;
+ unsigned int w, h;
+ unsigned int bw, d;
+
+ if (num_xics <= 0 || !rect) return NO;
+
+ *rect = NSMakeRect(0, 0, 0, 0);
+
+ if (XGetICValues(xics[num_xics - 1], XNClientWindow, &win, NULL))
+ return NO;
+ dpy = [XGServer currentXDisplay];
+ if (XTranslateCoordinates(dpy, win, DefaultRootWindow(dpy), 0, 0,
+ &abs_x, &abs_y, &dummy) == 0)
+ return NO;
+ XGetGeometry(dpy, win, &dummy, &x, &y, &w, &h, &bw, &d);
+
+ // X Window Coordinates to GNUstep Coordinates
+ x = abs_x;
+ y = XDisplayHeight(dpy, 0) - (abs_y + h);
+
+ *rect = NSMakeRect((float)x, (float)y, (float)w, (float)h);
+
+ return YES;
+}
+
+- (BOOL) statusArea: (NSRect *)rect
+{
+ if (num_xics > 0 && (xim_style & XIMStatusArea))
+ {
+ XRectangle area;
+ int dummy = 0;
+ XVaNestedList arglist = NULL;
+
+ if (!(arglist = XVaCreateNestedList(dummy, XNArea, &area, NULL)))
+ {
+ return NO;
+ }
+ XGetICValues(xics[num_xics - 1], XNStatusAttributes, arglist, NULL);
+
+ rect->origin.x = area.x;
+ rect->origin.y = area.y;
+ rect->size.width = area.width;
+ rect->size.height = area.height;
+
+ if (arglist) { XFree(arglist); arglist = NULL; }
+
+ return YES;
+ }
+ return NO;
+}
+
+- (BOOL) preeditArea: (NSRect *)rect
+{
+ if (num_xics > 0
+ && ((xim_style & XIMPreeditArea) || (xim_style & XIMPreeditPosition)))
+ {
+ XRectangle area;
+ int dummy = 0;
+ XVaNestedList arglist = NULL;
+
+ if (!(arglist = XVaCreateNestedList(dummy, XNArea, &area, NULL)))
+ {
+ return NO;
+ }
+ XGetICValues(xics[num_xics - 1], XNPreeditAttributes, arglist, NULL);
+
+ rect->origin.x = area.x;
+ rect->origin.y = area.y;
+ rect->size.width = area.width;
+ rect->size.height = area.height;
+
+ if (arglist) { XFree(arglist); arglist = NULL; }
+
+ return YES;
+ }
+ return NO;
+}
+
+- (BOOL) preeditSpot: (NSPoint *)p
+{
+ if (num_xics > 0 && (xim_style & XIMPreeditPosition))
+ {
+ XPoint spot;
+ int dummy = 0;
+ XVaNestedList arglist = NULL;
+
+ if (!(arglist = XVaCreateNestedList(dummy, XNSpotLocation, &spot, NULL)))
+ {
+ return NO;
+ }
+ XGetICValues(xics[num_xics - 1], XNPreeditAttributes, arglist, NULL);
+
+ p->x = spot.x;
+ p->y = spot.y;
+
+ if (arglist) { XFree(arglist); arglist = NULL; }
+
+ return YES;
+ }
+ return NO;
+}
+
+- (BOOL) setStatusArea: (NSRect *)rect
+{
+ if (num_xics > 0 && (xim_style & XIMStatusArea))
+ {
+ XRectangle area;
+ int dummy = 0;
+ XVaNestedList arglist = NULL;
+
+ area.x = rect->origin.x;
+ area.y = rect->origin.y;
+ area.width = rect->size.width;
+ area.height = rect->size.height;
+
+ if (!(arglist = XVaCreateNestedList(dummy, XNArea, &area, NULL)))
+ {
+ return NO;
+ }
+ XSetICValues(xics[num_xics - 1], XNStatusAttributes, arglist, NULL);
+
+ if (arglist) { XFree(arglist); arglist = NULL; }
+
+ return YES;
+ }
+ return NO;
+}
+
+- (BOOL) setPreeditArea: (NSRect *)rect
+{
+ if (num_xics > 0
+ && ((xim_style & XIMPreeditArea) || (xim_style & XIMPreeditPosition)))
+ {
+ XRectangle area;
+ int dummy = 0;
+ XVaNestedList arglist = NULL;
+
+ area.x = rect->origin.x;
+ area.y = rect->origin.y;
+ area.width = rect->size.width;
+ area.height = rect->size.height;
+
+ if (!(arglist = XVaCreateNestedList(dummy, XNArea, &area, NULL)))
+ {
+ return NO;
+ }
+ XSetICValues(xics[num_xics - 1], XNPreeditAttributes, arglist, NULL);
+
+ if (arglist) { XFree(arglist); arglist = NULL; }
+
+ return YES;
+ }
+ return NO;
+}
+
+- (BOOL) setPreeditSpot: (NSPoint *)p
+{
+ if (num_xics > 0 && (xim_style & XIMPreeditPosition))
+ {
+ XPoint spot;
+ int dummy = 0;
+ XVaNestedList arglist = NULL;
+
+ spot.x = p->x;
+ spot.y = p->y;
+
+ if (!(arglist = XVaCreateNestedList(dummy, XNSpotLocation, &spot, NULL)))
+ {
+ return NO;
+ }
+ XSetICValues(xics[num_xics - 1], XNPreeditAttributes, arglist, NULL);
+
+ if (arglist) { XFree(arglist); arglist = NULL; }
+
+ return YES;
+ }
+ return NO;
+}
+
+@end // XIMInputServer (InputMethod)
- Extension to XIM support (2),
Kazunobu Kuriyama <=