Skip to content

Commit 4380758

Browse files
committed
helloforeignwindow: Initialization of window moved to invokable function, since it is not possible to join the window group in the constructor, and waiting for termination of thread to shut down gracefully.
1 parent e55cbe9 commit 4380758

File tree

2 files changed

+167
-110
lines changed

2 files changed

+167
-110
lines changed

helloforeignwindow/src/helloforeignwindowapp.cpp

Lines changed: 138 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
/* Copyright (c) 2012 Research In Motion Limited.
2-
*
3-
* Licensed under the Apache License, Version 2.0 (the "License");
4-
* you may not use this file except in compliance with the License.
5-
* You may obtain a copy of the License at
6-
*
7-
* http://www.apache.org/licenses/LICENSE-2.0
8-
*
9-
* Unless required by applicable law or agreed to in writing, software
10-
* distributed under the License is distributed on an "AS IS" BASIS,
11-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12-
* See the License for the specific language governing permissions and
13-
* limitations under the License.
14-
*/
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
1515
#include "helloforeignwindowapp.h"
1616

1717
#include <bb/cascades/AbsoluteLayoutProperties>
@@ -23,6 +23,58 @@
2323

2424
using namespace bb::cascades;
2525

26+
27+
HelloForeignWindowApp::HelloForeignWindowApp()
28+
{
29+
mTvOn = false;
30+
mTvInitialized = false;
31+
32+
// Here we create a QMLDocument and load the main UI QML file.
33+
QmlDocument *qml = QmlDocument::create().load("helloforeignwindow.qml");
34+
35+
if (!qml->hasErrors()) {
36+
37+
// Set a context property for the QML to the application object, so that we
38+
// can call invokable functions in the app from QML.
39+
qml->setContextProperty("foreignWindowApp", this);
40+
41+
// The application Page is created from QML.
42+
mAppPage = qml->createRootNode<Page>();
43+
44+
if (mAppPage) {
45+
46+
Application::setScene(mAppPage);
47+
48+
// Start the thread in which we render to the custom window.
49+
start();
50+
}
51+
}
52+
}
53+
54+
HelloForeignWindowApp::~HelloForeignWindowApp()
55+
{
56+
//Cleanup screen context.
57+
screen_destroy_context(mScreenCtx);
58+
59+
// Stop the thread.
60+
terminate();
61+
wait();
62+
}
63+
64+
void HelloForeignWindowApp::run()
65+
{
66+
while (true) {
67+
68+
// A short sleep in between renders.
69+
usleep(25000);
70+
71+
if (mTvOn && mTvInitialized) {
72+
// If the TV is on render noise.
73+
doNoise(true);
74+
}
75+
}
76+
}
77+
2678
void HelloForeignWindowApp::doNoise(bool noise)
2779
{
2880
unsigned char *ptr = NULL;
@@ -57,16 +109,7 @@ void HelloForeignWindowApp::doNoise(bool noise)
57109
screen_post_window(mScreenWindow, mScreenBuf[0], 1, mRect, 0);
58110
}
59111

60-
void HelloForeignWindowApp::onWindowAttached(unsigned long handle, const QString &group,
61-
const QString &id)
62-
{
63-
// Application can verify that the attached window is the one expected.
64-
qDebug() << "handle: " << handle;
65-
qDebug() << "group: " << group;
66-
qDebug() << "id: " << id;
67-
}
68-
69-
void HelloForeignWindowApp::createForeignWindow(const QString &group, const QString id, int x,
112+
bool HelloForeignWindowApp::createForeignWindow(const QString &group, const QString id, int x,
70113
int y, int width, int height)
71114
{
72115
QByteArray groupArr = group.toAscii();
@@ -78,130 +121,126 @@ void HelloForeignWindowApp::createForeignWindow(const QString &group, const QStr
78121
mRect[2] = width;
79122
mRect[3] = height;
80123

81-
//You must create a context before you create a window.
82-
screen_create_context(&mScreenCtx, SCREEN_APPLICATION_CONTEXT);
124+
// You must create a context before you create a window.
125+
if (screen_create_context(&mScreenCtx, SCREEN_APPLICATION_CONTEXT) != 0) {
126+
return false;
127+
}
83128

84129
// Create a child window of the current window group, join the window group and set
85130
// a window id.
86-
screen_create_window_type(&mScreenWindow, mScreenCtx, SCREEN_CHILD_WINDOW);
87-
screen_join_window_group(mScreenWindow, groupArr.constData());
88-
screen_set_window_property_cv(mScreenWindow, SCREEN_PROPERTY_ID_STRING, idArr.length(),
89-
idArr.constData());
131+
if (screen_create_window_type(&mScreenWindow, mScreenCtx, SCREEN_CHILD_WINDOW) != 0) {
132+
return false;
133+
}
134+
if (screen_join_window_group(mScreenWindow, groupArr.constData()) != 0) {
135+
return false;
136+
}
137+
if (screen_set_window_property_cv(mScreenWindow, SCREEN_PROPERTY_ID_STRING, idArr.length(),
138+
idArr.constData()) != 0) {
139+
return false;
140+
}
90141

91142
// In this application we will render to a pixmap buffer and then blit that to
92143
// the window, we set the usage to native (default is read and write but we do not need that here).
93144
int usage = SCREEN_USAGE_NATIVE;
94-
screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_USAGE, &usage);
145+
if (screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_USAGE, &usage) != 0) {
146+
return false;
147+
}
95148

96149
// The window size is specified in QML so we need to set up the buffer size to
97150
// correspond to that, the default size would be the full screen.
98-
screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_BUFFER_SIZE, mRect + 2);
99-
screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_SOURCE_SIZE, mRect + 2);
151+
if (screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_BUFFER_SIZE, mRect + 2) != 0) {
152+
return false;
153+
}
154+
if (screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_SOURCE_SIZE, mRect + 2) != 0) {
155+
return false;
156+
}
100157

