Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 7 Mar 2003 14:00:47 -0500
From:      The Anarcat <anarcat@anarcat.ath.cx>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   ports/49010: [patch] dead keys can't be entered in mozilla-devel-gtk2-1.3b
Message-ID:  <20030307190035.CECD32F4@shall.anarcat.ath.cx>

next in thread | raw e-mail | index | archive | help

>Number:         49010
>Category:       ports
>Synopsis:       [patch] dead keys can't be entered in mozilla-devel-gtk2-1.3b
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Mar 07 11:10:11 PST 2003
>Closed-Date:
>Last-Modified:
>Originator:     The Anarcat
>Release:        FreeBSD 5.0-RELEASE i386
>Organization:
>Environment:
System: FreeBSD lenny.anarcat.ath.cx 5.0-RELEASE FreeBSD 5.0-RELEASE #1: Sun Feb 16 23:11:48 EST 2003 anarcat@lenny.anarcat.ath.cx:/usr/src/sys/i386/compile/LENNII i386

>Description:

The latest development version of the Mozilla port, compiled with
gtk2, shows a pretty annoying bug for non-english users: carets and
other dead keys cannot be entered in forms and such.

The bugzilla database has the whole story:

http://bugzilla.mozilla.org/show_bug.cgi?id=176713

is the original bug, which actually depends on:

http://bugzilla.mozilla.org/show_bug.cgi?id=176514

which appeared because XIM was disabled as described in:

http://bugzilla.mozilla.org/show_bug.cgi?id=176514#c5

>How-To-Repeat:

1. Start mozilla-gtk2-1.3b
2. try to type a dead key (say a caret) followed by a "e"

You should see "ê", but instead "e" shows up.

>Fix:

[note that I'm still waiting confirmation from the Mozilla developpers
that my patch is sane, but it looks ok and works]

The port can carry the following patch:

--- /usr/ports/www/mozilla-devel-gtk2/Makefile.orig	Fri Mar  7 13:56:49 2003
+++ /usr/ports/www/mozilla-devel-gtk2/Makefile	Fri Mar  7 13:56:43 2003
@@ -16,4 +16,6 @@
 WITH_GTK2=	yes
 MOZILLA=	mozilla-devel-gtk2
 
+EXTRA_PATCHES=	${FILESDIR}/xim_dekita2.patch
+
 .include "${MASTERDIR}/Makefile"

And this should be put in the files section of the master port. This
patch is also available in bugzilla:

http://bugzilla.mozilla.org/attachment.cgi?id=116566&action=view

