From c9f1884efd85052d45add121a8e314bd30fa519b Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Fri, 19 Apr 2013 10:36:11 +0000 Subject: Re #1655: Initial implementation of pjsua CLI app for Windows Mobile (5.x & 6.x). git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4484 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip-apps/src/pjsua/wm/main_wm.c | 406 ++++++++++++++++++++++++++++++++++++++ pjsip-apps/src/pjsua/wm/pjsua.bmp | Bin 0 -> 12178 bytes 2 files changed, 406 insertions(+) create mode 100644 pjsip-apps/src/pjsua/wm/main_wm.c create mode 100644 pjsip-apps/src/pjsua/wm/pjsua.bmp (limited to 'pjsip-apps/src/pjsua/wm') diff --git a/pjsip-apps/src/pjsua/wm/main_wm.c b/pjsip-apps/src/pjsua/wm/main_wm.c new file mode 100644 index 00000000..8ab13384 --- /dev/null +++ b/pjsip-apps/src/pjsua/wm/main_wm.c @@ -0,0 +1,406 @@ +/* $Id$ */ +/* + * Copyright (C) 2013 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 + +#include +#include +#include +#include +#include "..\pjsua_app.h" + +#define MAINWINDOWCLASS TEXT("PjsuaDlg") +#define MAINWINDOWTITLE TEXT("PJSUA") +#define LOGO_PATH TEXT("\\Program Files\\pjsua\\pjsua.bmp") + +#define WM_APP_INIT WM_USER + 1 +#define WM_APP_DESTROY WM_USER + 2 +#define WM_APP_RESTART WM_USER + 3 + +static HINSTANCE g_hInst; +static HWND g_hWndMenuBar; +static HWND g_hWndMain; +static HWND g_hWndLbl; +static HWND g_hWndImg; +static HBITMAP g_hBmp; + +static int restart_argc = 0; +static char **restart_argv = NULL; + +/* Helper funtions to init/restart/destroy the pjsua */ +static void LibInit(); +static void LibDestroy(); +static void LibRestart(); + +/* pjsua app callbacks */ +static void lib_on_started(pj_status_t status, const char* title); +static pj_bool_t lib_on_stopped(pj_bool_t restart, int argc, char** argv); +static void lib_on_config_init(pjsua_app_config *cfg); + +LRESULT CALLBACK DialogProc(const HWND hWnd, + const UINT Msg, + const WPARAM wParam, + const LPARAM lParam) +{ + LRESULT res = 0; + + switch (Msg) { + case WM_CREATE: + g_hWndMain = hWnd; + break; + + case WM_COMMAND: /* Exit menu */ + case WM_CLOSE: + PostQuitMessage(0); + break; + + case WM_HOTKEY: + /* Exit app when back is pressed. */ + if (VK_TBACK == HIWORD(lParam) && (0 != (MOD_KEYUP & LOWORD(lParam)))) { + PostQuitMessage(0); + } else { + return DefWindowProc(hWnd, Msg, wParam, lParam); + } + break; + + case WM_CTLCOLORSTATIC: + /* Set text and background color for static windows */ + SetTextColor((HDC)wParam, RGB(255, 255, 255)); + SetBkColor((HDC)wParam, RGB(0, 0, 0)); + return (LRESULT)GetStockObject(BLACK_BRUSH); + + case WM_APP_INIT: + LibInit(); + break; + + case WM_APP_DESTROY: + LibDestroy(); + PostQuitMessage(0); + break; + + case WM_APP_RESTART: + LibRestart(); + break; + + default: + return DefWindowProc(hWnd, Msg, wParam, lParam); + } + + return res; +} + + +/* === GUI === */ + +pj_status_t gui_init() +{ + WNDCLASS wc; + HWND hWnd = NULL; + RECT r; + DWORD dwStyle; + enum { LABEL_HEIGHT = 30 }; + enum { MENU_ID_EXIT = 50000 }; + BITMAP bmp; + HMENU hRootMenu; + SHMENUBARINFO mbi; + + pj_status_t status = PJ_SUCCESS; + + /* Check if app is running. If it's running then focus on the window */ + hWnd = FindWindow(MAINWINDOWCLASS, MAINWINDOWTITLE); + + if (NULL != hWnd) { + SetForegroundWindow(hWnd); + return status; + } + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = (WNDPROC)DialogProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = g_hInst; + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wc.lpszMenuName = 0; + wc.lpszClassName = MAINWINDOWCLASS; + + if (!RegisterClass(&wc) != 0) { + DWORD err = GetLastError(); + return PJ_RETURN_OS_ERROR(err); + } + + /* Create the app. window */ + g_hWndMain = CreateWindow(MAINWINDOWCLASS, MAINWINDOWTITLE, + WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + (HWND)NULL, NULL, g_hInst, (LPSTR)NULL); + if (g_hWndMain == NULL) { + DWORD err = GetLastError(); + return PJ_RETURN_OS_ERROR(err); + } + + /* Create exit menu */ + hRootMenu = CreateMenu(); + AppendMenu(hRootMenu, MF_STRING, MENU_ID_EXIT, L"Exit"); + + /* Initialize menubar */ + ZeroMemory(&mbi, sizeof(SHMENUBARINFO)); + mbi.cbSize = sizeof(SHMENUBARINFO); + mbi.hwndParent = g_hWndMain; + mbi.dwFlags = SHCMBF_HIDESIPBUTTON|SHCMBF_HMENU; + mbi.nToolBarId = (UINT)hRootMenu; + mbi.hInstRes = g_hInst; + + if (FALSE == SHCreateMenuBar(&mbi)) { + DWORD err = GetLastError(); + return PJ_RETURN_OS_ERROR(err); + } + + /* Store menu window handle */ + g_hWndMenuBar = mbi.hwndMB; + + /* Show the menu */ + DrawMenuBar(g_hWndMain); + ShowWindow(g_hWndMenuBar, SW_SHOW); + + /* Override back button */ + SendMessage(g_hWndMenuBar, SHCMBM_OVERRIDEKEY, VK_TBACK, + MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, + SHMBOF_NODEFAULT | SHMBOF_NOTIFY)); + + /* Get main window size */ + GetClientRect(g_hWndMain, &r); +#if defined(WIN32_PLATFORM_PSPC) && WIN32_PLATFORM_PSPC != 0 + /* Adjust the height for PocketPC platform */ + r.bottom -= GetSystemMetrics(SM_CYMENU); +#endif + + /* Create logo */ + g_hBmp = SHLoadDIBitmap(LOGO_PATH); // for jpeg, uses SHLoadImageFile() + if (g_hBmp == NULL) { + DWORD err = GetLastError(); + return PJ_RETURN_OS_ERROR(err); + } + GetObject(g_hBmp, sizeof(bmp), &bmp); + + dwStyle = SS_CENTERIMAGE | SS_REALSIZEIMAGE | SS_BITMAP | + WS_CHILD | WS_VISIBLE; + g_hWndImg = CreateWindow(TEXT("STATIC"), NULL, dwStyle, + (r.right-r.left-bmp.bmWidth)/2, + (r.bottom-r.top-bmp.bmHeight)/2, + bmp.bmWidth, bmp.bmHeight, + g_hWndMain, (HMENU)0, g_hInst, NULL); + if (g_hWndImg == NULL) { + DWORD err = GetLastError(); + return PJ_RETURN_OS_ERROR(err); + } + SendMessage(g_hWndImg, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)g_hBmp); + + /* Create label */ + dwStyle = WS_CHILD | WS_VISIBLE | ES_CENTER; + g_hWndLbl = CreateWindow(TEXT("STATIC"), NULL, dwStyle, + 0, r.bottom-LABEL_HEIGHT, r.right-r.left, LABEL_HEIGHT, + g_hWndMain, (HMENU)0, g_hInst, NULL); + if (g_hWndLbl == NULL) { + DWORD err = GetLastError(); + return PJ_RETURN_OS_ERROR(err); + } + SetWindowText(g_hWndLbl, _T("Please wait..")); + + return status; +} + + +pj_status_t gui_start() +{ + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return (msg.wParam); +} + +void gui_destroy(void) +{ + if (g_hWndMain) { + DestroyWindow(g_hWndMain); + g_hWndMain = NULL; + } + if (g_hWndMenuBar) { + DestroyWindow(g_hWndMenuBar); + g_hWndMenuBar = NULL; + } + if (g_hWndLbl) { + DestroyWindow(g_hWndLbl); + g_hWndLbl = NULL; + } + if (g_hWndImg) { + DestroyWindow(g_hWndImg); + g_hWndImg = NULL; + } + if (g_hBmp) { + DeleteObject(g_hBmp); + g_hBmp = NULL; + } + UnregisterClass(MAINWINDOWCLASS, g_hInst); +} + +/* === ENGINE === */ + +/* Called when pjsua is started */ +void lib_on_started(pj_status_t status, const char* title) +{ + wchar_t wtitle[128]; + + PJ_UNUSED_ARG(status); + + pj_ansi_to_unicode(title, strlen(title), wtitle, PJ_ARRAY_SIZE(wtitle)); + SetWindowText(g_hWndLbl, wtitle); +} + +/* Called when pjsua is stopped */ +pj_bool_t lib_on_stopped(pj_bool_t restart, int argc, char** argv) +{ + if (restart) { + restart_argc = argc; + restart_argv = argv; + + // Schedule Lib Restart + PostMessage(g_hWndMain, WM_APP_RESTART, 0, 0); + } else { + /* Destroy & quit GUI, e.g: clean up window, resources */ + PostMessage(g_hWndMain, WM_APP_DESTROY, 0, 0); + } + + return PJ_FALSE; +} + +/* Called before pjsua initializing config. */ +void lib_on_config_init(pjsua_app_config *cfg) +{ + PJ_UNUSED_ARG(cfg); +} + +void LibInit() +{ + char* argv[] = { + "", + "--use-cli", + "--cli-telnet-port=0", + "--no-cli-console" + }; + app_cfg_t app_cfg; + pj_status_t status; + + pj_bzero(&app_cfg, sizeof(app_cfg)); + app_cfg.argc = PJ_ARRAY_SIZE(argv); + app_cfg.argv = argv; + app_cfg.on_started = &lib_on_started; + app_cfg.on_stopped = &lib_on_stopped; + app_cfg.on_config_init = &lib_on_config_init; + + SetWindowText(g_hWndLbl, _T("Initializing..")); + status = app_init(&app_cfg); + if (status != PJ_SUCCESS) + goto on_return; + + SetWindowText(g_hWndLbl, _T("Starting..")); + status = app_run(PJ_FALSE); + if (status != PJ_SUCCESS) + goto on_return; + +on_return: + if (status != PJ_SUCCESS) + SetWindowText(g_hWndLbl, _T("Initialization failed")); +} + +void LibDestroy() +{ + app_destroy(); +} + +void LibRestart() +{ + app_cfg_t app_cfg; + pj_status_t status; + + /* Destroy pjsua app first */ + + app_destroy(); + + /* Reinit pjsua app */ + + pj_bzero(&app_cfg, sizeof(app_cfg)); + app_cfg.argc = restart_argc; + app_cfg.argv = restart_argv; + app_cfg.on_started = &lib_on_started; + app_cfg.on_stopped = &lib_on_stopped; + app_cfg.on_config_init = &lib_on_config_init; + + status = app_init(&app_cfg); + if (status != PJ_SUCCESS) { + SetWindowText(g_hWndLbl, _T("app_init() failed")); + return; + } + + /* Run pjsua app */ + + status = app_run(PJ_FALSE); + if (status != PJ_SUCCESS) { + SetWindowText(g_hWndLbl, _T("app_run() failed")); + return; + } +} + + +/* === MAIN === */ + +int WINAPI WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPWSTR lpCmdLine, + int nShowCmd +) +{ + int status; + + PJ_UNUSED_ARG(hPrevInstance); + PJ_UNUSED_ARG(lpCmdLine); + PJ_UNUSED_ARG(nShowCmd); + + // store the hInstance in global + g_hInst = hInstance; + + status = gui_init(); + if (status != 0) + goto on_return; + + // Start the engine + PostMessage(g_hWndMain, WM_APP_INIT, 0, 0); + + status = gui_start(); + +on_return: + LibDestroy(); + gui_destroy(); + + return status; +} diff --git a/pjsip-apps/src/pjsua/wm/pjsua.bmp b/pjsip-apps/src/pjsua/wm/pjsua.bmp new file mode 100644 index 00000000..6fd0c95b Binary files /dev/null and b/pjsip-apps/src/pjsua/wm/pjsua.bmp differ -- cgit v1.2.3