101158
// Use negative Z order so that the window appears under the main window.
102159
// This is needed by the ForeignWindow functionality.
103160
int z = -5;
104-
screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_ZORDER, &z);
161+
if (screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_ZORDER, &z) != 0) {
162+
return false;
163+
}
105164

106165
// Set the window position on screen.
107166
int pos[2] = { x, y };
108-
screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_POSITION, pos);
167+
if (screen_set_window_property_iv(mScreenWindow, SCREEN_PROPERTY_POSITION, pos) != 0) {
168+
return false;
169+
}
109170

110171
// Finally create the window buffers, in this application we will only use one buffer.
111-
screen_create_window_buffers(mScreenWindow, 1);
172+
if (screen_create_window_buffers(mScreenWindow, 1) != 0) {
173+
return false;
174+
}
112175

113176
// In this sample we use a pixmap to render to, a pixmap. This allows us to have
114177
// full control of exactly which pixels we choose to push to the screen.
115178
screen_pixmap_t screen_pix;
116-
screen_create_pixmap(&screen_pix, mScreenCtx);
179+
if (screen_create_pixmap(&screen_pix, mScreenCtx) != 0) {
180+
return false;
181+
}
117182

118183
// A combination of write and native usage is necessary to blit the pixmap to screen.
119184
usage = SCREEN_USAGE_WRITE | SCREEN_USAGE_NATIVE;
120-
screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_USAGE, &usage);
185+
if(screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_USAGE, &usage) != 0) {
186+
return false;
187+
}
121188

122189
// Set the width and height of the buffer to correspond to the one we specified in QML.
123190
mSize[0] = width;
124191
mSize[1] = height;
125-
screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_BUFFER_SIZE, mSize);
192+
if (screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_BUFFER_SIZE, mSize) != 0) {
193+
return false;
194+
}
126195

127196
// Create the pixmap buffer and get a reference to it for rendering in the doNoise function.
128-
screen_create_pixmap_buffer(screen_pix);
129-
screen_get_pixmap_property_pv(screen_pix, SCREEN_PROPERTY_RENDER_BUFFERS,
130-
(void **) &mScreenPixelBuffer);
197+
if (screen_create_pixmap_buffer(screen_pix) != 0) {
198+
return false;
199+
}
200+
if (screen_get_pixmap_property_pv(screen_pix, SCREEN_PROPERTY_RENDER_BUFFERS,
201+
(void **) &mScreenPixelBuffer) != 0) {
202+
return false;
203+
}
131204

