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