OpenCPN Partial API docs
Loading...
Searching...
No Matches
instance_handler.cpp
1/***************************************************************************
2 * Copyright (C) 2023 Alec Leamas *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
19
20#include <wx/filename.h>
21#include <wx/ipc.h>
22#include <wx/log.h>
23#include <wx/snglinst.h>
24#include <wx/string.h>
25
26#include "model/base_platform.h"
27#include "model/nav_object_database.h"
28
29#include "bbox.h"
30
31class StConnection : public wxConnection {
32public:
33 StConnection() {}
34 ~StConnection() {}
35 bool OnExec(const wxString &topic, const wxString &data);
36
38 std::function<void()> update_route_mgr_dlg;
39 // if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
40 // pRouteManagerDialog->UpdateLists();
41
43 std::function<void(LLBBox)> gframe_center_view;
44 // gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
45
47 std::function<void()> raise;
48 // gFrame->InvalidateAllGL();
49 // gFrame->RefreshAllCanvas(false);
50 // gFrame->Raise();
51};
52
53// Client class, to be used by subsequent instances in OnInit
54class StClient : public wxClient {
55public:
56 StClient() {};
57 wxConnectionBase *OnMakeConnection() { return new StConnection; }
58};
59
60// Opens a file passed from another instance
61bool StConnection::OnExec(const wxString &topic, const wxString &data) {
62 // not setup yet
63 // if (!gFrame) return false;
64
65 wxString path(data);
66 if (path.IsEmpty()) {
67 raise();
68 } else {
70 pSet->load_file(path.fn_str());
71 int wpt_dups;
72 // Import with full vizibility of names and objects
73 pSet->LoadAllGPXObjects(!pSet->IsOpenCPN(), wpt_dups, true);
75 LLBBox box = pSet->GetBBox();
76 if (box.GetValid()) {
78 }
79 delete pSet;
80 return true;
81 }
82 return true;
83}
84
85// Server class, for listening to connection requests
86class StServer : public wxServer {
87public:
88 wxConnectionBase *OnAcceptConnection(const wxString &topic);
89};
90
92static bool IsToplevelModal() {
93 for (auto w = wxTopLevelWindows.GetFirst(); w; w = w->GetNext()) {
94 wxDialog *dlg = dynamic_cast<wxDialog *>(w->GetData());
95 if (dlg && dlg->IsModal()) {
96 return true;
97 }
98 }
99 return false;
100}
101
102// Accepts a connection from another instance
103wxConnectionBase *StServer::OnAcceptConnection(const wxString &topic) {
104 if (topic.Lower() == "opencpn" && !IsToplevelModal()) {
105 return new StConnection();
106 }
107 return 0;
108}
109
110class InstanceHandler : public wxSingleInstanceChecker {
111public:
112 bool Init(const std::vector<std::string> &params) {
113 if (wxSingleInstanceChecker::IsAnotherRunning()) {
114 wxChar separator = wxFileName::GetPathSeparator();
115 wxString service_name =
116 g_BasePlatform->GetPrivateDataDir() + separator + _T("opencpn-ipc");
117
118 auto checker = new wxSingleInstanceChecker(
119 _T("_OpenCPN_SILock"), g_BasePlatform->GetPrivateDataDir());
120 if (!checker->IsAnotherRunning()) {
121 StServer *m_server = new StServer;
122 if (!m_server->Create(service_name)) {
123 wxLogDebug(wxT("Failed to create an IPC service."));
124 return false;
125 }
126 } else {
127 wxLogNull logNull;
128 StClient *client = new StClient;
129 // ignored under DDE, host name in TCP/IP based classes
130 wxString hostName = wxT("localhost");
131 // Create the connection service, topic
132 wxConnectionBase *connection =
133 client->MakeConnection(hostName, service_name, _T("OpenCPN"));
134 if (connection) {
135 // Ask the other instance to open a file or raise itself
136 if (params.empty()) {
137 for (size_t n = 0; n < params.size(); n++) {
138 wxString path(params[n]);
139 if (::wxFileExists(path)) {
140 connection->Execute(path);
141 }
142 }
143 }
144 connection->Execute(wxT(""));
145 connection->Disconnect();
146 delete connection;
147 } else {
148 // If we get here, it means that the wxWidgets single-instance-detect
149 // logic found the lock file, And so thinks another instance is
150 // running. But that instance is not reachable, for some reason. So,
151 // the safe thing to do is delete the lockfile, and exit. Next start
152 // will proceed normally. This may leave a zombie OpenCPN, but at
153 // least O starts.
154 wxString lockFile = wxString(g_BasePlatform->GetPrivateDataDir() +
155 separator + _T("_OpenCPN_SILock"));
156 if (wxFileExists(lockFile)) wxRemoveFile(lockFile);
157
158 wxMessageBox(
159 _("Sorry, an existing instance of OpenCPN may be too busy "
160 "to respond.\nPlease retry."),
161 wxT("OpenCPN"), wxICON_INFORMATION | wxOK);
162 }
163 delete client;
164 return false; // exit quietly
165 }
166 }
167 return true;
168 }
169};
wxString & GetPrivateDataDir()
Return dir path for opencpn.log, etc., respecting -c cli option.
std::function< void(LLBBox)> gframe_center_view
Center global view to a given box callback.
std::function< void()> raise
Raise current OPenCPN main window to top of GUI application stack.
std::function< void()> update_route_mgr_dlg
Update RouteManagerDialog callback.