From 7b2cce9d5d19fd6e05cf0373b51807da19d4e82b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Peter=20K=C3=BCmmel?= Date: Sat, 2 Dec 2006 17:39:31 +0000 Subject: [PATCH] Clean up quit code. We still need a solution for the Mac. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16135 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/frontends/Application.C | 6 +- src/frontends/Application.h | 3 +- src/frontends/Gui.h | 21 ++-- src/frontends/LyXView.C | 7 +- src/frontends/qt4/GuiApplication.C | 11 +-- src/frontends/qt4/GuiApplication.h | 2 +- src/frontends/qt4/GuiImplementation.C | 135 +++++++++++++------------- src/frontends/qt4/GuiImplementation.h | 27 +++--- src/frontends/qt4/GuiView.C | 45 +++++---- src/lyx_main.C | 43 +++----- src/lyx_main.h | 7 -- src/lyxfunc.C | 15 ++- 12 files changed, 154 insertions(+), 168 deletions(-) diff --git a/src/frontends/Application.C b/src/frontends/Application.C index e7f64e339e..0f3fa8c2d8 100644 --- a/src/frontends/Application.C +++ b/src/frontends/Application.C @@ -55,9 +55,9 @@ LyXView & Application::createView(unsigned int width, 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); diff --git a/src/frontends/Application.h b/src/frontends/Application.h index 03cdf36c6a..748f1cf7b7 100644 --- a/src/frontends/Application.h +++ b/src/frontends/Application.h @@ -168,8 +168,7 @@ public: * remove a I/O read callback * @param fd socket descriptor (file/socket/etc) */ - template - 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, diff --git a/src/frontends/Gui.h b/src/frontends/Gui.h index 442508f7ea..0d7ec628ab 100644 --- a/src/frontends/Gui.h +++ b/src/frontends/Gui.h @@ -38,23 +38,26 @@ public: virtual ~Gui() {} /// - virtual int newView() = 0; + virtual LyXView& createRegisteredView() = 0; /// - virtual LyXView & view(int id) = 0; - + virtual bool unregisterView(int id) = 0; /// - virtual int newWorkArea(unsigned int width, unsigned int height, int view_id) = 0; + virtual bool closeAllViews()= 0; + /// - virtual WorkArea & workArea(int id) = 0; + virtual LyXView& view(int id) const = 0; /// - virtual bool closeAll() = 0; + std::vector const & viewIds() + { + return view_ids_; + } + + virtual int newWorkArea(unsigned int width, unsigned int height, int view_id) = 0; /// - std::vector const & viewIds() { return view_ids_; }; + virtual WorkArea & workArea(int id) = 0; protected: - /// view of a buffer. Eventually there will be several. - std::map > buffer_views_; std::vector view_ids_; }; diff --git a/src/frontends/LyXView.C b/src/frontends/LyXView.C index 4fd5da524e..fee535079d 100644 --- a/src/frontends/LyXView.C +++ b/src/frontends/LyXView.C @@ -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::updateWindowTitle() void LyXView::dispatch(FuncRequest const & cmd) { - if (cmd.action == LFUN_WINDOW_CLOSE) { - close(); - closed(id_); - return; - } - theLyXFunc().setLyXView(this); lyx::dispatch(cmd); } diff --git a/src/frontends/qt4/GuiApplication.C b/src/frontends/qt4/GuiApplication.C index e41fa106ad..99b5a78794 100644 --- a/src/frontends/qt4/GuiApplication.C +++ b/src/frontends/qt4/GuiApplication.C @@ -95,6 +95,9 @@ GuiApplication::~GuiApplication() GuiApplication::GuiApplication(int & argc, char ** argv) : QApplication(argc, argv), Application(argc, argv) { + // Qt bug? setQuitOnLastWindowClosed(true); does not work + setQuitOnLastWindowClosed(false); + #ifdef Q_WS_X11 // doubleClickInterval() is 400 ms on X11 which is just too long. // On Windows and Mac OS X, the operating system's value is used. @@ -277,14 +280,8 @@ void GuiApplication::registerSocketCallback(int fd, boost::function func boost::shared_ptr(new socket_callback(fd, func)); } -template<> -void Application::unregisterSocketCallback(int fd) -{ - GuiApplication* ptr = static_cast(this); - ptr->unregisterSocketCallbackImpl(fd); -} -void GuiApplication::unregisterSocketCallbackImpl(int fd) +void GuiApplication::unregisterSocketCallback(int fd) { socket_callbacks_.erase(fd); } diff --git a/src/frontends/qt4/GuiApplication.h b/src/frontends/qt4/GuiApplication.h index ed0fe31b42..af495688f0 100644 --- a/src/frontends/qt4/GuiApplication.h +++ b/src/frontends/qt4/GuiApplication.h @@ -75,7 +75,7 @@ public: virtual void updateColor(LColor_color col); virtual void registerSocketCallback( int fd, boost::function func); - void unregisterSocketCallbackImpl(int fd); + void unregisterSocketCallback(int fd); //@} /// diff --git a/src/frontends/qt4/GuiImplementation.C b/src/frontends/qt4/GuiImplementation.C index a4ea5833b0..1400fd6e97 100644 --- a/src/frontends/qt4/GuiImplementation.C +++ b/src/frontends/qt4/GuiImplementation.C @@ -24,113 +24,119 @@ #include "funcrequest.h" #include "lyxfunc.h" +#include + using boost::shared_ptr; + +namespace +{ + template + void updateIds(std::map const & stdmap, std::vector & ids) + { + ids.clear(); + typename std::map::const_iterator it; + for (it = stdmap.begin(); it != stdmap.end(); ++it) + ids.push_back(it->first); + } +} + + namespace lyx { namespace frontend { -GuiImplementation::GuiImplementation(): max_view_id_(0), max_wa_id_(0) +GuiImplementation::GuiImplementation() { + view_ids_.clear(); + work_area_ids_.clear(); } -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; + updateIds(views_, view_ids_); + int id = 0; + while (views_.find(id) != views_.end()) + id++; + views_.insert(std::pair(id, new GuiView(id))); + updateIds(views_, view_ids_); + return *views_[id]; } -LyXView& GuiImplementation::view(int id) +bool GuiImplementation::unregisterView(int id) { + updateIds(views_, view_ids_); BOOST_ASSERT(views_.find(id) != views_.end()); + BOOST_ASSERT(views_[id]); - return *views_[id]; + std::map::iterator it; + for (it = views_.begin(); it != views_.end(); ++it) { + if (it->first == id) { + std::vector 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; + } + } + updateIds(views_, view_ids_); + return true; } -bool GuiImplementation::closeAll() +bool GuiImplementation::closeAllViews() { - // ATM never used - 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 view_ids_tmp = view_ids_; - view_ids_.clear(); + updateIds(views_, view_ids_); + if (views_.empty()) + { + // quit in CloseEvent will not be triggert + qApp->quit(); + return true; + } - 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 const cmap = views_; + std::map::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(); - + view_ids_.clear(); + work_area_ids_.clear(); return true; } -void GuiImplementation::unregisterView(GuiView * view) +LyXView& GuiImplementation::view(int id) const { - std::map::iterator I; - - for (I = views_.begin(); I != views_.end(); ++I) { - if (I->second == view) { - std::vector 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; - } - } - - buildViewIds(); - - if (views_.empty()) { - theLyXFunc().setLyXView(0); - dispatch(FuncRequest(LFUN_LYX_QUIT)); - return; - } - - theLyXFunc().setLyXView(views_.begin()->second); + BOOST_ASSERT(views_.find(id) != views_.end()); + return *views_.find(id)->second; } -void GuiImplementation::buildViewIds() +std::vector const & GuiImplementation::workAreaIds() { - view_ids_.clear(); - std::map::const_iterator I; - for (I = views_.begin(); I != views_.end(); ++I) - view_ids_.push_back(I->first); + updateIds(work_areas_, work_area_ids_); + return 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_; + updateIds(views_, view_ids_); + int id = 0; + while (work_areas_.find(id) != work_areas_.end()) + id++; GuiView * view = views_[view_id]; - work_areas_[id] = new GuiWorkArea(w, h, id, *view); + work_areas_.insert(std::pair + (id, new GuiWorkArea(w, h, id, *view))); // FIXME BufferView creation should be independant of WorkArea creation buffer_views_[id].reset(new BufferView); @@ -147,7 +153,6 @@ int GuiImplementation::newWorkArea(unsigned int w, unsigned int h, int view_id) WorkArea& GuiImplementation::workArea(int id) { BOOST_ASSERT(work_areas_.find(id) != work_areas_.end()); - return *work_areas_[id]; } diff --git a/src/frontends/qt4/GuiImplementation.h b/src/frontends/qt4/GuiImplementation.h index 221391988c..697bbd6d4d 100644 --- a/src/frontends/qt4/GuiImplementation.h +++ b/src/frontends/qt4/GuiImplementation.h @@ -38,19 +38,17 @@ public: GuiImplementation(); virtual ~GuiImplementation() {} - virtual int newView(); - virtual LyXView& view(int id); + + virtual LyXView& createRegisteredView(); + virtual bool closeAllViews(); + virtual bool unregisterView(int id); + + virtual LyXView& view(int id) const; + 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 +65,14 @@ private: */ std::map work_areas_; /// - size_t max_view_id_; - /// - size_t max_wa_id_; + + /// view of a buffer. Eventually there will be several. + std::map > buffer_views_; + + + std::vector const & workAreaIds(); + + std::vector work_area_ids_; }; } // namespace frontend diff --git a/src/frontends/qt4/GuiView.C b/src/frontends/qt4/GuiView.C index bf8d700230..df06173e36 100644 --- a/src/frontends/qt4/GuiView.C +++ b/src/frontends/qt4/GuiView.C @@ -155,6 +155,12 @@ unsigned int GuiView::GuiViewPrivate::lastIconSize = 0; GuiView::GuiView(int id) : QMainWindow(), LyXView(id), commandbuffer_(0), d(*new GuiViewPrivate) { + // Qt bug? signal lastWindowClosed does not work + setAttribute(Qt::WA_QuitOnClose, false); + // FIXME: enable to avoid memory leaks but it prduces a crash + // after a new window has been close (click into the menu) + //setAttribute(Qt::WA_DeleteOnClose, false); + // hardcode here the platform specific icon size d.smallIconSize = 14; // scaling problems d.normalIconSize = 20; // ok, default @@ -210,9 +216,30 @@ void GuiView::init() 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(); + theBufferList().quitWriteAll(); + close_event->accept(); + // quit the event loop + qApp->quit(); + } + close_event->accept(); +} void GuiView::saveGeometry() { + static bool done = false; + if (done) + return; + else + done = true; + // FIXME: // change the ifdef to 'geometry = normalGeometry();' only // when Trolltech has fixed the broken normalGeometry on X11: @@ -552,24 +579,6 @@ void GuiView::moveEvent(QMoveEvent *) } -void GuiView::closeEvent(QCloseEvent * close_event) -{ - GuiImplementation & gui - = static_cast(theApp()->gui()); - - vector 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")); diff --git a/src/lyx_main.C b/src/lyx_main.C index 23692a194f..a029f52e41 100644 --- a/src/lyx_main.C +++ b/src/lyx_main.C @@ -177,13 +177,6 @@ frontend::Application * theApp() 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 @@ int LyX::exec(int & argc, char * argv[]) 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 @@ void LyX::prepareExit() from_utf8(package().temp_dir())); Alert::warning(_("Unable to remove temporary directory"), msg); } + + if (use_gui) { + if (pimpl_->session_) + pimpl_->session_->writeFile(); + pimpl_->session_.reset(); + pimpl_->lyx_server_.reset(); + pimpl_->lyx_socket_.reset(); + } + + // Kill the application object before exiting. This avoid crash + // on exit on Linux. + if (pimpl_->application_) + pimpl_->application_.reset(); } @@ -455,22 +456,6 @@ void LyX::earlyExit(int status) } -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 & files) { diff --git a/src/lyx_main.h b/src/lyx_main.h index bdbef3b302..c79a2c08f7 100644 --- a/src/lyx_main.h +++ b/src/lyx_main.h @@ -66,13 +66,6 @@ public: /// 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; diff --git a/src/lyxfunc.C b/src/lyxfunc.C index e8c7676382..5a5e955dd9 100644 --- a/src/lyxfunc.C +++ b/src/lyxfunc.C @@ -1034,12 +1034,6 @@ void LyXFunc::dispatch(FuncRequest const & cmd) 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,11 @@ void LyXFunc::dispatch(FuncRequest const & cmd) LyX::ref().session().lastFilePos().save(FileName(lyx_view_->buffer()->fileName()), boost::tie(view()->cursor().pit(), view()->cursor().pos()) ); } - - LyX::ref().quit(); + + // save the geometry of the current view + lyx_view_->saveGeometry(); + // quitting is trigged by the gui code (leaving the event loop) + theApp()->gui().closeAllViews(); break; case LFUN_TOC_VIEW: { @@ -1670,7 +1667,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd) 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: { -- 2.39.2