* #27232: jni: added pjproject checkout as regular git content

We will remove it once the next release of pjsip (with Android support)
comes out and is merged into SFLphone.
diff --git a/jni/pjproject-android/pjsip-apps/src/vidgui/vidgui.cpp b/jni/pjproject-android/pjsip-apps/src/vidgui/vidgui.cpp
new file mode 100644
index 0000000..9e1d540
--- /dev/null
+++ b/jni/pjproject-android/pjsip-apps/src/vidgui/vidgui.cpp
@@ -0,0 +1,735 @@
+/* $Id: vidgui.cpp 4060 2012-04-17 09:55:30Z ming $ */
+/* 
+ * Copyright (C) 2011-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include "vidgui.h"
+#include "vidwin.h"
+
+#if defined(PJ_WIN32)
+#   define SDL_MAIN_HANDLED
+#endif
+
+#include <SDL.h>
+#include <assert.h>
+#include <QMessageBox>
+
+#define LOG_FILE		"vidgui.log"
+#define THIS_FILE		"vidgui.cpp"
+
+///////////////////////////////////////////////////////////////////////////
+//
+// SETTINGS
+//
+
+//
+// These configure SIP registration
+//
+#define USE_REGISTRATION	0
+#define SIP_DOMAIN		"pjsip.org"
+#define SIP_USERNAME		"vidgui"
+#define SIP_PASSWORD		"secret"
+#define SIP_PORT		5080
+#define SIP_TCP			1
+
+//
+// NAT helper settings
+//
+#define USE_ICE			1
+#define USE_STUN		0
+#define STUN_SRV		"stun.pjsip.org"
+
+//
+// Devices settings
+//
+#define DEFAULT_CAP_DEV		PJMEDIA_VID_DEFAULT_CAPTURE_DEV
+//#define DEFAULT_CAP_DEV		1
+#define DEFAULT_REND_DEV	PJMEDIA_VID_DEFAULT_RENDER_DEV
+
+
+//
+// End of Settings
+///////////////////////////////////////////////////////////////////////////
+
+
+MainWin *MainWin::theInstance_;
+
+MainWin::MainWin(QWidget *parent)
+: QWidget(parent), accountId_(-1), currentCall_(-1),
+  preview_on(false), video_(NULL), video_prev_(NULL)
+{
+    theInstance_ = this;
+
+    initLayout();
+    emit signalCallReleased();
+}
+
+MainWin::~MainWin()
+{
+    quit();
+    theInstance_ = NULL;
+}
+
+MainWin *MainWin::instance()
+{
+    return theInstance_;
+}
+
+void MainWin::initLayout()
+{
+    //statusBar_ = new QStatusBar(this);
+
+    /* main layout */
+    QHBoxLayout *hbox_main = new QHBoxLayout;
+    //QVBoxLayout *vbox_left = new QVBoxLayout;
+    vbox_left = new QVBoxLayout;
+    QVBoxLayout *vbox_right = new QVBoxLayout;
+    hbox_main->addLayout(vbox_left);
+    hbox_main->addLayout(vbox_right);
+
+    /* Left pane */
+    QHBoxLayout *hbox_url = new QHBoxLayout;
+    hbox_url->addWidget(new QLabel(tr("Url:")));
+    hbox_url->addWidget(url_=new QLineEdit(tr("sip:")), 1);
+    vbox_left->addLayout(hbox_url);
+
+    /* Right pane */
+    vbox_right->addWidget((localUri_ = new QLabel));
+    vbox_right->addWidget((vidEnabled_ = new QCheckBox(tr("Enable &video"))));
+    vbox_right->addWidget((previewButton_=new QPushButton(tr("Start &Preview"))));
+    vbox_right->addWidget((callButton_=new QPushButton(tr("Call"))));
+    vbox_right->addWidget((hangupButton_=new QPushButton(tr("Hangup"))));
+    vbox_right->addWidget((quitButton_=new QPushButton(tr("Quit"))));
+
+#if PJMEDIA_HAS_VIDEO
+    vidEnabled_->setCheckState(Qt::Checked);
+#else
+    vidEnabled_->setCheckState(Qt::Unchecked);
+    vidEnabled_->setEnabled(false);
+#endif
+
+    /* Outest layout */
+    QVBoxLayout *vbox_outest = new QVBoxLayout;
+    vbox_outest->addLayout(hbox_main);
+    vbox_outest->addWidget((statusBar_ = new QLabel));
+
+    setLayout(vbox_outest);
+
+    connect(previewButton_, SIGNAL(clicked()), this, SLOT(preview()));
+    connect(callButton_, SIGNAL(clicked()), this, SLOT(call()));
+    connect(hangupButton_, SIGNAL(clicked()), this, SLOT(hangup()));
+    connect(quitButton_, SIGNAL(clicked()), this, SLOT(quit()));
+    //connect(this, SIGNAL(close()), this, SLOT(quit()));
+    connect(vidEnabled_, SIGNAL(stateChanged(int)), this, SLOT(onVidEnabledChanged(int)));
+
+    // UI updates must be done in the UI thread!
+    connect(this, SIGNAL(signalNewCall(int, bool)),
+	    this, SLOT(onNewCall(int, bool)));
+    connect(this, SIGNAL(signalCallReleased()),
+	    this, SLOT(onCallReleased()));
+    connect(this, SIGNAL(signalInitVideoWindow()),
+	    this, SLOT(initVideoWindow()));
+    connect(this, SIGNAL(signalShowStatus(const QString&)),
+	    this, SLOT(doShowStatus(const QString&)));
+}
+
+void MainWin::quit()
+{
+    delete video_prev_;
+    video_prev_ = NULL;
+    delete video_;
+    video_ = NULL;
+
+    pjsua_destroy();
+    qApp->quit();
+}
+
+void MainWin::showStatus(const char *msg)
+{
+    PJ_LOG(3,(THIS_FILE, "%s", msg));
+
+    QString msg_ = QString::fromUtf8(msg);
+    emit signalShowStatus(msg_);
+}
+
+void MainWin::doShowStatus(const QString& msg)
+{
+    //statusBar_->showMessage(msg);
+    statusBar_->setText(msg);
+}
+
+void MainWin::showError(const char *title, pj_status_t status)
+{
+    char errmsg[PJ_ERR_MSG_SIZE];
+    char errline[120];
+
+    pj_strerror(status, errmsg, sizeof(errmsg));
+    snprintf(errline, sizeof(errline), "%s error: %s", title, errmsg);
+    showStatus(errline);
+}
+
+void MainWin::onVidEnabledChanged(int state)
+{
+    pjsua_call_setting call_setting;
+
+    if (currentCall_ == -1)
+	return;
+
+    pjsua_call_setting_default(&call_setting);
+    call_setting.vid_cnt = (state == Qt::Checked);
+
+    pjsua_call_reinvite2(currentCall_, &call_setting, NULL);
+}
+
+void MainWin::onNewCall(int cid, bool incoming)
+{
+    pjsua_call_info ci;
+
+    pj_assert(currentCall_ == -1);
+    currentCall_ = cid;
+
+    pjsua_call_get_info(cid, &ci);
+    url_->setText(ci.remote_info.ptr);
+    url_->setEnabled(false);
+    hangupButton_->setEnabled(true);
+
+    if (incoming) {
+	callButton_->setText(tr("Answer"));
+	callButton_->setEnabled(true);
+    } else {
+	callButton_->setEnabled(false);
+    }
+
+    //video_->setText(ci.remote_contact.ptr);
+    //video_->setWindowTitle(ci.remote_contact.ptr);
+}
+
+void MainWin::onCallReleased()
+{
+    url_->setEnabled(true);
+    callButton_->setEnabled(true);
+    callButton_->setText(tr("Call"));
+    hangupButton_->setEnabled(false);
+    currentCall_ = -1;
+
+    delete video_;
+    video_ = NULL;
+}
+
+void MainWin::preview()
+{
+    if (preview_on) {
+	delete video_prev_;
+	video_prev_ = NULL;
+
+	pjsua_vid_preview_stop(DEFAULT_CAP_DEV);
+
+	showStatus("Preview stopped");
+	previewButton_->setText(tr("Start &Preview"));
+    } else {
+	pjsua_vid_win_id wid;
+	pjsua_vid_win_info wi;
+	pjsua_vid_preview_param pre_param;
+	pj_status_t status;
+
+	pjsua_vid_preview_param_default(&pre_param);
+	pre_param.rend_id = DEFAULT_REND_DEV;
+	pre_param.show = PJ_FALSE;
+
+	status = pjsua_vid_preview_start(DEFAULT_CAP_DEV, &pre_param);
+	if (status != PJ_SUCCESS) {
+	    char errmsg[PJ_ERR_MSG_SIZE];
+	    pj_strerror(status, errmsg, sizeof(errmsg));
+	    QMessageBox::critical(0, "Error creating preview", errmsg);
+	    return;
+	}
+	wid = pjsua_vid_preview_get_win(DEFAULT_CAP_DEV);
+	pjsua_vid_win_get_info(wid, &wi);
+
+	video_prev_ = new VidWin(&wi.hwnd);
+        video_prev_->putIntoLayout(vbox_left);
+	//Using this will cause SDL window to display blank
+	//screen sometimes, probably because it's using different
+	//X11 Display
+	//status = pjsua_vid_win_set_show(wid, PJ_TRUE);
+	//This is handled by VidWin now
+	//video_prev_->show_sdl();
+	showStatus("Preview started");
+
+	previewButton_->setText(tr("Stop &Preview"));
+    }
+    preview_on = !preview_on;
+}
+
+
+void MainWin::call()
+{
+    if (callButton_->text() == "Answer") {
+	pjsua_call_setting call_setting;
+
+	pj_assert(currentCall_ != -1);
+
+	pjsua_call_setting_default(&call_setting);
+	call_setting.vid_cnt = (vidEnabled_->checkState()==Qt::Checked);
+
+	pjsua_call_answer2(currentCall_, &call_setting, 200, NULL, NULL);
+	callButton_->setEnabled(false);
+    } else {
+	pj_status_t status;
+	QString dst = url_->text();
+	char uri[256];
+	pjsua_call_setting call_setting;
+
+	pj_ansi_strncpy(uri, dst.toAscii().data(), sizeof(uri));
+	pj_str_t uri2 = pj_str((char*)uri);
+
+	pj_assert(currentCall_ == -1);
+
+	pjsua_call_setting_default(&call_setting);
+	call_setting.vid_cnt = (vidEnabled_->checkState()==Qt::Checked);
+
+	status = pjsua_call_make_call(accountId_, &uri2, &call_setting,
+				      NULL, NULL, &currentCall_);
+	if (status != PJ_SUCCESS) {
+	    showError("make call", status);
+	    return;
+	}
+    }
+}
+
+void MainWin::hangup()
+{
+    pj_assert(currentCall_ != -1);
+    //pjsua_call_hangup(currentCall_, PJSIP_SC_BUSY_HERE, NULL, NULL);
+    pjsua_call_hangup_all();
+    emit signalCallReleased();
+}
+
+
+void MainWin::initVideoWindow()
+{
+    pjsua_call_info ci;
+    unsigned i;
+
+    if (currentCall_ == -1)
+	return;
+
+    delete video_;
+    video_ = NULL;
+
+    pjsua_call_get_info(currentCall_, &ci);
+    for (i = 0; i < ci.media_cnt; ++i) {
+	if ((ci.media[i].type == PJMEDIA_TYPE_VIDEO) &&
+	    (ci.media[i].dir & PJMEDIA_DIR_DECODING))
+	{
+	    pjsua_vid_win_info wi;
+	    pjsua_vid_win_get_info(ci.media[i].stream.vid.win_in, &wi);
+
+	    video_= new VidWin(&wi.hwnd);
+            video_->putIntoLayout(vbox_left);
+
+	    break;
+	}
+    }
+}
+
+void MainWin::on_reg_state(pjsua_acc_id acc_id)
+{
+    pjsua_acc_info info;
+
+    pjsua_acc_get_info(acc_id, &info);
+
+    char reg_status[80];
+    char status[120];
+
+    if (!info.has_registration) {
+	pj_ansi_snprintf(reg_status, sizeof(reg_status), "%.*s",
+			 (int)info.status_text.slen,
+			 info.status_text.ptr);
+
+    } else {
+	pj_ansi_snprintf(reg_status, sizeof(reg_status),
+			 "%d/%.*s (expires=%d)",
+			 info.status,
+			 (int)info.status_text.slen,
+			 info.status_text.ptr,
+			 info.expires);
+
+    }
+
+    snprintf(status, sizeof(status),
+	     "%.*s: %s\n",
+	     (int)info.acc_uri.slen, info.acc_uri.ptr,
+	     reg_status);
+    showStatus(status);
+}
+
+void MainWin::on_call_state(pjsua_call_id call_id, pjsip_event *e)
+{
+    pjsua_call_info ci;
+
+    PJ_UNUSED_ARG(e);
+
+    pjsua_call_get_info(call_id, &ci);
+
+    if (currentCall_ == -1 && ci.state < PJSIP_INV_STATE_DISCONNECTED &&
+	ci.role == PJSIP_ROLE_UAC)
+    {
+	emit signalNewCall(call_id, false);
+    }
+
+    char status[80];
+    if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
+	snprintf(status, sizeof(status), "Call is %s (%s)",
+	         ci.state_text.ptr,
+	         ci.last_status_text.ptr);
+	showStatus(status);
+	emit signalCallReleased();
+    } else {
+	snprintf(status, sizeof(status), "Call is %s", pjsip_inv_state_name(ci.state));
+	showStatus(status);
+    }
+}
+
+void MainWin::on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
+                               pjsip_rx_data *rdata)
+{
+    PJ_UNUSED_ARG(acc_id);
+    PJ_UNUSED_ARG(rdata);
+
+    if (currentCall_ != -1) {
+	pjsua_call_answer(call_id, PJSIP_SC_BUSY_HERE, NULL, NULL);
+	return;
+    }
+
+    emit signalNewCall(call_id, true);
+
+    pjsua_call_info ci;
+    char status[80];
+
+    pjsua_call_get_info(call_id, &ci);
+    snprintf(status, sizeof(status), "Incoming call from %.*s",
+             (int)ci.remote_info.slen, ci.remote_info.ptr);
+    showStatus(status);
+}
+
+void MainWin::on_call_media_state(pjsua_call_id call_id)
+{
+    pjsua_call_info ci;
+
+    pjsua_call_get_info(call_id, &ci);
+
+    for (unsigned i=0; i<ci.media_cnt; ++i) {
+	if (ci.media[i].type == PJMEDIA_TYPE_AUDIO) {
+	    switch (ci.media[i].status) {
+	    case PJSUA_CALL_MEDIA_ACTIVE:
+		pjsua_conf_connect(ci.media[i].stream.aud.conf_slot, 0);
+		pjsua_conf_connect(0, ci.media[i].stream.aud.conf_slot);
+		break;
+	    default:
+		break;
+	    }
+	} else if (ci.media[i].type == PJMEDIA_TYPE_VIDEO) {
+	    emit signalInitVideoWindow();
+	}
+    }
+}
+
+//
+// pjsua callbacks
+//
+static void on_reg_state(pjsua_acc_id acc_id)
+{
+    MainWin::instance()->on_reg_state(acc_id);
+}
+
+static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
+{
+    MainWin::instance()->on_call_state(call_id, e);
+}
+
+static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
+                             pjsip_rx_data *rdata)
+{
+    MainWin::instance()->on_incoming_call(acc_id, call_id, rdata);
+}
+
+static void on_call_media_state(pjsua_call_id call_id)
+{
+    MainWin::instance()->on_call_media_state(call_id);
+}
+
+//
+// initStack()
+//
+bool MainWin::initStack()
+{
+    pj_status_t status;
+
+    //showStatus("Creating stack..");
+    status = pjsua_create();
+    if (status != PJ_SUCCESS) {
+	showError("pjsua_create", status);
+	return false;
+    }
+
+    showStatus("Initializing stack..");
+
+    pjsua_config ua_cfg;
+    pjsua_config_default(&ua_cfg);
+    pjsua_callback ua_cb;
+    pj_bzero(&ua_cb, sizeof(ua_cb));
+    ua_cfg.cb.on_reg_state = &::on_reg_state;
+    ua_cfg.cb.on_call_state = &::on_call_state;
+    ua_cfg.cb.on_incoming_call = &::on_incoming_call;
+    ua_cfg.cb.on_call_media_state = &::on_call_media_state;
+#if USE_STUN
+    ua_cfg.stun_srv_cnt = 1;
+    ua_cfg.stun_srv[0] = pj_str((char*)STUN_SRV);
+#endif
+
+    pjsua_logging_config log_cfg;
+    pjsua_logging_config_default(&log_cfg);
+    log_cfg.log_filename = pj_str((char*)LOG_FILE);
+
+    pjsua_media_config med_cfg;
+    pjsua_media_config_default(&med_cfg);
+    med_cfg.enable_ice = USE_ICE;
+
+    status = pjsua_init(&ua_cfg, &log_cfg, &med_cfg);
+    if (status != PJ_SUCCESS) {
+	showError("pjsua_init", status);
+	goto on_error;
+    }
+
+    //
+    // Create UDP and TCP transports
+    //
+    pjsua_transport_config udp_cfg;
+    pjsua_transport_id udp_id;
+    pjsua_transport_config_default(&udp_cfg);
+    udp_cfg.port = SIP_PORT;
+
+    status = pjsua_transport_create(PJSIP_TRANSPORT_UDP,
+                                    &udp_cfg, &udp_id);
+    if (status != PJ_SUCCESS) {
+	showError("UDP transport creation", status);
+	goto on_error;
+    }
+
+    pjsua_transport_info udp_info;
+    status = pjsua_transport_get_info(udp_id, &udp_info);
+    if (status != PJ_SUCCESS) {
+	showError("UDP transport info", status);
+	goto on_error;
+    }
+
+#if SIP_TCP
+    pjsua_transport_config tcp_cfg;
+    pjsua_transport_config_default(&tcp_cfg);
+    tcp_cfg.port = 0;
+
+    status = pjsua_transport_create(PJSIP_TRANSPORT_TCP,
+                                    &tcp_cfg, NULL);
+    if (status != PJ_SUCCESS) {
+	showError("TCP transport creation", status);
+	goto on_error;
+    }
+#endif
+
+    //
+    // Create account
+    //
+    pjsua_acc_config acc_cfg;
+    pjsua_acc_config_default(&acc_cfg);
+#if USE_REGISTRATION
+    acc_cfg.id = pj_str( (char*)"<sip:" SIP_USERNAME "@" SIP_DOMAIN ">");
+    acc_cfg.reg_uri = pj_str((char*) ("sip:" SIP_DOMAIN));
+    acc_cfg.cred_count = 1;
+    acc_cfg.cred_info[0].realm = pj_str((char*)"*");
+    acc_cfg.cred_info[0].scheme = pj_str((char*)"digest");
+    acc_cfg.cred_info[0].username = pj_str((char*)SIP_USERNAME);
+    acc_cfg.cred_info[0].data = pj_str((char*)SIP_PASSWORD);
+
+# if SIP_TCP
+    acc_cfg.proxy[acc_cfg.proxy_cnt++] = pj_str((char*) "<sip:" SIP_DOMAIN ";transport=tcp>");
+# endif
+
+#else
+    char sip_id[80];
+    snprintf(sip_id, sizeof(sip_id),
+	     "sip:%s@%.*s:%u", SIP_USERNAME,
+	     (int)udp_info.local_name.host.slen,
+	     udp_info.local_name.host.ptr,
+	     udp_info.local_name.port);
+    acc_cfg.id = pj_str(sip_id);
+#endif
+
+    acc_cfg.vid_cap_dev = DEFAULT_CAP_DEV;
+    acc_cfg.vid_rend_dev = DEFAULT_REND_DEV;
+    acc_cfg.vid_in_auto_show = PJ_TRUE;
+    acc_cfg.vid_out_auto_transmit = PJ_TRUE;
+
+    status = pjsua_acc_add(&acc_cfg, PJ_TRUE, &accountId_);
+    if (status != PJ_SUCCESS) {
+	showError("Account creation", status);
+	goto on_error;
+    }
+
+    localUri_->setText(acc_cfg.id.ptr);
+
+    //
+    // Start pjsua!
+    //
+    showStatus("Starting stack..");
+    status = pjsua_start();
+    if (status != PJ_SUCCESS) {
+	showError("pjsua_start", status);
+	goto on_error;
+    }
+
+    showStatus("Ready");
+
+    return true;
+
+on_error:
+    pjsua_destroy();
+    return false;
+}
+
+/*
+ * A simple registrar, invoked by default_mod_on_rx_request()
+ */
+static void simple_registrar(pjsip_rx_data *rdata)
+{
+    pjsip_tx_data *tdata;
+    const pjsip_expires_hdr *exp;
+    const pjsip_hdr *h;
+    unsigned cnt = 0;
+    pjsip_generic_string_hdr *srv;
+    pj_status_t status;
+
+    status = pjsip_endpt_create_response(pjsua_get_pjsip_endpt(),
+				 rdata, 200, NULL, &tdata);
+    if (status != PJ_SUCCESS)
+	return;
+
+    exp = (pjsip_expires_hdr*)
+	  pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
+
+    h = rdata->msg_info.msg->hdr.next;
+    while (h != &rdata->msg_info.msg->hdr) {
+	if (h->type == PJSIP_H_CONTACT) {
+	    const pjsip_contact_hdr *c = (const pjsip_contact_hdr*)h;
+	    int e = c->expires;
+
+	    if (e < 0) {
+		if (exp)
+		    e = exp->ivalue;
+		else
+		    e = 3600;
+	    }
+
+	    if (e > 0) {
+		pjsip_contact_hdr *nc = (pjsip_contact_hdr*)
+					pjsip_hdr_clone(tdata->pool, h);
+		nc->expires = e;
+		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)nc);
+		++cnt;
+	    }
+	}
+	h = h->next;
+    }
+
+    srv = pjsip_generic_string_hdr_create(tdata->pool, NULL, NULL);
+    srv->name = pj_str((char*)"Server");
+    srv->hvalue = pj_str((char*)"pjsua simple registrar");
+    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)srv);
+
+    pjsip_endpt_send_response2(pjsua_get_pjsip_endpt(),
+                               rdata, tdata, NULL, NULL);
+}
+
+/* Notification on incoming request */
+static pj_bool_t default_mod_on_rx_request(pjsip_rx_data *rdata)
+{
+    /* Simple registrar */
+    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
+                         &pjsip_register_method) == 0)
+    {
+	simple_registrar(rdata);
+	return PJ_TRUE;
+    }
+
+    return PJ_FALSE;
+}
+
+/* The module instance. */
+static pjsip_module mod_default_handler =
+{
+    NULL, NULL,				/* prev, next.		*/
+    { (char*)"mod-default-handler", 19 },	/* Name.		*/
+    -1,					/* Id			*/
+    PJSIP_MOD_PRIORITY_APPLICATION+99,	/* Priority	        */
+    NULL,				/* load()		*/
+    NULL,				/* start()		*/
+    NULL,				/* stop()		*/
+    NULL,				/* unload()		*/
+    &default_mod_on_rx_request,		/* on_rx_request()	*/
+    NULL,				/* on_rx_response()	*/
+    NULL,				/* on_tx_request.	*/
+    NULL,				/* on_tx_response()	*/
+    NULL,				/* on_tsx_state()	*/
+
+};
+
+int main(int argc, char *argv[])
+{
+    /* At least on Linux, we have to initialize SDL video subsystem prior to
+     * creating/initializing QApplication, otherwise we'll segfault miserably
+     * in SDL_CreateWindow(). Here's a stack trace if you're interested:
+
+	Thread [7] (Suspended: Signal 'SIGSEGV' received. Description: Segmentation fault.)
+	13 XCreateIC()
+	12 SetupWindowData()
+	11 X11_CreateWindow()
+	10 SDL_CreateWindow()
+	..
+     */
+    if ( SDL_InitSubSystem(SDL_INIT_VIDEO) < 0 ) {
+        printf("Unable to init SDL: %s\n", SDL_GetError());
+        return 1;
+    }
+
+    QApplication app(argc, argv);
+
+    MainWin win;
+    win.show();
+
+    if (!win.initStack()) {
+	win.quit();
+	return 1;
+    }
+
+    /* We want to be registrar too! */
+    if (pjsua_get_pjsip_endpt()) {
+	pjsip_endpt_register_module(pjsua_get_pjsip_endpt(),
+				    &mod_default_handler);
+    }
+
+    return app.exec();
+}
+