Fix IM window position for a new window (#13094)

This commit is contained in:
Koji Yokota 2024-09-30 09:00:56 +09:00
parent 475d8e6433
commit a086804eb4
5 changed files with 184 additions and 35 deletions

View File

@ -1083,6 +1083,13 @@ struct GuiApplication::Private
/// ///
KeyModifier meta_fake_bit; KeyModifier meta_fake_bit;
/// input method uses this to preserve initial input item transform
bool first_work_area = true;
/// geometry of the input item of the first working area
QRectF item_rect_base_;
/// input item transformation of the first working area
QTransform item_trans_base_;
/// The result of last dispatch action /// The result of last dispatch action
DispatchResult dispatch_result_; DispatchResult dispatch_result_;
@ -2301,6 +2308,42 @@ docstring GuiApplication::viewStatusMessage()
} }
bool GuiApplication::isFirstWorkArea() const
{
return d->first_work_area;
}
void GuiApplication::firstWorkAreaDone()
{
d->first_work_area = false;
}
QRectF GuiApplication::baseInputItemRectangle()
{
return d->item_rect_base_;
}
void GuiApplication::setBaseInputItemRectangle(QRectF rect)
{
d->item_rect_base_ = rect;
}
QTransform GuiApplication::baseInputItemTransform()
{
return d->item_trans_base_;
}
void GuiApplication::setBaseInputItemTransform(QTransform trans)
{
d->item_trans_base_ = trans;
}
string GuiApplication::inputLanguageCode() const string GuiApplication::inputLanguageCode() const
{ {
QLocale loc = inputMethod()->locale(); QLocale loc = inputMethod()->locale();
@ -2586,6 +2629,11 @@ void GuiApplication::createView(bool autoShow, int view_id)
if (d->global_menubar_) if (d->global_menubar_)
d->global_menubar_->releaseKeyboard(); d->global_menubar_->releaseKeyboard();
// need to reset system input method coords with the preserved one
// when the new view is the second one or later
if (d->views_.size() > 0)
current_view_->currentWorkArea()->resetInputItemGeometry(true);
// create new view // create new view
int id = view_id; int id = view_id;
while (d->views_.find(id) != d->views_.end()) while (d->views_.find(id) != d->views_.end())

View File

@ -185,6 +185,19 @@ public:
/// return the status bar state string /// return the status bar state string
docstring viewStatusMessage(); docstring viewStatusMessage();
/// if current work area is the first one in the lyx application
bool isFirstWorkArea() const;
/// mark first work area is already set up
void firstWorkAreaDone();
/// input item rectangle of the base view
QRectF baseInputItemRectangle();
/// set input item rectangle of the base view
void setBaseInputItemRectangle(QRectF rect);
/// input item transform of the base view
QTransform baseInputItemTransform();
/// set input item transform of the base view
void setBaseInputItemTransform(QTransform trans);
/// \name Methods to process FuncRequests /// \name Methods to process FuncRequests
//@{ //@{
/// process the func request /// process the func request

View File

@ -286,7 +286,7 @@ void GuiWorkArea::setFullScreen(bool full_screen)
{ {
d->buffer_view_->setFullScreen(full_screen); d->buffer_view_->setFullScreen(full_screen);
queryInputItemTransform(); queryInputItemGeometry();
if (full_screen && lyxrc.full_screen_scrollbar) if (full_screen && lyxrc.full_screen_scrollbar)
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@ -705,10 +705,10 @@ void GuiWorkArea::focusInEvent(QFocusEvent * e)
if ((e->reason() == Qt::PopupFocusReason || e->reason() == Qt::ActiveWindowFocusReason) && if ((e->reason() == Qt::PopupFocusReason || e->reason() == Qt::ActiveWindowFocusReason) &&
!(this->inDialogMode())) { !(this->inDialogMode())) {
// Switched from most of dialogs or other apps, and not on a dialog (e.g. findreplaceadv) // Switched from most of dialogs or other apps, and not on a dialog (e.g. findreplaceadv)
d->item_trans_needs_reset_ = true; d->item_geom_needs_reset_ = true;
} else { } else {
// Switched from advanced search dialog or else (e.g. mouse event) // Switched from advanced search dialog or else (e.g. mouse event)
d->item_trans_needs_reset_ = false; d->item_geom_needs_reset_ = false;
} }
startBlinkingCaret(); startBlinkingCaret();
@ -1142,33 +1142,111 @@ void GuiWorkArea::resizeEvent(QResizeEvent * ev)
} }
void GuiWorkArea::queryInputItemTransform() void GuiWorkArea::queryInputItemGeometry()
{ {
LYXERR(
Debug::DEBUG,
"item_rect_ is aquired: x() = " << d->item_rect_.x() <<
" -> " << d->sys_im_->inputItemRectangle().x() <<
", y() = " << d->item_rect_.y() <<
" -> " << d->sys_im_->inputItemRectangle().y() <<
", width() = " << d->item_rect_.width() <<
" -> " << d->sys_im_->inputItemRectangle().width() <<
", height() = " << d->item_rect_.height() <<
" -> " << d->sys_im_->inputItemRectangle().height()
);
LYXERR( LYXERR(
Debug::DEBUG, Debug::DEBUG,
"item_trans_ is aquired: dx() = " << d->item_trans_.dx() << "item_trans_ is aquired: dx() = " << d->item_trans_.dx() <<
" -> " << d->im_->inputItemTransform().dx() << " -> " << d->sys_im_->inputItemTransform().dx() <<
", dy() = " << d->item_trans_.dy() << ", dy() = " << d->item_trans_.dy() <<
" -> " << d->im_->inputItemTransform().dy() " -> " << d->sys_im_->inputItemTransform().dy()
); );
d->item_trans_ = d->im_->inputItemTransform(); d->item_rect_ = d->sys_im_->inputItemRectangle();
d->item_trans_ = d->sys_im_->inputItemTransform();
// save coordinates of the base working area for later use necessary to
// creat new GuiViews
if (guiApp->isFirstWorkArea()) {
guiApp->setBaseInputItemRectangle(d->item_rect_);
guiApp->setBaseInputItemTransform(d->item_trans_);
guiApp->firstWorkAreaDone();
LYXERR(
Debug::DEBUG,
"base inputItemRectangle x = " <<
guiApp->baseInputItemRectangle().x() <<
", y = " << guiApp->baseInputItemRectangle().y() <<
", width = " << guiApp->baseInputItemRectangle().width() <<
", height = " << guiApp->baseInputItemRectangle().height()
);
LYXERR(
Debug::DEBUG,
"base inputItemTransform dx = " <<
guiApp->baseInputItemTransform().dx() <<
", dy = " << guiApp->baseInputItemTransform().dy()
);
}
} }
void GuiWorkArea::Private::resetInputItemTransform() void GuiWorkArea::resetInputItemGeometry()
{ {
if (item_trans_needs_reset_) { resetInputItemGeometry(false);
}
void GuiWorkArea::resetInputItemGeometry(bool is_new_view)
{
if (d->item_geom_needs_reset_) {
if (is_new_view) {
LYXERR( LYXERR(
Debug::DEBUG, Debug::DEBUG,
"(" << this << "QInputMethod::inputItemRectangle is reset: x = " <<
") item_trans_ is reset: dx() = " << im_->inputItemTransform().dx() << d->sys_im_->inputItemRectangle().x() <<
" -> " << item_trans_.dx() << " -> " << guiApp->baseInputItemRectangle().x() <<
", dy() = " << im_->inputItemTransform().dy() << ", y = " << d->sys_im_->inputItemRectangle().y() <<
" -> " << item_trans_.dy() " -> " << guiApp->baseInputItemRectangle().y() <<
", width = " << d->sys_im_->inputItemRectangle().width() <<
" -> " << guiApp->baseInputItemRectangle().width() <<
", height = " << d->sys_im_->inputItemRectangle().height() <<
" -> " << guiApp->baseInputItemRectangle().height()
); );
im_->setInputItemTransform(item_trans_); LYXERR(
item_trans_needs_reset_ = false; Debug::DEBUG,
"QInputMethod::inputItemTransform is reset: dx = " <<
d->sys_im_->inputItemTransform().dx() <<
" -> " << guiApp->baseInputItemTransform().dx() <<
", dy = " << d->sys_im_->inputItemTransform().dy() <<
" -> " << guiApp->baseInputItemTransform().dy()
);
d->sys_im_->setInputItemRectangle(guiApp->baseInputItemRectangle());
d->sys_im_->setInputItemTransform(guiApp->baseInputItemTransform());
} else {
LYXERR(
Debug::DEBUG,
"QInputMethod::inputItemRectangle is reset: x = " <<
d->sys_im_->inputItemRectangle().x() <<
" -> " << d->item_rect_.x() <<
", y = " << d->sys_im_->inputItemRectangle().y() <<
" -> " << d->item_rect_.y() <<
", width = " << d->sys_im_->inputItemRectangle().width() <<
" -> " << d->item_rect_.width() <<
", height = " << d->sys_im_->inputItemRectangle().height() <<
" -> " << d->item_rect_.height()
);
LYXERR(
Debug::DEBUG,
"QInputMethod::inputItemTransform is reset: dx = " <<
d->sys_im_->inputItemTransform().dx() <<
" -> " << d->item_trans_.dx() <<
", dy = " << d->sys_im_->inputItemTransform().dy() <<
" -> " << d->item_trans_.dy()
);
d->sys_im_->setInputItemRectangle(d->item_rect_);
d->sys_im_->setInputItemTransform(d->item_trans_);
}
d->item_geom_needs_reset_ = false;
} }
} }
@ -1179,7 +1257,7 @@ void GuiWorkArea::Private::paintPreeditText(GuiPainter & pain)
{ {
#ifdef DEBUG_PREEDIT #ifdef DEBUG_PREEDIT
// check the language that current input method uses // check the language that current input method uses
QLocale::Language lang = im_->locale().language(); QLocale::Language lang = sys_im_->locale().language();
if (lang != im_lang_) { if (lang != im_lang_) {
LYXERR0("QLocale = " << QLocale::languageToString(lang)); LYXERR0("QLocale = " << QLocale::languageToString(lang));
im_lang_ = lang; im_lang_ = lang;
@ -1188,7 +1266,7 @@ void GuiWorkArea::Private::paintPreeditText(GuiPainter & pain)
// Chinese IM may want cursor position even when preedit string is empty // Chinese IM may want cursor position even when preedit string is empty
// such a case is handled below // such a case is handled below
if (preedit_string_.empty() && im_->locale().language() != QLocale::Chinese) if (preedit_string_.empty() && sys_im_->locale().language() != QLocale::Chinese)
return; return;
// lower margin of the preedit area to separate the candidate window // lower margin of the preedit area to separate the candidate window
@ -1207,13 +1285,13 @@ void GuiWorkArea::Private::paintPreeditText(GuiPainter & pain)
// Chinese input methods may exit here just obtaining im_cursor_rect // Chinese input methods may exit here just obtaining im_cursor_rect
im_cursor_rect_ = im_cursor_rect_ =
QRectF(cur_x, cur_y - dim.height(), 1, dim.height() + preedit_lower_margin); QRectF(cur_x, cur_y - dim.height(), 1, dim.height() + preedit_lower_margin);
im_->update(Qt::ImCursorRectangle); sys_im_->update(Qt::ImCursorRectangle);
return; return;
} }
// reset item transformation since it can go wrong after the item gets // reset item transformation since it can go wrong after the item gets
// lost and regains focus or after a new tab (dis)appears etc. // lost and regains focus or after a new tab (dis)appears etc.
resetInputItemTransform(); p->resetInputItemGeometry();
// FIXME: shall we use real_current_font here? (see #10478) // FIXME: shall we use real_current_font here? (see #10478)
FontInfo const font = buffer_view_->cursor().getFont().fontInfo(); FontInfo const font = buffer_view_->cursor().getFont().fontInfo();
@ -1360,7 +1438,7 @@ void GuiWorkArea::Private::paintPreeditText(GuiPainter & pain)
} }
// Urge platform input method to make inputMethodQuery to check the values // Urge platform input method to make inputMethodQuery to check the values
// set above // set above
im_->update(Qt::ImQueryInput); sys_im_->update(Qt::ImQueryInput);
} }
@ -1910,9 +1988,9 @@ GuiWorkArea * TabWorkArea::addWorkArea(Buffer & buffer, GuiView & view)
updateTabTexts(); updateTabTexts();
// obtain new input item coordinates in the new and old work areas // obtain new input item coordinates in the new and old work areas
wa->queryInputItemTransform(); wa->queryInputItemGeometry();
if (currentWorkArea()) if (currentWorkArea())
currentWorkArea()->queryInputItemTransform(); currentWorkArea()->queryInputItemGeometry();
view.setBusy(false); view.setBusy(false);
@ -1940,7 +2018,7 @@ bool TabWorkArea::removeWorkArea(GuiWorkArea * work_area)
else else
// Show tabbar only if there's more than one tab. // Show tabbar only if there's more than one tab.
showBar(count() > 1); showBar(count() > 1);
currentWorkArea()->queryInputItemTransform(); currentWorkArea()->queryInputItemGeometry();
} else } else
lastWorkAreaRemoved(); lastWorkAreaRemoved();