--- /dev/null	Fri Mar  7 13:57:43 2003
+++ /usr/ports/www/mozilla-devel/files/xim_dekita2.patch	Fri Mar  7 10:28:19 2003
@@ -0,0 +1,517 @@
+Index: Makefile.in
+===================================================================
+RCS file: /cvsroot/mozilla/widget/src/gtk2/Makefile.in,v
+retrieving revision 1.24
+diff -u -r1.24 Makefile.in
+--- widget/src/gtk2/Makefile.in 28 Dec 2002 01:14:45 -0000      1.24
++++ widget/src/gtk2/Makefile.in 7 Mar 2003 07:39:24 -0000
+@@ -90,7 +90,7 @@
+ CFLAGS         += $(MOZ_GTK2_CFLAGS)
+ CXXFLAGS       += $(MOZ_GTK2_CFLAGS)
+ 
+-#DEFINES         += -DUSE_XIM
++DEFINES         += -DUSE_XIM
+ 
+ INCLUDES       += \
+                -I$(srcdir)/../xpwidgets \
+Index: nsWindow.cpp
+===================================================================
+RCS file: /cvsroot/mozilla/widget/src/gtk2/nsWindow.cpp,v
+retrieving revision 1.68
+diff -u -r1.68 nsWindow.cpp
+--- widget/src/gtk2/nsWindow.cpp	5 Mar 2003 23:17:28 -0000	1.68
++++ widget/src/gtk2/nsWindow.cpp	6 Mar 2003 02:22:39 -0000
+@@ -179,6 +179,7 @@
+ nsWeakPtr                     gRollupWindow;
+ 
+ #ifdef USE_XIM
++static nsWindow         *gIMEFocusWindow       = NULL;
+ 
+ struct nsXICLookupEntry {
+     PLDHashEntryHdr mKeyHash;
+@@ -186,7 +187,9 @@
+     GtkIMContext* mXIC;
+ };
+ 
+-PLDHashTable nsWindow::gXICLookupTable;
++PLDHashTable            nsWindow::gXICLookupTable;
++GdkEventKey*            nsWindow::gIMEKeyEvent = NULL;
++PRBool                  nsWindow::gIMEStringCommited = PR_TRUE;
+ 
+ static void IM_commit_cb              (GtkIMContext *context,
+                                        const gchar *str,
+@@ -257,61 +260,6 @@
+ #endif
+ }
+ 
+-#ifdef USE_XIM
+-void
+-nsWindow::IMEGetShellWindow(void)
+-{
+-    GtkWidget* top_window = nsnull;
+-    GetToplevelWidget(&top_window);
+-    if (top_window) {
+-        mIMEShellWindow = get_window_for_gtk_widget(top_window);
+-    }
+-}
+-
+-GtkIMContext*
+-nsWindow::IMEGetContext()
+-{
+-    if (!mIMEShellWindow) {
+-        return NULL;
+-    }
+-    PLDHashEntryHdr* hash_entry;
+-    nsXICLookupEntry* entry;
+-
+-    hash_entry = PL_DHashTableOperate(&gXICLookupTable,
+-                                      mIMEShellWindow, PL_DHASH_LOOKUP);
+-
+-    if (hash_entry) {
+-        entry = NS_REINTERPRET_CAST(nsXICLookupEntry *, hash_entry);
+-        if (entry->mXIC) {
+-            return entry->mXIC;
+-        }
+-    }
+-    return NULL;
+-}
+-
+-void
+-nsWindow::IMECreateContext(GdkWindow* aGdkWindow)
+-{
+-    PLDHashEntryHdr* hash_entry;
+-    nsXICLookupEntry* entry;
+-    GtkIMContext *im = gtk_im_multicontext_new();
+-    if (im) {
+-        hash_entry = PL_DHashTableOperate(&gXICLookupTable, this, PL_DHASH_ADD);
+-        if (hash_entry) {
+-            entry = NS_REINTERPRET_CAST(nsXICLookupEntry *, hash_entry);
+-            entry->mShellWindow = this;
+-            entry->mXIC = im;
+-        }
+-        gtk_im_context_set_client_window(im, aGdkWindow);
+-        g_signal_connect(G_OBJECT(im), "commit",
+-                         G_CALLBACK(IM_commit_cb), this);
+-        g_signal_connect(G_OBJECT(im), "preedit_changed",
+-                         G_CALLBACK(IM_preedit_changed_cb), this);
+-        this->mIMEShellWindow = this;
+-    }
+-}
+-#endif
+-
+ nsWindow::~nsWindow()
+ {
+     LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
+@@ -397,22 +345,7 @@
+     }
+ 
+ #ifdef USE_XIM
+-    GtkIMContext *im = IMEGetContext();
+-    // If this is the focus window and we have an IM context we need
+-    // to unset the focus on this window before we destroy the window.
+-    if (im && gFocusWindow == this) {
+-        LOGFOCUS(("  gtk_im_context_focus_out() from Destroy()\n"));
+-        gtk_im_context_focus_out(im);
+-    }
+-
+-    // if shell, delete GtkIMContext
+-    if (im && mShell) {
+-        gtk_im_context_reset(im);
+-        PL_DHashTableOperate(&gXICLookupTable, this, PL_DHASH_REMOVE);
+-        g_object_unref(G_OBJECT(im));
+-    }
+-
+-    mIMEShellWindow = nsnull;
++    IMEDestroyContext();
+ #endif
+ 
+     // make sure that we remove ourself as the focus window
+@@ -656,21 +589,30 @@
+         return NS_OK;
+     }
+ 
++#ifdef USE_XIM
++    if (mWindowType == eWindowType_child && !mIMEShellWindow) {
++        IMEGetShellWindow();
++    }
++#endif
++
+     // If there is already a focued child window, dispatch a LOSTFOCUS
+     // event from that widget and unset its got focus flag.
+-    if (gFocusWindow)
++    if (gFocusWindow) {
++#ifdef USE_XIM
++        // If same ic is focused, do not call LoseFocus()
++        if (mIMEShellWindow != gFocusWindow->mIMEShellWindow) {
++            gFocusWindow->IMELoseFocus();
++        }
++#endif
+         gFocusWindow->LoseFocus();
++    }
+ 
+     // Set this window to be the focused child window, update our has
+     // focus flag and dispatch a GOTFOCUS event.
+     gFocusWindow = this;
+ 
+ #ifdef USE_XIM
+-    GtkIMContext *im = IMEGetContext();
+-    if (im && !mIsTopLevel) {
+-        LOGFOCUS(("  gtk_im_context_focus_in()\n"));
+-        gtk_im_context_focus_in(im);
+-    }
++    IMESetFocus();
+ #endif
+ 
+     LOGFOCUS(("  widget now has focus - dispatching events [%p]\n", 
+@@ -1165,18 +1107,6 @@
+ void
+ nsWindow::LoseFocus(void)
+ {
+-#ifdef USE_XIM
+-    GtkIMContext *im = IMEGetContext();
+-    if (im && !mIsTopLevel) {
+-        LOGFOCUS(("  gtk_im_context_focus_out()\n"));
+-        gtk_im_context_focus_out(im);
+-        IMEComposeStart();
+-        IMEComposeText(NULL, 0, NULL, NULL);
+-        IMEComposeEnd();
+-        LOG(("gtk_im_context_focus_out\n"));
+-    }
+-#endif
+-
+     // make sure that we reset our repeat counter so the next keypress
+     // for this widget will get the down event
+     mInKeyRepeat = PR_FALSE;
+@@ -1449,6 +1379,7 @@
+     DispatchEvent(&event, status);
+ }
+ 
++
+ void
+ nsWindow::OnContainerFocusInEvent(GtkWidget *aWidget, GdkEventFocus *aEvent)
+ {
+@@ -1516,6 +1447,9 @@
+ 
+  foundit:
+ 
++#ifdef USE_XIM
++    gFocusWindow->IMELoseFocus();
++#endif
+     gFocusWindow->LoseFocus();
+ 
+     // We only dispatch a deactivate event if we are a toplevel
+@@ -1537,7 +1471,7 @@
+ #ifdef USE_XIM
+     GtkIMContext *im = IMEGetContext();
+     if (im) {
+-        if (gtk_im_context_filter_keypress(im, aEvent)) {
++        if (IMFilterKeypress(im, aEvent)) {
+             LOGFOCUS(("  keypress filtered by XIM\n"));
+             return TRUE;
+         }
+@@ -1621,7 +1555,7 @@
+ #ifdef USE_XIM
+     GtkIMContext *im = IMEGetContext();
+     if (im) {
+-        if (gtk_im_context_filter_keypress(im, aEvent)) {
++        if (IMFilterKeypress(im, aEvent)) {
+             LOGFOCUS(("  keypress filtered by XIM\n"));
+             return TRUE;
+         }
+@@ -2155,6 +2089,15 @@
+ 
+         // and the drawing area
+         mDrawingarea = moz_drawingarea_new(nsnull, mContainer);
++
++#ifdef USE_XIM
++#ifndef XIM_CREATE_IC_AT_FOCUS
++        if (mWindowType != eWindowType_popup) {
++            // create im context for shell
++            IMECreateContext(mShell->window);
++        }
++#endif /* XIM_CREATE_IC_AT_FOCUS */
++#endif /* USE_XIM */
+     }
+         break;
+     case eWindowType_child: {
+@@ -2167,11 +2110,13 @@
+             gtk_widget_realize(GTK_WIDGET(mContainer));
+ 
+             mDrawingarea = moz_drawingarea_new(nsnull, mContainer);
+-        }
+ #ifdef USE_XIM
+-        // get mIMEShellWindow and keep it
+-        IMEGetShellWindow();
+-#endif
++#ifndef XIM_CREATE_IC_AT_FOCUS
++            // create im context for gtk container
++            IMECreateContext(GTK_WIDGET(mContainer)->window);
++#endif /* XIM_CREATE_IC_AT_FOCUS */
++#endif /* USE_XIM */
++        }
+     }
+         break;
+     default:
+@@ -2216,13 +2161,6 @@
+                          G_CALLBACK(property_notify_event_cb), NULL);
+     }
+ 
+-#ifdef USE_XIM
+-    if (mShell) {
+-        // init GtkIMContext for shell
+-        IMECreateContext(mShell->window);
+-    }
+-#endif
+-
+     if (mContainer) {
+         g_signal_connect_after(G_OBJECT(mContainer), "size_allocate",
+                                G_CALLBACK(size_allocate_cb), NULL);
+@@ -3667,6 +3605,77 @@
+ }
+ 
+ #ifdef USE_XIM
++void
++nsWindow::IMEGetShellWindow(void)
++{
++    GtkWidget* top_window = nsnull;
++    GetToplevelWidget(&top_window);
++    if (top_window) {
++        mIMEShellWindow = get_window_for_gtk_widget(top_window);
++        if (mIMEShellWindow) {
++            return;
++        }
++    }
++
++    // find deepest nsWindow
++    if (!mDrawingarea) {
++        return;
++    }
++    GdkWindow *parent = gdk_window_get_parent(mDrawingarea->inner_window);
++    while (parent) {
++        nsWindow *window = get_window_for_gdk_window(parent);
++        if (window == nsnull) {
++           break;
++        }
++        if (window->mContainer) {
++            mIMEShellWindow = window;
++        }
++        parent = gdk_window_get_parent (parent);
++    }
++}
++
++GtkIMContext*
++nsWindow::IMEGetContext()
++{
++    if (!mIMEShellWindow) {
++        return NULL;
++    }
++    PLDHashEntryHdr* hash_entry;
++    nsXICLookupEntry* entry;
++
++    hash_entry = PL_DHashTableOperate(&gXICLookupTable,
++                                      mIMEShellWindow, PL_DHASH_LOOKUP);
++
++    if (hash_entry) {
++        entry = NS_REINTERPRET_CAST(nsXICLookupEntry *, hash_entry);
++        if (entry->mXIC) {
++            return entry->mXIC;
++        }
++    }
++    return NULL;
++}
++
++void
++nsWindow::IMECreateContext(GdkWindow* aGdkWindow)
++{
++    PLDHashEntryHdr* hash_entry;
++    nsXICLookupEntry* entry;
++    GtkIMContext *im = gtk_im_multicontext_new();
++    if (im) {
++        hash_entry = PL_DHashTableOperate(&gXICLookupTable, this, PL_DHASH_ADD);
++        if (hash_entry) {
++            entry = NS_REINTERPRET_CAST(nsXICLookupEntry *, hash_entry);
++            entry->mShellWindow = this;
++            entry->mXIC = im;
++        }
++        gtk_im_context_set_client_window(im, aGdkWindow);
++        g_signal_connect(G_OBJECT(im), "commit",
++                         G_CALLBACK(IM_commit_cb), this);
++        g_signal_connect(G_OBJECT(im), "preedit_changed",
++                         G_CALLBACK(IM_preedit_changed_cb), this);
++        this->mIMEShellWindow = this;
++    }
++}
+ 
+ void
+ nsWindow::IMEComposeStart(void)
+@@ -3737,6 +3746,26 @@
+     DispatchEvent(&compEvent, status);
+ }
+ 
++PRBool
++nsWindow::IMFilterKeypress  (GtkIMContext *context,
++                               GdkEventKey  *aEvent)
++{
++    gIMEKeyEvent = aEvent;
++    if (gtk_im_context_filter_keypress(context, aEvent)) {
++        /* return true if the keyevent is commited as string and
++        ** has been dispatched as TextEvent.
++        */
++        if( gIMEStringCommited ) {
++            return TRUE;
++        }
++        gIMEStringCommited = PR_TRUE;
++    }
++    gIMEKeyEvent = NULL;
++
++    /* the Keyevent is not filtered by IME */
++    return FALSE;
++}
++
+ /* static */
+ void
+ IM_preedit_changed_cb(GtkIMContext *context,
+@@ -3747,7 +3776,8 @@
+     PangoAttrList *feedback_list;
+ 
+     // call for focused window
+-    nsWindow *window = gFocusWindow;
++    // if gFocusWindow is null, use the last focused gIMEFocusWindow
++    nsWindow *window = gFocusWindow ? gFocusWindow : gIMEFocusWindow;
+     if (!window) return;
+   
+     // Should use cursor_pos ?
+@@ -3760,6 +3790,7 @@
+     if (!preedit_string || !*preedit_string) {
+         window->IMEComposeStart();
+         window->IMEComposeText(NULL, 0, NULL, NULL);
++        window->IMEComposeEnd();
+         return;
+     }
+ 
+@@ -3800,9 +3831,31 @@
+     glong uniStrLen;
+ 
+     // call for focused window
+-    nsWindow *window = gFocusWindow;
++    // if gFocusWindow is null, use the last focused gIMEFocusWindow
++    nsWindow *window = gFocusWindow ? gFocusWindow : gIMEFocusWindow;
+     if (!window) return;
+ 
++    /* if the IME does not change the keystrock, we won't send it 
++     * through the TextEvent.
++     */
++    nsWindow::gIMEStringCommited = PR_TRUE;
++    if ( nsWindow::gIMEKeyEvent )
++    {
++        char keyval_utf8[8]; /* should have at least 6 bytes of space */
++        gint keyval_utf8_len;
++        keyval_utf8_len = g_unichar_to_utf8( 
++                    gdk_keyval_to_unicode(nsWindow::gIMEKeyEvent->keyval),
++                    keyval_utf8);
++
++        keyval_utf8[keyval_utf8_len] = '\0';
++        if ( strcmp(utf8_str, keyval_utf8) == 0)
++        {
++            nsWindow::gIMEStringCommited = PR_FALSE;
++            return;
++        }
++        nsWindow::gIMEKeyEvent = NULL;
++    }
++
+     uniStr = NULL;
+     uniStrLen = 0;
+     uniStr = g_utf8_to_utf16(utf8_str, -1, NULL, &uniStrLen, NULL);
+@@ -3944,6 +3997,60 @@
+    *aTextRangeListLengthResult = count + 1;
+ 
+    pango_attr_iterator_destroy(aFeedbackIterator);
++}
++
++void
++nsWindow::IMELoseFocus(void)
++{
++    GtkIMContext *im = IMEGetContext();
++    if (!im) {
++        return;
++    }
++    gtk_im_context_focus_out(im);
++}
++
++void
++nsWindow::IMESetFocus(void)
++{
++    GtkIMContext *im = IMEGetContext();
++#ifdef XIM_CREATE_IC_AT_FOCUS
++    if (!im && mIMEShellWindow) {
++        if (mIMEShellWindow->mShell) {
++            // init GtkIMContext for shell
++            mIMEShellWindow->IMECreateContext(mIMEShellWindow->mShell->window);
++        } else if (mIMEShellWindow->mContainer) {
++            // init GtkIMContext for mContainer
++            mIMEShellWindow->IMECreateContext(GTK_WIDGET(mIMEShellWindow->mContainer)->window);
++        }
++    }
++    im = IMEGetContext();
++#endif /* XIM_CREATE_IC_AT_FOCUS */
++    if (!im) {
++        return;
++    }
++    gtk_im_context_focus_in(im);
++    gIMEFocusWindow = this;
++}
++
++void
++nsWindow::IMEDestroyContext(void)
++{
++    GtkIMContext *im = IMEGetContext();
++    if (im) {
++        // If this is the focus window and we have an IM context we need
++        // to unset the focus on this window before we destroy the window.
++        if (gIMEFocusWindow == this) {
++            gIMEFocusWindow->IMELoseFocus();
++            gIMEFocusWindow = nsnull;
++        }
++        // if shell, delete GtkIMContext
++        if (mIMEShellWindow == this) {
++            gtk_im_context_set_client_window(im, NULL);
++            PL_DHashTableOperate(&gXICLookupTable, this, PL_DHASH_REMOVE);
++            g_object_unref(G_OBJECT(im));
++        }
++    }
++    mIMEShellWindow = nsnull;
+ }
+ 
+ #endif
+Index: nsWindow.h
+===================================================================
+RCS file: /cvsroot/mozilla/widget/src/gtk2/nsWindow.h,v
+retrieving revision 1.32
+diff -u -r1.32 nsWindow.h
+--- widget/src/gtk2/nsWindow.h	17 Feb 2003 18:50:01 -0000	1.32
++++ widget/src/gtk2/nsWindow.h	6 Mar 2003 02:22:39 -0000
+@@ -239,6 +239,9 @@
+     static guint32     mLastButtonPressTime;
+ 
+ #ifdef USE_XIM
++    void               IMEDestroyContext(void);
++    void               IMESetFocus(void);
++    void               IMELoseFocus(void);
+     void               IMEComposeStart(void);
+     void               IMEComposeText(const PRUnichar *aText,
+                                       const PRInt32 aLen,
+@@ -249,9 +252,13 @@
+     void               IMEGetShellWindow(void);
+     GtkIMContext*      IMEGetContext(void);
+     void               IMECreateContext(GdkWindow* aGdkWindow);
+- 
++    PRBool             IMFilterKeypress  (GtkIMContext *context,
++                                                 GdkEventKey  *aEvent);
++
+     nsWindow*          mIMEShellWindow;
+     static PLDHashTable gXICLookupTable;
++    static GdkEventKey* gIMEKeyEvent;
++    static PRBool      gIMEStringCommited;
+ #endif
+ 
+ private:
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ports-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030307190035.CECD32F4>