132205
// We get the stride (the number of bytes between pixels on different rows), its used
133206
// later on when we perform the rendering to the pixmap buffer.
134-
screen_get_buffer_property_iv(mScreenPixelBuffer, SCREEN_PROPERTY_STRIDE, &mStride);
135-
}
136-
137-
void HelloForeignWindowApp::run()
138-
{
139-
while (true) {
140-
141-
// A short sleep in between renders.
142-
usleep(25000);
143-
144-
if (mTvOn) {
145-
// If the TV is on render noise.
146-
doNoise(true);
147-
}
207+
if (screen_get_buffer_property_iv(mScreenPixelBuffer, SCREEN_PROPERTY_STRIDE, &mStride) != 0) {
208+
return false;
148209
}
149-
}
150-
151-
HelloForeignWindowApp::HelloForeignWindowApp()
152-
{
153-
154-
// Here we create a QMLDocument and load the main UI QML file.
155-
QmlDocument *qml = QmlDocument::create().load("helloforeignwindow.qml");
156-
157-
if (!qml->hasErrors()) {
158-
159-
// Set a context property for the QML to the application object, so that we
160-
// can call invokable functions in the app from QML.
161-
qml->setContextProperty("foreignWindowApp", this);
162-
163-
// The application Page is created from QML.
164-
Page *appPage = qml->createRootNode<Page>();
165-
166-
if (appPage) {
167-
mTvOn = false;
168-
169-
// Get the foreign window Control specified in QML and attach to the window attached signal.
170-
ForeignWindow *foreignWindow = appPage->findChild<ForeignWindow*>("myForeignWindow");
171-
QObject::connect(foreignWindow, SIGNAL(windowAttached(unsigned long,QString,QString)),
172-
this, SLOT(onWindowAttached(unsigned long, QString, QString)));
173-
174-
AbsoluteLayoutProperties *layoutProperties =
175-
dynamic_cast<AbsoluteLayoutProperties*>(foreignWindow->layoutProperties());
176210

177-
// Set up the foreign window at the position specified by its LayoutProperties and the dimensions
178-
// given by its preferred width and height.
179-
createForeignWindow(ForeignWindow::mainWindowGroupId(), "HelloForeignWindowAppID",
180-
(int) layoutProperties->positionX(), (int) layoutProperties->positionY(),
181-
(int) foreignWindow->preferredWidth(), (int) foreignWindow->preferredHeight());
211+
return true;
212+
}
182213

183-
Application::setScene(appPage);
214+
void HelloForeignWindowApp::initForeignWindow() {
184215

185-
// Start the thread in which we render to the custom window.
186-
start();
187-
}
188-
}
216+
// Get the foreign window Control specified in QML and attach to the window attached signal.
217+
ForeignWindow *foreignWindow = mAppPage->findChild<ForeignWindow*>("myForeignWindow");
189218

190-
}
219+
AbsoluteLayoutProperties *layoutProperties =
220+
dynamic_cast<AbsoluteLayoutProperties*>(foreignWindow->layoutProperties());
191221

192-
HelloForeignWindowApp::~HelloForeignWindowApp()
193-
{
194-
//Cleanup screen context.
195-
screen_destroy_context(mScreenCtx);
222+
// Set up the foreign window at the position specified by its LayoutProperties and the dimensions
223+
// given by its preferred width and height.
224+
if(createForeignWindow(ForeignWindow::mainWindowGroupId(), "HelloForeignWindowAppID",
225+
(int) layoutProperties->positionX(), (int) layoutProperties->positionY(),
226+
(int) foreignWindow->preferredWidth(), (int) foreignWindow->preferredHeight()) == false) {
227+
qWarning() << "The ForeginWindow was not properly initialized";
228+
}
196229

197-
// Stop the thread.
198-
terminate();
230+
// Initialization of the window has been performed.
231+
mTvInitialized = true;
199232
}
200233

201234
void HelloForeignWindowApp::tvPower(bool on)
202235
{
203236
mTvOn = on;
204237

238+
// Initialize the ForeignWindow if not already done, we can not do this when the application
239+
// starts since it is not possible to join the application window group at that stage.
240+
if (mTvInitialized == false) {
241+
initForeignWindow();
242+
}
243+
205244
// If the TV is off, render one frame of a black screen (noise false).
206245
if (mTvOn == false) {
207246
doNoise(false);

helloforeignwindow/src/helloforeignwindowapp.h

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@
1919
#include <screen/screen.h>
2020
#include <QThread>
2121

22+
using namespace bb::cascades;
23+
24+
using namespace bb::cascades;
25+
26+
namespace bb
27+
{
28+
namespace cascades
29+
{
30+
class Page;
31+
}
32+
}
33+
2234
/**
2335
* HelloForeignWindowApp
2436
*
@@ -30,15 +42,6 @@
3042
class HelloForeignWindowApp: public QThread
3143
{
3244
Q_OBJECT
33-
public slots:
34-
/**
35-
* Slot function that is called when a window is attached to any of cascade's windows groups.
36-
*
37-
* @param windowHandle a window handle of the child window which was attached, it can be cast to screen_window_t type.
38-
* @param windowGroupId a string representing the group id which this window has joined (typically but not necessarily matches the main window group).
39-
* @param windowId a string representing the id of the window if the window had it set; QString::null otherwise.
40-
*/
41-
void onWindowAttached(unsigned long handle, const QString &group, const QString &id);
4245

4346
public:
4447
HelloForeignWindowApp();
@@ -60,11 +63,20 @@ public slots:
6063
* @param x window position in x direction
6164
* @param y window position in y direction
6265
* @param width window width
63-
* @param height window heigth
66+
* @param height window height
67+
*
68+
* @return true if creation was successful otherwise false.
6469
*/
65-
void createForeignWindow(const QString &group, const QString id, int x, int y, int width,
70+
bool createForeignWindow(const QString &group, const QString id, int x, int y, int width,
6671
int height);
6772

73+
/**
74+
* This function retrieves the size and position of the ForeignWIndow from QML and
75+
* then create the window that should be rendered in it via createForeignWindow.
76+
*
77+
*/
78+
void initForeignWindow();
79+
6880
/**
6981
* QThread run function, we run the custom window rendering in a separate thread to avoid lag
7082
* in the rest of the Cascades UI.
@@ -81,6 +93,9 @@ public slots:
8193
// Boolean that controls if the TV power is on or off (show noise or not).
8294
bool mTvOn;
8395

96+
// Boolean that is true if the tv window has been initialized.
97+
bool mTvInitialized;
98+
8499
// Screen context handle.
85100
screen_context_t mScreenCtx;
86101

@@ -101,6 +116,9 @@ public slots:
101116

102117
// Pixel buffer stride.
103118
int mStride;
119+
120+
// The application page.
121+
Page *mAppPage;
104122
};
105123

106124
#endif // ifndef _HELLOFOREIGNWINDOW_H_

0 commit comments

Comments
 (0)