libraries/qr3/src/NotifierProxy.cpp
changeset 0 7f656887cf89
child 86 849a0b46c767
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // NotifierProxy.cpp
       
     2 // 
       
     3 // Copyright (c) 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 #include <fshell/common.mmh>
       
    13 #include <e32notif.h>
       
    14 #include <e32ver.h>
       
    15 
       
    16 #ifndef FSHELL_WSERV_SUPPORT
       
    17 
       
    18 EXPORT_C TInt StartNotifierProxyThreadFunction(TAny*)
       
    19 	{
       
    20 	return KErrNotSupported;
       
    21 	}
       
    22 
       
    23 EXPORT_C TInt ShutdownProxyNotifier()
       
    24 	{
       
    25 	return KErrNotSupported;
       
    26 	}
       
    27 
       
    28 EXPORT_C TBool NotifierProxyIsRunning()
       
    29 	{
       
    30 	return EFalse;
       
    31 	}
       
    32 
       
    33 #else
       
    34 
       
    35 #include "NotifierProxy.h"
       
    36 #include <fshell/clogger.h>
       
    37 #include "utils.h"
       
    38 
       
    39 _LIT(KRealNotifierServerName,   "RealNtfyr");
       
    40 _LIT8(KRealNotifierServerName8, "RealNtfyr");
       
    41 
       
    42 #define LeaveIfErr(_err, _args...) \
       
    43 	do \
       
    44 		{ \
       
    45 		if (_err < 0) \
       
    46 			{ \
       
    47 			RClogger::Slog(_args); \
       
    48 			User::Leave(_err); \
       
    49 			} \
       
    50 		} \
       
    51 		while (0)
       
    52 
       
    53 const TInt KShutdownProxy = 1000;
       
    54 const TInt KPingProxy = 1001;
       
    55 const TInt KInfoPrintTime = 2000000; // 2 seconds
       
    56 
       
    57 TInt RRealNotifier::Connect()
       
    58 	{
       
    59 	return CreateSession(KRealNotifierServerName, TVersion(KNotifierMajorVersionNumber,KNotifierMinorVersionNumber,KNotifierBuildVersionNumber),-1);
       
    60 	}
       
    61 
       
    62 CNotifierProxyServer::CNotifierProxyServer()
       
    63 	: CServer2(0, ESharableSessions)
       
    64 	{
       
    65 	}
       
    66 
       
    67 void CNotifierProxyServer::ConstructL()
       
    68 	{
       
    69 	//__DEBUGGER();
       
    70 	SetupWindowL();
       
    71 	TFontSpec spec(_L("Roman"), 12);
       
    72 	LeaveIfErr(iScreenDevice->GetNearestFontInPixels(iFont, spec), _L("Couldn't find a suitable font"));
       
    73 	iPeriodic = CPeriodic::NewL(CActive::EPriorityStandard);
       
    74 	iText.ReserveL(8);
       
    75 	iUndertaker = new(ELeave) CPanicDialogWatcher(*this);
       
    76 	iUndertaker->ConstructL();
       
    77 
       
    78 	StartL(KRealNotifierServerName); // We start with the name of what we're going to rename the real notifier to, this way we ensure that the following code can only be run by one thread at once
       
    79 
       
    80 	RMemoryAccess::LoadDriver();
       
    81 	LeaveIfErr(iMemAccess.Open(), _L("Couldn't open mem access"));
       
    82 
       
    83 	TServerKernelInfoBuf buf;
       
    84 	TInt err = iMemAccess.GetObjectInfo(EServer, _L("!Notifier"), buf);
       
    85 	User::LeaveIfError(err);
       
    86 	TUint8* realServer = buf().iAddressOfKernelObject;
       
    87 	err = iMemAccess.GetObjectInfo(EServer, KRealNotifierServerName, buf);
       
    88 	User::LeaveIfError(err);
       
    89 	TUint8* myServer = buf().iAddressOfKernelObject;
       
    90 
       
    91 	// Should really have some kind of swap operation here...
       
    92 	iMemAccess.InPlaceObjectRename(EServer, realServer, KRealNotifierServerName8);
       
    93 	iMemAccess.InPlaceObjectRename(EServer, myServer, _L8("!Notifier"));
       
    94 	iProxying = ETrue;
       
    95 	}
       
    96 
       
    97 CNotifierProxyServer::~CNotifierProxyServer()
       
    98 	{
       
    99 	delete iRedrawer;
       
   100 	//delete iAnimationTimer;
       
   101 	//delete iBitmap;
       
   102 	//delete iDsa;
       
   103 	delete iScreenDevice;
       
   104 	delete iGc;
       
   105 	iWin.Close();
       
   106 	iWg.Close();
       
   107 	iWs.Close();
       
   108 	delete iPeriodic;
       
   109 	iText.ResetAndDestroy();
       
   110 	delete iUndertaker;
       
   111 
       
   112 	if (iProxying)
       
   113 		{
       
   114 		TServerKernelInfoBuf buf;
       
   115 		TInt err = iMemAccess.GetObjectInfo(EServer, KRealNotifierServerName, buf);
       
   116 		if (!err)
       
   117 			{
       
   118 			TUint8* realServer = buf().iAddressOfKernelObject;
       
   119 			iMemAccess.InPlaceObjectRename(EServer, realServer, _L8("!Notifier"));
       
   120 			// Temporarily both us and the real server will have name !Notifier. When we finish destructing, we'll clean up and the system should be back in the state it was
       
   121 			}
       
   122 		}
       
   123 	iMemAccess.Close();
       
   124 	RMemoryAccess::CloseDriver();
       
   125 	}
       
   126 
       
   127 CSession2* CNotifierProxyServer::NewSessionL(const TVersion& /*aVersion*/, const RMessage2& /*aMessage*/) const
       
   128 	{
       
   129 	CNotifierProxySession* res = new(ELeave) CNotifierProxySession();
       
   130 	CleanupStack::PushL(res);
       
   131 	res->ConstructL();
       
   132 	CleanupStack::Pop(res);
       
   133 	return res;
       
   134 	}
       
   135 
       
   136 void CNotifierProxySession::ConstructL()
       
   137 	{
       
   138 	User::LeaveIfError(iRealNotifier.Connect());
       
   139 	}
       
   140 
       
   141 CNotifierProxyServer& CNotifierProxySession::Server()
       
   142 	{
       
   143 	return *const_cast<CNotifierProxyServer*>(static_cast<const CNotifierProxyServer*>(CSession2::Server()));
       
   144 	}
       
   145 
       
   146 const CNotifierProxyServer& CNotifierProxySession::Server() const
       
   147 	{
       
   148 	return *static_cast<const CNotifierProxyServer*>(CSession2::Server());
       
   149 	}
       
   150 
       
   151 void CNotifierProxySession::ServiceL(const RMessage2 &aMessage)
       
   152 	{
       
   153 	switch (aMessage.Function())
       
   154 		{
       
   155 		case ENotifierInfoPrint:
       
   156 			{
       
   157 			//__DEBUGGER();
       
   158 			RBuf buf;
       
   159 			CleanupClosePushL(buf);
       
   160 			buf.CreateL(aMessage.GetDesLengthL(0));
       
   161 			aMessage.ReadL(0, buf);
       
   162 			RThread client;
       
   163 			TInt err = aMessage.Client(client);
       
   164 			TUint clientId = 0;
       
   165 			if (!err) clientId = client.Id();
       
   166 			client.Close();
       
   167 			Server().InfoPrint(buf, clientId);
       
   168 			CleanupStack::PopAndDestroy(&buf);
       
   169 			aMessage.Complete(KErrNone);
       
   170 			break;
       
   171 			}
       
   172 		case EStartNotifier:
       
   173 			{
       
   174 			TUid notifierUid = TUid::Uid(aMessage.Int0());
       
   175 			RBuf8 buf, responseBuf;
       
   176 			CleanupClosePushL(buf);
       
   177 			buf.CreateL(aMessage.GetDesLengthL(1));
       
   178 			aMessage.ReadL(1, buf);
       
   179 			TInt res = KErrNone;
       
   180 			if (aMessage.Ptr2())
       
   181 				{
       
   182 				CleanupClosePushL(responseBuf);
       
   183 				responseBuf.CreateL(aMessage.GetDesMaxLengthL(2));
       
   184 				res = iRealNotifier.StartNotifier(notifierUid, buf, responseBuf);
       
   185 				if (res == KErrNone || responseBuf.Length())
       
   186 					{
       
   187 					aMessage.WriteL(2, responseBuf);
       
   188 					}
       
   189 				CleanupStack::PopAndDestroy(&responseBuf);
       
   190 				}
       
   191 			else
       
   192 				{
       
   193 				res = iRealNotifier.StartNotifier(notifierUid, buf);
       
   194 				}
       
   195 			CleanupStack::PopAndDestroy(&buf);
       
   196 			aMessage.Complete(res);
       
   197 			break;
       
   198 			}
       
   199 		case EStartNotifierFromSpecifiedDll:
       
   200 		case EStartNotifierFromSpecifiedDllAndGetResponse:
       
   201 			aMessage.Complete(KErrNotSupported); // This is what the docs say - god knows why the client bothers to pass it through
       
   202 			break;
       
   203 		case ECancelNotifier:
       
   204 			{
       
   205 			TUid notifierUid = TUid::Uid(aMessage.Int0());
       
   206 			TInt res = iRealNotifier.CancelNotifier(notifierUid);
       
   207 			aMessage.Complete(res);
       
   208 			break;
       
   209 			}
       
   210 		case EUpdateNotifier:
       
   211 			{
       
   212 			TUid notifierUid = TUid::Uid(aMessage.Int0());
       
   213 			RBuf8 buf, responseBuf;
       
   214 			CleanupClosePushL(buf);
       
   215 			buf.CreateL(aMessage.GetDesLengthL(1));
       
   216 			aMessage.ReadL(1, buf);
       
   217 			CleanupClosePushL(responseBuf);
       
   218 			responseBuf.CreateL(aMessage.GetDesMaxLengthL(2));
       
   219 			TInt res = iRealNotifier.UpdateNotifier(notifierUid, buf, responseBuf);
       
   220 			if (res == KErrNone || responseBuf.Length())
       
   221 				{
       
   222 				aMessage.WriteL(2, responseBuf);
       
   223 				}
       
   224 			CleanupStack::PopAndDestroy(&responseBuf);
       
   225 			CleanupStack::PopAndDestroy(&buf);
       
   226 			aMessage.Complete(res);
       
   227 			break;
       
   228 			}
       
   229 		case EUpdateNotifierAndGetResponse:
       
   230 		case EStartNotifierAndGetResponse:
       
   231 		case ENotifierNotify:
       
   232 			{
       
   233 			CAsyncWaiter* waiter = new(ELeave) CAsyncWaiter(iRealNotifier, aMessage);
       
   234 			waiter->ForwardMessageL();
       
   235 			break;
       
   236 			}
       
   237 		case ENotifierNotifyCancel:
       
   238 			iRealNotifier.NotifyCancel();
       
   239 			aMessage.Complete(KErrNone);
       
   240 			break;
       
   241 		case KShutdownProxy:
       
   242 			CActiveScheduler::Stop();
       
   243 			break;
       
   244 		case KPingProxy:
       
   245 			aMessage.Complete(KErrNone);
       
   246 			break;
       
   247 		default:
       
   248 			__DEBUGGER();
       
   249 			aMessage.Complete(KErrNotSupported);
       
   250 		}
       
   251 	}
       
   252 
       
   253 void CNotifierProxySession::Disconnect(const RMessage2 &aMessage)
       
   254 	{
       
   255 	iRealNotifier.Close();
       
   256 	//TODO Need to wait for any CAsyncWaiters to be completed? If so, do it here and defer the super call until that time
       
   257 	CSession2::Disconnect(aMessage);
       
   258 	}
       
   259 
       
   260 CAsyncWaiter::CAsyncWaiter(RRealNotifier& aRealNotifier, const RMessage2& aMessage)
       
   261 	: CActive(CActive::EPriorityStandard), iRealNotifier(aRealNotifier), iMsg(aMessage)
       
   262 	{
       
   263 	CActiveScheduler::Add(this);
       
   264 	}
       
   265 
       
   266 CAsyncWaiter::~CAsyncWaiter()
       
   267 	{
       
   268 	iBuf.Close();
       
   269 	iWideBuf.Close();
       
   270 	iResponseBuf.Close();
       
   271 	}
       
   272 
       
   273 void CAsyncWaiter::ForwardMessageL()
       
   274 	{
       
   275 	switch (iMsg.Function())
       
   276 		{
       
   277 		case EUpdateNotifierAndGetResponse:
       
   278 			{
       
   279 			TUid notifierUid = TUid::Uid(iMsg.Int0());
       
   280 			iBuf.CreateL(iMsg.GetDesLengthL(1));
       
   281 			iMsg.ReadL(1, iBuf);
       
   282 			iResponseBuf.CreateL(iMsg.GetDesMaxLengthL(2));
       
   283 			iRealNotifier.UpdateNotifierAndGetResponse(iStatus, notifierUid, iBuf, iResponseBuf);
       
   284 			SetActive();
       
   285 			break;
       
   286 			}
       
   287 		case EStartNotifierAndGetResponse:
       
   288 			{
       
   289 			TUid notifierUid = TUid::Uid(iMsg.Int0());
       
   290 			iBuf.CreateL(iMsg.GetDesLengthL(1));
       
   291 			iMsg.ReadL(1, iBuf);
       
   292 			iResponseBuf.CreateL(iMsg.GetDesMaxLengthL(2));
       
   293 			iRealNotifier.StartNotifierAndGetResponse(iStatus, notifierUid, iBuf, iResponseBuf);
       
   294 			SetActive();
       
   295 			break;
       
   296 			}
       
   297 		case ENotifierNotify:
       
   298 			{
       
   299 			// iWideBuf is the combined buffer
       
   300 			iWideBuf.CreateL(iMsg.GetDesLengthL(1));
       
   301 			iMsg.ReadL(1, iWideBuf);
       
   302 			// iResponseBuf is the button val
       
   303 			iResponseBuf.CreateMaxL(sizeof(TInt));
       
   304 			TInt comboLineLen = iMsg.Int2();
       
   305 			TInt comboButLen = iMsg.Int3();
       
   306 			const TUint16* ptr = iWideBuf.Ptr();
       
   307 			iTempPtrs[0].Set(ptr, comboLineLen >> 16);
       
   308 			ptr += iTempPtrs[0].Length();
       
   309 			iTempPtrs[1].Set(ptr, comboLineLen & 0xFFFF);
       
   310 			ptr += iTempPtrs[1].Length();
       
   311 			iTempPtrs[2].Set(ptr, comboButLen >> 16);
       
   312 			ptr += iTempPtrs[2].Length();
       
   313 			iTempPtrs[3].Set(ptr, comboButLen & 0xFFFF);
       
   314 			
       
   315 			iRealNotifier.Notify(iTempPtrs[0], iTempPtrs[1], iTempPtrs[2], iTempPtrs[3], *(TInt*)iResponseBuf.Ptr(), iStatus);
       
   316 			SetActive();
       
   317 			break;
       
   318 			}
       
   319 		default:
       
   320 			__DEBUGGER();
       
   321 		}
       
   322 	}
       
   323 
       
   324 void CAsyncWaiter::RunL()
       
   325 	{
       
   326 	TInt res = iStatus.Int();
       
   327 	switch (iMsg.Function())
       
   328 		{
       
   329 		case EUpdateNotifierAndGetResponse:
       
   330 		case EStartNotifierAndGetResponse:
       
   331 			if (res == KErrNone || iResponseBuf.Length())
       
   332 				{
       
   333 				TInt err = iMsg.Write(2, iResponseBuf);
       
   334 				if (err)
       
   335 					{
       
   336 					res = err;
       
   337 					}
       
   338 				}
       
   339 			iMsg.Complete(res);
       
   340 			break;
       
   341 		case ENotifierNotify:
       
   342 			{
       
   343 			TInt err = iMsg.Write(0, iResponseBuf);
       
   344 			if (err) res = err;
       
   345 			iMsg.Complete(res);
       
   346 			break;
       
   347 			}
       
   348 		default:
       
   349 			__DEBUGGER();
       
   350 			User::Leave(KErrNotSupported);
       
   351 		}
       
   352 	delete this; // Our work here is done
       
   353 	}
       
   354 
       
   355 void CAsyncWaiter::DoCancel()
       
   356 	{
       
   357 	// We never call Cancel on our waiters
       
   358 	}
       
   359 
       
   360 void MainL()
       
   361 	{
       
   362 	CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
       
   363 	CleanupStack::PushL(scheduler);
       
   364 	CActiveScheduler::Install(scheduler);
       
   365 	CNotifierProxyServer* server = new(ELeave) CNotifierProxyServer;
       
   366 	CleanupStack::PushL(server);
       
   367 	server->ConstructL();
       
   368 	CActiveScheduler::Start();
       
   369 	CleanupStack::PopAndDestroy(2, scheduler); // server, scheduler
       
   370 	}
       
   371 
       
   372 EXPORT_C TInt StartNotifierProxyThreadFunction(TAny*)
       
   373 	{
       
   374 	TInt err = KErrNoMemory;
       
   375 	CTrapCleanup* cleanup = CTrapCleanup::New();
       
   376 	if (cleanup)
       
   377 		{
       
   378 		TRAP(err, MainL());
       
   379 		delete cleanup;
       
   380 		}
       
   381 	return err;
       
   382 	}
       
   383 
       
   384 class RDebugNotifier : public RNotifier
       
   385 	{
       
   386 public:
       
   387 	TInt ShutdownProxy()
       
   388 		{
       
   389 		return SendReceive(KShutdownProxy, TIpcArgs());
       
   390 		}
       
   391 	TInt PingProxy()
       
   392 		{
       
   393 		return SendReceive(KPingProxy, TIpcArgs());
       
   394 		}
       
   395 	};
       
   396 
       
   397 EXPORT_C TInt ShutdownProxyNotifier()
       
   398 	{
       
   399 	RDebugNotifier notifier;
       
   400 	TInt err = notifier.Connect();
       
   401 	if (err == KErrNotFound)
       
   402 		{
       
   403 		// Oh dear, !Notifier isn't running. Meaning we renamed it then crashed, probably. Try renaming the real one
       
   404 		RMemoryAccess::LoadDriver();
       
   405 		RMemoryAccess mem;
       
   406 		err = mem.Open();
       
   407 		if (err) return err;
       
   408 		TServerKernelInfoBuf buf;
       
   409 		TInt err = mem.GetObjectInfo(EServer, KRealNotifierServerName, buf);
       
   410 		if (!err)
       
   411 			{
       
   412 			TUint8* realServer = buf().iAddressOfKernelObject;
       
   413 			mem.InPlaceObjectRename(EServer, realServer, _L8("!Notifier"));
       
   414 			}
       
   415 		mem.Close();
       
   416 		return err;
       
   417 		}
       
   418 
       
   419 	err = notifier.ShutdownProxy();
       
   420 	if (err == KErrServerTerminated) err = KErrNone; // It's expected to get KErrServerTerminated, because we deliberately don't complete the message. This way the client is more likely to get the completion once the server has actually gone, and not slightly before
       
   421 	notifier.Close();
       
   422 
       
   423 	return err;
       
   424 	}
       
   425 
       
   426 EXPORT_C TBool NotifierProxyIsRunning()
       
   427 	{
       
   428 	RDebugNotifier notifier;
       
   429 	TInt err = notifier.Connect();
       
   430 	if (err) return EFalse; // Not even original notifier is running?!
       
   431 	err = notifier.PingProxy();
       
   432 	notifier.Close();
       
   433 	return err == KErrNone; // The real proxy will return KErrNotSupported in this scenario
       
   434 	}
       
   435 
       
   436 
       
   437 void CNotifierProxyServer::SetupWindowL()
       
   438 	{
       
   439 	//__DEBUGGER();
       
   440 	LeaveIfErr(iWs.Connect(), _L("Couldn't connect to windowserver"));
       
   441 	//iWs.SetAutoFlush(ETrue);
       
   442 	iRedrawer = new(ELeave) CRedrawer(*this);
       
   443 	iRedrawer->Go();
       
   444 
       
   445 	iScreenDevice = new(ELeave) CWsScreenDevice(iWs);
       
   446 	LeaveIfErr(iScreenDevice->Construct(), _L("Couldn't construct screen device")); // User default screen number
       
   447 	LeaveIfErr(iScreenDevice->CreateContext(iGc), _L("Couldn't create gc"));
       
   448 	iWg = RWindowGroup(iWs);
       
   449 	LeaveIfErr(iWg.Construct(2, EFalse), _L("Couldn't construct windowgroup"));
       
   450 	iWin = RWindow(iWs);
       
   451 	LeaveIfErr(iWin.Construct(iWg, (TUint32)this), _L("Couldn't construct window"));
       
   452 
       
   453 	iWin.SetBackgroundColor(KRgbBlack);
       
   454 	iWg.SetOrdinalPosition(0, 1000); // 1000 is ECoeWinPriorityAlwaysAtFront, but I don't want the dependancy on a cone header
       
   455 	TRect rect(TPoint(), TSize(iScreenDevice->SizeInPixels().iWidth, 50));
       
   456 	iWin.SetExtent(rect.iTl, rect.Size());
       
   457 	iWin.SetVisible(EFalse);
       
   458 	iWin.Activate();
       
   459 	iWs.Flush();
       
   460 	
       
   461 	//iBitmap = new(ELeave) CFbsBitmap;
       
   462 	//LeaveIfErr(iBitmap->Create(iScreenDevice->SizeInPixels(), EColor16MU), _L("Couldn't create bitmap"));
       
   463 	//iDsa = CDirectScreenAccess::NewL(iWs, *iScreenDevice, iWin, *this);
       
   464 	}
       
   465 
       
   466 void CNotifierProxyServer::DoWservInitiatedRedraw(const TRect& /*aRect*/)
       
   467 	{
       
   468 	//__DEBUGGER();
       
   469 	// This code based on CCoeControl::HandleRedrawEvent
       
   470 	//iWin.BeginRedraw(aRect);
       
   471 	iWin.BeginRedraw(TRect(TPoint(), iWin.Size()));
       
   472 	iGc->Activate(iWin);
       
   473 
       
   474 	iGc->UseFont(iFont);
       
   475 	iGc->SetPenColor(KRgbGreen);
       
   476 	iGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
       
   477 	iGc->SetBrushColor(KRgbBlack);
       
   478 	for (TInt i = 0; i < iText.Count(); i++)
       
   479 		{
       
   480 		TPoint drawPoint(0, iFont->FontMaxAscent() + i * iFont->FontLineGap());
       
   481 		if (drawPoint.iY > iWin.Size().iHeight)
       
   482 			{
       
   483 			// We've more to draw than we have room. Bail.
       
   484 			break;
       
   485 			}
       
   486 		//iGc->DrawText(iText[i]->iText, drawPoint);
       
   487 		iGc->DrawText(iText[i]->iText, BoxForLine(i), iFont->FontMaxAscent());
       
   488 		}
       
   489 	iGc->DiscardFont();
       
   490 	iGc->Deactivate();
       
   491 	iWin.EndRedraw();
       
   492 	}
       
   493 
       
   494 TRect CNotifierProxyServer::BoxForLine(TInt aLineIndex)
       
   495 	{
       
   496 	TRect textBox = TRect(0, aLineIndex * iFont->FontLineGap(), iWin.Size().iWidth, (aLineIndex+1) * iFont->FontLineGap());
       
   497 	return textBox;
       
   498 	}
       
   499 
       
   500 RWsSession& CNotifierProxyServer::WsSession()
       
   501 	{
       
   502 	return iWs;
       
   503 	}
       
   504 
       
   505 void CNotifierProxyServer::InfoPrint(const TDesC& aText, TUint aClientId)
       
   506 	{
       
   507 	TPtrC text(aText);
       
   508 	TInt newline = aText.Locate('\n');
       
   509 	if (newline != KErrNotFound)
       
   510 		{
       
   511 		// UIQ supported 2-line infoprints so some code puts a newline in - if so split it up and treat as two calls
       
   512 		TPtrC first = aText.Left(newline);
       
   513 		TPtrC second = aText.Mid(newline+1);
       
   514 		InfoPrint(first, aClientId);
       
   515 		//InfoPrint(second, aClientId);
       
   516 		text.Set(second); // Drop through at this point - prevents recursing if there are many newlines (also stops more than one newline from being recognised)
       
   517 		}
       
   518 
       
   519 	CLine* line = new CLine(text, aClientId);
       
   520 	if (!line) return; // OOM
       
   521 
       
   522 	// Check if client should be getting frequent flyer miles, if so limit it
       
   523 	for (TInt i = iText.Count() - 1; i >= 0; i--)
       
   524 		{
       
   525 		CLine* line = iText[i];
       
   526 		if (aClientId && aClientId == line->iClientId && text.Left(6) == line->iText.Left(6))
       
   527 			{
       
   528 			iText.Remove(i);
       
   529 			// And restart timer if the one we've just removed was at index zero, ie about to be removed anyway (otherwise timer will remove the new one sooner at the time when the old one was due)
       
   530 			if (i == 0) iPeriodic->Cancel(); // (cancelling it here will cause it to be restarted in DisplayAndStartTimer)
       
   531 			}
       
   532 		}
       
   533 
       
   534 	TInt err = iText.Append(line);
       
   535 	if (err)
       
   536 		{
       
   537 		delete line;
       
   538 		}
       
   539 	else
       
   540 		{
       
   541 		RecalculateWindow();
       
   542 		iWin.Invalidate();
       
   543 		DisplayAndStartTimer();
       
   544 		iWs.Flush();
       
   545 		}
       
   546 	}
       
   547 
       
   548 CRedrawer::CRedrawer(CNotifierProxyServer& aServer) 
       
   549 	: CActive(CActive::EPriorityStandard), iServer(aServer)
       
   550 	{
       
   551 	CActiveScheduler::Add(this);
       
   552 	}
       
   553 
       
   554 void CRedrawer::Go()
       
   555 	{
       
   556 	if (!IsActive())
       
   557 		{
       
   558 		iServer.WsSession().RedrawReady(&iStatus);
       
   559 		SetActive();
       
   560 		}
       
   561 	}
       
   562 
       
   563 void CRedrawer::RunL()
       
   564 	{
       
   565 	TWsRedrawEvent redrawEvent;
       
   566 	iServer.WsSession().GetRedraw(redrawEvent);
       
   567 	TRect rect=redrawEvent.Rect();
       
   568 	
       
   569 	iServer.DoWservInitiatedRedraw(rect);
       
   570 	Go();
       
   571 	iServer.WsSession().Flush();
       
   572 	}
       
   573 
       
   574 void CRedrawer::DoCancel()
       
   575 	{
       
   576 	iServer.WsSession().RedrawReadyCancel();
       
   577 	}
       
   578 
       
   579 CRedrawer::~CRedrawer()
       
   580 	{
       
   581 	Cancel();
       
   582 	}
       
   583 
       
   584 void CNotifierProxyServer::RecalculateWindow()
       
   585 	{
       
   586 	// Grow or shrink the window if needed to display all the text we have
       
   587 	TInt numLines = iText.Count();
       
   588 	
       
   589 	const TInt KMaxWindowHeight = 200;
       
   590 	TInt newHeight = Min(BoxForLine(0).Height() * numLines, KMaxWindowHeight); // Don't exceed our defined max height
       
   591 	TInt currentHeight = iWin.Size().iHeight;
       
   592 	if (newHeight != currentHeight)
       
   593 		{
       
   594 		iWin.SetSize(TSize(iWin.Size().iWidth, newHeight));
       
   595 		}
       
   596 	}
       
   597 
       
   598 TInt CNotifierProxyServer::StaticTick(TAny* aSelf)
       
   599 	{
       
   600 	static_cast<CNotifierProxyServer*>(aSelf)->Tick();
       
   601 	return 0;
       
   602 	}
       
   603 
       
   604 void CNotifierProxyServer::Tick()
       
   605 	{
       
   606 	// Remove 1 line from the top of the infoprint each time the timer fires, if nothing left hide the window
       
   607 	if (iText.Count())
       
   608 		{
       
   609 		iText.Remove(0);
       
   610 		}
       
   611 
       
   612 	if (iText.Count() == 0)
       
   613 		{
       
   614 		iWin.SetVisible(EFalse);
       
   615 		iPeriodic->Cancel(); // No need for further ticks
       
   616 		}
       
   617 	else
       
   618 		{
       
   619 		RecalculateWindow();
       
   620 		iWin.Invalidate();
       
   621 		}
       
   622 	iWs.Flush();
       
   623 	}
       
   624 	
       
   625 void CNotifierProxyServer::DisplayAndStartTimer()
       
   626 	{
       
   627 	if (iText.Count())
       
   628 		{
       
   629 		iWin.SetVisible(ETrue);
       
   630 		if (!iPeriodic->IsActive())
       
   631 			{
       
   632 			iPeriodic->Start(KInfoPrintTime, KInfoPrintTime, TCallBack(&StaticTick, this));
       
   633 			}
       
   634 		}
       
   635 	}
       
   636 
       
   637 CLine::CLine(const TDesC& aText, TUint aClientId)
       
   638 	: iText(aText), iClientId(aClientId)
       
   639 	{
       
   640 	//iTimeOfPrint.UniversalTime();
       
   641 	}
       
   642 
       
   643 CPanicDialogWatcher::CPanicDialogWatcher(CNotifierProxyServer& aServer)
       
   644 	: CActive(CActive::EPriorityStandard), iServer(aServer)
       
   645 	{
       
   646 	CActiveScheduler::Add(this);
       
   647 	}
       
   648 
       
   649 void CPanicDialogWatcher::ConstructL()
       
   650 	{
       
   651 	User::LeaveIfError(iUndertaker.Create());
       
   652 	iUndertaker.Logon(iStatus, iThreadHandle);
       
   653 	SetActive();
       
   654 	}
       
   655 
       
   656 CPanicDialogWatcher::~CPanicDialogWatcher()
       
   657 	{
       
   658 	Cancel();
       
   659 	iUndertaker.Close();
       
   660 	}
       
   661 
       
   662 void CPanicDialogWatcher::RunL()
       
   663 	{
       
   664 	TInt threadHandle = iThreadHandle;
       
   665 	iUndertaker.Logon(iStatus, iThreadHandle);
       
   666 	SetActive();
       
   667 
       
   668 	RThread thread;
       
   669 	thread.SetHandle(threadHandle);
       
   670 	iTempName = thread.FullName();
       
   671 	PrettyName(EListThread, iTempName);
       
   672 	if (thread.ExitType() == EExitPanic)
       
   673 		{
       
   674 		TExitCategoryName cat = thread.ExitCategory();
       
   675 		TBuf<256> buf;
       
   676 		buf.Format(_L("Panic: %S %d from %S"), &cat, thread.ExitReason(), &iTempName);
       
   677 		iServer.InfoPrint(buf, 0);
       
   678 		}
       
   679 	else if (thread.ExitType() == EExitKill)
       
   680 		{
       
   681 		TBuf<256> buf;
       
   682 		buf.Format(_L("Kill %d: Tid %d %S"), thread.ExitReason(), TUint(thread.Id()), &iTempName);
       
   683 		iServer.InfoPrint(buf, 0);
       
   684 		}
       
   685 	else if (thread.ExitType() == EExitTerminate)
       
   686 		{
       
   687 		TBuf<256> buf;
       
   688 		buf.Format(_L("Terminate %d: Tid %d %S"), thread.ExitReason(), TUint(thread.Id()), &iTempName);
       
   689 		iServer.InfoPrint(buf, 0);
       
   690 		}
       
   691 	thread.Close();
       
   692 	}
       
   693 
       
   694 void CPanicDialogWatcher::DoCancel()
       
   695 	{
       
   696 	iUndertaker.LogonCancel();
       
   697 	}
       
   698 
       
   699 #endif