Here a patch which cleans up the quitting code. All leaving the event loop no starts here:
+void GuiView::closeEvent(QCloseEvent * close_event) +{ + theApp()->gui().unregisterView(id()); + if (theApp()->gui().viewIds().empty()) + { + // this is the place were we leave the frontend + // and is the only point were we begin to quit + saveGeometry(); + close_event->accept(); + // quit the event loop + qApp->quit(); + } +} I've tested it on Windows and Linux, and hope it also works for the Mac. Saving now also works for 'Exit'. We only come back to lyx_main.C by leaving the event loop, so no 'quit()' is required any more. Please test or comment it. Peter
Index: src/lyxfunc.C =================================================================== --- src/lyxfunc.C (Revision 16123) +++ src/lyxfunc.C (Arbeitskopie) @@ -1034,12 +1034,6 @@ break; case LFUN_LYX_QUIT: - if (argument == "closeOnly") { - 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. @@ -1048,8 +1042,9 @@ LyX::ref().session().lastFilePos().save(lyx_view_->buffer()->fileName(), boost::tie(view()->cursor().pit(), view()->cursor().pos()) ); } - - LyX::ref().quit(); + + // quitting is trigged by the gui code (leaving the event loop) + theApp()->gui().closeAllRegisteredViews(); break; case LFUN_TOC_VIEW: { @@ -1670,7 +1665,7 @@ BOOST_ASSERT(lyx_view_); BOOST_ASSERT(theApp()); lyx_view_->close(); - // We return here because lyx_view does not exists anymore. + lyx_view_->closed(lyx_view_->id()); return; case LFUN_BOOKMARK_GOTO: { Index: src/frontends/Application.h =================================================================== --- src/frontends/Application.h (Revision 16123) +++ src/frontends/Application.h (Arbeitskopie) @@ -168,8 +168,7 @@ * remove a I/O read callback * @param fd socket descriptor (file/socket/etc) */ - template<class T> - void unregisterSocketCallback(T fd); + virtual void unregisterSocketCallback(int fd) = 0; /// Create the main window with given geometry settings. LyXView & createView(unsigned int width, unsigned int height, Index: src/frontends/qt4/GuiImplementation.C =================================================================== --- src/frontends/qt4/GuiImplementation.C (Revision 16123) +++ src/frontends/qt4/GuiImplementation.C (Arbeitskopie) @@ -30,103 +30,91 @@ namespace frontend { -GuiImplementation::GuiImplementation(): max_view_id_(0), max_wa_id_(0) +GuiImplementation::GuiImplementation() { } -int GuiImplementation::newView() +LyXView& GuiImplementation::createRegisteredView() { - size_t const id = max_view_id_; - ++max_view_id_; - - views_[id] = new GuiView(id); - view_ids_.push_back(id); - - return id; + size_t const id = viewIds().size(); + views_.insert(std::pair<int, GuiView *>(id, new GuiView(id))); + return *views_[id]; } -LyXView& GuiImplementation::view(int id) +bool GuiImplementation::unregisterView(int id) { - BOOST_ASSERT(views_.find(id) != views_.end()); + if (id < 0 && id >= viewIds().size()) + return false; + if (!views_[id]) + return false; - return *views_[id]; + std::map<int, GuiView *>::iterator it; + for (it = views_.begin(); it != views_.end(); ++it) { + if (it->first == id) { + std::vector<int> const & wa_ids = it->second->workAreaIds(); + for (size_t i = 0; i < wa_ids.size(); ++i) + work_areas_.erase(wa_ids[i]); + views_.erase(id); + break; + } + } + return true; } -bool GuiImplementation::closeAll() +bool GuiImplementation::closeAllRegisteredViews() { - // ATM never used - if (!theBufferList().quitWriteAll()) - return false; + if (views_.empty()) + return true; - // 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(); + std::map<int, GuiView*> const cmap = views_; + std::map<int, GuiView*>::const_iterator it; + for (it = cmap.begin(); it != cmap.end(); ++it) + { + it->second->close(); + // unregisterd by the CloseEvent } - views_.clear(); - view_ids_.clear(); work_areas_.clear(); - return true; } - -void GuiImplementation::unregisterView(GuiView * view) +LyXView& GuiImplementation::view(int id) const { - std::map<int, GuiView *>::iterator I; + BOOST_ASSERT(views_.find(id) != views_.end()); + return *views_.find(id)->second; +} - for (I = views_.begin(); I != views_.end(); ++I) { - if (I->second == view) { - std::vector<int> const & wa_ids = view->workAreaIds(); - for (size_t i = 0; i < wa_ids.size(); ++i) - work_areas_.erase(wa_ids[i]); - views_.erase(I->first); - break; - } - } +template<class T> + std::vector<int> const & GuiImplementation_Ids + (std::map<int, T*> const & stdmap, std::vector<int> & ids) +{ + ids.clear(); + typename std::map<int, T*>::const_iterator it; + for (it = stdmap.begin(); it != stdmap.end(); ++it) + ids.push_back(it->first); + return ids; +} - buildViewIds(); - if (views_.empty()) { - theLyXFunc().setLyXView(0); - dispatch(FuncRequest(LFUN_LYX_QUIT)); - return; - } - - theLyXFunc().setLyXView(views_.begin()->second); +std::vector<int> const & GuiImplementation::viewIds() +{ + return GuiImplementation_Ids(views_, view_ids_); } -void GuiImplementation::buildViewIds() +std::vector<int> const & GuiImplementation::workAreaIds() { - view_ids_.clear(); - std::map<int, GuiView *>::const_iterator I; - for (I = views_.begin(); I != views_.end(); ++I) - view_ids_.push_back(I->first); + return GuiImplementation_Ids(work_areas_, work_area_ids_); } int GuiImplementation::newWorkArea(unsigned int w, unsigned int h, int view_id) { - size_t const id = max_wa_id_; - ++max_wa_id_; + size_t const id = workAreaIds().size(); GuiView * view = views_[view_id]; @@ -147,7 +135,6 @@ WorkArea& GuiImplementation::workArea(int id) { BOOST_ASSERT(work_areas_.find(id) != work_areas_.end()); - return *work_areas_[id]; } Index: src/frontends/qt4/GuiImplementation.h =================================================================== --- src/frontends/qt4/GuiImplementation.h (Revision 16123) +++ src/frontends/qt4/GuiImplementation.h (Arbeitskopie) @@ -38,19 +38,18 @@ GuiImplementation(); virtual ~GuiImplementation() {} - virtual int newView(); - virtual LyXView& view(int id); + + virtual LyXView& createRegisteredView(); + virtual bool closeAllRegisteredViews(); + virtual bool unregisterView(int id); + + virtual LyXView& view(int id) const; + virtual std::vector<int> const & viewIds(); + virtual int newWorkArea(unsigned int width, unsigned int height, int view_id); virtual WorkArea& workArea(int id); - virtual bool closeAll(); -public Q_SLOTS: - /// - void unregisterView(GuiView * view); - private: - /// - void buildViewIds(); /// Multiple views container. /** @@ -67,9 +66,9 @@ */ std::map<int, GuiWorkArea *> work_areas_; /// - size_t max_view_id_; - /// - size_t max_wa_id_; + std::vector<int> const & workAreaIds(); + + std::vector<int> work_area_ids_; }; } // namespace frontend Index: src/frontends/qt4/GuiApplication.C =================================================================== --- src/frontends/qt4/GuiApplication.C (Revision 16123) +++ src/frontends/qt4/GuiApplication.C (Arbeitskopie) @@ -277,14 +277,8 @@ boost::shared_ptr<socket_callback>(new socket_callback(fd, func)); } -template<> -void Application::unregisterSocketCallback<int>(int fd) -{ - GuiApplication* ptr = static_cast<GuiApplication*>(this); - ptr->unregisterSocketCallbackImpl(fd); -} -void GuiApplication::unregisterSocketCallbackImpl(int fd) +void GuiApplication::unregisterSocketCallback(int fd) { socket_callbacks_.erase(fd); } Index: src/frontends/qt4/GuiApplication.h =================================================================== --- src/frontends/qt4/GuiApplication.h (Revision 16123) +++ src/frontends/qt4/GuiApplication.h (Arbeitskopie) @@ -75,7 +75,7 @@ virtual void updateColor(LColor_color col); virtual void registerSocketCallback( int fd, boost::function<void()> func); - void unregisterSocketCallbackImpl(int fd); + void unregisterSocketCallback(int fd); //@} /// Index: src/frontends/qt4/GuiView.C =================================================================== --- src/frontends/qt4/GuiView.C (Revision 16123) +++ src/frontends/qt4/GuiView.C (Arbeitskopie) @@ -155,6 +155,9 @@ GuiView::GuiView(int id) : QMainWindow(), LyXView(id), commandbuffer_(0), d(*new GuiViewPrivate) { + setAttribute(Qt::WA_QuitOnClose, false); + //setAttribute(Qt::WA_DeleteOnClose, false); + // hardcode here the platform specific icon size d.smallIconSize = 14; // scaling problems d.normalIconSize = 20; // ok, default @@ -210,6 +213,19 @@ updateMenubar(); } +void GuiView::closeEvent(QCloseEvent * close_event) +{ + theApp()->gui().unregisterView(id()); + if (theApp()->gui().viewIds().empty()) + { + // this is the place were we leave the frontend + // and is the only point were we begin to quit + saveGeometry(); + close_event->accept(); + // quit the event loop + qApp->quit(); + } +} void GuiView::saveGeometry() { @@ -552,24 +568,6 @@ } -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(); - hide(); // don't remove this hide, it prevents a crash on exit - gui.unregisterView(this); -} - - void GuiView::show() { QMainWindow::setWindowTitle(qt_("LyX")); Index: src/frontends/Gui.h =================================================================== --- src/frontends/Gui.h (Revision 16123) +++ src/frontends/Gui.h (Arbeitskopie) @@ -38,19 +38,22 @@ virtual ~Gui() {} /// - virtual int newView() = 0; + virtual LyXView& createRegisteredView() = 0; /// - virtual LyXView & view(int id) = 0; + virtual bool closeAllRegisteredViews()= 0; + /// + virtual bool unregisterView(int id) = 0; /// + virtual LyXView& view(int id) const = 0; + /// + virtual std::vector<int> const & viewIds() = 0; + + 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_; }; protected: /// view of a buffer. Eventually there will be several. Index: src/frontends/Application.C =================================================================== --- src/frontends/Application.C (Revision 16123) +++ src/frontends/Application.C (Arbeitskopie) @@ -55,9 +55,9 @@ unsigned int iconSizeXY, const std::string & geometryArg) { - int view_id = gui().newView(); - LyXView & view = gui().view(view_id); - + LyXView & view = gui().createRegisteredView(); + int view_id = view.id(); + theLyXFunc().setLyXView(&view); /*int workArea_id_ =*/ gui().newWorkArea(width, height, view_id); Index: src/frontends/LyXView.C =================================================================== --- src/frontends/LyXView.C (Revision 16123) +++ src/frontends/LyXView.C (Arbeitskopie) @@ -17,6 +17,7 @@ #include "Toolbars.h" #include "Menubar.h" #include "WorkArea.h" +#include "Gui.h" #include "buffer.h" #include "bufferparams.h" @@ -398,12 +399,6 @@ void LyXView::dispatch(FuncRequest const & cmd) { - if (cmd.action == LFUN_WINDOW_CLOSE) { - close(); - closed(id_); - return; - } - theLyXFunc().setLyXView(this); lyx::dispatch(cmd); } Index: src/lyx_main.C =================================================================== --- src/lyx_main.C (Revision 16123) +++ src/lyx_main.C (Arbeitskopie) @@ -177,13 +177,6 @@ LyX::~LyX() { - // Static data are not treated in the same way at all on the Mac (and - // the LyX singleton has static methods). This is the reason why the - // exit command on the Mac bypasses our dispatch machinery altogether. - // On Linux and Windows we won't pass a second time through quit() - // because quitting will already be set to true. - if (!quitting) - quit(); } @@ -402,12 +395,7 @@ exit_status = pimpl_->application_->exec(); - // FIXME: Do we still need this reset? - // I assume it is the reason for strange Mac crashs - // Test by reverting rev 16110 (Peter) - // Kill the application object before exiting. This avoid crash - // on exit on Linux. - pimpl_->application_.reset(); + prepareExit(); // Restore original font resources after Application is destroyed. support::restoreFontResources(); @@ -442,6 +430,19 @@ from_utf8(package().temp_dir())); Alert::warning(_("Unable to remove temporary directory"), msg); } + + // Kill the application object before exiting. This avoid crash + // on exit on Linux. + if (pimpl_->application_) + pimpl_->application_.reset(); + + if (use_gui) { + if (pimpl_->session_) + pimpl_->session_->writeFile(); + pimpl_->session_.reset(); + pimpl_->lyx_server_.reset(); + pimpl_->lyx_socket_.reset(); + } } @@ -455,22 +456,6 @@ } -void LyX::quit() -{ - lyxerr[Debug::INFO] << "Running QuitLyX." << endl; - - prepareExit(); - if (use_gui) { - if (pimpl_->session_) - pimpl_->session_->writeFile(); - pimpl_->lyx_server_.reset(); - pimpl_->lyx_socket_.reset(); - if (pimpl_->application_) - pimpl_->application_->exit(0); - } -} - - int LyX::loadFiles(int & argc, char * argv[], vector<string> & files) { Index: src/lyx_main.h =================================================================== --- src/lyx_main.h (Revision 16123) +++ src/lyx_main.h (Arbeitskopie) @@ -64,13 +64,6 @@ /// in the case of failure void emergencyCleanup() const; - /// Ask the LyX class to exit. - /** - In GUI mode, after this function has been called, application_ leaves - the main event loop and returns from the call to Application::start(). - */ - void quit(); - /// BufferList & bufferList(); BufferList const & bufferList() const;