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);
* 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,
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<int> const & viewIds()
+ {
+ return view_ids_;
+ }
+
+ virtual int newWorkArea(unsigned int width, unsigned int height, int view_id) = 0;
///
- std::vector<int> const & viewIds() { return view_ids_; };
+ virtual WorkArea & workArea(int id) = 0;
protected:
- /// view of a buffer. Eventually there will be several.
- std::map<int, boost::shared_ptr<BufferView> > buffer_views_;
std::vector<int> view_ids_;
};
#include "Toolbars.h"
#include "Menubar.h"
#include "WorkArea.h"
+#include "Gui.h"
#include "buffer.h"
#include "bufferparams.h"
void LyXView::dispatch(FuncRequest const & cmd)
{
- if (cmd.action == LFUN_WINDOW_CLOSE) {
- close();
- closed(id_);
- return;
- }
-
theLyXFunc().setLyXView(this);
lyx::dispatch(cmd);
}
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.
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);
}
virtual void updateColor(LColor_color col);
virtual void registerSocketCallback(
int fd, boost::function<void()> func);
- void unregisterSocketCallbackImpl(int fd);
+ void unregisterSocketCallback(int fd);
//@}
///
#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;
+ 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];
}
-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<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;
+ }
+ }
+ 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<int> 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<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();
-
+ view_ids_.clear();
+ work_area_ids_.clear();
return true;
}
-void GuiImplementation::unregisterView(GuiView * view)
+LyXView& GuiImplementation::view(int id) const
{
- 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;
- }
- }
-
- 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<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);
+ 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);
WorkArea& GuiImplementation::workArea(int id)
{
BOOST_ASSERT(work_areas_.find(id) != work_areas_.end());
-
return *work_areas_[id];
}
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.
/**
*/
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
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
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:
}
-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"));
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();
}
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();
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();
}
}
-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)
{
/// 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;
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.
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: {
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: {