You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Dialog.cxx 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright (C) 2010 D. R. Commander. All Rights Reserved.
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. // -=- Dialog.cxx
  20. // Base-class for any Dialog classes we might require
  21. #ifdef HAVE_CONFIG_H
  22. #include <config.h>
  23. #endif
  24. #include <rfb_win32/Dialog.h>
  25. #include <rfb_win32/TCharArray.h>
  26. #include <rfb/LogWriter.h>
  27. #include <rdr/Exception.h>
  28. #include <rfb_win32/Win32Util.h>
  29. #ifdef _DIALOG_CAPTURE
  30. #ifdef PropSheet_IndexToId
  31. #include <rfb_win32/DeviceFrameBuffer.h>
  32. #include <extra/LoadBMP.cxx>
  33. #else
  34. #undef _DIALOG_CAPTURE
  35. #pragma message(" NOTE: Not building Dialog Capture support.")
  36. #endif
  37. #endif
  38. using namespace rfb;
  39. using namespace rfb::win32;
  40. static LogWriter dlog("Dialog");
  41. static LogWriter plog("PropSheet");
  42. Dialog::Dialog(HINSTANCE inst_)
  43. : inst(inst_), handle(0), alreadyShowing(false)
  44. {
  45. }
  46. Dialog::~Dialog()
  47. {
  48. }
  49. bool Dialog::showDialog(const TCHAR* resource, HWND owner)
  50. {
  51. if (alreadyShowing) return false;
  52. handle = 0;
  53. alreadyShowing = true;
  54. INT_PTR result = DialogBoxParam(inst, resource, owner,
  55. staticDialogProc, (LPARAM)this);
  56. if (result<0)
  57. throw rdr::SystemException("DialogBoxParam failed", GetLastError());
  58. alreadyShowing = false;
  59. return (result == 1);
  60. }
  61. bool Dialog::isItemChecked(int id) {
  62. return SendMessage(GetDlgItem(handle, id), BM_GETCHECK, 0, 0) == BST_CHECKED;
  63. }
  64. int Dialog::getItemInt(int id) {
  65. BOOL trans;
  66. int result = GetDlgItemInt(handle, id, &trans, TRUE);
  67. if (!trans)
  68. throw rdr::Exception("unable to read dialog Int");
  69. return result;
  70. }
  71. TCHAR* Dialog::getItemString(int id) {
  72. TCharArray tmp(256);
  73. if (!GetDlgItemText(handle, id, tmp.buf, 256))
  74. tmp.buf[0] = 0;
  75. return tmp.takeBuf();
  76. }
  77. void Dialog::setItemChecked(int id, bool state) {
  78. SendMessage(GetDlgItem(handle, id), BM_SETCHECK, state ? BST_CHECKED : BST_UNCHECKED, 0);
  79. }
  80. void Dialog::setItemInt(int id, int value) {
  81. SetDlgItemInt(handle, id, value, TRUE);
  82. }
  83. void Dialog::setItemString(int id, const TCHAR* s) {
  84. SetDlgItemText(handle, id, s);
  85. }
  86. void Dialog::enableItem(int id, bool state) {
  87. EnableWindow(GetDlgItem(handle, id), state);
  88. }
  89. INT_PTR CALLBACK Dialog::staticDialogProc(HWND hwnd, UINT msg,
  90. WPARAM wParam, LPARAM lParam)
  91. {
  92. if (msg == WM_INITDIALOG)
  93. SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
  94. LONG_PTR self = GetWindowLongPtr(hwnd, GWLP_USERDATA);
  95. if (!self) return FALSE;
  96. return ((Dialog*)self)->dialogProc(hwnd, msg, wParam, lParam);
  97. }
  98. BOOL Dialog::dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  99. {
  100. switch (msg) {
  101. case WM_INITDIALOG:
  102. handle = hwnd;
  103. initDialog();
  104. return TRUE;
  105. case WM_COMMAND:
  106. switch (LOWORD(wParam)) {
  107. case IDOK:
  108. if (onOk()) {
  109. EndDialog(hwnd, 1);
  110. return TRUE;
  111. }
  112. return FALSE;
  113. case IDCANCEL:
  114. EndDialog(hwnd, 0);
  115. return TRUE;
  116. default:
  117. return onCommand(LOWORD(wParam), HIWORD(wParam));
  118. };
  119. case WM_HELP:
  120. return onHelp(((HELPINFO*)lParam)->iCtrlId);
  121. }
  122. return FALSE;
  123. }
  124. PropSheetPage::PropSheetPage(HINSTANCE inst, const TCHAR* id) : Dialog(inst), propSheet(0) {
  125. page.dwSize = sizeof(page);
  126. page.dwFlags = 0; // PSP_USECALLBACK;
  127. page.hInstance = inst;
  128. page.pszTemplate = id;
  129. page.pfnDlgProc = staticPageProc;
  130. page.lParam = (LPARAM)this;
  131. page.pfnCallback = 0; // staticPageProc;
  132. }
  133. PropSheetPage::~PropSheetPage() {
  134. }
  135. INT_PTR CALLBACK PropSheetPage::staticPageProc(HWND hwnd, UINT msg,
  136. WPARAM wParam, LPARAM lParam)
  137. {
  138. if (msg == WM_INITDIALOG)
  139. SetWindowLongPtr(hwnd, GWLP_USERDATA, ((PROPSHEETPAGE*)lParam)->lParam);
  140. LONG_PTR self = GetWindowLongPtr(hwnd, GWLP_USERDATA);
  141. if (!self) return FALSE;
  142. return ((PropSheetPage*)self)->dialogProc(hwnd, msg, wParam, lParam);
  143. }
  144. BOOL PropSheetPage::dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  145. {
  146. switch (msg) {
  147. case WM_INITDIALOG:
  148. handle = hwnd;
  149. initDialog();
  150. return TRUE;
  151. case WM_NOTIFY:
  152. switch (((NMHDR*)lParam)->code) {
  153. case PSN_APPLY:
  154. onOk();
  155. return FALSE;
  156. };
  157. return FALSE;
  158. case WM_COMMAND:
  159. return onCommand(LOWORD(wParam), HIWORD(wParam));
  160. case WM_HELP:
  161. return onHelp(((HELPINFO*)lParam)->iCtrlId);
  162. }
  163. return FALSE;
  164. }
  165. PropSheet::PropSheet(HINSTANCE inst_, const TCHAR* title_, std::list<PropSheetPage*> pages_, HICON icon_)
  166. : icon(icon_), pages(pages_), inst(inst_), title(tstrDup(title_)), handle(0), alreadyShowing(0) {
  167. }
  168. PropSheet::~PropSheet() {
  169. }
  170. // For some reason, DLGTEMPLATEEX isn't defined in the Windows headers - go figure...
  171. struct DLGTEMPLATEEX {
  172. WORD dlgVer;
  173. WORD signature;
  174. DWORD helpID;
  175. DWORD exStyle;
  176. DWORD style;
  177. WORD cDlgItems;
  178. short x;
  179. short y;
  180. short cx;
  181. short cy;
  182. };
  183. static int CALLBACK removeCtxtHelp(HWND /*hwnd*/, UINT message, LPARAM lParam) {
  184. if (message == PSCB_PRECREATE) {
  185. // Remove the context-help style, to remove the titlebar ? button
  186. // *** Nasty hack to cope with new & old dialog template formats...
  187. if (((DLGTEMPLATEEX*)lParam)->signature == 0xffff)
  188. ((DLGTEMPLATEEX*)lParam)->style &= ~DS_CONTEXTHELP;
  189. else
  190. ((LPDLGTEMPLATE)lParam)->style &= ~DS_CONTEXTHELP;
  191. }
  192. return TRUE;
  193. }
  194. bool PropSheet::showPropSheet(HWND owner, bool showApply, bool showCtxtHelp, bool capture) {
  195. if (alreadyShowing) return false;
  196. alreadyShowing = true;
  197. int count = pages.size();
  198. HPROPSHEETPAGE* hpages = new HPROPSHEETPAGE[count];
  199. try {
  200. // Create the PropertSheet page GDI objects.
  201. std::list<PropSheetPage*>::iterator pspi;
  202. int i = 0;
  203. for (pspi=pages.begin(); pspi!=pages.end(); pspi++) {
  204. hpages[i] = CreatePropertySheetPage(&((*pspi)->page));
  205. (*pspi)->setPropSheet(this);
  206. i++;
  207. }
  208. // Initialise and create the PropertySheet itself
  209. PROPSHEETHEADER header;
  210. header.dwSize = sizeof(PROPSHEETHEADER); // Requires comctl32.dll 4.71 or greater, ie IE 4 or later
  211. header.dwFlags = PSH_MODELESS | (showApply ? 0 : PSH_NOAPPLYNOW) | (showCtxtHelp ? 0 : PSH_USECALLBACK);
  212. header.pfnCallback = removeCtxtHelp;
  213. header.hwndParent = owner;
  214. header.hInstance = inst;
  215. header.pszCaption = title.buf;
  216. header.nPages = count;
  217. header.nStartPage = 0;
  218. header.phpage = hpages;
  219. if (icon) {
  220. header.hIcon = icon;
  221. header.dwFlags |= PSH_USEHICON;
  222. }
  223. handle = (HWND)PropertySheet(&header);
  224. if ((handle == 0) || (handle == (HWND)-1))
  225. throw rdr::SystemException("PropertySheet failed", GetLastError());
  226. centerWindow(handle, owner);
  227. plog.info("created %p", handle);
  228. (void)capture;
  229. #ifdef _DIALOG_CAPTURE
  230. if (capture) {
  231. plog.info("capturing \"%s\"", (const char*)CStr(title.buf));
  232. char* tmpdir = getenv("TEMP");
  233. HDC dc = GetWindowDC(handle);
  234. DeviceFrameBuffer fb(dc);
  235. int i=0;
  236. while (true) {
  237. int id = PropSheet_IndexToId(handle, i);
  238. if (!id) break;
  239. PropSheet_SetCurSelByID(handle, id);
  240. MSG msg;
  241. while (PeekMessage(&msg, handle, 0, 0, PM_REMOVE)) {
  242. if (!PropSheet_IsDialogMessage(handle, &msg))
  243. DispatchMessage(&msg);
  244. }
  245. fb.grabRect(fb.getRect());
  246. TCHAR title[128];
  247. if (!GetWindowText(PropSheet_GetCurrentPageHwnd(handle), title, sizeof(title)))
  248. _stprintf(title, _T("capture%d"), i);
  249. CharArray pageTitle(strDup(title));
  250. for (int j=0; j<strlen(pageTitle.buf); j++) {
  251. if (pageTitle.buf[j] == '/' || pageTitle.buf[j] == '\\' || pageTitle.buf[j] == ':')
  252. pageTitle.buf[j] = '-';
  253. }
  254. char filename[256];
  255. sprintf(filename, "%s\\%s.bmp", tmpdir, pageTitle.buf);
  256. vlog.debug("writing to %s", filename);
  257. saveBMP(filename, &fb);
  258. i++;
  259. }
  260. ReleaseDC(handle, dc);
  261. } else {
  262. #endif
  263. try {
  264. if (owner)
  265. EnableWindow(owner, FALSE);
  266. // Run the PropertySheet
  267. MSG msg;
  268. while (GetMessage(&msg, 0, 0, 0)) {
  269. if (!PropSheet_IsDialogMessage(handle, &msg))
  270. DispatchMessage(&msg);
  271. if (!PropSheet_GetCurrentPageHwnd(handle))
  272. break;
  273. }
  274. if (owner)
  275. EnableWindow(owner, TRUE);
  276. } catch (...) {
  277. if (owner)
  278. EnableWindow(owner, TRUE);
  279. throw;
  280. }
  281. #ifdef _DIALOG_CAPTURE
  282. }
  283. #endif
  284. plog.info("finished %p", handle);
  285. DestroyWindow(handle);
  286. handle = 0;
  287. alreadyShowing = false;
  288. // Clear up the pages' GDI objects
  289. for (pspi=pages.begin(); pspi!=pages.end(); pspi++)
  290. (*pspi)->setPropSheet(0);
  291. delete [] hpages; hpages = 0;
  292. return true;
  293. } catch (rdr::Exception&) {
  294. alreadyShowing = false;
  295. std::list<PropSheetPage*>::iterator pspi;
  296. for (pspi=pages.begin(); pspi!=pages.end(); pspi++)
  297. (*pspi)->setPropSheet(0);
  298. delete [] hpages; hpages = 0;
  299. throw;
  300. }
  301. }
  302. void PropSheet::reInitPages() {
  303. std::list<PropSheetPage*>::iterator pspi;
  304. for (pspi=pages.begin(); pspi!=pages.end(); pspi++) {
  305. if ((*pspi)->handle)
  306. (*pspi)->initDialog();
  307. }
  308. }
  309. bool PropSheet::commitPages() {
  310. bool result = true;
  311. std::list<PropSheetPage*>::iterator pspi;
  312. for (pspi=pages.begin(); pspi!=pages.end(); pspi++) {
  313. if ((*pspi)->handle)
  314. result = result && (*pspi)->onOk();
  315. }
  316. return result;
  317. }
  318. void PropSheetPage::setChanged(bool changed) {
  319. if (propSheet) {
  320. if (changed)
  321. PropSheet_Changed(propSheet->handle, handle);
  322. else
  323. PropSheet_UnChanged(propSheet->handle, handle);
  324. }
  325. }