Abdelrazak Younes wrote: > Peter Kümmel wrote: >> In the last patch is a bug for Mac. >> Here the corrected. >> >> >> ------------------------------------------------------------------------ >> >> 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(); > > What's the difference between this and closeAll()? Can a view be > unregistered?
Yes, this is one of the most important change, unregister only in the CloseEvent and quit when no views left. > >> 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()); > > I am not sure this signal is caught anywhere. I created it at some point > but I did not make use of it at the end. You should maybe check whether > it is used or not. > Ok. >> 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; > > Yes, that's definitely better than the template based solution. It also was not a correct solution. > >> >> /// 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() > > I'd rather keep the max_view_id_ vector as this is used quite often in max_view_id_ is private; but, yes, viewIds() is now much more expensive. > LyX::updateInset(). But this LyX::updateInset() is not good at all so > we'd better clean this up at the same time. How? Must first have a look at it. Maybe we could make viewIds() private. > >> -int GuiImplementation::newView() >> +LyXView& GuiImplementation::createRegisteredView() > > Same question: can a View be unregistered? If not, then newView() is > more explicit IMHO. > >> { >> - size_t const id = max_view_id_; >> - ++max_view_id_; >> - This is totally wrong, fixed in the new patch. >> - 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 > > This is a bad name :-). It is just a helper function that uses nothing > to do with GuiImplementation so just call it extractIds() and put that > in the anon namespace. Yes, that's better. >> + (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(); >> + } >> +} > > I think this could be a good solution but the problem here is that I > think there is a bug in QtMac. This is a theory that could well explain > Bennett's report about non-saved files on exit: I also have the impression that QCloseEvent isn't called on the Mac, I've added an output in the new patch to verify it. > > qApp->exit() seems to always results in killing the application. It > seems that the LyX destructor is always called the moment just after > that. The execution process in LyX::exec() is thus not properly done and > prepareExit() is not called here: qApp->quit(); should only close the event loop and return, but we will see it with Bennetts backtrace (now I'm pessimistic for the Mac) >> @@ -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(); > > > > Abdel. > The are no new big changes in the new patch. Thanks for the comments Abdel, this is really a hairy stuff, costs me several hours. Peter