Hello,

This patch sanitize the different way to exit from lyx:

1) exit request with a direct call to LFUN_WINDOW_CLOSE: user menu.

2) automatic exit when the last window is closed.

I needed some more small changes to the LFUN in order to make this work properly for all tested use cases.

Bo, concerning session stuff, I had to change things a bit again. So now, the geometry saving is ensured to be done because LyXView::close() is _always_ called on exit.

I am all ears WRT comments to the code and bug reports. But I can't work on this in the short term so I am going going to commit this now as this a clear improvement over the current situation.

Abdel.
Index: src/frontends/Gui.h
===================================================================
--- src/frontends/Gui.h (revision 15520)
+++ src/frontends/Gui.h (working copy)
@@ -46,6 +46,8 @@
        virtual int newWorkArea(unsigned int width, unsigned int height, int 
view_id) = 0;
        ///
        virtual WorkArea & workArea(int id) = 0;
+       ///
+       virtual bool closeAll() = 0;
 
        ///
        std::vector<int> const & viewIds() { return view_ids_; };
Index: src/frontends/qt4/Alert_pimpl.C
===================================================================
--- src/frontends/qt4/Alert_pimpl.C     (revision 15520)
+++ src/frontends/qt4/Alert_pimpl.C     (working copy)
@@ -28,24 +28,39 @@
 
 #include <algorithm>
 
