Bug 729774 part.1 nsGtkIMModule should manage composition state more closely r=karlt

This commit is contained in:
Masayuki Nakano 2012-03-09 13:27:51 +09:00
parent 523a6b04cd
commit c29ddcb682
2 changed files with 66 additions and 33 deletions

View File

@ -114,8 +114,8 @@ nsGtkIMModule::nsGtkIMModule(nsWindow* aOwnerWindow) :
#endif
mDummyContext(nsnull),
mCompositionStart(PR_UINT32_MAX), mProcessingKeyEvent(nsnull),
mIsComposing(false), mIsIMFocused(false),
mIgnoreNativeCompositionEvent(false)
mCompositionState(eCompositionState_NotComposing),
mIsIMFocused(false), mIgnoreNativeCompositionEvent(false)
{
#ifdef PR_LOGGING
if (!gGtkIMLog) {
@ -412,7 +412,7 @@ nsGtkIMModule::OnKeyEvent(nsWindow* aCaller, GdkEventKey* aEvent,
// composed characters.
bool filterThisEvent = isFiltered && mFilterKeyEvent;
if (mIsComposing && !isFiltered) {
if (IsComposing() && !isFiltered) {
if (aEvent->type == GDK_KEY_PRESS) {
if (!mDispatchedCompositionString.IsEmpty()) {
// If there is composition string, we shouldn't dispatch
@ -448,8 +448,10 @@ void
nsGtkIMModule::OnFocusChangeInGecko(bool aFocus)
{
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
("GtkIMModule(%p): OnFocusChangeInGecko, aFocus=%s mIsComposing=%s, mIsIMFocused=%s, mIgnoreNativeCompositionEvent=%s",
this, aFocus ? "YES" : "NO", mIsComposing ? "YES" : "NO",
("GtkIMModule(%p): OnFocusChangeInGecko, aFocus=%s, "
"mCompositionState=%s, mIsIMFocused=%s, "
"mIgnoreNativeCompositionEvent=%s",
this, aFocus ? "YES" : "NO", GetCompositionStateName(),
mIsIMFocused ? "YES" : "NO",
mIgnoreNativeCompositionEvent ? "YES" : "NO"));
if (aFocus) {
@ -463,8 +465,8 @@ void
nsGtkIMModule::ResetIME()
{
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
("GtkIMModule(%p): ResetIME, mIsComposing=%s, mIsIMFocused=%s",
this, mIsComposing ? "YES" : "NO", mIsIMFocused ? "YES" : "NO"));
("GtkIMModule(%p): ResetIME, mCompositionState=%s, mIsIMFocused=%s",
this, GetCompositionStateName(), mIsIMFocused ? "YES" : "NO"));
GtkIMContext *im = GetContext();
if (NS_UNLIKELY(!im)) {
@ -485,8 +487,8 @@ nsGtkIMModule::ResetInputState(nsWindow* aCaller)
}
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
("GtkIMModule(%p): ResetInputState, aCaller=%p, mIsComposing=%s",
this, aCaller, mIsComposing ? "YES" : "NO"));
("GtkIMModule(%p): ResetInputState, aCaller=%p, mCompositionState=%s",
this, aCaller, GetCompositionStateName()));
if (aCaller != mLastFocusedWindow) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
@ -495,7 +497,7 @@ nsGtkIMModule::ResetInputState(nsWindow* aCaller)
return NS_OK;
}
if (!mIsComposing) {
if (!IsComposing()) {
return NS_OK;
}
@ -524,7 +526,7 @@ nsGtkIMModule::CancelIMEComposition(nsWindow* aCaller)
return NS_OK;
}
if (!mIsComposing) {
if (!IsComposing()) {
return NS_OK;
}
@ -830,7 +832,7 @@ nsGtkIMModule::OnEndCompositionNative(GtkIMContext *aContext)
// Note that the native commit can be fired *after* ResetIME().
mIgnoreNativeCompositionEvent = false;
if (!mIsComposing || shouldIgnoreThisEvent) {
if (!IsComposing() || shouldIgnoreThisEvent) {
// If we already handled the commit event, we should do nothing here.
return;
}
@ -868,13 +870,13 @@ nsGtkIMModule::OnChangeCompositionNative(GtkIMContext *aContext)
nsAutoString compositionString;
GetCompositionString(compositionString);
if (!mIsComposing && compositionString.IsEmpty()) {
if (!IsComposing() && compositionString.IsEmpty()) {
mDispatchedCompositionString.Truncate();
return; // Don't start the composition with empty string.
}
// Be aware, widget can be gone
DispatchTextEvent(compositionString, true);
DispatchTextEvent(compositionString, false);
}
/* static */
@ -989,7 +991,7 @@ nsGtkIMModule::OnCommitCompositionNative(GtkIMContext *aContext,
// signal, we would dispatch compositionstart, text, compositionend
// events with empty string. Of course, they are unnecessary events
// for Web applications and our editor.
if (!mIsComposing && !commitString[0]) {
if (!IsComposing() && !commitString[0]) {
return;
}
@ -1000,7 +1002,7 @@ nsGtkIMModule::OnCommitCompositionNative(GtkIMContext *aContext,
// If IME doesn't change their keyevent that generated this commit,
// don't send it through XIM - just send it as a normal key press
// event.
if (!mIsComposing && mProcessingKeyEvent) {
if (!IsComposing() && mProcessingKeyEvent) {
char keyval_utf8[8]; /* should have at least 6 bytes of space */
gint keyval_utf8_len;
guint32 keyval_unicode;
@ -1031,7 +1033,7 @@ nsGtkIMModule::CommitCompositionBy(const nsAString& aString)
this, NS_ConvertUTF16toUTF8(aString).get(),
NS_ConvertUTF16toUTF8(mDispatchedCompositionString).get()));
if (!DispatchTextEvent(aString, false)) {
if (!DispatchTextEvent(aString, true)) {
return false;
}
// We should dispatch the compositionend event here because some IMEs
@ -1067,7 +1069,7 @@ nsGtkIMModule::DispatchCompositionStart()
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
("GtkIMModule(%p): DispatchCompositionStart", this));
if (mIsComposing) {
if (IsComposing()) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" WARNING, we're already in composition"));
return true;
@ -1120,7 +1122,7 @@ nsGtkIMModule::DispatchCompositionStart()
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" mCompositionStart=%u", mCompositionStart));
mIsComposing = true;
mCompositionState = eCompositionState_CompositionStartDispatched;
nsCompositionEvent compEvent(true, NS_COMPOSITION_START,
mLastFocusedWindow);
InitEvent(compEvent);
@ -1144,7 +1146,7 @@ nsGtkIMModule::DispatchCompositionEnd()
"mDispatchedCompositionString=\"%s\"",
this, NS_ConvertUTF16toUTF8(mDispatchedCompositionString).get()));
if (!mIsComposing) {
if (!IsComposing()) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" WARNING, we have alrady finished the composition"));
return false;
@ -1164,7 +1166,7 @@ nsGtkIMModule::DispatchCompositionEnd()
nsEventStatus status;
nsCOMPtr<nsIWidget> kungFuDeathGrip = mLastFocusedWindow;
mLastFocusedWindow->DispatchEvent(&compEvent, status);
mIsComposing = false;
mCompositionState = eCompositionState_NotComposing;
mCompositionStart = PR_UINT32_MAX;
mDispatchedCompositionString.Truncate();
if (static_cast<nsWindow*>(kungFuDeathGrip.get())->IsDestroyed() ||
@ -1179,11 +1181,11 @@ nsGtkIMModule::DispatchCompositionEnd()
bool
nsGtkIMModule::DispatchTextEvent(const nsAString &aCompositionString,
bool aCheckAttr)
bool aIsCommit)
{
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
("GtkIMModule(%p): DispatchTextEvent, aCheckAttr=%s",
this, aCheckAttr ? "TRUE" : "FALSE"));
("GtkIMModule(%p): DispatchTextEvent, aIsCommit=%s",
this, aIsCommit ? "TRUE" : "FALSE"));
if (!mLastFocusedWindow) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
@ -1191,7 +1193,7 @@ nsGtkIMModule::DispatchTextEvent(const nsAString &aCompositionString,
return false;
}
if (!mIsComposing) {
if (!IsComposing()) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" The composition wasn't started, force starting..."));
nsCOMPtr<nsIWidget> kungFuDeathGrip = mLastFocusedWindow;
@ -1224,7 +1226,7 @@ nsGtkIMModule::DispatchTextEvent(const nsAString &aCompositionString,
PRUint32 targetOffset = mCompositionStart;
nsAutoTArray<nsTextRange, 4> textRanges;
if (aCheckAttr) {
if (!aIsCommit) {
// NOTE: SetTextRangeList() assumes that mDispatchedCompositionString
// has been updated already.
SetTextRangeList(textRanges);
@ -1242,6 +1244,10 @@ nsGtkIMModule::DispatchTextEvent(const nsAString &aCompositionString,
textEvent.rangeArray = textRanges.Elements();
textEvent.theText = mDispatchedCompositionString.get();
mCompositionState = aIsCommit ?
eCompositionState_CommitTextEventDispatched :
eCompositionState_TextEventDispatched;
mLastFocusedWindow->DispatchEvent(&textEvent, status);
if (lastFocusedWindow->IsDestroyed() ||
lastFocusedWindow != mLastFocusedWindow) {

View File

@ -173,12 +173,39 @@ protected:
// event.
GdkEventKey* mProcessingKeyEvent;
// mCompositionState indicates current status of composition.
enum eCompositionState {
eCompositionState_NotComposing,
eCompositionState_CompositionStartDispatched,
eCompositionState_TextEventDispatched,
eCompositionState_CommitTextEventDispatched
};
eCompositionState mCompositionState;
bool IsComposing()
{
return (mCompositionState != eCompositionState_NotComposing);
}
#ifdef PR_LOGGING
const char* GetCompositionStateName()
{
switch (mCompositionState) {
case eCompositionState_NotComposing:
return "NotComposing";
case eCompositionState_CompositionStartDispatched:
return "CompositionStartDispatched";
case eCompositionState_TextEventDispatched:
return "TextEventDispatched";
case eCompositionState_CommitTextEventDispatched:
return "CommitTextEventDispatched";
default:
return "InvaildState";
}
}
#endif // PR_LOGGING
// mIsComposing is set to TRUE when we dispatch the composition start
// event. And it's set to FALSE when we dispatches the composition end
// event. Note that mCompositionString can be empty string even if this is
// TRUE.
bool mIsComposing;
// mIsIMFocused is set to TRUE when we call gtk_im_context_focus_in(). And
// it's set to FALSE when we call gtk_im_context_focus_out().
bool mIsIMFocused;
@ -303,10 +330,10 @@ protected:
bool DispatchCompositionStart();
bool DispatchCompositionEnd();
// Dispatches a text event. If aCheckAttr is TRUE, dispatches a committed
// Dispatches a text event. If aIsCommit is TRUE, dispatches a committed
// text event. Otherwise, dispatches a composing text event.
bool DispatchTextEvent(const nsAString& aCompositionString,
bool aCheckAttr);
bool aIsCommit);
};