1 /**
2  * main-client.cpp
3  * This file is part of the YATE Project http://YATE.null.ro
4  *
5  * Yet Another Telephony Engine - a fully featured software PBX and IVR
6  * Copyright (C) 2004-2014 Null Team
7  *
8  * This software is distributed under multiple licenses;
9  * see the COPYING file in the main directory for licensing
10  * information for this specific distribution.
11  *
12  * This use of this software may be subject to additional restrictions.
13  * See the LEGAL file in the main directory for details.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18  */
19 
20 #include "yatengine.h"
21 
22 #include "resource.h"
23 #include <commctrl.h>
24 #include <stdio.h>
25 
26 using namespace TelEngine;
27 
28 class DialogWrapper
29 {
30 public:
DialogWrapper()31     inline DialogWrapper()
32 	: m_wnd(0)
33 	{ }
34     virtual ~DialogWrapper();
35     virtual int wndFunc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp);
36     virtual int command(WORD id, LPARAM lp);
hwnd() const37     inline HWND hwnd() const
38 	{ return m_wnd; }
39     static bool insert(DialogWrapper* dlg, int id);
40 private:
41     HWND m_wnd;
42 };
43 
44 static HMODULE s_handle = 0;
45 static HICON s_icon = 0;
46 static HWND s_main = 0;
47 
48 // set the status text on bottom of the window
mainStatus(const char * stat)49 static void mainStatus(const char* stat)
50 {
51     if (s_main)
52 	::SetDlgItemText(s_main,IDC_STATUS,stat);
53 }
54 
55 // recompute tabs visibility and show/hide child dialogs
tabsVisibility()56 static void tabsVisibility()
57 {
58     if (!s_main)
59 	return;
60     HWND tabs = ::GetDlgItem(s_main,IDC_MAINTABS);
61     int current = TabCtrl_GetCurSel(tabs);
62     int numtabs = TabCtrl_GetItemCount(tabs);
63     for (int i=0; i<numtabs; i++) {
64 	TCITEM item;
65 	item.mask = TCIF_PARAM;
66 	if (TabCtrl_GetItem(tabs,i,&item))
67 	    ::ShowWindow((HWND)item.lParam,(i == current) ? SW_SHOW : SW_HIDE);
68     }
69 }
70 
innerDialog(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)71 static int CALLBACK innerDialog(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
72 {
73     DialogWrapper* dlg = reinterpret_cast<DialogWrapper*>(::GetWindowLong(wnd,DWL_USER));
74     if (dlg)
75 	return dlg->wndFunc(wnd,msg,wp,lp);
76     switch (msg) {
77 	case WM_INITDIALOG:
78 	    dlg = reinterpret_cast<DialogWrapper*>(lp);
79 	    ::SetWindowLong(wnd,DWL_USER,(long)dlg);
80 	    if (dlg)
81 		return dlg->wndFunc(wnd,msg,wp,lp);
82 	    break;
83 	case WM_CLOSE:
84 	    DestroyWindow(wnd);
85 	    break;
86 	default:
87 	    return 0;
88     }
89     return 1;
90 }
91 
~DialogWrapper()92 DialogWrapper::~DialogWrapper()
93 {
94     if (m_wnd) {
95 	::SetWindowLong(m_wnd,DWL_USER,0);
96 	DestroyWindow(m_wnd);
97 	if (s_main) {
98 	    HWND tabs = ::GetDlgItem(s_main,IDC_MAINTABS);
99 	    int numtabs = tabs ? TabCtrl_GetItemCount(tabs) : 0;
100 	    for (int i=0; i<numtabs; i++) {
101 		TCITEM item;
102 		item.mask = TCIF_PARAM;
103 		if (TabCtrl_GetItem(tabs,i,&item) && ((HWND)item.lParam == m_wnd)) {
104 		    BOOL current = (TabCtrl_GetCurSel(tabs) == i);
105 		    TabCtrl_DeleteItem(tabs,i);
106 		    if (current) {
107 			TabCtrl_SetCurSel(tabs,0);
108 			tabsVisibility();
109 		    }
110 		}
111 	    }
112 	}
113     }
114 }
115 
wndFunc(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)116 int DialogWrapper::wndFunc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
117 {
118     switch (msg) {
119 	case WM_INITDIALOG:
120 	    m_wnd = wnd;
121 	    break;
122 	case WM_CLOSE:
123 	    DestroyWindow(wnd);
124 	    break;
125 	case WM_NCDESTROY:
126 	    ::SetWindowLong(wnd,DWL_USER,0);
127 	    m_wnd = 0;
128 	    delete this;
129 	    return 0;
130 	case WM_COMMAND:
131 	    return command(LOWORD(wp),lp);
132 	default:
133 	    return 0;
134     }
135     return 1;
136 }
137 
command(WORD id,LPARAM lp)138 int DialogWrapper::command(WORD id, LPARAM lp)
139 {
140 #if 0
141     char buf[128];
142     sprintf(buf,"id=%u lparam=0x%08X",id,lp);
143     ::MessageBox(hwnd(),buf,"WM_COMMAND",MB_OK);
144 #endif
145     return 0;
146 }
147 
148 
insert(DialogWrapper * dlg,int id)149 bool DialogWrapper::insert(DialogWrapper* dlg, int id)
150 {
151     if (!(s_main && dlg && id))
152 	return false;
153     HWND tabs = ::GetDlgItem(s_main,IDC_MAINTABS);
154     if (!tabs)
155 	return false;
156     HWND wnd = ::CreateDialogParam(s_handle,MAKEINTRESOURCE(id),tabs,innerDialog,(LPARAM)dlg);
157     if (!wnd)
158 	return false;
159 
160     char buf[128];
161     ::LoadString(s_handle,id,buf,sizeof(buf));
162 
163     TCITEM item;
164     item.mask = TCIF_TEXT | TCIF_PARAM;
165     item.lParam = (LPARAM)wnd;
166     item.pszText = buf;
167     TabCtrl_InsertItem(tabs,TabCtrl_GetItemCount(tabs),&item);
168 
169     RECT rect;
170     ::GetClientRect(tabs,&rect);
171     TabCtrl_AdjustRect(tabs,FALSE,&rect);
172     ::MoveWindow(wnd,rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top,TRUE);
173     ::ShowWindow(wnd,SW_SHOW);
174     return true;
175 }
176 
initMainDlg(HWND wnd)177 static void initMainDlg(HWND wnd)
178 {
179     DWORD ver = ::GetVersion();
180     if (((ver & 0xff) >= 4) || ((ver & 0xff00) >= 0x5f00)) {
181 	/* set icons in the new shell */
182 	::SendMessage(wnd,WM_SETICON,ICON_BIG,(LPARAM)s_icon);
183 	s_icon = (HICON)::LoadImage(s_handle,MAKEINTRESOURCE(IDI_NULLTEAM),IMAGE_ICON,16,16,0);
184 	if (s_icon)
185 	    ::SendMessage(wnd,WM_SETICON,ICON_SMALL,(LPARAM)s_icon);
186     }
187     HMENU smenu = ::GetSystemMenu(wnd,FALSE);
188     ::DeleteMenu(smenu,SC_MAXIMIZE,MF_BYCOMMAND);
189     ::DeleteMenu(smenu,SC_SIZE,MF_BYCOMMAND);
190     s_main = wnd;
191     DialogWrapper::insert(new DialogWrapper,IDD_CALLS);
192     tabsVisibility();
193 }
194 
mainDialog(HWND wnd,UINT msg,WPARAM wp,LPARAM lp)195 static int CALLBACK mainDialog(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
196 {
197     switch (msg) {
198 	case WM_INITDIALOG:
199 	    initMainDlg(wnd);
200 	    break;
201 	case WM_CLOSE:
202 	    ::EndDialog(wnd,1);
203 	    break;
204 	case WM_QUERYDRAGICON:
205 	    /* in some cases this is used as application icon */
206 	    return (int)s_icon;
207 	case WM_PAINT:
208 	    if (s_icon && IsIconic(wnd)) {
209 		/* handle iconic draw in the old shell */
210 		PAINTSTRUCT ps;
211 		::BeginPaint(wnd,&ps);
212 		::DefWindowProc(wnd,WM_ICONERASEBKGND,(WPARAM)ps.hdc,0);
213 		::DrawIcon(ps.hdc,2,2,s_icon);
214 		::EndPaint(wnd,&ps);
215 		break;
216 	    }
217 	    return 0;
218 	case WM_NOTIFY:
219 	    if ((wp == IDC_MAINTABS) && (((LPNMHDR)lp)->code == TCN_SELCHANGE))
220 		tabsVisibility();
221 	    break;
222 	default:
223 	    return 0;
224     }
225     return 1;
226 }
227 
228 class WinClientThread : public Thread
229 {
230 public:
231     void run();
232 };
233 
234 class WinClientPlugin : public Plugin
235 {
236 public:
WinClientPlugin()237     WinClientPlugin()
238 	: m_thread(0)
239 	{ }
240     virtual void initialize(void);
isBusy() const241     virtual bool isBusy() const
242 	{ return true; }
243 private:
244     WinClientThread* m_thread;
245 };
246 
run()247 void WinClientThread::run()
248 {
249     s_handle = ::GetModuleHandle(0);
250     s_icon = ::LoadIcon(s_handle,MAKEINTRESOURCE(IDI_NULLTEAM));
251     ::InitCommonControls();
252     int ret = ::DialogBox(s_handle,MAKEINTRESOURCE(IDD_TCLIENT),0,mainDialog);
253     s_main = 0;
254     if (s_icon)
255 	::DestroyIcon(s_icon);
256     if (ret < 0)
257 	ret = 127;
258     Engine::halt(ret);
259 }
260 
initialize()261 void WinClientPlugin::initialize()
262 {
263     if (!m_thread) {
264 	m_thread = new WinClientThread;
265 	if (m_thread->error())
266 	    Engine::halt(1);
267 	else
268 	    m_thread->startup();
269     }
270 }
271 
272 INIT_PLUGIN(WinClientPlugin);
273 
274 // We force mainCRTStartup as entry point (from linker settings) so we get
275 //  the parser called even for a GUI application
main(int argc,const char ** argv,const char ** envp)276 extern "C" int main(int argc, const char** argv, const char** envp)
277 {
278     return Engine::main(argc,argv,envp,TelEngine::Engine::Client);
279 }
280