--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/eswt_akn/org.eclipse.ercp.swt.s60/native/src/swtdisplay.cpp Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,614 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nokia Corporation - S60 implementation
+ *******************************************************************************/
+
+
+#include <apgwgnam.h>
+#include <swtlaffacade.h>
+#include <akntitle.h>
+#include "swtdisplay.h"
+#include "eswtwidgetscore.h"
+#include "methodwrappers.h"
+#include "swtevents.h"
+#include "swtkeymapper.h"
+#include "swttimer.h"
+#include "utils.h"
+#include "swtdialogbroker.h"
+#include "swtserver.h"
+#include "swtmidremconobserver.h"
+#include "swtuiutils.h"
+#include "methodcall.h"
+#include "swtfont.h"
+
+// Default name displayed in the tasklist
+_LIT(KAppDisplayName, "eSWT");
+
+#define ASSERT_JAVAUITHREAD() ASSERT( IsCurrentThreadJavaUi() )
+#define ASSERT_NATIVEUITHREAD() ASSERT( IsCurrentThreadNativeUi() )
+
+
+// ======== MEMBER FUNCTIONS ========
+
+
+// Java Ui Thread
+CSwtDisplay* CSwtDisplay::NewL(JNIEnv& aJniEnv, jobject aPeer, TInt aDisplayParameter)
+{
+ jweak globalPeer = aJniEnv.NewWeakGlobalRef(aPeer);
+ if (globalPeer == NULL)
+ User::Leave(KErrNoMemory);
+
+ CSwtDisplay* self = NULL;
+ TRAPD(error, (self=DoNewL(aJniEnv, globalPeer, aDisplayParameter)));
+ if (error)
+ {
+ aJniEnv.DeleteWeakGlobalRef(globalPeer);
+ User::Leave(error);
+ }
+
+ return self;
+}
+
+// Java Ui Thread
+void CSwtDisplay::Dispose(JNIEnv& aJniEnv)
+{
+ iDisposing = ETrue;
+
+ if (iEventQueue)
+ iEventQueue->PrepareForDestruction();
+
+ TMethodWrapper0<CSwtDisplay> uiDestructor(*this, &CSwtDisplay::DestroyInNativeUiThread);
+ ExecuteInNativeUiThread(uiDestructor);
+
+ jweak globalPeer = static_cast<jweak>(iPeer);
+ aJniEnv.DeleteWeakGlobalRef(globalPeer);
+
+ delete iEventQueue;
+ iEventQueue = NULL;
+
+ iJavaUiThread.Close();
+ iClient.Close();
+
+ // No more Window Server events.
+ java::ui::CoreUiAvkonEswt::getInstance().getJavaUiAppUi()->removeChild(this);
+
+ // This will callback in CoreUiAvkonEswtSupportImpl::dispose,
+ // the core ui will dissapear and native ui thread will exit.
+ java::ui::CoreUiAvkonEswt::getInstance().dispose();
+}
+
+// Java Ui Thread
+void CSwtDisplay::RequestRunDialogL(TSwtPeer aPeer, TInt aDialogType,
+ TInt aStyle, const TDesC& aTitle, const TDesC& aText1, const TDesC& aText2,
+ const TInt aInt1, const TInt aInt2, const TInt aInt3)
+{
+ TMethodWrapper0<CSwtDisplay> fp(*this, &CSwtDisplay::DialogAboutToOpen);
+ ExecuteInNativeUiThread(fp);
+ CSwtDialogBroker* dlgBroker(NULL);
+ CallMethodL(dlgBroker, this, &CSwtDisplay::CreateDialogBrokerL);
+ dlgBroker->SetExtraData(aInt1, aInt2, aInt3);
+ CallMethodL(dlgBroker, &CSwtDialogBroker::RequestRunDialogL, aPeer, aDialogType,
+ aStyle, aTitle, aText1, aText2);
+}
+
+// Native Ui Thread
+void CSwtDisplay::OfferWsEventL(const TSwtWsEvent& aEvent, CCoeControl* aDestination /*= NULL*/)
+{
+ ASSERT_NATIVEUITHREAD();
+
+ switch (aEvent)
+ {
+ case SwtWsEventEndKeyPressed:
+ {
+ // At this point the application is already sent to background by Avkon
+ // - Send close event to display ( happening before anything has been disposed )
+ // - Close event can be modified doIt=false
+ // - If doIt==false then we don't do anything
+ // - If doIt==true then we notify the runtime of exit
+ if (!iCloseEventDispatchTimer)
+ {
+ iCloseEventDispatchTimer = CPeriodic::NewL(CActive::EPriorityStandard);
+ }
+ if (!iCloseEventDispatchTimer->IsActive())
+ {
+ iCloseEventDispatched = EFalse;
+ PostCloseEventL(iPeer, iCloseEventDispatched);
+ iCloseEventDispatchTimer->Start(5000000, 0, TCallBack(CloseEventDispatchTimerCallback, this));
+ }
+ }
+ break;
+
+ case SwtWsEventShutdown:
+ {
+ // MIDP's wrapper asks the runtime to exit the process. It is the MIDlet's
+ // responsibilty to call Display.dispose inside destroyApp().
+ // eRCP's wrapper does not exit the process and does not dispose the display.
+ void* env = NULL;
+ void* args = NULL;
+ if (iVM && iVM->AttachCurrentThread(&env, args) >= 0)
+ {
+ JNIEnv* jniEnv = reinterpret_cast<JNIEnv*>(env);
+ TBool failed;
+ CallStaticVoidJavaMethod(failed,
+ jniEnv,
+ "org/eclipse/swt/internal/symbian/ExitNotificationWrapper",
+ "notifyExit",
+ "(I)V",
+ iApplicationUid);
+ iVM->DetachCurrentThread();
+ }
+ }
+ break;
+
+ case SwtWsEventAppFocusGained:
+ case SwtWsEventAppFocusLost:
+ {
+ TBool focused = aEvent == SwtWsEventAppFocusGained;
+
+ // UiUtils intentionally handled separately although it is an app focus observer also.
+ iUiUtils->HandleAppFocusChangeL(focused);
+
+ // Inform other observers.
+ const TInt count = iAppFocusObservers.Count();
+ for (TInt i = 0; i < count; i++)
+ {
+ iAppFocusObservers[i]->HandleAppFocusChangeL(focused);
+ }
+
+ // Inform Java
+ PostForegroundEventL(iPeer, focused);
+ }
+ break;
+
+ case SwtWsEventWindowVisibilityChanged:
+ {
+ if (iMenuArranger)
+ {
+ iMenuArranger->HandleWindowVisibilityChangeL(aDestination);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (aEvent == CSwtLafFacade::GetConstant(CSwtLafFacade::EBrowserFreeRam)
+ || aEvent == CSwtLafFacade::GetConstant(CSwtLafFacade::EBrowserMemoryGood))
+ {
+ iUiUtils->HandleFreeRamEventL(aEvent);
+ }
+}
+
+// Native Ui Thread
+void CSwtDisplay::RemoveDialogBroker(CSwtDialogBroker* aBroker)
+{
+ ASSERT(aBroker);
+ for (TInt i = iDialogBrokers.Count()-1; i > -1; i--)
+ {
+ if (iDialogBrokers[i] == aBroker)
+ {
+ iDialogBrokers.Remove(i);
+ }
+ }
+ delete aBroker;
+ aBroker = NULL;
+}
+
+// From java::ui::CoreAppUiChild
+// Native Ui Thread
+void CSwtDisplay::HandleForegroundEventL(TBool /*aForeground*/)
+{
+}
+
+// From java::ui::CoreAppUiChild
+// Native Ui Thread
+void CSwtDisplay::HandleSwitchOnEventL(CCoeControl* /*aDestination*/)
+{
+}
+
+// From java::ui::CoreAppUiChild
+// Native Ui Thread
+void CSwtDisplay::HandleApplicationSpecificEventL(TInt /*aType*/, const TWsEvent& /*aEvent*/)
+{
+}
+
+// From java::ui::CoreAppUiChild
+// Native Ui Thread
+void CSwtDisplay::HandleCommandL(TInt aCommand)
+{
+ ASSERT_NATIVEUITHREAD();
+
+ // System request to exit the application ( e.g. close from task list or out-of-memory )
+ if (aCommand == EEikCmdExit)
+ {
+ // Exiting is handled in HandleWsEventL. Let's not do anything here
+ // to prevent duplicates.
+ }
+
+ if (aCommand == EAknCmdHelp)
+ {
+ MSwtCommandArranger* commandArranger = CommandArranger();
+ if (commandArranger)
+ {
+ commandArranger->DoHelpOperationL();
+ }
+ }
+}
+
+// From java::ui::CoreAppUiChild
+// Native Ui Thread
+void CSwtDisplay::HandleResourceChangeL(TInt aType)
+{
+ if (iDisposing)
+ {
+ return;
+ }
+
+ TBool colorChange(EFalse);
+ switch (aType)
+ {
+ // KAknsMessageSkinChange and KEikColorResourceChange are always sent in tandem.
+ // ( See AknsAppSkinInstance.cpp ) Unfortunately we have to pass them both events
+ // to the Avkon components as some do not react to them in the same matter.
+ // eSWT components must pass both events to their Avkon contained or inherited
+ // components and try to handle other jobs ( like font update ) only once.
+ case KAknsMessageSkinChange:
+ case KEikColorResourceChange:
+ colorChange = ETrue;
+ // Intentional fall through;
+ case KEikDynamicLayoutVariantSwitch:
+ if (iMenuArranger)
+ {
+ iMenuArranger->HandleResolutionChangeL();
+ }
+ // Intentional fall through;
+ case KEikMessageFontChange:
+ // Update system font
+ {
+ if (iSystemFont)
+ {
+ iSystemFont->RemoveRef();
+ iSystemFont = NULL;
+ }
+ iSystemFont = CSwtFont::NewL(Device(), *AknLayoutUtils::FontFromId(
+ CSwtLafFacade::GetFontId(CSwtLafFacade::EForm2MidpLabelPaneT1Font, 0)));
+ // Send the Settings Event
+ // KAknsMessageSkinChange and KEikColorResourceChange are always sent in tandem.
+ if (aType != KEikColorResourceChange && iEventQueue)
+ {
+ iEventQueue->PushL(new(ELeave) CSwtSettingsEvent(iPeer, colorChange));
+ }
+ }
+ break;
+ // Not really needed to be handled here.
+ case KEikMessageFadeAllWindows:
+ case KEikMessageUnfadeWindows:
+ break;
+ default:
+ ASSERT(ETrue);
+ break;
+ }
+
+ if (iUiUtils)
+ {
+ iUiUtils->HandleResourceChangedL(aType);
+ }
+
+ // Forward HandleResourceChange to observers
+ const TInt observerNb = iResourceChangeObservers.Count();
+ for (TInt observerIndex=0; observerIndex<observerNb; ++observerIndex)
+ {
+ if (iResourceChangeObservers[observerIndex])
+ {
+ iResourceChangeObservers[observerIndex]->OfferResourceChangeL(aType);
+ }
+ }
+}
+
+// From java::ui::CoreAppUiChild
+// Native Ui Thread
+TBool CSwtDisplay::HandleWsEventL(const TWsEvent& aEvent, CCoeControl* aDestination)
+{
+ TSwtWsEvent swtEventType = SwtWsEventUnknown;
+ TInt eventType = aEvent.Type();
+
+ switch (eventType)
+ {
+ case KAknUidValueEndKeyCloseEvent:
+ // Let CSwtDisplay::OfferWsEventL handle end ( red ) key.
+ // CAknAppUi::HandleWsEventL should not handle it.
+ swtEventType = SwtWsEventEndKeyPressed;
+ break;
+
+ case EEventUser:
+ if ((*reinterpret_cast<TApaSystemEvent*>(aEvent.EventData())) == EApaSystemEventShutdown)
+ {
+ // Oom or exit from task-list:
+ // - Send close event to display ( happening before anything has been disposed )
+ // - Close event's doIt is ignored
+ // - After calling the close event listeners then we notify the runtime of exit
+ if (!iCoeEnv->IsSystem())
+ {
+ swtEventType = SwtWsEventShutdown;
+ }
+ }
+ break;
+
+#ifdef RD_SCALABLE_UI_V2
+ // In versions higher than 3.23 different event is sent, when closing
+ // midlet using the C-key.
+ case KAknShutOrHideApp:
+ swtEventType = SwtWsEventShutdown;
+ break;
+#endif //RD_SCALABLE_UI_V2
+
+ case EEventFocusGained:
+ swtEventType = SwtWsEventAppFocusGained;
+ break;
+
+ case EEventFocusLost:
+ swtEventType = SwtWsEventAppFocusLost;
+ break;
+
+ case EEventWindowVisibilityChanged:
+ swtEventType = SwtWsEventWindowVisibilityChanged;
+ break;
+
+ default:
+ break;
+ }
+
+ if (swtEventType != SwtWsEventUnknown)
+ {
+ OfferWsEventL(swtEventType, aDestination);
+ }
+
+ // Returning ETrue here means that CAknAppUi will not handle the event.
+ return (eventType == KAknUidValueEndKeyCloseEvent);
+}
+
+// From MSwtDisplay
+// Any thread
+#ifdef _DEBUG
+TBool CSwtDisplay::IsCurrentThreadNativeUi() const
+{
+ return (RThread().Id() == iNativeUiThread.Id());
+}
+#endif
+
+// From MSwtDisplay
+// Any thread
+TSwtPeer CSwtDisplay::JavaPeer()
+{
+ return iPeer;
+}
+
+// From MSwtDisplay
+// Native UI Thread
+void CSwtDisplay::SetNameInTaskListL(const TDesC* aNewName)
+{
+ // This code seems to have no effect on the task list.
+ CApaWindowGroupName* wgName = java::ui::CoreUiAvkonEswt::getInstance().getWindowGroupName();
+ if (wgName)
+ {
+ if (aNewName)
+ {
+ wgName->SetCaptionL(*aNewName);
+ }
+ else
+ {
+ wgName->SetCaptionL(KAppDisplayName);
+ }
+ // Refresh displayed name in tasklist
+ wgName->SetWindowGroupName(iCoeEnv->RootWin());
+ }
+}
+
+// From MSwtDisplay
+// Native UI Thread
+// For eRCP
+void CSwtDisplay::SetUIDInTaskList(TInt aNewUID)
+{
+ CApaWindowGroupName* wgName = java::ui::CoreUiAvkonEswt::getInstance().getWindowGroupName();
+ if (wgName)
+ {
+ wgName->SetAppUid((TUid::Uid(aNewUID)));
+ // Refresh displayed name in tasklist
+ wgName->SetWindowGroupName(iCoeEnv->RootWin());
+ }
+}
+
+// From MSwtDisplay
+// Native UI Thread
+// For eRCP
+void CSwtDisplay::SetAppVisible(TBool aVisible)
+{
+ CApaWindowGroupName* wgName = java::ui::CoreUiAvkonEswt::getInstance().getWindowGroupName();
+ if (wgName)
+ {
+ wgName->SetHidden(!aVisible);
+ // Refresh displayed name in tasklist
+ wgName->SetWindowGroupName(iCoeEnv->RootWin());
+ }
+}
+
+// From MSwtDisplay
+// Native UI Thread
+void CSwtDisplay::SetUiReady(TBool aFullScreenUi)
+{
+ if (!iUiReady)
+ {
+ iUiReady = ETrue;
+ java::ui::CoreUiAvkonAppUi* appUi = java::ui::CoreUiAvkonEswt::getInstance().getJavaUiAppUi();
+ if (appUi)
+ {
+ if (!appUi->isStartupCancelled())
+ {
+ // Bring app to foreground
+ RWindowGroup& group = iCoeEnv->RootWin();
+ group.SetOrdinalPosition(0);
+ }
+ appUi->stopStartScreen(aFullScreenUi);
+ }
+ }
+}
+
+// From MSwtDisplay
+// Native UI Thread
+TBool CSwtDisplay::IsUiReady() const
+{
+ return iUiReady;
+}
+
+// Java Ui Thread
+CSwtDisplay* CSwtDisplay::DoNewL(JNIEnv& aJniEnv, TSwtPeer aPeer, TInt aApplicationUid)
+{
+ CSwtDisplay* self = new(ELeave) CSwtDisplay(aPeer);
+ CleanupStack::PushL(self);
+ self->iApplicationUid = aApplicationUid;
+ self->ConstructInJavaUiThreadL(aJniEnv);
+ CleanupStack::Pop(self);
+ return self;
+}
+
+// Java Ui Thread
+void CSwtDisplay::ConstructInJavaUiThreadL(JNIEnv& aJniEnv)
+{
+ iDisposing = EFalse;
+
+ // Step 1 : Get CAknAppUi
+ java::ui::CoreUiAvkonEswt& ui = java::ui::CoreUiAvkonEswt::getInstance();
+ ui.ensureInitialized(TUid::Uid(iApplicationUid));
+ User::LeaveIfError(iJavaUiThread.Open(RThread().Id()));
+#ifdef _DEBUG
+ iNativeUiThread = ui.getEswtSupport().thread();
+#endif //_DEBUG
+ ui.getEswtSupport().setDisplay(this);
+
+ // Step 2: Construct display base in java ui thread
+ ASwtDisplayBase::ConstructInJavaUiThreadL();
+
+ // Step 3: Open a session to the function server
+ User::LeaveIfError(iClient.Connect());
+
+ // Step 4: Construct in native ui thread
+ TMethodWrapper0<CSwtDisplay> uiConstructor(*this, &CSwtDisplay::ConstructInNativeUiThreadL);
+ TInt error = ExecuteInNativeUiThread(uiConstructor);
+ if (error) // Cannot use LeaveIfError(), it wouldn't leave on errors >0
+ User::Leave(error);
+
+ // Step 5: Store the Jni
+ User::LeaveIfError(aJniEnv.GetJavaVM(&iVM));
+
+ // Step 6: Set CoreUi child. Ready to receive Window Server events.
+ // CoreUI takes the ownership of the CSwtDisplay object.
+ ui.getJavaUiAppUi()->setEswtChild(this);
+}
+
+// Native Ui Thread
+void CSwtDisplay::DoExecuteInNativeUiThreadL(const MSwtFunctor* aFunctor)
+{
+ (*aFunctor)(); // It doesn't look like it but this may leave
+}
+
+// Native Ui Thread
+TInt CSwtDisplay::CloseEventDispatchTimerCallback(TAny* aThis)
+{
+ CSwtDisplay* self = static_cast< CSwtDisplay* >(aThis);
+ ASSERT(self);
+
+ TRAPD(err, self->HandleCloseEventDispatchTimerCallbackL());
+ return err;
+}
+
+// Native Ui Thread
+CSwtDisplay::~CSwtDisplay()
+{
+ // Cannot have anything here. Use Dispose().
+ // The object will be deleted from CoreUi.
+}
+
+// Native Ui Thread
+void CSwtDisplay::ConstructInNativeUiThreadL()
+{
+ ASwtDisplayBase::ConstructInNativeUiThreadL();
+
+ if (java::ui::CoreUiAvkonEswt::getInstance().getJavaUiAppUi()->isForeground())
+ {
+ iUiUtils->HandleAppFocusChangeL(ETrue);
+ }
+ else
+ {
+ iUiUtils->HandleAppFocusChangeL(EFalse);
+ }
+
+ // iAppFocusObservers empty at this point
+}
+
+// Native Ui Thread
+void CSwtDisplay::DestroyInNativeUiThread()
+{
+ ASSERT_NATIVEUITHREAD();
+
+ ASwtDisplayBase::DestroyInNativeUiThread();
+
+ if (iCloseEventDispatchTimer)
+ {
+ if (iCloseEventDispatchTimer->IsActive())
+ {
+ iCloseEventDispatchTimer->Cancel();
+ }
+ delete iCloseEventDispatchTimer;
+ iCloseEventDispatchTimer = NULL;
+ }
+
+ CSwtDialogBroker* dlgBroker(NULL);
+ for (TInt i = iDialogBrokers.Count() - 1; i > -1; i--)
+ {
+ dlgBroker = iDialogBrokers[ i ];
+ iDialogBrokers.Remove(i);
+ delete dlgBroker;
+ }
+ iDialogBrokers.Close();
+}
+
+// Native Ui Thread
+CSwtDialogBroker* CSwtDisplay::CreateDialogBrokerL()
+{
+ CSwtDialogBroker* dlgBroker = new(ELeave) CSwtDialogBroker(this, CSwtDialogBroker::ENoRequest);
+ iDialogBrokers.Append(dlgBroker);
+ return dlgBroker;
+}
+
+// Native Ui Thread
+void CSwtDisplay::HandleCloseEventDispatchTimerCallbackL()
+{
+ iCloseEventDispatchTimer->Cancel();
+ if (iCloseEventDispatched)
+ {
+ return;
+ }
+
+ // The event did not dispatch in 5 seconds. Destroy the UI.
+ OfferWsEventL(SwtWsEventShutdown);
+}
+
+// Native Ui Thread
+void CSwtDisplay::DialogAboutToOpen()
+{
+ ASSERT_NATIVEUITHREAD();
+ if (!IsUiReady())
+ {
+ SetUiReady(EFalse);
+ }
+}
+
+
+