From bca2539c532ad67f56d4150fd101e666918b7201 Mon Sep 17 00:00:00 2001 From: "tajima%eng.sun.com" Date: Tue, 15 May 2001 03:08:08 +0000 Subject: [PATCH] 53989 XIM: over-the-spot hangs with VJE3.0 and ATOK X (checked in the patch of katakai@japan.sun.com) r/sr=blizzard --- widget/src/gtk/nsGtkIMEHelper.cpp | 61 ++-- widget/src/gtk/nsGtkIMEHelper.h | 20 +- widget/src/gtk/nsWidget.cpp | 505 +-------------------------- widget/src/gtk/nsWidget.h | 51 +-- widget/src/gtk/nsWindow.cpp | 546 +++++++++++++++++++++++++++++- widget/src/gtk/nsWindow.h | 60 ++++ 6 files changed, 645 insertions(+), 598 deletions(-) diff --git a/widget/src/gtk/nsGtkIMEHelper.cpp b/widget/src/gtk/nsGtkIMEHelper.cpp index 572d7a5e4f7b..2bf17224f2be 100644 --- a/widget/src/gtk/nsGtkIMEHelper.cpp +++ b/widget/src/gtk/nsGtkIMEHelper.cpp @@ -31,7 +31,6 @@ #include "nsIPref.h" #include -#include "nsWidget.h" #include "nsWindow.h" static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID); @@ -817,14 +816,14 @@ nsIMEGtkIC::preedit_start_cbproc(XIC xic, XPointer client_data, { nsIMEGtkIC *thisXIC = (nsIMEGtkIC*)client_data; if (!thisXIC) return 0; - nsWidget *widget = thisXIC->mFocusWidget; - if (!widget) return 0; + nsWindow *fwin = thisXIC->mFocusWindow; + if (!fwin) return 0; if (!thisXIC->mPreedit) { thisXIC->mPreedit = new nsIMEPreedit(); } thisXIC->mPreedit->Reset(); - widget->ime_preedit_start(); + fwin->ime_preedit_start(); return 0; } @@ -834,8 +833,8 @@ nsIMEGtkIC::preedit_draw_cbproc(XIC xic, XPointer client_data, { nsIMEGtkIC *thisXIC = (nsIMEGtkIC*)client_data; if (!thisXIC) return 0; - nsWidget *widget = thisXIC->mFocusWidget; - if (!widget) return 0; + nsWindow *fwin = thisXIC->mFocusWindow; + if (!fwin) return 0; XIMPreeditDrawCallbackStruct *call_data = (XIMPreeditDrawCallbackStruct *) call_data_p; @@ -847,7 +846,7 @@ nsIMEGtkIC::preedit_draw_cbproc(XIC xic, XPointer client_data, thisXIC->mPreedit->SetPreeditString(text, call_data->chg_first, call_data->chg_length); - widget->ime_preedit_draw(); + fwin->ime_preedit_draw(thisXIC); return 0; } @@ -864,10 +863,10 @@ nsIMEGtkIC::preedit_done_cbproc(XIC xic, XPointer client_data, { nsIMEGtkIC *thisXIC = (nsIMEGtkIC*)client_data; if (!thisXIC) return 0; - nsWidget *widget = thisXIC->mFocusWidget; - if (!widget) return 0; + nsWindow *fwin = thisXIC->mFocusWindow; + if (!fwin) return 0; - widget->ime_preedit_done(); + fwin->ime_preedit_done(); return 0; } @@ -877,8 +876,8 @@ nsIMEGtkIC::status_start_cbproc(XIC xic, XPointer client_data, { nsIMEGtkIC *thisXIC = (nsIMEGtkIC*)client_data; if (!thisXIC) return 0; - nsWidget *widget = thisXIC->mFocusWidget; - if (!widget) return 0; + nsWindow *fwin = thisXIC->mFocusWindow; + if (!fwin) return 0; if (!gStatus) return 0; // focus_window is changed @@ -893,8 +892,8 @@ nsIMEGtkIC::status_draw_cbproc(XIC xic, XPointer client_data, { nsIMEGtkIC *thisXIC = (nsIMEGtkIC*)client_data; if (!thisXIC) return 0; - nsWidget *widget = thisXIC->mFocusWidget; - if (!widget) return 0; + nsWindow *fwin = thisXIC->mFocusWindow; + if (!fwin) return 0; if (!gStatus) return 0; @@ -939,10 +938,10 @@ nsIMEGtkIC::status_done_cbproc(XIC xic, XPointer client_data, return 0; } -nsWidget * -nsIMEGtkIC::GetFocusWidget() +nsWindow * +nsIMEGtkIC::GetFocusWindow() { - return mFocusWidget; + return mFocusWindow; } // workaround for kinput2/over-the-spot/ic-per-shell @@ -965,10 +964,10 @@ nsIMEGtkIC::GetFocusWidget() // *OverTheSpotConversion.modeLocation: bottomleft void -nsIMEGtkIC::SetFocusWidget(nsWidget * aFocusWidget) +nsIMEGtkIC::SetFocusWindow(nsWindow * aFocusWindow) { - mFocusWidget = aFocusWidget; - GdkWindow *gdkWindow = (GdkWindow*)aFocusWidget->GetNativeData(NS_NATIVE_WINDOW); + mFocusWindow = aFocusWindow; + GdkWindow *gdkWindow = (GdkWindow*)aFocusWindow->GetNativeData(NS_NATIVE_WINDOW); if (!gdkWindow) return; gdk_im_begin((GdkIC *) mIC, gdkWindow); @@ -987,20 +986,20 @@ nsIMEGtkIC::SetFocusWidget(nsWidget * aFocusWidget) } void -nsIMEGtkIC::UnsetFocusWidget() +nsIMEGtkIC::UnsetFocusWindow() { gdk_im_end(); } -nsIMEGtkIC *nsIMEGtkIC::GetXIC(nsWidget * aFocusWidget, GdkFont *aFontSet) +nsIMEGtkIC *nsIMEGtkIC::GetXIC(nsWindow * aFocusWindow, GdkFont *aFontSet) { - return nsIMEGtkIC::GetXIC(aFocusWidget, aFontSet, 0); + return nsIMEGtkIC::GetXIC(aFocusWindow, aFontSet, 0); } -nsIMEGtkIC *nsIMEGtkIC::GetXIC(nsWidget * aFocusWidget, +nsIMEGtkIC *nsIMEGtkIC::GetXIC(nsWindow * aFocusWindow, GdkFont *aFontSet, GdkFont *aStatusFontSet) { - nsIMEGtkIC *newic = new nsIMEGtkIC(aFocusWidget, aFontSet, aStatusFontSet); + nsIMEGtkIC *newic = new nsIMEGtkIC(aFocusWindow, aFontSet, aStatusFontSet); if (!newic->mIC || !newic->mIC->xic) { delete newic; return nsnull; @@ -1032,7 +1031,7 @@ nsIMEGtkIC::~nsIMEGtkIC() mIC = 0; mIC_backup = 0; mPreedit = 0; - mFocusWidget = 0; + mFocusWindow = 0; } // xim.input_policy: @@ -1393,20 +1392,20 @@ nsIMEGtkIC::SetPreeditArea(int aX, int aY, int aW, int aH) { } } -nsIMEGtkIC::nsIMEGtkIC(nsWidget *aFocusWidget, GdkFont *aFontSet) +nsIMEGtkIC::nsIMEGtkIC(nsWindow *aFocusWindow, GdkFont *aFontSet) { - ::nsIMEGtkIC(aFocusWidget, aFontSet, 0); + ::nsIMEGtkIC(aFocusWindow, aFontSet, 0); } -nsIMEGtkIC::nsIMEGtkIC(nsWidget *aFocusWidget, GdkFont *aFontSet, +nsIMEGtkIC::nsIMEGtkIC(nsWindow *aFocusWindow, GdkFont *aFontSet, GdkFont *aStatusFontSet) { - mFocusWidget = 0; + mFocusWindow = 0; mIC = 0; mIC_backup = 0; mPreedit = 0; - GdkWindow *gdkWindow = (GdkWindow *) aFocusWidget->GetNativeData(NS_NATIVE_WINDOW); + GdkWindow *gdkWindow = (GdkWindow *) aFocusWindow->GetNativeData(NS_NATIVE_WINDOW); if (!gdkWindow) { return; } diff --git a/widget/src/gtk/nsGtkIMEHelper.h b/widget/src/gtk/nsGtkIMEHelper.h index 88226450bff4..0f82aae2c3a1 100644 --- a/widget/src/gtk/nsGtkIMEHelper.h +++ b/widget/src/gtk/nsGtkIMEHelper.h @@ -110,7 +110,7 @@ typedef struct { XIMProc1 callback; } XIMCallback1; -class nsWidget; +class nsWindow; enum nsIMEPolicy { NSIME_UNKNOWN=0, @@ -130,10 +130,10 @@ class nsIMEGtkIC { static GdkIMStyle gInputStyle; static nsIMEPolicy gInputPolicy; static nsIMEStatus *gStatus; - nsWidget *mClientWidget; - nsWidget *mFocusWidget; - nsIMEGtkIC(nsWidget*, GdkFont*, GdkFont*); - nsIMEGtkIC(nsWidget*, GdkFont*); + nsWindow *mClientWindow; + nsWindow *mFocusWindow; + nsIMEGtkIC(nsWindow*, GdkFont*, GdkFont*); + nsIMEGtkIC(nsWindow*, GdkFont*); GdkICPrivate *mIC; GdkICPrivate *mIC_backup; nsIMEPreedit *mPreedit; @@ -141,11 +141,11 @@ class nsIMEGtkIC { public: nsIMEPreedit *GetPreedit() {return mPreedit;} ~nsIMEGtkIC(); - static nsIMEGtkIC *GetXIC(nsWidget*, GdkFont*, GdkFont*); - static nsIMEGtkIC *GetXIC(nsWidget*, GdkFont*); - void SetFocusWidget(nsWidget * aFocusWidget); - nsWidget* GetFocusWidget(); - static void UnsetFocusWidget(); + static nsIMEGtkIC *GetXIC(nsWindow*, GdkFont*, GdkFont*); + static nsIMEGtkIC *GetXIC(nsWindow*, GdkFont*); + void SetFocusWindow(nsWindow * aFocusWindow); + nsWindow* GetFocusWindow(); + static void UnsetFocusWindow(); static GdkIMStyle GetInputStyle(); static nsIMEPolicy GetInputPolicy(); diff --git a/widget/src/gtk/nsWidget.cpp b/widget/src/gtk/nsWidget.cpp index 97fa0092c741..89ec75b81d55 100644 --- a/widget/src/gtk/nsWidget.cpp +++ b/widget/src/gtk/nsWidget.cpp @@ -42,7 +42,6 @@ #include "nsGtkUtils.h" // for nsGtkUtils::gdk_keyboard_get_modifiers() #include "nsIPref.h" -#include "nsGtkIMEHelper.h" static NS_DEFINE_CID(kRegionCID, NS_REGION_CID); static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID); @@ -67,18 +66,11 @@ private: *mLast; // valid only for head of list }; -static nsWidget *GetShellWidget(GdkWindow *gdkWindow); - PRUint32 nsWidget::sWidgetCount = 0; // this is the nsWindow with the focus nsWidget *nsWidget::sFocusWindow = 0; -#ifdef USE_XIM -GdkFont *nsWidget::gPreeditFontset = nsnull; -GdkFont *nsWidget::gStatusFontset = nsnull; -GdkIMStyle nsWidget::gInputStyle = (GdkIMStyle)nsnull; -#endif // USE_XIM // this is the last time that an event happened. we keep this // around so that we can synth drag events properly guint32 nsWidget::sLastEventTime = 0; @@ -118,89 +110,6 @@ void nsWidget::GetLastEventTime(guint32 *aTime) *aTime = sLastEventTime; } -#ifdef USE_XIM -nsresult nsWidget::KillICSpotTimer () -{ - if(mICSpotTimer) - { - mICSpotTimer->Cancel(); - mICSpotTimer = nsnull; - } - return NS_OK; -} -nsresult nsWidget::PrimeICSpotTimer () -{ - KillICSpotTimer(); - nsresult err; - mICSpotTimer = do_CreateInstance("@mozilla.org/timer;1", &err); - if (NS_FAILED(err)) - return err; - mICSpotTimer->Init(ICSpotCallback, this, 1000); - return NS_OK; -} -void nsWidget::ICSpotCallback(nsITimer * aTimer, void * aClosure) -{ - nsWidget *widget= NS_REINTERPRET_CAST(nsWidget*, aClosure); - if( ! widget) return; - nsresult res = widget->UpdateICSpot(); - if(NS_SUCCEEDED(res)) - { - widget->PrimeICSpotTimer(); - } -} -nsresult nsWidget::UpdateICSpot() -{ - // set spot location - nsCompositionEvent compEvent; - compEvent.widget = (nsWidget*)this; - compEvent.point.x = 0; - compEvent.point.y = 0; - compEvent.time = 0; - compEvent.message = NS_COMPOSITION_QUERY; - compEvent.eventStructType = NS_COMPOSITION_QUERY; - compEvent.compositionMessage = NS_COMPOSITION_QUERY; - static gint oldx =0; - static gint oldy =0; - static gint oldw =0; - static gint oldh =0; - compEvent.theReply.mCursorPosition.x=-1; - compEvent.theReply.mCursorPosition.y=-1; - this->OnComposition(compEvent); - // set SpotLocation - if((compEvent.theReply.mCursorPosition.x < 0) && - (compEvent.theReply.mCursorPosition.y < 0)) - return NS_ERROR_FAILURE; - - // In over-the-spot style, pre-edit can not be drawn properly when - // IMESetFocusWidget() is called at height=1 and width=1 - // After resizing, we need to call SetPreeditArea() again - if((oldw != mBounds.width) || (oldh != mBounds.height)) { - GdkWindow *gdkWindow = (GdkWindow*)this->GetNativeData(NS_NATIVE_WINDOW); - if (mXIC && gdkWindow) { - mXIC->SetPreeditArea(0, 0, - (int)((GdkWindowPrivate*)gdkWindow)->width, - (int)((GdkWindowPrivate*)gdkWindow)->height); - } - oldw = mBounds.width; - oldh = mBounds.height; - } - - if((compEvent.theReply.mCursorPosition.x != oldx)|| - (compEvent.theReply.mCursorPosition.y != oldy)) - { - nsPoint spot; - spot.x = compEvent.theReply.mCursorPosition.x; - spot.y = compEvent.theReply.mCursorPosition.y + - compEvent.theReply.mCursorPosition.height; - SetXICBaseFontSize( compEvent.theReply.mCursorPosition.height - 1); - SetXICSpotLocation(spot); - oldx = compEvent.theReply.mCursorPosition.x; - oldy = compEvent.theReply.mCursorPosition.y; - } - return NS_OK; -} -#endif // USE_XIM - nsCOMPtr nsWidget::gRollupListener; nsWeakPtr nsWidget::gRollupWidget; PRBool nsWidget::gRollupConsumeRollupEvent = PR_FALSE; @@ -268,20 +177,6 @@ nsWidget::nsWidget() sWidgetCount++; -#ifdef USE_XIM - mIMEEnable = PR_TRUE; - mXIC = 0; - - mIMEShellWidget = 0; - mIMECallComposeStart = PR_FALSE; - mIMECallComposeEnd = PR_TRUE; - mIMEIsBeingActivate = PR_FALSE; - - mICSpotTimer = nsnull; -#endif // USE_XIM - mIMECompositionUniString = nsnull; - mIMECompositionUniStringSize = 0; - mListenForResizes = PR_FALSE; mHasFocus = PR_FALSE; if (mGDKHandlerInstalled == PR_FALSE) { @@ -320,11 +215,6 @@ nsWidget::nsWidget() nsWidget::~nsWidget() { -#ifdef USE_XIM - mXIC = 0; - KillICSpotTimer(); -#endif // USE_XIM - #ifdef NOISY_DESTROY IndentByDepth(stdout); printf("nsWidget::~nsWidget:%p\n", this); @@ -336,10 +226,6 @@ nsWidget::~nsWidget() // to be called once Destroy(); - if (mIMECompositionUniString) { - delete[] mIMECompositionUniString; - mIMECompositionUniString = nsnull; - } NS_ASSERTION(!ModalWidgetList::Find(this), "destroying widget without first clearing modality."); #ifdef NS_DEBUG if (mIsToplevel) { @@ -727,10 +613,6 @@ nsWidget::LoseFocus(void) if (mHasFocus == PR_FALSE) return; -#ifdef USE_XIM - IMEUnsetFocusWidget(); -#endif // USE_XIM - sFocusWindow = 0; mHasFocus = PR_FALSE; @@ -2521,137 +2403,11 @@ void nsWidget::SetBackgroundColorNative(GdkColor *aColorNor, ////////////////////////////////////////////////////////////////////// -#ifdef USE_XIM -void -nsWidget::GetXIC() -{ - if (gInputStyle == nsnull) { - gInputStyle = nsIMEGtkIC::GetInputStyle(); - } - if (gPreeditFontset == nsnull) { - gPreeditFontset = gdk_fontset_load("-*-*-medium-r-*-*-16-*-*-*-*-*-*-*"); - mXICFontSize = 16; // default - } - if (gStatusFontset == nsnull) { - gStatusFontset = gdk_fontset_load("-*-*-medium-r-*-*-16-*-*-*-*-*-*-*"); - } - IMEGetShellWidget(); - if (!gInputStyle || !gPreeditFontset || !gStatusFontset || !mIMEShellWidget) { - return; - } - - if (mIMEShellWidget->mXIC){ - mXIC = mIMEShellWidget->mXIC; - } else { - mXIC = nsIMEGtkIC::GetXIC(mIMEShellWidget, gPreeditFontset, - gStatusFontset); - if (mXIC) { - // fix me! need to know how to get spot location - mXIC->SetPreeditSpotLocation(0, 14); - mIMEShellWidget->mXIC = mXIC; - } - } - return; -} -#endif // USE_XIM - NS_IMETHODIMP nsWidget::ResetInputState() { -#ifdef USE_XIM - if (mIMEEnable == PR_FALSE) return NS_OK; - - if (mXIC) { - IMEGetShellWidget(); - if (!mIMEShellWidget) return NS_OK; - - // while being called for NS_ACTIVE and NS_DEACTIVATE, - // ignore ResetInputState() call - if (mIMEShellWidget->mIMEIsBeingActivate == PR_TRUE) { - return NS_OK; - } - - PRInt32 uniCharSize = - mXIC->ResetIC(&(mIMECompositionUniString), - &(mIMECompositionUniStringSize)); - - if (uniCharSize) { - mIMECompositionUniString[uniCharSize] = 0; - - IMEComposeStart(nsnull); - IMEComposeText(nsnull, - mIMECompositionUniString, - uniCharSize, - nsnull); - } - - // Call IMEComposeEnd() to reset the state of field - IMEComposeEnd(nsnull); - if (gInputStyle & GDK_IM_PREEDIT_POSITION) { - UpdateICSpot(); - } - } -#endif // USE_XIM return NS_OK; } -#ifdef USE_XIM -void -nsWidget::GetXYFromPosition(unsigned long *aX, - unsigned long *aY) -{ - if (mIMEEnable == PR_FALSE) return; - if (nsnull == mXIC) return; - if (mXIC) { - GdkFont *gfontset = mXIC->GetPreeditFont(); - if (gfontset) { - // this is currently not working well - // We change from += ascent to -= descent because we change the nsCaret - // code to return the nsPoint from the top of the cursor to the bottom - // of the cursor - *aY -= gfontset->descent; - } - } - return; -} - -void -nsWidget::SetXICBaseFontSize(int height) -{ - if (mIMEEnable == PR_FALSE) return; - if (nsnull == mXIC) return; - if (mXIC) { - if (height == mXICFontSize) return; - if (height%2) { - height-=1; - } - if (height<2) return; - if (gPreeditFontset) { - gdk_font_unref(gPreeditFontset); - } - char xlfdbase[128]; - sprintf(xlfdbase, "-*-*-medium-r-*-*-%d-*-*-*-*-*-*-*", height); - gPreeditFontset = gdk_fontset_load(xlfdbase); - if (gPreeditFontset) { - mXIC->SetPreeditFont(gPreeditFontset); - } - mXICFontSize = height; - } -} -void -nsWidget::SetXICSpotLocation(nsPoint aPoint) -{ - if (mIMEEnable == PR_FALSE) return; - if (nsnull == mXIC) return; - if (mXIC) { - unsigned long x, y; - x = aPoint.x, y = aPoint.y; - GetXYFromPosition(&x, &y); - mXIC->SetPreeditSpotLocation(x, y); - } - return; -} -#endif // USE_XIM - /********************** class ModalWidgetList ***********************/ /* This silly little thing is a linked list of widgets that have been declared modal, in the order of their declaration. We do this only @@ -2904,267 +2660,10 @@ static gint debugHandleWindowClose(GtkWidget *window, void *data) #endif /* NS_DEBUG */ -#ifdef USE_XIM -void -nsWidget::ime_preedit_start() { - IMEComposeStart(nsnull); +void nsWidget::IMECommitEvent(GdkEventKey *aEvent) { + NS_ASSERTION(0, "nsWidget::IMECommitEvent() shouldn't be called!\n"); } -void -nsWidget::ime_preedit_draw() { - IMEComposeStart(nsnull); - nsIMEPreedit *preedit = mXIC->GetPreedit(); - IMEComposeText(nsnull, - preedit->GetPreeditString(), - preedit->GetPreeditLength(), - preedit->GetPreeditFeedback()); - if (mXIC->IsPreeditComposing() == PR_FALSE) { - IMEComposeEnd(nsnull); - } -} - -void -nsWidget::ime_preedit_done() { - IMEComposeEnd(nsnull); -} - -void -nsWidget::IMEUnsetFocusWidget() -{ - KillICSpotTimer(); -} - -void -nsWidget::IMESetFocusWidget() -{ - if (!mXIC) { - GetXIC(); - } - - IMEGetShellWidget(); - if (!mIMEShellWidget) return; - - if (mXIC) { - if (mXIC->IsPreeditComposing() == PR_FALSE) { - IMEComposeEnd(nsnull); - } - mXIC->SetFocusWidget(this); - if (gInputStyle & GDK_IM_PREEDIT_POSITION) { - UpdateICSpot(); - PrimeICSpotTimer(); - } - } -} - -void -nsWidget::IMEBeingActivate(PRBool aActive) -{ - IMEGetShellWidget(); - if (!mIMEShellWidget) return; - mIMEShellWidget->mIMEIsBeingActivate = aActive; -} -#endif // USE_XIM - -void -nsWidget::IMEComposeStart(guint aTime) -{ -#ifdef USE_XIM - if (mIMECallComposeStart == PR_TRUE) { - return; - } -#endif // USE_XIM - nsCompositionEvent compEvent; - compEvent.widget = (nsWidget *) this; - compEvent.point.x = compEvent.point.y = 0; - compEvent.time = aTime; - compEvent.message = compEvent.eventStructType - = compEvent.compositionMessage = NS_COMPOSITION_START; - - OnComposition(compEvent); - -#ifdef USE_XIM - mIMECallComposeStart = PR_TRUE; - mIMECallComposeEnd = PR_FALSE; -#endif // USE_XIM -} - -void -nsWidget::IMECommitEvent(GdkEventKey *aEvent) { - PRInt32 srcLen = aEvent->length; - - if (srcLen && aEvent->string && aEvent->string[0] && - nsGtkIMEHelper::GetSingleton()) { - - PRInt32 uniCharSize; - uniCharSize = nsGtkIMEHelper::GetSingleton()->MultiByteToUnicode( - aEvent->string, - srcLen, - &(mIMECompositionUniString), - &(mIMECompositionUniStringSize)); - - if (uniCharSize) { - mIMECompositionUniString[uniCharSize] = 0; - if(sFocusWindow == 0 && mXIC != 0) { - // Commit event happens when Mozilla window does not have - // input focus but Lookup window (candidate) window has the focus - // At the case, we have to call IME events with focused widget - nsWidget *widget = mXIC->GetFocusWidget(); - if (widget) { - widget->IMEComposeStart(aEvent->time); - widget->IMEComposeText(aEvent, - mIMECompositionUniString, - uniCharSize, - nsnull); - widget->IMEComposeEnd(aEvent->time); - } - } else { - IMEComposeStart(aEvent->time); - IMEComposeText(aEvent, - mIMECompositionUniString, - uniCharSize, - nsnull); - IMEComposeEnd(aEvent->time); - } - } - } - -#ifdef USE_XIM - if (gInputStyle & GDK_IM_PREEDIT_POSITION) { - // update spot location - IMEGetShellWidget(); - if (!mIMEShellWidget) return; - nsIMEGtkIC *XIC_tmp = mXIC ? mXIC : mIMEShellWidget->mXIC; - if (XIC_tmp) { - nsWidget *widget = XIC_tmp->GetFocusWidget(); - if (widget) { - widget->UpdateICSpot(); - widget->PrimeICSpotTimer(); - } - } - } -#endif // USE_XIM -} - -void -nsWidget::IMEComposeText(GdkEventKey *aEvent, - const PRUnichar *aText, const PRInt32 aLen, - const char *aFeedback) { - nsTextEvent textEvent; - if (aEvent) { - textEvent.isShift = (aEvent->state & GDK_SHIFT_MASK) ? PR_TRUE : PR_FALSE; - textEvent.isControl = (aEvent->state & GDK_CONTROL_MASK) ? PR_TRUE : PR_FALSE; - textEvent.isAlt = (aEvent->state & GDK_MOD1_MASK) ? PR_TRUE : PR_FALSE; - // XXX - textEvent.isMeta = PR_FALSE; //(aEvent->state & GDK_MOD2_MASK) ? PR_TRUE : PR_FALSE; - textEvent.time = aEvent->time; - } else { - textEvent.time = 0; - textEvent.isShift = textEvent.isControl = - textEvent.isAlt = textEvent.isMeta = PR_FALSE; - } - textEvent.message = textEvent.eventStructType = NS_TEXT_EVENT; - textEvent.widget = (nsWidget *)this; - textEvent.point.x = textEvent.point.y = 0; - - if (aLen == 0) { - textEvent.theText = nsnull; - textEvent.rangeCount = 0; - textEvent.rangeArray = nsnull; - } else { - textEvent.theText = (PRUnichar*)aText; - textEvent.rangeCount = 0; - textEvent.rangeArray = nsnull; -#ifdef USE_XIM - if (aFeedback) { - nsIMEPreedit::IMSetTextRange(aLen, - aFeedback, - &(textEvent.rangeCount), - &(textEvent.rangeArray)); - } -#endif // USE_XIM - } - OnText(textEvent); -#ifdef USE_XIM - if (textEvent.rangeArray) { - delete[] textEvent.rangeArray; - } -#endif // USE_XIM -} - -void -nsWidget::IMEComposeEnd(guint aTime) -{ -#ifdef USE_XIM - if (mIMECallComposeEnd == PR_TRUE) { - return; - } -#endif // USE_XIM - - nsCompositionEvent compEvent; - compEvent.widget = (nsWidget *) this; - compEvent.point.x = compEvent.point.y = 0; - compEvent.time = aTime; - compEvent.message = compEvent.eventStructType - = compEvent.compositionMessage = NS_COMPOSITION_END; - OnComposition(compEvent); - -#ifdef USE_XIM - mIMECallComposeStart = PR_FALSE; - mIMECallComposeEnd = PR_TRUE; -#endif // USE_XIM -} - -#ifdef USE_XIM -void -nsWidget::IMEGetShellWidget(void) -{ - if (!mIMEShellWidget) { - mIMEShellWidget = GetShellWidget((GdkWindow*) - GetNativeData(NS_NATIVE_WINDOW)); - NS_ASSERTION(mIMEShellWidget, "GetShellWidget() fails"); - } -} - -// FIXME: need to find more efficient way for finding the shell widget -static nsWidget * -GetShellWidget(GdkWindow *gdkWindow) -{ - GdkWindow *parent = gdk_window_get_parent(gdkWindow); - nsWidget *root_win = nsnull; - gpointer data; - - while (parent) { - gdk_window_get_user_data(parent, &data); - if (GTK_IS_OBJECT(data)) { - root_win = (nsWidget *) gtk_object_get_data(GTK_OBJECT(data), "nsWindow"); - if(root_win && root_win->mIsToplevel == PR_TRUE){ - return root_win; - } - } - parent = gdk_window_get_parent(parent); - } - return nsnull; -} - -void -nsWidget::IMEDestroyIC() -{ - if (!mXIC) return; - if (mIsToplevel == PR_TRUE) { - delete mXIC; - } else { - // see discussion in bug 53989 - nsWidget *widget = mXIC->GetFocusWidget(); - if (widget && widget == this && mIMEShellWidget) { - mXIC->SetFocusWidget(mIMEShellWidget); - mXIC->UnsetFocusWidget(); - } - } - mXIC = 0; -} - -#endif // USE_XIM - void nsWidget::DispatchSetFocusEvent(void) { NS_ASSERTION(0, "nsWidget::DispatchSetFocusEvent shouldn't be called!\n"); diff --git a/widget/src/gtk/nsWidget.h b/widget/src/gtk/nsWidget.h index a701765f3a54..953c640cfebb 100644 --- a/widget/src/gtk/nsWidget.h +++ b/widget/src/gtk/nsWidget.h @@ -36,10 +36,6 @@ class nsILookAndFeel; class nsIAppShell; class nsIToolkit; -#ifdef USE_XIM -class nsIMEGtkIC; -class nsIMEPreedit; -#endif // USE_XIM #include @@ -49,6 +45,7 @@ class nsIMEPreedit; #include "nsITimer.h" #include "nsITimerCallback.h" + #define NSRECT_TO_GDKRECT(ns,gdk) \ PR_BEGIN_MACRO \ gdk.x = ns.x; \ @@ -309,52 +306,8 @@ protected: PRBool HandlePopup(PRInt32 inMouseX, PRInt32 inMouseY, PRBool isWheel); PRBool IsMouseInWindow ( GdkWindow* inWindow, PRInt32 inMouseX, PRInt32 inMouseY ) ; -#ifdef USE_XIM -protected: - PRBool mIMEEnable; - void GetXIC(); - static GdkFont *gPreeditFontset; - static GdkFont *gStatusFontset; - static GdkIMStyle gInputStyle; - nsIMEGtkIC *mXIC; - PRBool mIMECallComposeStart; - PRBool mIMECallComposeEnd; - PRBool mIMEIsBeingActivate; - nsWidget* mIMEShellWidget; - void SetXICSpotLocation(nsPoint aPoint); - void SetXICBaseFontSize(int height); - - void GetXYFromPosition(unsigned long *aX, unsigned long *aY); - nsCOMPtr mICSpotTimer; - static void ICSpotCallback(nsITimer* aTimer, void* aClosure); - nsresult KillICSpotTimer(); - nsresult PrimeICSpotTimer(); - nsresult UpdateICSpot(); - int mXICFontSize; - public: - void ime_preedit_start(); - void ime_preedit_draw(); - void ime_preedit_done(); - void ime_status_draw(); - - void IMEUnsetFocusWidget(); - void IMESetFocusWidget(); - void IMEGetShellWidget(); - void IMEDestroyIC(); - void IMEBeingActivate(PRBool aActive); -#endif // USE_XIM -protected: - void IMEComposeStart(guint aTime); - void IMEComposeText(GdkEventKey*, - const PRUnichar *aText, - const PRInt32 aLen, - const char *aFeedback); - void IMEComposeEnd(guint aTime); - PRUnichar* mIMECompositionUniString; - PRInt32 mIMECompositionUniStringSize; -public: - void IMECommitEvent(GdkEventKey *aEvent); + virtual void IMECommitEvent(GdkEventKey *aEvent); protected: diff --git a/widget/src/gtk/nsWindow.cpp b/widget/src/gtk/nsWindow.cpp index 5994f043fb8c..48b8d65f9fb6 100644 --- a/widget/src/gtk/nsWindow.cpp +++ b/widget/src/gtk/nsWindow.cpp @@ -59,6 +59,8 @@ #include "nsIDragService.h" #include "nsIDragSessionGTK.h" +#include "nsGtkIMEHelper.h" + #include #ifdef NEED_USLEEP_PROTOTYPE @@ -118,6 +120,20 @@ nsWindow *nsWindow::mLastLeaveWindow = NULL; PRBool gJustGotDeactivate = PR_FALSE; PRBool gJustGotActivate = PR_FALSE; +#ifdef USE_XIM + +struct nsXICLookupEntry { + PLDHashEntryHdr mKeyHash; + nsWindow* mShellWindow; + nsIMEGtkIC* mXIC; +}; + +PLDHashTable nsWindow::gXICLookupTable; +GdkFont *nsWindow::gPreeditFontset = nsnull; +GdkFont *nsWindow::gStatusFontset = nsnull; +GdkIMStyle nsWindow::gInputStyle = (GdkIMStyle)nsnull; +#endif // USE_XIM + static void printDepth(int depth) { int i; for (i=0; i < depth; i++) @@ -166,6 +182,23 @@ nsWindow::nsWindow() mDragMotionY = 0; mDragMotionTime = 0; + // for commit character + mIMECompositionUniString = nsnull; + mIMECompositionUniStringSize = 0; + +#ifdef USE_XIM + mIMEEnable = PR_TRUE; //currently will not be used + mIMEShellWindow = 0; + mIMECallComposeStart = PR_FALSE; + mIMECallComposeEnd = PR_TRUE; + mIMEIsBeingActivate = PR_FALSE; + mICSpotTimer = nsnull; + if (gXICLookupTable.ops == NULL) { + PL_DHashTableInit(&gXICLookupTable, PL_DHashGetStubOps(), nsnull, + sizeof(nsXICLookupEntry), PL_DHASH_MIN_SIZE); + } +#endif // USE_XIM + // check to see if we should set our raise pref if (!gRaisePrefInitialized) { gRaisePrefInitialized = PR_TRUE; @@ -188,6 +221,15 @@ nsWindow::nsWindow() //------------------------------------------------------------------------- nsWindow::~nsWindow() { +#ifdef USE_XIM + KillICSpotTimer(); +#endif // USE_XIM + + if (mIMECompositionUniString) { + delete[] mIMECompositionUniString; + mIMECompositionUniString = nsnull; + } + // make sure to unset any drag motion timers here. ResetDragMotionTimer(0, 0, 0, 0, 0); @@ -310,14 +352,14 @@ NS_IMETHODIMP nsWindow::WidgetToScreen(const nsRect& aOldRect, nsRect& aNewRect) void nsWindow::DestroyNative(void) { -#ifdef USE_XIM - IMEDestroyIC(); -#endif // USE_XIM - // destroy all of the children that are nsWindow() classes // preempting the gdk destroy system. DestroyNativeChildren(); +#ifdef USE_XIM + IMEDestroyIC(); +#endif // USE_XIM + if (mSuperWin) { // remove the key from the hash table for the shell_window g_hash_table_remove(mWindowLookupTable, mSuperWin->shell_window); @@ -1157,7 +1199,7 @@ nsWindow::SetFocus(PRBool aRaise) mHasFocus = PR_TRUE; #ifdef USE_XIM - if (sFocusWindow) sFocusWindow->IMESetFocusWidget(); + IMESetFocusWindow(); #endif // USE_XIM DispatchSetFocusEvent(); @@ -1172,6 +1214,22 @@ nsWindow::SetFocus(PRBool aRaise) return NS_OK; } +/* virtual */ void +nsWindow::LoseFocus(void) +{ + // doesn't do anything. needed for nsWindow housekeeping, really. + if (mHasFocus == PR_FALSE) + return; + +#ifdef USE_XIM + IMEUnsetFocusWindow(); +#endif // USE_XIM + + sFocusWindow = 0; + mHasFocus = PR_FALSE; + +} + void nsWindow::DispatchSetFocusEvent(void) { #ifdef DEBUG_FOCUS @@ -3487,3 +3545,481 @@ PRBool ChildWindow::IsChild() const return PR_TRUE; } +#ifdef USE_XIM +nsresult nsWindow::KillICSpotTimer () +{ + if(mICSpotTimer) + { + mICSpotTimer->Cancel(); + mICSpotTimer = nsnull; + } + return NS_OK; +} + +nsresult nsWindow::PrimeICSpotTimer () +{ + KillICSpotTimer(); + nsresult err; + mICSpotTimer = do_CreateInstance("@mozilla.org/timer;1", &err); + if (NS_FAILED(err)) + return err; + mICSpotTimer->Init(ICSpotCallback, this, 1000); + return NS_OK; +} + +void nsWindow::ICSpotCallback(nsITimer * aTimer, void * aClosure) +{ + nsWindow *window= NS_REINTERPRET_CAST(nsWindow*, aClosure); + if( ! window) return; + nsresult res = NS_ERROR_FAILURE; + + nsIMEGtkIC *xic = window->IMEGetInputContext(PR_FALSE); + if (xic) { + res = window->UpdateICSpot(xic); + } + if(NS_SUCCEEDED(res)) + { + window->PrimeICSpotTimer(); + } +} + +nsresult nsWindow::UpdateICSpot(nsIMEGtkIC *aXIC) +{ + // set spot location + nsCompositionEvent compEvent; + compEvent.widget = NS_STATIC_CAST(nsWidget *, this); + compEvent.point.x = 0; + compEvent.point.y = 0; + compEvent.time = 0; + compEvent.message = NS_COMPOSITION_QUERY; + compEvent.eventStructType = NS_COMPOSITION_QUERY; + compEvent.compositionMessage = NS_COMPOSITION_QUERY; + static gint oldx =0; + static gint oldy =0; + static gint oldw =0; + static gint oldh =0; + compEvent.theReply.mCursorPosition.x=-1; + compEvent.theReply.mCursorPosition.y=-1; + this->OnComposition(compEvent); + // set SpotLocation + if((compEvent.theReply.mCursorPosition.x < 0) && + (compEvent.theReply.mCursorPosition.y < 0)) + return NS_ERROR_FAILURE; + + // In over-the-spot style, pre-edit can not be drawn properly when + // IMESetFocusWindow() is called at height=1 and width=1 + // After resizing, we need to call SetPreeditArea() again + if((oldw != mBounds.width) || (oldh != mBounds.height)) { + GdkWindow *gdkWindow = (GdkWindow*)this->GetNativeData(NS_NATIVE_WINDOW); + if (gdkWindow) { + aXIC->SetPreeditArea(0, 0, + (int)((GdkWindowPrivate*)gdkWindow)->width, + (int)((GdkWindowPrivate*)gdkWindow)->height); + } + oldw = mBounds.width; + oldh = mBounds.height; + } + + if((compEvent.theReply.mCursorPosition.x != oldx)|| + (compEvent.theReply.mCursorPosition.y != oldy)) + { + nsPoint spot; + spot.x = compEvent.theReply.mCursorPosition.x; + spot.y = compEvent.theReply.mCursorPosition.y + + compEvent.theReply.mCursorPosition.height; + SetXICBaseFontSize(aXIC, compEvent.theReply.mCursorPosition.height - 1); + SetXICSpotLocation(aXIC, spot); + oldx = compEvent.theReply.mCursorPosition.x; + oldy = compEvent.theReply.mCursorPosition.y; + } + return NS_OK; +} + +void +nsWindow::GetXYFromPosition(nsIMEGtkIC* aXIC, + unsigned long *aX, + unsigned long *aY) +{ + GdkFont *gfontset = aXIC->GetPreeditFont(); + if (gfontset) { + // this is currently not working well + // We change from += ascent to -= descent because we change the nsCaret + // code to return the nsPoint from the top of the cursor to the bottom + // of the cursor + *aY -= gfontset->descent; + } + return; +} + +void +nsWindow::SetXICBaseFontSize(nsIMEGtkIC* aXIC, int height) +{ + if (height == mXICFontSize) return; + if (height%2) { + height-=1; + } + if (height<2) return; + if (gPreeditFontset) { + gdk_font_unref(gPreeditFontset); + } + char xlfdbase[128]; + sprintf(xlfdbase, "-*-*-medium-r-*-*-%d-*-*-*-*-*-*-*", height); + gPreeditFontset = gdk_fontset_load(xlfdbase); + if (gPreeditFontset) { + aXIC->SetPreeditFont(gPreeditFontset); + } + mXICFontSize = height; +} + +void +nsWindow::SetXICSpotLocation(nsIMEGtkIC* aXIC, nsPoint aPoint) +{ + unsigned long x, y; + x = aPoint.x, y = aPoint.y; + GetXYFromPosition(aXIC, &x, &y); + aXIC->SetPreeditSpotLocation(x, y); +} + +void +nsWindow::ime_preedit_start() { + IMEComposeStart(nsnull); +} + +void +nsWindow::ime_preedit_draw(nsIMEGtkIC *aXIC) { + IMEComposeStart(nsnull); + nsIMEPreedit *preedit = aXIC->GetPreedit(); + IMEComposeText(nsnull, + preedit->GetPreeditString(), + preedit->GetPreeditLength(), + preedit->GetPreeditFeedback()); + if (aXIC->IsPreeditComposing() == PR_FALSE) { + IMEComposeEnd(nsnull); + } +} + +void +nsWindow::ime_preedit_done() { + IMEComposeEnd(nsnull); +} + +void +nsWindow::IMEUnsetFocusWindow() +{ + KillICSpotTimer(); +} + +void +nsWindow::IMESetFocusWindow() +{ + // there is only one place to get ShellWindow + IMEGetShellWindow(); + + nsIMEGtkIC *xic = IMEGetInputContext(PR_TRUE); + + if (xic) { + if (xic->IsPreeditComposing() == PR_FALSE) { + IMEComposeEnd(nsnull); + } + xic->SetFocusWindow(this); + if (gInputStyle & GDK_IM_PREEDIT_POSITION) { + UpdateICSpot(xic); + PrimeICSpotTimer(); + } + } +} + +void +nsWindow::IMEBeingActivate(PRBool aActive) +{ + // mIMEShellWindow has been retrieved in IMESetFocusWindow() + if (mIMEShellWindow) { + mIMEShellWindow->mIMEIsBeingActivate = aActive; + } else { + NS_ASSERTION(0, "mIMEShellWindow should exist"); + } +} + +void +nsWindow::IMEGetShellWindow(void) +{ + if (!mIMEShellWindow) { + nsWindow *mozAreaWindow = nsnull; + GtkWidget *top_mozarea = GetMozArea(); + if (top_mozarea) { + mozAreaWindow = NS_STATIC_CAST(nsWindow *, + gtk_object_get_data(GTK_OBJECT(top_mozarea), "nsWindow")); + } + mIMEShellWindow = mozAreaWindow; + NS_ASSERTION(mIMEShellWindow, "IMEGetShellWindow() fails"); + } +} + +nsIMEGtkIC* +nsWindow::IMEGetInputContext(PRBool aCreate) +{ + PLDHashEntryHdr* hash_entry; + nsXICLookupEntry* entry; + + if (!mIMEShellWindow) { + return nsnull; + } + + 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; + } + } + + // create new XIC + if (aCreate) { + if (gInputStyle == nsnull) { + gInputStyle = nsIMEGtkIC::GetInputStyle(); + } + if (gPreeditFontset == nsnull) { + gPreeditFontset = gdk_fontset_load("-*-*-medium-r-*-*-16-*-*-*-*-*-*-*"); + mXICFontSize = 16; // default + } + if (gStatusFontset == nsnull) { + gStatusFontset = gdk_fontset_load("-*-*-medium-r-*-*-16-*-*-*-*-*-*-*"); + } + if (!gInputStyle || !gPreeditFontset || !gStatusFontset) { + return nsnull; + } + nsIMEGtkIC *xic = nsIMEGtkIC::GetXIC(mIMEShellWindow, gPreeditFontset, + gStatusFontset); + if (xic) { + xic->SetPreeditSpotLocation(0, 14); + hash_entry = PL_DHashTableOperate(&gXICLookupTable, + mIMEShellWindow, + PL_DHASH_ADD); + if (hash_entry) { + entry = NS_REINTERPRET_CAST(nsXICLookupEntry *, hash_entry); + entry->mShellWindow = mIMEShellWindow; + entry->mXIC = xic; + } + mIMEShellWindow->mIMEShellWindow = mIMEShellWindow; + return xic; + } + } + return nsnull; +} + +void +nsWindow::IMEDestroyIC() +{ + // do not call IMEGetShellWindow() here + // user mIMEShellWindow to retrieve XIC + nsIMEGtkIC *xic = IMEGetInputContext(PR_FALSE); + + // xic=null means mIMEShellWindow is destroyed before + // or xic is never created for this widget + if (!xic) { + return; + } + + if (mIMEShellWindow == this) { + // shell widget is being destroyed + // remove XIC from hashtable by mIMEShellWindow key + PL_DHashTableOperate(&gXICLookupTable, mIMEShellWindow, PL_DHASH_REMOVE); + delete xic; + } else { + // xic and mIMEShellWindow are valid + // see discussion in bug 53989 + nsWindow *fwin = xic->GetFocusWindow(); + if (fwin && fwin == this) { + xic->SetFocusWindow(mIMEShellWindow); + xic->UnsetFocusWindow(); + } + } +} +#endif // USE_XIM + +void +nsWindow::IMEComposeStart(guint aTime) +{ +#ifdef USE_XIM + if (mIMECallComposeStart == PR_TRUE) { + return; + } +#endif // USE_XIM + nsCompositionEvent compEvent; + compEvent.widget = NS_STATIC_CAST(nsWidget *, this); + compEvent.point.x = compEvent.point.y = 0; + compEvent.time = aTime; + compEvent.message = compEvent.eventStructType + = compEvent.compositionMessage = NS_COMPOSITION_START; + + OnComposition(compEvent); + +#ifdef USE_XIM + mIMECallComposeStart = PR_TRUE; + mIMECallComposeEnd = PR_FALSE; +#endif // USE_XIM +} + +void +nsWindow::IMECommitEvent(GdkEventKey *aEvent) { + PRInt32 srcLen = aEvent->length; + + if (srcLen && aEvent->string && aEvent->string[0] && + nsGtkIMEHelper::GetSingleton()) { + + PRInt32 uniCharSize; + uniCharSize = nsGtkIMEHelper::GetSingleton()->MultiByteToUnicode( + aEvent->string, + srcLen, + &(mIMECompositionUniString), + &(mIMECompositionUniStringSize)); + + if (uniCharSize) { +#ifdef USE_XIM + nsIMEGtkIC *xic = IMEGetInputContext(PR_FALSE); + mIMECompositionUniString[uniCharSize] = 0; + if(sFocusWindow == 0 && xic != 0) { + // Commit event happens when Mozilla window does not have + // input focus but Lookup window (candidate) window has the focus + // At the case, we have to call IME events with focused widget + nsWindow *window = xic->GetFocusWindow(); + if (window) { + window->IMEComposeStart(aEvent->time); + window->IMEComposeText(aEvent, + mIMECompositionUniString, + uniCharSize, + nsnull); + window->IMEComposeEnd(aEvent->time); + } + } else +#endif // USE_XIM + { + IMEComposeStart(aEvent->time); + IMEComposeText(aEvent, + mIMECompositionUniString, + uniCharSize, + nsnull); + IMEComposeEnd(aEvent->time); + } + } + } + +#ifdef USE_XIM + if (gInputStyle & GDK_IM_PREEDIT_POSITION) { + // update spot location + nsIMEGtkIC *xic = IMEGetInputContext(PR_FALSE); + if (xic) { + nsWindow *window = xic->GetFocusWindow(); + if (window) { + window->UpdateICSpot(xic); + window->PrimeICSpotTimer(); + } + } + } +#endif // USE_XIM +} + +void +nsWindow::IMEComposeText(GdkEventKey *aEvent, + const PRUnichar *aText, const PRInt32 aLen, + const char *aFeedback) { + nsTextEvent textEvent; + if (aEvent) { + textEvent.isShift = (aEvent->state & GDK_SHIFT_MASK) ? PR_TRUE : PR_FALSE; + textEvent.isControl = (aEvent->state & GDK_CONTROL_MASK) ? PR_TRUE : PR_FALSE; + textEvent.isAlt = (aEvent->state & GDK_MOD1_MASK) ? PR_TRUE : PR_FALSE; + // XXX + textEvent.isMeta = PR_FALSE; //(aEvent->state & GDK_MOD2_MASK) ? PR_TRUE : PR_FALSE; + textEvent.time = aEvent->time; + } else { + textEvent.time = 0; + textEvent.isShift = textEvent.isControl = + textEvent.isAlt = textEvent.isMeta = PR_FALSE; + } + textEvent.message = textEvent.eventStructType = NS_TEXT_EVENT; + textEvent.widget = NS_STATIC_CAST(nsWidget *, this); + textEvent.point.x = textEvent.point.y = 0; + + if (aLen == 0) { + textEvent.theText = nsnull; + textEvent.rangeCount = 0; + textEvent.rangeArray = nsnull; + } else { + textEvent.theText = (PRUnichar*)aText; + textEvent.rangeCount = 0; + textEvent.rangeArray = nsnull; +#ifdef USE_XIM + if (aFeedback) { + nsIMEPreedit::IMSetTextRange(aLen, + aFeedback, + &(textEvent.rangeCount), + &(textEvent.rangeArray)); + } +#endif // USE_XIM + } + OnText(textEvent); +#ifdef USE_XIM + if (textEvent.rangeArray) { + delete[] textEvent.rangeArray; + } +#endif // USE_XIM +} + +void +nsWindow::IMEComposeEnd(guint aTime) +{ +#ifdef USE_XIM + if (mIMECallComposeEnd == PR_TRUE) { + return; + } +#endif // USE_XIM + + nsCompositionEvent compEvent; + compEvent.widget = NS_STATIC_CAST(nsWidget*, this); + compEvent.point.x = compEvent.point.y = 0; + compEvent.time = aTime; + compEvent.message = compEvent.eventStructType + = compEvent.compositionMessage = NS_COMPOSITION_END; + OnComposition(compEvent); + +#ifdef USE_XIM + mIMECallComposeStart = PR_FALSE; + mIMECallComposeEnd = PR_TRUE; +#endif // USE_XIM +} + +NS_IMETHODIMP nsWindow::ResetInputState() +{ +#ifdef USE_XIM + nsIMEGtkIC *xic = IMEGetInputContext(PR_FALSE); + if (xic) { + // while being called for NS_ACTIVE and NS_DEACTIVATE, + // ignore ResetInputState() call + if (mIMEShellWindow->mIMEIsBeingActivate == PR_TRUE) { + return NS_OK; + } + + PRInt32 uniCharSize = + xic->ResetIC(&(mIMECompositionUniString), + &(mIMECompositionUniStringSize)); + + if (uniCharSize) { + mIMECompositionUniString[uniCharSize] = 0; + + IMEComposeStart(nsnull); + IMEComposeText(nsnull, + mIMECompositionUniString, + uniCharSize, + nsnull); + } + + // Call IMEComposeEnd() to reset the state of field + IMEComposeEnd(nsnull); + if (gInputStyle & GDK_IM_PREEDIT_POSITION) { + UpdateICSpot(xic); + } + } +#endif // USE_XIM + return NS_OK; +} diff --git a/widget/src/gtk/nsWindow.h b/widget/src/gtk/nsWindow.h index b6f7cf3822ea..a12ce1d7d10e 100644 --- a/widget/src/gtk/nsWindow.h +++ b/widget/src/gtk/nsWindow.h @@ -33,6 +33,12 @@ #include "gtkmozarea.h" #include "gdksuperwin.h" +#ifdef USE_XIM +#include "pldhash.h" +class nsIMEGtkIC; +class nsIMEPreedit; +#endif // USE_XIM + class nsFont; class nsIAppShell; @@ -89,6 +95,11 @@ public: NS_IMETHOD GetAttention(void); NS_IMETHOD Destroy(); + virtual void LoseFocus(void); + + // nsIKBStateControl + NS_IMETHOD ResetInputState(); + void QueueDraw(); void UnqueueDraw(); void DoPaint(PRInt32 x, PRInt32 y, PRInt32 width, PRInt32 height, @@ -309,7 +320,56 @@ protected: static void dumpWindowChildren(Window aWindow, unsigned int depth); #endif +#ifdef USE_XIM +protected: + nsIMEGtkIC* IMEGetInputContext(PRBool aCreate); + PRBool mIMEEnable; + static GdkFont *gPreeditFontset; + static GdkFont *gStatusFontset; + static GdkIMStyle gInputStyle; + static PLDHashTable gXICLookupTable; + PRBool mIMECallComposeStart; + PRBool mIMECallComposeEnd; + PRBool mIMEIsBeingActivate; + nsWindow* mIMEShellWindow; + void SetXICSpotLocation(nsIMEGtkIC* aXIC, nsPoint aPoint); + void SetXICBaseFontSize(nsIMEGtkIC* aXIC, int height); + void GetXYFromPosition(nsIMEGtkIC* aXIC, unsigned long *aX, unsigned long *aY); + nsCOMPtr mICSpotTimer; + static void ICSpotCallback(nsITimer* aTimer, void* aClosure); + nsresult KillICSpotTimer(); + nsresult PrimeICSpotTimer(); + nsresult UpdateICSpot(nsIMEGtkIC* aXIC); + int mXICFontSize; + +public: + void ime_preedit_start(); + void ime_preedit_draw(nsIMEGtkIC* aXIC); + void ime_preedit_done(); + void ime_status_draw(); + + void IMEUnsetFocusWindow(); + void IMESetFocusWindow(); + void IMEGetShellWindow(); + void IMEDestroyIC(); + void IMEBeingActivate(PRBool aActive); +#endif // USE_XIM + +protected: + void IMEComposeStart(guint aTime); + void IMEComposeText(GdkEventKey*, + const PRUnichar *aText, + const PRInt32 aLen, + const char *aFeedback); + void IMEComposeEnd(guint aTime); + +public: + virtual void IMECommitEvent(GdkEventKey *aEvent); + private: + PRUnichar* mIMECompositionUniString; + PRInt32 mIMECompositionUniStringSize; + nsresult SetMiniIcon(GdkPixmap *window_pixmap, GdkBitmap *window_mask); nsresult SetIcon(GdkPixmap *window_pixmap,