summaryrefslogtreecommitdiff
path: root/pjsip-apps/src/pjsystest/main_wm.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjsip-apps/src/pjsystest/main_wm.c')
-rw-r--r--pjsip-apps/src/pjsystest/main_wm.c444
1 files changed, 444 insertions, 0 deletions
diff --git a/pjsip-apps/src/pjsystest/main_wm.c b/pjsip-apps/src/pjsystest/main_wm.c
new file mode 100644
index 0000000..aaaac1e
--- /dev/null
+++ b/pjsip-apps/src/pjsystest/main_wm.c
@@ -0,0 +1,444 @@
+/* $Id: main_wm.c 3553 2011-05-05 06:14:19Z nanang $ */
+/*
+ * Copyright (C) 2008-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 "gui.h"
+#include "systest.h"
+#include <windows.h>
+
+
+#include "gui.h"
+#include <pjlib.h>
+#include <windows.h>
+#include <winuserm.h>
+#include <aygshell.h>
+
+#define MAINWINDOWCLASS TEXT("SysTestDlg")
+#define MAINWINDOWTITLE TEXT("PJSYSTEST")
+
+typedef struct menu_handler_t {
+ UINT id;
+ gui_menu_handler handler;
+} menu_handler_t;
+
+static HINSTANCE g_hInst;
+static HWND g_hWndMenuBar;
+static HWND g_hWndMain;
+static HWND g_hWndLog;
+static pj_thread_t *g_log_thread;
+static gui_menu *g_menu;
+static unsigned g_menu_handler_cnt;
+static menu_handler_t g_menu_handlers[64];
+
+static pj_log_func *g_log_writer_orig;
+
+static pj_status_t gui_update_menu(gui_menu *menu);
+
+static void log_writer(int level, const char *buffer, int len)
+{
+ wchar_t buf[512];
+ int cur_len;
+
+ PJ_UNUSED_ARG(level);
+
+ pj_ansi_to_unicode(buffer, len, buf, 512);
+
+ if (!g_hWndLog)
+ return;
+
+ /* For now, ignore log messages from other thread to avoid deadlock */
+ if (g_log_thread == pj_thread_this()) {
+ cur_len = (int)SendMessage(g_hWndLog, WM_GETTEXTLENGTH, 0, 0);
+ SendMessage(g_hWndLog, EM_SETSEL, (WPARAM)cur_len, (LPARAM)cur_len);
+ SendMessage(g_hWndLog, EM_REPLACESEL, (WPARAM)0, (LPARAM)buf);
+ }
+
+ //uncomment to forward to the original log writer
+ if (g_log_writer_orig)
+ (*g_log_writer_orig)(level, buffer, len);
+}
+
+/* execute menu handler for id menu specified, return FALSE if menu handler
+ * is not found.
+ */
+static BOOL handle_menu(UINT id)
+{
+ unsigned i;
+
+ for (i = 0; i < g_menu_handler_cnt; ++i) {
+ if (g_menu_handlers[i].id == id) {
+ /* menu handler found, execute it */
+ (*g_menu_handlers[i].handler)();
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* generate submenu and register the menu handler, then return next menu id */
+static UINT generate_submenu(HMENU parent, UINT id_start, gui_menu *menu)
+{
+ unsigned i;
+ UINT id = id_start;
+
+ if (!menu)
+ return id;
+
+ /* generate submenu */
+ for (i = 0; i < menu->submenu_cnt; ++i) {
+
+ if (menu->submenus[i] == NULL) {
+
+ /* add separator */
+ AppendMenu(parent, MF_SEPARATOR, 0, 0);
+
+ } else if (menu->submenus[i]->submenu_cnt != 0) {
+
+ /* this submenu item has children, generate popup menu */
+ HMENU hMenu;
+ wchar_t buf[64];
+
+ pj_ansi_to_unicode(menu->submenus[i]->title,
+ pj_ansi_strlen(menu->submenus[i]->title),
+ buf, 64);
+
+ hMenu = CreatePopupMenu();
+ AppendMenu(parent, MF_STRING|MF_ENABLED|MF_POPUP, (UINT)hMenu, buf);
+ id = generate_submenu(hMenu, id, menu->submenus[i]);
+
+ } else {
+
+ /* this submenu item is leaf, register the handler */
+ wchar_t buf[64];
+
+ pj_ansi_to_unicode(menu->submenus[i]->title,
+ pj_ansi_strlen(menu->submenus[i]->title),
+ buf, 64);
+
+ AppendMenu(parent, MF_STRING, id, buf);
+
+ if (menu->submenus[i]->handler) {
+ g_menu_handlers[g_menu_handler_cnt].id = id;
+ g_menu_handlers[g_menu_handler_cnt].handler =
+ menu->submenus[i]->handler;
+ ++g_menu_handler_cnt;
+ }
+
+ ++id;
+ }
+ }
+
+ return id;
+}
+
+BOOL InitDialog()
+{
+ /* update menu */
+ if (gui_update_menu(g_menu) != PJ_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+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;
+ if (FALSE == InitDialog()){
+ DestroyWindow(g_hWndMain);
+ }
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(g_hWndMain);
+ break;
+
+ case WM_DESTROY:
+ if (g_hWndMenuBar)
+ DestroyWindow(g_hWndMenuBar);
+ g_hWndMenuBar = NULL;
+ g_hWndMain = NULL;
+ PostQuitMessage(0);
+ break;
+
+ case WM_HOTKEY:
+ /* Exit app when back is pressed. */
+ if (VK_TBACK == HIWORD(lParam) && (0 != (MOD_KEYUP & LOWORD(lParam)))) {
+ DestroyWindow(g_hWndMain);
+ } else {
+ return DefWindowProc(hWnd, Msg, wParam, lParam);
+ }
+ break;
+
+ case WM_COMMAND:
+ res = handle_menu(LOWORD(wParam));
+ break;
+
+ default:
+ return DefWindowProc(hWnd, Msg, wParam, lParam);
+ }
+
+ return res;
+}
+
+
+/* === API === */
+
+pj_status_t gui_init(gui_menu *menu)
+{
+ WNDCLASS wc;
+ HWND hWnd = NULL;
+ RECT r;
+ DWORD dwStyle;
+
+ 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;
+ }
+
+ g_menu = menu;
+
+ 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(WHITE_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);
+
+ /* Create edit control to print log */
+ GetClientRect(g_hWndMain, &r);
+ dwStyle = WS_CHILD | WS_VISIBLE | WS_VSCROLL |
+ ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL | ES_LEFT;
+ g_hWndLog = CreateWindow(
+ TEXT("EDIT"), // Class name
+ NULL, // Window text
+ dwStyle, // Window style
+ 0, // x-coordinate of the upper-left corner
+ 0, // y-coordinate of the upper-left corner
+ r.right-r.left, // Width of the window for the edit
+ // control
+ r.bottom-r.top, // Height of the window for the edit
+ // control
+ g_hWndMain, // Window handle to the parent window
+ (HMENU) 0, // Control identifier
+ g_hInst, // Instance handle
+ NULL); // Specify NULL for this parameter when
+ // you create a control
+
+ /* Resize the log */
+ if (g_hWndMenuBar) {
+ RECT r_menu = {0};
+
+ GetWindowRect(g_hWndLog, &r);
+ GetWindowRect(g_hWndMenuBar, &r_menu);
+ if (r.bottom > r_menu.top) {
+ MoveWindow(g_hWndLog, 0, 0, r.right-r.left,
+ (r.bottom-r.top)-(r_menu.bottom-r_menu.top), TRUE);
+ }
+ }
+
+ /* Focus it, so SP user can scroll the log */
+ SetFocus(g_hWndLog);
+
+ /* Get the log thread */
+ g_log_thread = pj_thread_this();
+
+ /* Redirect log & update log decor setting */
+ /*
+ log_decor = pj_log_get_decor();
+ log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_CR;
+ pj_log_set_decor(log_decor);
+ */
+ g_log_writer_orig = pj_log_get_log_func();
+ pj_log_set_log_func(&log_writer);
+
+ return status;
+}
+
+static pj_status_t gui_update_menu(gui_menu *menu)
+{
+ enum { MENU_ID_START = 50000 };
+ UINT id_start = MENU_ID_START;
+ HMENU hRootMenu;
+ SHMENUBARINFO mbi;
+
+ /* delete existing menu */
+ if (g_hWndMenuBar) {
+ DestroyWindow(g_hWndMenuBar);
+ g_hWndMenuBar = NULL;
+ }
+
+ /* delete menu handler map */
+ g_menu_handler_cnt = 0;
+
+ /* smartphone can only have two root menus */
+ pj_assert(menu->submenu_cnt <= 2);
+
+ /* generate menu tree */
+ hRootMenu = CreateMenu();
+ id_start = generate_submenu(hRootMenu, id_start, menu);
+
+ /* 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;
+
+ /* store current menu */
+ g_menu = menu;
+
+ /* 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));
+
+
+ return PJ_SUCCESS;
+}
+
+enum gui_key gui_msgbox(const char *title, const char *message, enum gui_flag flag)
+{
+ wchar_t buf_title[64];
+ wchar_t buf_msg[512];
+ UINT wflag = 0;
+ int retcode;
+
+ pj_ansi_to_unicode(title, pj_ansi_strlen(title), buf_title, 64);
+ pj_ansi_to_unicode(message, pj_ansi_strlen(message), buf_msg, 512);
+
+ switch (flag) {
+ case WITH_OK:
+ wflag = MB_OK;
+ break;
+ case WITH_YESNO:
+ wflag = MB_YESNO;
+ break;
+ case WITH_OKCANCEL:
+ wflag = MB_OKCANCEL;
+ break;
+ }
+
+ retcode = MessageBox(g_hWndMain, buf_msg, buf_title, wflag);
+
+ switch (retcode) {
+ case IDOK:
+ return KEY_OK;
+ case IDYES:
+ return KEY_YES;
+ case IDNO:
+ return KEY_NO;
+ default:
+ return KEY_CANCEL;
+ }
+}
+
+void gui_sleep(unsigned sec)
+{
+ pj_thread_sleep(sec * 1000);
+}
+
+pj_status_t gui_start(gui_menu *menu)
+{
+ MSG msg;
+
+ PJ_UNUSED_ARG(menu);
+
+ 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;
+ }
+}
+
+
+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 = systest_init();
+ if (status != 0)
+ goto on_return;
+
+ status = systest_run();
+
+on_return:
+ systest_deinit();
+
+ return status;
+}