Fix Undocked Outliner & multiple window crashes (#11004).

There are more independent crashes occuring in this scenario and this
fix targets only one of them, in particular the one in which different
window's outliner sends outliner command to a wrong window. The fix
itself gives an option for lfun to know which window it belongs to.

https://www.mail-archive.com/lyx-devel@lists.lyx.org/msg203619.html
This commit is contained in:
Pavel Sanda 2018-03-12 14:34:24 +01:00
parent e41c80e224
commit 8725614e3f
7 changed files with 56 additions and 16 deletions

View File

@ -31,38 +31,39 @@ FuncRequest const FuncRequest::noaction(LFUN_NOACTION);
FuncRequest::FuncRequest(Origin o)
: action_(LFUN_NOACTION), origin_(o), x_(0), y_(0),
button_(mouse_button::none), modifier_(NoModifier)
button_(mouse_button::none), modifier_(NoModifier), view_origin_(0)
{}
FuncRequest::FuncRequest(FuncCode act, Origin o)
: action_(act), origin_(o), x_(0), y_(0),
button_(mouse_button::none), modifier_(NoModifier)
button_(mouse_button::none), modifier_(NoModifier), view_origin_(0)
{}
FuncRequest::FuncRequest(FuncCode act, docstring const & arg, Origin o)
: action_(act), argument_(arg), origin_(o), x_(0), y_(0),
button_(mouse_button::none), modifier_(NoModifier)
button_(mouse_button::none), modifier_(NoModifier), view_origin_(0)
{}
FuncRequest::FuncRequest(FuncCode act, string const & arg, Origin o)
: action_(act), argument_(from_utf8(arg)), origin_(o), x_(0), y_(0),
button_(mouse_button::none), modifier_(NoModifier)
button_(mouse_button::none), modifier_(NoModifier), view_origin_(0)
{}
FuncRequest::FuncRequest(FuncCode act, int ax, int ay,
mouse_button::state but, KeyModifier modifier, Origin o)
: action_(act), origin_(o), x_(ax), y_(ay), button_(but),
modifier_(modifier)
modifier_(modifier), view_origin_(0)
{}
FuncRequest::FuncRequest(FuncRequest const & cmd, docstring const & arg, Origin o)
: action_(cmd.action()), argument_(arg), origin_(o),
x_(cmd.x_), y_(cmd.y_), button_(cmd.button_), modifier_(NoModifier)
x_(cmd.x_), y_(cmd.y_), button_(cmd.button_), modifier_(NoModifier),
view_origin_(0)
{}

View File

@ -24,6 +24,10 @@ namespace lyx {
class LyXErr;
namespace frontend {
class GuiView;
}
/**
* This class encapsulates a LyX action and its argument
* in order to pass it around easily.
@ -70,6 +74,10 @@ public:
///
void setOrigin(Origin o) { origin_ = o; }
///
frontend::GuiView* view_origin() const { return view_origin_; }
///
void setViewOrigin(frontend::GuiView* o) { view_origin_ = o; }
///
int x() const { return x_; }
///
int y() const { return y_; }
@ -97,6 +105,9 @@ private:
docstring argument_;
/// who initiated the action
Origin origin_;
/// to which view should be this command sent (see bug #11004)
/// NULL=current view
frontend::GuiView* view_origin_;
/// the x coordinate of a mouse press
int x_;
/// the y coordinate of a mouse press

View File

@ -1387,7 +1387,16 @@ static docstring makeDispatchMessage(docstring const & msg,
DispatchResult const & GuiApplication::dispatch(FuncRequest const & cmd)
{
DispatchResult dr;
Buffer * buffer = 0;
if (cmd.view_origin() && current_view_ != cmd.view_origin()) {
//setCurrentView(cmd.view_origin); //does not work
dr.setError(true);
dr.setMessage(_("Wrong focus!"));
d->dispatch_result_ = dr;
return d->dispatch_result_;
}
if (current_view_ && current_view_->currentBufferView()) {
current_view_->currentBufferView()->cursor().saveBeforeDispatchPosXY();
buffer = &current_view_->currentBufferView()->buffer();
@ -1395,7 +1404,6 @@ DispatchResult const & GuiApplication::dispatch(FuncRequest const & cmd)
// This handles undo groups automagically
UndoGroupHelper ugh(buffer);
DispatchResult dr;
// redraw the screen at the end (first of the two drawing steps).
// This is done unless explicitly requested otherwise
dr.screenUpdate(Update::FitCursor);

View File

@ -303,17 +303,17 @@ QModelIndex TocModels::currentIndex(QString const & type,
}
void TocModels::goTo(QString const & type, QModelIndex const & index) const
FuncRequest TocModels::goTo(QString const & type, QModelIndex const & index) const
{
const_iterator it = models_.find(type);
if (it == models_.end() || !index.isValid()) {
LYXERR(Debug::GUI, "TocModels::goTo(): QModelIndex is invalid!");
return;
return FuncRequest(LFUN_NOACTION);
}
LASSERT(index.model() == it.value()->model(), return);
LASSERT(index.model() == it.value()->model(), return FuncRequest(LFUN_NOACTION));
TocItem const item = it.value()->tocItem(index);
LYXERR(Debug::GUI, "TocModels::goTo " << item.asString());
dispatch(item.action());
return item.action();
}

View File

@ -22,6 +22,7 @@ namespace lyx {
class Buffer;
class BufferView;
class DocIterator;
class FuncRequest;
namespace frontend {
@ -124,9 +125,7 @@ public:
QModelIndex currentIndex(QString const & type,
DocIterator const & dit) const;
///
void goTo(QString const & type, QModelIndex const & index) const;
///
void init(Buffer const & buffer);
FuncRequest goTo(QString const & type, QModelIndex const & index) const;
///
void updateItem(QString const & type, DocIterator const & dit);
///

View File

@ -178,6 +178,7 @@ bool TocWidget::getStatus(Cursor & cur, FuncRequest const & cmd,
void TocWidget::doDispatch(Cursor & cur, FuncRequest const & cmd)
{
Inset * inset = itemInset();
FuncRequest tmpcmd(cmd);
@ -235,6 +236,7 @@ void TocWidget::on_tocTV_activated(QModelIndex const & index)
void TocWidget::on_tocTV_pressed(QModelIndex const & index)
{
Qt::MouseButtons const button = QApplication::mouseButtons();
if (button & Qt::LeftButton) {
goTo(index);
@ -249,7 +251,7 @@ void TocWidget::goTo(QModelIndex const & index)
LYXERR(Debug::GUI, "goto " << index.row()
<< ", " << index.column());
gui_view_.tocModels().goTo(current_type_, index);
sendDispatch(gui_view_.tocModels().goTo(current_type_, index));
}
@ -314,6 +316,7 @@ void TocWidget::setTreeDepth(int depth)
void TocWidget::on_typeCO_currentIndexChanged(int index)
{
if (index == -1)
return;
current_type_ = typeCO->itemData(index).toString();
@ -328,14 +331,29 @@ void TocWidget::outline(FuncCode func_code)
QModelIndexList const & list = tocTV->selectionModel()->selectedIndexes();
if (list.isEmpty())
return;
//if another window is active, this attempt will fail,
//but it will work at least for the second attempt
gui_view_.activateWindow();
enableControls(false);
goTo(list[0]);
dispatch(FuncRequest(func_code));
sendDispatch(FuncRequest(func_code));
enableControls(true);
gui_view_.setFocus();
}
void TocWidget::sendDispatch(FuncRequest fr)
{
fr.setViewOrigin(&gui_view_);
DispatchResult dr=dispatch(fr);
if (dr.error())
gui_view_.message(dr.message());
}
void TocWidget::on_moveUpTB_clicked()
{
outline(LFUN_OUTLINE_UP);

View File

@ -40,6 +40,9 @@ public:
void init(QString const & str);
///
void doDispatch(Cursor & cur, FuncRequest const & fr);
///send request to lyx::dispatch with proper guiview handle
///(if ToC is detached current_view can be different window)
void sendDispatch(FuncRequest fr);
///
bool getStatus(Cursor & cur, FuncRequest const & fr, FuncStatus & status)
const;