View File

@ -69,8 +69,14 @@ public:
/// return true if the key is part of a shortcut /// return true if the key is part of a shortcut
bool queryKeySym(KeySymbol const & key, KeyModifier mod) const; bool queryKeySym(KeySymbol const & key, KeyModifier mod) const;
/// Ask relative position of input item coordinates against the main coordinates
void queryInputItemTransform(); /// Ask relative position of the input item coordinates against the main
/// coordinates to the system input method
void queryInputItemGeometry();
/// Restore coordinate transformation information
void resetInputItemGeometry();
/// Restore coordinate transformation information
void resetInputItemGeometry(bool is_new_view);
bool inDialogMode() const; bool inDialogMode() const;
void setDialogMode(bool mode); void setDialogMode(bool mode);

View File

@ -137,7 +137,7 @@ struct GuiWorkArea::Private
bool need_resize_ = false; bool need_resize_ = false;
/// provides access to the platform input method /// provides access to the platform input method
QInputMethod * im_ = QGuiApplication::inputMethod(); QInputMethod * sys_im_ = QGuiApplication::inputMethod();
/// the current preedit text of the input method /// the current preedit text of the input method
docstring preedit_string_; docstring preedit_string_;
/// Number of lines used by preedit text /// Number of lines used by preedit text
@ -146,8 +146,12 @@ struct GuiWorkArea::Private
QList<QInputMethodEvent::Attribute> preedit_attr_; QList<QInputMethodEvent::Attribute> preedit_attr_;
QRectF im_cursor_rect_; QRectF im_cursor_rect_;
QRectF im_anchor_rect_; QRectF im_anchor_rect_;
/// geometry of the input item
QRectF item_rect_;
/// transformation from input item coordinates to the working area
QTransform item_trans_; QTransform item_trans_;
bool item_trans_needs_reset_ = false; /// whether item_rect_ and item_trans need to be reset
bool item_geom_needs_reset_ = false;
/// for debug /// for debug
QLocale::Language im_lang_ = QLocale::AnyLanguage; QLocale::Language im_lang_ = QLocale::AnyLanguage;