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
This commit is contained in:
Peter Kümmel 2006-12-02 17:39:31 +00:00
parent 19df31aa0a
commit 7b2cce9d5d
12 changed files with 158 additions and 172 deletions

View File

@ -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);

View File

@ -168,8 +168,7 @@ public:
* 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,

View File

@ -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 bool closeAllViews()= 0;
///
virtual LyXView& view(int id) const = 0;
///
std::vector<int> const & viewIds()
{
return view_ids_;
}
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.
std::map<int, boost::shared_ptr<BufferView> > buffer_views_;
std::vector<int> view_ids_;
};

View File

@ -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);
}

View File

@ -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<void()> func
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);
}

View File

@ -75,7 +75,7 @@ public:
virtual void updateColor(LColor_color col);
virtual void registerSocketCallback(
int fd, boost::function<void()> func);
void unregisterSocketCallbackImpl(int fd);
void unregisterSocketCallback(int fd);
//@}
///

View File

@ -24,113 +24,119 @@
#include "funcrequest.h"
#include "lyxfunc.h"
#include <QApplication>
using boost::shared_ptr;
namespace
{
template<class T>
void updateIds(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);
}
}
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;
}
LyXView& GuiImplementation::view(int id)
{
BOOST_ASSERT(views_.find(id) != views_.end());
updateIds(views_, view_ids_);
int id = 0;
while (views_.find(id) != views_.end())
id++;
views_.insert(std::pair<int, GuiView *>(id, new GuiView(id)));
updateIds(views_, view_ids_);
return *views_[id];
}
bool GuiImplementation::closeAll()
bool GuiImplementation::unregisterView(int id)
{
// ATM never used
if (!theBufferList().quitWriteAll())
return false;
updateIds(views_, view_ids_);
BOOST_ASSERT(views_.find(id) != views_.end());
BOOST_ASSERT(views_[id]);
// 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 *>::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;
}
}
views_.clear();
view_ids_.clear();
work_areas_.clear();
updateIds(views_, view_ids_);
return true;
}
void GuiImplementation::unregisterView(GuiView * view)
bool GuiImplementation::closeAllViews()
{
std::map<int, GuiView *>::iterator I;
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;
}
updateIds(views_, view_ids_);
if (views_.empty())
{
// quit in CloseEvent will not be triggert
qApp->quit();
return true;
}
buildViewIds();
if (views_.empty()) {
theLyXFunc().setLyXView(0);
dispatch(FuncRequest(LFUN_LYX_QUIT));
return;
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
}
theLyXFunc().setLyXView(views_.begin()->second);
views_.clear();
work_areas_.clear();
view_ids_.clear();
work_area_ids_.clear();
return true;
}
void GuiImplementation::buildViewIds()
LyXView& GuiImplementation::view(int id) const
{
view_ids_.clear();
std::map<int, GuiView *>::const_iterator I;
for (I = views_.begin(); I != views_.end(); ++I)
view_ids_.push_back(I->first);
BOOST_ASSERT(views_.find(id) != views_.end());
return *views_.find(id)->second;
}
std::vector<int> const & GuiImplementation::workAreaIds()
{
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<int, GuiWorkArea *>
(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];
}

View File

@ -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<int, GuiWorkArea *> work_areas_;
///
size_t max_view_id_;
///
size_t max_wa_id_;
/// view of a buffer. Eventually there will be several.
std::map<int, boost::shared_ptr<BufferView> > buffer_views_;
std::vector<int> const & workAreaIds();
std::vector<int> work_area_ids_;
};
} // namespace frontend

View File

@ -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<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"));

View File

@ -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<FileName> & files)
{

View File

@ -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;

View File

@ -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: {