|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (developer.feedback@nokia.com) |
|
6 ** |
|
7 ** This file is part of the HbServers module of the UI Extensions for Mobile. |
|
8 ** |
|
9 ** GNU Lesser General Public License Usage |
|
10 ** This file may be used under the terms of the GNU Lesser General Public |
|
11 ** License version 2.1 as published by the Free Software Foundation and |
|
12 ** appearing in the file LICENSE.LGPL included in the packaging of this file. |
|
13 ** Please review the following information to ensure the GNU Lesser General |
|
14 ** Public License version 2.1 requirements will be met: |
|
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
16 ** |
|
17 ** In addition, as a special exception, Nokia gives you certain additional |
|
18 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
20 ** |
|
21 ** If you have questions regarding the use of this file, please contact |
|
22 ** Nokia at developer.feedback@nokia.com. |
|
23 ** |
|
24 ****************************************************************************/ |
|
25 #include "hbthemeserverapplication_p.h" |
|
26 #include "hbthemeserver_p.h" |
|
27 #include "hbthemecommon_p.h" |
|
28 #include "hbtheme.h" |
|
29 |
|
30 #include <QWindowsStyle> |
|
31 #include <QLibrary> |
|
32 #include <QDebug> |
|
33 |
|
34 #if defined (Q_OS_SYMBIAN) |
|
35 #include "hbthemecommon_symbian_p.h" |
|
36 #include <eikenv.h> |
|
37 #include <apgwgnam.h> |
|
38 #endif |
|
39 |
|
40 static const QLatin1String APP_NAME("HbThemeServer"); |
|
41 static const QLatin1String RESOURCE_LIB_NAME("HbCore"); |
|
42 static const QLatin1String TEST_RESOURCE_LIB_NAME("HbTestResources"); |
|
43 static const QLatin1String WIN32_DEBUG_SUFFIX("d"); |
|
44 static const QLatin1String MAC_DEBUG_SUFFIX("_debug"); |
|
45 static const QLatin1String STOP_MESSAGE("stop"); |
|
46 |
|
47 bool HbThemeServerApplication::Options::help = false; |
|
48 bool HbThemeServerApplication::Options::start = false; |
|
49 bool HbThemeServerApplication::Options::stop = false; |
|
50 bool HbThemeServerApplication::Options::persistent = false; |
|
51 QString HbThemeServerApplication::Options::error = QString(); |
|
52 |
|
53 HbThemeServerApplication::HbThemeServerApplication(int &argc, char *argv[]) : |
|
54 QtSingleApplication(argc, argv), server(0) |
|
55 { |
|
56 setApplicationName(APP_NAME); |
|
57 |
|
58 #ifdef QT_DEBUG |
|
59 //temporary solution until Hb specific style is ready |
|
60 setStyle(new QWindowsStyle); |
|
61 #endif // QT_DEBUG |
|
62 |
|
63 #if QT_VERSION >= 0x040601 |
|
64 setAttribute(Qt::AA_S60DontConstructApplicationPanes); |
|
65 #endif // QT_VERSION |
|
66 |
|
67 // ignore command line arguments on Symbian |
|
68 #ifdef Q_OS_SYMBIAN |
|
69 Options::start = true; |
|
70 Options::persistent = true; |
|
71 #else |
|
72 QStringList args = arguments(); |
|
73 args.removeFirst(); // ignore argv0 |
|
74 const bool wasEmpty = args.isEmpty(); |
|
75 const bool restart = args.removeAll(QLatin1String("-restart")); |
|
76 Options::start = args.removeAll(QLatin1String("-start")) || restart; |
|
77 Options::stop = args.removeAll(QLatin1String("-stop")) || restart; |
|
78 Options::persistent = args.removeAll(QLatin1String("-persistent")); |
|
79 Options::help = args.removeAll(QLatin1String("-help")) || args.removeAll(QLatin1String("-h")) || !args.isEmpty() || wasEmpty; |
|
80 if (!args.isEmpty()) { |
|
81 Options::error = tr("Unknown option(s): '%1'").arg(args.join(QLatin1String(" "))); |
|
82 } |
|
83 #endif // Q_OS_SYMBIAN |
|
84 } |
|
85 |
|
86 HbThemeServerApplication::~HbThemeServerApplication() |
|
87 { |
|
88 delete server; |
|
89 } |
|
90 |
|
91 bool HbThemeServerApplication::initialize() |
|
92 { |
|
93 #if defined (Q_OS_SYMBIAN) |
|
94 CEikonEnv * env = CEikonEnv::Static(); |
|
95 if ( env ) { |
|
96 CApaWindowGroupName* wgName = CApaWindowGroupName::NewLC(env->WsSession()); |
|
97 env->RootWin().SetOrdinalPosition(0, ECoeWinPriorityNeverAtFront); // avoid coming to foreground |
|
98 wgName->SetHidden(ETrue); // hides us from FSW and protects us from OOM FW etc. |
|
99 wgName->SetSystem(ETrue); // Allow only application with PowerManagement cap to shut us down |
|
100 wgName->SetCaptionL(_L("HbThemeServer")); // TODO: use QCoreApplication::applicationName() |
|
101 wgName->SetAppUid(KNullUid); |
|
102 wgName->SetWindowGroupName(env->RootWin()); |
|
103 CleanupStack::PopAndDestroy(); |
|
104 RThread::RenameMe(_L("HbThemeServer")); // TODO: use QCoreApplication::applicationName() |
|
105 } |
|
106 #endif |
|
107 |
|
108 // as for theme initialization, an instance needs to be created before starting the server |
|
109 HbTheme::instance(); |
|
110 |
|
111 // load resource libraries in order to make binary resources accessible |
|
112 bool result = loadLibrary(RESOURCE_LIB_NAME); |
|
113 #ifdef HB_DEVELOPER |
|
114 loadLibrary(TEST_RESOURCE_LIB_NAME); |
|
115 #endif |
|
116 return result; |
|
117 } |
|
118 |
|
119 int HbThemeServerApplication::exec() |
|
120 { |
|
121 if (!server) { |
|
122 server = new HbThemeServer; |
|
123 } |
|
124 |
|
125 if (server->startServer()) { |
|
126 #if !defined(Q_OS_SYMBIAN) && defined(QT_DEBUG) |
|
127 server->showMinimized(); |
|
128 #endif |
|
129 return QtSingleApplication::exec(); |
|
130 } |
|
131 |
|
132 return EXIT_FAILURE; |
|
133 } |
|
134 |
|
135 void HbThemeServerApplication::stop() |
|
136 { |
|
137 #ifndef Q_OS_SYMBIAN |
|
138 sendMessage(STOP_MESSAGE); |
|
139 #endif // Q_OS_SYMBIAN |
|
140 } |
|
141 |
|
142 bool HbThemeServerApplication::loadLibrary(const QString &name) |
|
143 { |
|
144 // To load resources embedded in hb library |
|
145 QLibrary library(name); |
|
146 bool result = library.load(); |
|
147 |
|
148 if (!result) { |
|
149 // Library may not be loaded, if it was built in debug mode and the name in debug mode is |
|
150 // different, change the name to debug version in that scenario |
|
151 QString alternateName = name; |
|
152 #ifdef Q_OS_WIN32 |
|
153 alternateName += WIN32_DEBUG_SUFFIX; |
|
154 #elif defined(Q_OS_MAC) |
|
155 alternateName += MAC_DEBUG_SUFFIX; |
|
156 #endif |
|
157 // On symbian library name in debug mode is same as that in release mode, |
|
158 // so no need to do anything for that |
|
159 library.setFileName(alternateName); |
|
160 result = library.load(); |
|
161 } |
|
162 #ifdef THEME_SERVER_TRACES |
|
163 if (result) { |
|
164 qDebug() << "HbThemeServerApplication::loadLibrary(): loaded library " << name; |
|
165 } |
|
166 else { |
|
167 qDebug() << "HbThemeServerApplication::loadLibrary(): could not load library " << name; |
|
168 } |
|
169 #endif // THEME_SERVER_TRACES |
|
170 |
|
171 return result; |
|
172 } |
|
173 |
|
174 void HbThemeServerApplication::receiveMessage(const QString &message) |
|
175 { |
|
176 if (!server) |
|
177 return; |
|
178 |
|
179 if (message == STOP_MESSAGE) { |
|
180 server->stopServer(); |
|
181 quit(); |
|
182 } |
|
183 } |
|
184 |
|
185 bool HbThemeServerApplication::acquireLock() { |
|
186 #ifdef Q_OS_SYMBIAN |
|
187 // Guard against starting multiple copies of the server |
|
188 Lock lock; |
|
189 Lock::State lockState; |
|
190 for(;;) { |
|
191 lockState = lock.acquire(); |
|
192 if (lockState == Lock::Acquired) { |
|
193 break; |
|
194 } else if (lockState == Lock::Reserved) { |
|
195 // Process may be starting, wait for server object to be created |
|
196 if (Lock::serverExists()) { |
|
197 #ifdef THEME_SERVER_TRACES |
|
198 qDebug() << "HbThemeServer::main: serverExists!!!"; |
|
199 #endif |
|
200 break; |
|
201 } else { |
|
202 const TInt KTimeout = 100000; // 100 ms |
|
203 User::After(KTimeout); |
|
204 } |
|
205 } else { |
|
206 break; |
|
207 } |
|
208 } |
|
209 |
|
210 if (lockState != Lock::Acquired) { |
|
211 // With KErrAlreadyExists client should try to connect, otherwise bail out. |
|
212 #ifdef THEME_SERVER_TRACES |
|
213 qDebug() << "HbThemeServer::main: Lock not acquired!!!"; |
|
214 #endif |
|
215 RProcess::Rendezvous(lockState == Lock::Reserved ? KErrAlreadyExists : KErrGeneral); |
|
216 } |
|
217 |
|
218 return (lockState == Lock::Acquired); |
|
219 #else |
|
220 return true; |
|
221 #endif |
|
222 |
|
223 |
|
224 } |
|
225 |
|
226 |
|
227 #ifdef Q_OS_SYMBIAN |
|
228 Lock::Lock() |
|
229 { |
|
230 // Using a file for interprocess lock |
|
231 const int NumMessageSlots = 1; |
|
232 if (mFs.Connect(NumMessageSlots) == KErrNone) { |
|
233 mFs.CreatePrivatePath(EDriveC); |
|
234 if (mFs.SetSessionToPrivate(EDriveC) == KErrNone) { |
|
235 _LIT(KFileName, "lockFile"); |
|
236 const TUint mode = EFileShareReadersOrWriters; |
|
237 if (mFile.Create(mFs, KFileName, mode) == KErrAlreadyExists) { |
|
238 mFile.Open(mFs, KFileName, mode); |
|
239 } |
|
240 } |
|
241 } |
|
242 } |
|
243 |
|
244 // Try to acquire lock |
|
245 Lock::State Lock::acquire() |
|
246 { |
|
247 State state = Error; |
|
248 // If process holding the lock crashes, file server releases the lock |
|
249 if (mFile.SubSessionHandle()) { |
|
250 TInt error = mFile.Lock(0, 1); |
|
251 if (error == KErrNone) { |
|
252 state = Acquired; |
|
253 } else if (error == KErrLocked) { |
|
254 state = Reserved; |
|
255 } |
|
256 } |
|
257 return state; |
|
258 } |
|
259 |
|
260 // Check if Symbian server exists |
|
261 bool Lock::serverExists() |
|
262 { |
|
263 TFindServer findHbServer(KThemeServerName); |
|
264 TFullName name; |
|
265 return findHbServer.Next(name) == KErrNone; |
|
266 } |
|
267 |
|
268 #endif |