+using std::pair;
+using std::make_pair;
 
 namespace lyx {
 
 using lyx::support::bformat;
 using lyx::docstring;
 
-using std::pair;
-using std::make_pair;
+namespace {
 
+class MessageBox: public QMessageBox
+{
+public:
+       MessageBox(QWidget * parent = 0): QMessageBox(parent)
+       {
+               setAttribute(Qt::WA_DeleteOnClose, true);
+               setAttribute(Qt::WA_QuitOnClose, false);
+       }
+};
 
+} // anonymous namespace
+
+
 int prompt_pimpl(docstring const & tit, docstring const & question,
                 int default_button, int cancel_button,
                 docstring const & b1, docstring const & b2, docstring const & 
b3)
 {
        docstring const title = bformat(_("LyX: %1$s"), tit);
 
+       MessageBox mb;
+
        // FIXME replace that with theApp->gui()->currentView()
-       int res = QMessageBox::information(qApp->focusWidget(),
+       int res = mb.information(qApp->focusWidget(),
                                           toqstr(title),
                                           toqstr(formatted(question)),
                                           toqstr(b1),
@@ -63,7 +78,9 @@
 void warning_pimpl(docstring const & tit, docstring const & message)
 {
        docstring const title = bformat(_("LyX: %1$s"), tit);
-       QMessageBox::warning(qApp->focusWidget(),
+
+       MessageBox mb;
+       mb.warning(qApp->focusWidget(),
                             toqstr(title),
                             toqstr(formatted(message)));
 }
@@ -72,7 +89,8 @@
 void error_pimpl(docstring const & tit, docstring const & message)
 {
        docstring const title = bformat(_("LyX: %1$s"), tit);
-       QMessageBox::critical(qApp->focusWidget(),
+       MessageBox mb;
+       mb.critical(qApp->focusWidget(),
                              toqstr(title),
                              toqstr(formatted(message)));
 }
@@ -81,7 +99,8 @@
 void information_pimpl(docstring const & tit, docstring const & message)
 {
        docstring const title = bformat(_("LyX: %1$s"), tit);
-       QMessageBox::information(qApp->focusWidget(),
+       MessageBox mb;
+       mb.information(qApp->focusWidget(),
                                 toqstr(title),
                                 toqstr(formatted(message)));
 }
Index: src/frontends/qt4/GuiApplication.C
===================================================================
--- src/frontends/qt4/GuiApplication.C  (revision 15520)
+++ src/frontends/qt4/GuiApplication.C  (working copy)
@@ -165,7 +165,7 @@
 
        // trigger LFUN_LYX_QUIT instead of QApplication::quit() directly
        // since LFUN_LYX_QUIT may have more cleanup stuff
-       dispatch(FuncRequest(LFUN_LYX_QUIT));
+       dispatch(FuncRequest(LFUN_LYX_QUIT, "force"));
 }
 
 
Index: src/frontends/qt4/GuiImplementation.C
===================================================================
--- src/frontends/qt4/GuiImplementation.C       (revision 15520)
+++ src/frontends/qt4/GuiImplementation.C       (working copy)
@@ -20,6 +20,7 @@
 #include "GuiWorkArea.h"
 
 #include "BufferView.h"
+#include "bufferlist.h"
 #include "funcrequest.h"
 #include "lyxfunc.h"
 
@@ -42,9 +43,6 @@
        views_[id] = new GuiView(id);
        view_ids_.push_back(id);
 
-       QObject::connect(views_[id], SIGNAL(destroyed(QObject *)),
-               this, SLOT(cleanupViews(QObject *)));
-
        return id;
 }
 
@@ -57,9 +55,39 @@
 }
 
 
-void GuiImplementation::cleanupViews(QObject * qobj)
+bool GuiImplementation::closeAll()
 {
-       GuiView * view = static_cast<GuiView *>(qobj);
+       if (!theBufferList().quitWriteAll())
+               return false;
+
+       // In order to know if it is the last opened window,
+       // GuiView::closeEvent() check for (view_ids_.size() == 1)
+       // We deny this check by setting the vector size to zero.
+       // But we still need the vector, hence the temporary copy.
+       std::vector<int> view_ids_tmp = view_ids_;
+       view_ids_.clear();
+
+       for (size_t i = 0; i < view_ids_tmp.size(); ++i) {
+               // LFUN_LYX_QUIT has already been triggered so we need
+               // to disable the lastWindowClosed() signal before closing
+               // the last window.
+               views_[view_ids_tmp[i]]->setAttribute(Qt::WA_QuitOnClose, 
false);
+               views_[view_ids_tmp[i]]->close();
+               // The view_ids_ vector is reconstructed in the closeEvent; so
+               // let's clear that out again!
+               view_ids_.clear();
+       }
+
+       views_.clear();
+       view_ids_.clear();
+       work_areas_.clear();
+
+       return true;
+}
+
+
+void GuiImplementation::unregisterView(GuiView * view)
+{
        std::map<int, GuiView *>::iterator I;
 
        for (I = views_.begin(); I != views_.end(); ++I) {
@@ -76,6 +104,7 @@
 //             dispatch(FuncRequest(LFUN_LYX_QUIT));
                return;
        }
+
        theLyXFunc().setLyXView(views_.begin()->second);
 }
 
Index: src/frontends/qt4/GuiImplementation.h
===================================================================
--- src/frontends/qt4/GuiImplementation.h       (revision 15520)
+++ src/frontends/qt4/GuiImplementation.h       (working copy)
@@ -38,14 +38,15 @@
        GuiImplementation();
        virtual ~GuiImplementation() {}
 
-       int newView();
-       LyXView& view(int id);
-       int newWorkArea(unsigned int width, unsigned int height, int view_id);
-       WorkArea& workArea(int id);
+       virtual int newView();
+       virtual LyXView& view(int id);
+       virtual int newWorkArea(unsigned int width, unsigned int height, int 
view_id);
+       virtual WorkArea& workArea(int id);
+       virtual bool closeAll();
 
-private Q_SLOTS:
+public Q_SLOTS:
        ///
-       void cleanupViews(QObject * view);
+       void unregisterView(GuiView * view);
 
 private:
        ///
Index: src/frontends/qt4/GuiView.C
===================================================================
--- src/frontends/qt4/GuiView.C (revision 15520)
+++ src/frontends/qt4/GuiView.C (working copy)
@@ -12,33 +12,33 @@
 
 #include <config.h>
 
+#include "GuiImplementation.h"
+
+#include "GuiView.h"
+#include "QLMenubar.h"
+#include "QLToolbar.h"
+#include "QCommandBuffer.h"
+#include "qt_helpers.h"
+
+#include "frontends/Application.h"
+#include "frontends/Gui.h"
+#include "frontends/WorkArea.h"
+
+#include "support/filetools.h"
+#include "support/convert.h"
+#include "support/lstrings.h"
+
 #include "BufferView.h"
+#include "bufferlist.h"
+#include "debug.h"
+#include "funcrequest.h"
 #include "lyx_cb.h"
 #include "lyxrc.h"
 #include "lyx_main.h"
 #include "session.h"
 #include "lyxfunc.h"
 #include "MenuBackend.h"
-#include "funcrequest.h"
-#include "funcrequest.h"
 
-#include "debug.h"
-
-#include "frontends/WorkArea.h"
-#include "support/filetools.h"
-#include "support/convert.h"
-#include "support/lstrings.h"
-
-// This include must be declared before everything else because
-// of boost/Qt/LyX clash...
-#include "GuiImplementation.h"
-
-#include "GuiView.h"
-#include "QLMenubar.h"
-#include "QLToolbar.h"
-#include "QCommandBuffer.h"
-#include "qt_helpers.h"
-
 #include <QAction>
 #include <QApplication>
 #include <QCloseEvent>
@@ -46,12 +46,11 @@
 #include <QStatusBar>
 #include <QToolBar>
 
-
 #include <boost/bind.hpp>
 
-
+using std::endl;
 using std::string;
-using std::endl;
+using std::vector;
 
 namespace lyx {
 
@@ -264,9 +263,20 @@
 }
 
 
-void GuiView::closeEvent(QCloseEvent *)
+void GuiView::closeEvent(QCloseEvent * close_event)
 {
+       GuiImplementation & gui 
+               = static_cast<GuiImplementation &>(theApp->gui());
+
+       vector<int> const & view_ids = gui.viewIds();
+
+       if (view_ids.size() == 1 && !theBufferList().quitWriteAll()) {
+               close_event->ignore();
+               return;
+       }
+
        saveGeometry();
+       gui.unregisterView(this);
 }
 
 
Index: src/frontends/qt4/GuiView.h
===================================================================
--- src/frontends/qt4/GuiView.h (revision 15520)
+++ src/frontends/qt4/GuiView.h (working copy)
@@ -42,6 +42,10 @@
  * GuiView - Qt4 implementation of LyXView
  *
  * qt4-private implementation of the main LyX window.
+ *
+ * Note: any QObject emits a destroyed(QObject *) Qt signal when it
+ *       is deleted.This might be useful for closing other dialogs
+ *       depending on a given GuiView.
  */
 class GuiView : public QMainWindow, public LyXView {
        Q_OBJECT
Index: src/lyx_main.C
===================================================================
--- src/lyx_main.C      (revision 15520)
+++ src/lyx_main.C      (working copy)
@@ -397,23 +397,10 @@
 {
        lyxerr[Debug::INFO] << "Running QuitLyX." << endl;
 
-       if (use_gui) {
-               if (!noask && !pimpl_->buffer_list_.quitWriteAll())
-                       return;
-
-               // The LyXView Geometry settings are stored when LyXView::close
-               // is called explicitely but a straight quit() command would not
-               // guarante that. So we make sure this is done here:
-               vector<int> const & view_ids = 
pimpl_->application_->gui().viewIds();
-               for (size_t i = 0; i < view_ids.size(); ++i)
-                       
pimpl_->application_->gui().view(view_ids[i]).saveGeometry();
-
-               pimpl_->session_->writeFile();
-       }
-
        prepareExit();
 
        if (use_gui) {
+               pimpl_->session_->writeFile();
                pimpl_->lyx_server_.reset();
                pimpl_->lyx_socket_.reset();
                pimpl_->application_->exit(0);
Index: src/lyxfunc.C
===================================================================
--- src/lyxfunc.C       (revision 15520)
+++ src/lyxfunc.C       (working copy)
@@ -1022,13 +1022,23 @@
                        break;
 
                case LFUN_LYX_QUIT:
+                       if (argument != "force") {
+                               if (!theApp->gui().closeAll())
+                                       break;
+                               lyx_view_ = 0;
+                       }
+
+                       // FIXME: this code needs to be transfered somewhere 
else
+                       // as lyx_view_ will most certainly be null and a same 
buffer
+                       // might be visible in more than one LyXView.
                        if (lyx_view_ && lyx_view_->view()->buffer()) {
                                // save cursor Position for opened files to 
.lyx/session
                                
LyX::ref().session().saveFilePosition(lyx_view_->buffer()->fileName(),
                                        boost::tie(view()->cursor().pit(), 
view()->cursor().pos()) );
                                // save bookmarks to .lyx/session
                                view()->saveSavedPositions();
-                       }                       
+                       }
+
                        LyX::ref().quit(argument == "force");
                        break;
 

Reply via email to