commit 8725614e3f147253ad2f900bcbbf9324fdd09e32
Author: Pavel Sanda <sa...@lyx.org>
Date:   Mon Mar 12 14:34:24 2018 +0100

    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
---
 src/FuncRequest.cpp                  |   13 +++++++------
 src/FuncRequest.h                    |   11 +++++++++++
 src/frontends/qt4/GuiApplication.cpp |   10 +++++++++-
 src/frontends/qt4/TocModel.cpp       |    8 ++++----
 src/frontends/qt4/TocModel.h         |    5 ++---
 src/frontends/qt4/TocWidget.cpp      |   22 ++++++++++++++++++++--
 src/frontends/qt4/TocWidget.h        |    3 +++
 7 files changed, 56 insertions(+), 16 deletions(-)

diff --git a/src/FuncRequest.cpp b/src/FuncRequest.cpp
index cd47c55..ef357ee 100644
--- a/src/FuncRequest.cpp
+++ b/src/FuncRequest.cpp
@@ -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)
 {}
 
 
diff --git a/src/FuncRequest.h b/src/FuncRequest.h
index 20cd96a..80587f9 100644
--- a/src/FuncRequest.h
+++ b/src/FuncRequest.h
@@ -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
diff --git a/src/frontends/qt4/GuiApplication.cpp 
b/src/frontends/qt4/GuiApplication.cpp
index 1badbb7..410abe5 100644
--- a/src/frontends/qt4/GuiApplication.cpp
+++ b/src/frontends/qt4/GuiApplication.cpp
@@ -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);
diff --git a/src/frontends/qt4/TocModel.cpp b/src/frontends/qt4/TocModel.cpp
index 0733c1f..5136531 100644
--- a/src/frontends/qt4/TocModel.cpp
+++ b/src/frontends/qt4/TocModel.cpp
@@ -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();
 }
 
 
diff --git a/src/frontends/qt4/TocModel.h b/src/frontends/qt4/TocModel.h
index ed94218..8d33639 100644
--- a/src/frontends/qt4/TocModel.h
+++ b/src/frontends/qt4/TocModel.h
@@ -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);
        ///
diff --git a/src/frontends/qt4/TocWidget.cpp b/src/frontends/qt4/TocWidget.cpp
index b96a7c6..dcd9c4d 100644
--- a/src/frontends/qt4/TocWidget.cpp
+++ b/src/frontends/qt4/TocWidget.cpp
@@ -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);
diff --git a/src/frontends/qt4/TocWidget.h b/src/frontends/qt4/TocWidget.h
index 3f67606..9cb21bf 100644
--- a/src/frontends/qt4/TocWidget.h
+++ b/src/frontends/qt4/TocWidget.h
@@ -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;

Reply via email to