|
|
1.1 ! root 1: /* ! 2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved. ! 3: ! 4: Governed by the TrueCrypt License 2.4 the full text of which is contained ! 5: in the file License.txt included in TrueCrypt binary and source code ! 6: distribution packages. ! 7: */ ! 8: ! 9: #include <wx/mimetype.h> ! 10: #include <wx/sckipc.h> ! 11: #include "System.h" ! 12: ! 13: #ifdef TC_UNIX ! 14: #include <signal.h> ! 15: #include <sys/utsname.h> ! 16: #include "Platform/Unix/Process.h" ! 17: #endif ! 18: ! 19: #include "Application.h" ! 20: #include "GraphicUserInterface.h" ! 21: #include "FatalErrorHandler.h" ! 22: #include "Forms/DeviceSelectionDialog.h" ! 23: #include "Forms/MainFrame.h" ! 24: #include "Forms/MountOptionsDialog.h" ! 25: ! 26: namespace TrueCrypt ! 27: { ! 28: GraphicUserInterface::GraphicUserInterface () : BackgroundMode (false), mMainFrame (nullptr) ! 29: { ! 30: #ifdef TC_UNIX ! 31: signal (SIGHUP, OnSignal); ! 32: signal (SIGINT, OnSignal); ! 33: signal (SIGQUIT, OnSignal); ! 34: signal (SIGTERM, OnSignal); ! 35: #endif ! 36: ! 37: #ifdef TC_MACOSX ! 38: wxApp::s_macHelpMenuTitleName = _("Help"); ! 39: #endif ! 40: } ! 41: ! 42: GraphicUserInterface::~GraphicUserInterface () ! 43: { ! 44: FatalErrorHandler::Deregister(); ! 45: ! 46: #ifdef TC_UNIX ! 47: signal (SIGHUP, SIG_DFL); ! 48: signal (SIGINT, SIG_DFL); ! 49: signal (SIGQUIT, SIG_DFL); ! 50: signal (SIGTERM, SIG_DFL); ! 51: #endif ! 52: } ! 53: ! 54: void GraphicUserInterface::AppendToListCtrl (wxListCtrl *listCtrl, const vector <wstring> &itemFields, int imageIndex, void *itemDataPtr) const ! 55: { ! 56: InsertToListCtrl (listCtrl, listCtrl->GetItemCount(), itemFields, imageIndex, itemDataPtr); ! 57: } ! 58: ! 59: wxMenuItem *GraphicUserInterface::AppendToMenu (wxMenu &menu, const wxString &label, wxEvtHandler *handler, wxObjectEventFunction handlerFunction, int itemId) const ! 60: { ! 61: wxMenuItem *item = new wxMenuItem (&menu, itemId, label); ! 62: menu.Append (item); ! 63: ! 64: if (handler) ! 65: handler->Connect (item->GetId(), wxEVT_COMMAND_MENU_SELECTED, handlerFunction); ! 66: ! 67: return item; ! 68: } ! 69: ! 70: bool GraphicUserInterface::AskYesNo (const wxString &message, bool defaultYes, bool warning) const ! 71: { ! 72: return ShowMessage (message, ! 73: wxYES_NO | (warning ? wxICON_EXCLAMATION : wxICON_QUESTION) | (defaultYes ? wxYES_DEFAULT : wxNO_DEFAULT) ! 74: ) == wxYES; ! 75: } ! 76: ! 77: void GraphicUserInterface::AutoDismountVolumes (VolumeInfoList mountedVolumes, bool alwaysForce) ! 78: { ! 79: size_t mountedVolumeCount = Core->GetMountedVolumes().size(); ! 80: try ! 81: { ! 82: wxBusyCursor busy; ! 83: DismountVolumes (mountedVolumes, alwaysForce ? true : GetPreferences().ForceAutoDismount, false); ! 84: } ! 85: catch (...) { } ! 86: ! 87: if (Core->GetMountedVolumes().size() < mountedVolumeCount) ! 88: OnVolumesAutoDismounted(); ! 89: } ! 90: ! 91: void GraphicUserInterface::BeginInteractiveBusyState (wxWindow *window) ! 92: { ! 93: static auto_ptr <wxCursor> arrowWaitCursor; ! 94: ! 95: if (arrowWaitCursor.get() == nullptr) ! 96: arrowWaitCursor.reset (new wxCursor (wxCURSOR_ARROWWAIT)); ! 97: ! 98: window->SetCursor (*arrowWaitCursor); ! 99: } ! 100: ! 101: void GraphicUserInterface::ChangePassword (shared_ptr <VolumePath> volumePath, shared_ptr <VolumePassword> password, shared_ptr <KeyfileList> keyfiles, shared_ptr <VolumePassword> newPassword, shared_ptr <KeyfileList> newKeyfiles) const ! 102: { ! 103: Gui->ShowError (_("This feature is currently supported only in text mode.")); ! 104: throw UserAbort (SRC_POS); ! 105: } ! 106: ! 107: void GraphicUserInterface::ClearListCtrlSelection (wxListCtrl *listCtrl) const ! 108: { ! 109: foreach (long item, GetListCtrlSelectedItems (listCtrl)) ! 110: listCtrl->SetItemState (item, 0, wxLIST_STATE_SELECTED); ! 111: } ! 112: ! 113: void GraphicUserInterface::DoShowError (const wxString &message) const ! 114: { ! 115: ShowMessage (message, wxOK | wxICON_ERROR); ! 116: } ! 117: ! 118: void GraphicUserInterface::DoShowInfo (const wxString &message) const ! 119: { ! 120: ShowMessage (message, wxOK | wxICON_INFORMATION); ! 121: } ! 122: ! 123: void GraphicUserInterface::DoShowString (const wxString &str) const ! 124: { ! 125: ShowMessage (str, wxOK); ! 126: } ! 127: ! 128: void GraphicUserInterface::DoShowWarning (const wxString &message) const ! 129: { ! 130: ShowMessage (message, wxOK ! 131: #ifndef TC_MACOSX ! 132: | wxICON_EXCLAMATION ! 133: #endif ! 134: ); ! 135: } ! 136: ! 137: void GraphicUserInterface::EndInteractiveBusyState (wxWindow *window) const ! 138: { ! 139: static auto_ptr <wxCursor> arrowCursor; ! 140: ! 141: if (arrowCursor.get() == nullptr) ! 142: arrowCursor.reset (new wxCursor (wxCURSOR_ARROW)); ! 143: ! 144: window->SetCursor (*arrowCursor); ! 145: } ! 146: ! 147: wxTopLevelWindow *GraphicUserInterface::GetActiveWindow () const ! 148: { ! 149: #ifdef TC_WINDOWS ! 150: return dynamic_cast <wxTopLevelWindow *> (wxGetActiveWindow()); ! 151: #endif ! 152: if (wxTopLevelWindows.size() == 1) ! 153: return dynamic_cast <wxTopLevelWindow *> (wxTopLevelWindows.front()); ! 154: ! 155: #ifdef __WXGTK__ ! 156: wxLongLong startTime = wxGetLocalTimeMillis(); ! 157: do ! 158: { ! 159: #endif ! 160: foreach (wxWindow *window, wxTopLevelWindows) ! 161: { ! 162: wxTopLevelWindow *topLevelWin = dynamic_cast <wxTopLevelWindow *> (window); ! 163: if (topLevelWin && topLevelWin->IsActive() && topLevelWin->IsShown()) ! 164: return topLevelWin; ! 165: } ! 166: #ifdef __WXGTK__ ! 167: Yield(); // GTK does a lot of operations asynchronously, which makes it prone to many race conditions ! 168: } while (wxGetLocalTimeMillis() - startTime < 500); ! 169: #endif ! 170: ! 171: return dynamic_cast <wxTopLevelWindow *> (GetTopWindow()); ! 172: } ! 173: ! 174: shared_ptr <GetStringFunctor> GraphicUserInterface::GetAdminPasswordRequestHandler () ! 175: { ! 176: struct AdminPasswordRequestHandler : public GetStringFunctor ! 177: { ! 178: virtual string operator() () ! 179: { ! 180: wxPasswordEntryDialog dialog (Gui->GetActiveWindow(), LangString["ENTER_PASSWORD"] + L":", _("Administrator privileges required")); ! 181: ! 182: if (dialog.ShowModal() != wxID_OK) ! 183: throw UserAbort (SRC_POS); ! 184: ! 185: return StringConverter::ToSingle (wstring (dialog.GetValue())); ! 186: } ! 187: }; ! 188: ! 189: return shared_ptr <GetStringFunctor> (new AdminPasswordRequestHandler); ! 190: } ! 191: ! 192: int GraphicUserInterface::GetCharHeight (wxWindow *window) const ! 193: { ! 194: int width; ! 195: int height; ! 196: window->GetTextExtent (L"a", &width, &height); ! 197: ! 198: if (height < 1) ! 199: return 14; ! 200: ! 201: return height; ! 202: } ! 203: ! 204: int GraphicUserInterface::GetCharWidth (wxWindow *window) const ! 205: { ! 206: int width; ! 207: int height; ! 208: window->GetTextExtent (L"a", &width, &height); ! 209: ! 210: if (width < 1) ! 211: return 7; ! 212: ! 213: return width; ! 214: } ! 215: ! 216: wxFont GraphicUserInterface::GetDefaultBoldFont (wxWindow *window) const ! 217: { ! 218: return wxFont ( ! 219: #ifdef __WXGTK__ ! 220: 9 ! 221: #elif defined(TC_MACOSX) ! 222: 13 ! 223: #else ! 224: 10 ! 225: #endif ! 226: * GetCharHeight (window) / 13, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, ! 227: #ifdef __WXGTK__ ! 228: wxFONTWEIGHT_BOLD, false); ! 229: #elif defined(TC_MACOSX) ! 230: wxFONTWEIGHT_NORMAL, false); ! 231: #else ! 232: wxFONTWEIGHT_BOLD, false, L"Arial"); ! 233: #endif ! 234: } ! 235: ! 236: list <long> GraphicUserInterface::GetListCtrlSelectedItems (wxListCtrl *listCtrl) const ! 237: { ! 238: list <long> selectedItems; ! 239: ! 240: long item = -1; ! 241: while ((item = listCtrl->GetNextItem (item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) != -1) ! 242: selectedItems.push_back (item); ! 243: ! 244: return selectedItems; ! 245: } ! 246: ! 247: wxString GraphicUserInterface::GetListCtrlSubItemText (wxListCtrl *listCtrl, long itemIndex, int columnIndex) const ! 248: { ! 249: wxListItem item; ! 250: item.SetId (itemIndex); ! 251: item.SetColumn (columnIndex); ! 252: item.SetText (L""); ! 253: ! 254: if (!listCtrl->GetItem (item)) ! 255: throw ParameterIncorrect (SRC_POS); ! 256: ! 257: return item.GetText(); ! 258: } ! 259: ! 260: int GraphicUserInterface::GetScrollbarWidth (wxWindow *window, bool noScrollBar) const ! 261: { ! 262: int offset = 0; ! 263: #ifdef TC_WINDOWS ! 264: offset = 4; ! 265: #elif defined (__WXGTK__) ! 266: offset = 5; ! 267: #elif defined (TC_MACOSX) ! 268: offset = 9; ! 269: #endif ! 270: if (noScrollBar) ! 271: return offset; ! 272: ! 273: int width = wxSystemSettings::GetMetric (wxSYS_VSCROLL_X, window); ! 274: if (width == -1) ! 275: return 24; ! 276: ! 277: return width + offset; ! 278: } ! 279: ! 280: ! 281: void GraphicUserInterface::InsertToListCtrl (wxListCtrl *listCtrl, long itemIndex, const vector <wstring> &itemFields, int imageIndex, void *itemDataPtr) const ! 282: { ! 283: wxListItem item; ! 284: item.SetData (itemDataPtr); ! 285: item.SetId (itemIndex); ! 286: item.SetImage (imageIndex); ! 287: int col = 0; ! 288: foreach (wxString field, itemFields) ! 289: { ! 290: item.SetColumn (col++); ! 291: item.SetText (field); ! 292: if (col == 1) ! 293: { ! 294: throw_sys_if (listCtrl->InsertItem (item) == -1); ! 295: item.SetImage (-1); ! 296: continue; ! 297: } ! 298: ! 299: listCtrl->SetItem (item); ! 300: } ! 301: } ! 302: ! 303: bool GraphicUserInterface::IsTheOnlyTopLevelWindow (const wxWindow *window) const ! 304: { ! 305: foreach (wxWindow *w, wxTopLevelWindows) ! 306: { ! 307: if (w != window ! 308: && (dynamic_cast <const wxFrame *> (w) || dynamic_cast <const wxDialog *> (w)) ! 309: && StringConverter::GetTypeName (typeid (*w)).find ("wxTaskBarIcon") == string::npos) ! 310: { ! 311: return false; ! 312: } ! 313: } ! 314: return true; ! 315: } ! 316: ! 317: void GraphicUserInterface::MoveListCtrlItem (wxListCtrl *listCtrl, long itemIndex, long newItemIndex) const ! 318: { ! 319: if (itemIndex == newItemIndex || newItemIndex < 0 ! 320: || (newItemIndex > itemIndex && newItemIndex == listCtrl->GetItemCount())) ! 321: return; ! 322: ! 323: wxListItem item; ! 324: item.SetId (itemIndex); ! 325: item.SetData ((void *) nullptr); ! 326: item.SetImage (-1); ! 327: ! 328: if (!listCtrl->GetItem (item)) ! 329: throw ParameterIncorrect (SRC_POS); ! 330: ! 331: int itemState = listCtrl->GetItemState (itemIndex, wxLIST_STATE_SELECTED); ! 332: ! 333: vector <wstring> itemFields (listCtrl->GetColumnCount()); ! 334: for (size_t col = 0; col < itemFields.size(); ++col) ! 335: { ! 336: itemFields[col] = GetListCtrlSubItemText (listCtrl, itemIndex, col); ! 337: } ! 338: ! 339: listCtrl->DeleteItem (itemIndex); ! 340: ! 341: if (newItemIndex > listCtrl->GetItemCount() - 1) ! 342: AppendToListCtrl (listCtrl, itemFields, item.GetImage(), (void *) item.GetData()); ! 343: else ! 344: InsertToListCtrl (listCtrl, newItemIndex, itemFields, item.GetImage(), (void *) item.GetData()); ! 345: ! 346: item.SetId (newItemIndex); ! 347: listCtrl->SetItemState (item, itemState, wxLIST_STATE_SELECTED); ! 348: } ! 349: ! 350: VolumeInfoList GraphicUserInterface::MountAllDeviceHostedVolumes (MountOptions &options) const ! 351: { ! 352: MountOptionsDialog dialog (GetTopWindow(), options); ! 353: while (true) ! 354: { ! 355: options.Path.reset(); ! 356: ! 357: if (dialog.ShowModal() != wxID_OK) ! 358: return VolumeInfoList(); ! 359: ! 360: VolumeInfoList mountedVolumes = UserInterface::MountAllDeviceHostedVolumes (options); ! 361: ! 362: if (!mountedVolumes.empty()) ! 363: return mountedVolumes; ! 364: } ! 365: } ! 366: ! 367: shared_ptr <VolumeInfo> GraphicUserInterface::MountVolume (MountOptions &options) const ! 368: { ! 369: shared_ptr <VolumeInfo> volume; ! 370: ! 371: if (Core->IsVolumeMounted (*options.Path)) ! 372: { ! 373: ShowInfo (StringFormatter (LangString["VOLUME_ALREADY_MOUNTED"], wstring (*options.Path))); ! 374: return volume; ! 375: } ! 376: ! 377: try ! 378: { ! 379: if ((!options.Password || options.Password->IsEmpty()) ! 380: && (!options.Keyfiles || options.Keyfiles->empty()) ! 381: && !Core->IsPasswordCacheEmpty()) ! 382: { ! 383: // Cached password ! 384: try ! 385: { ! 386: wxBusyCursor busy; ! 387: return UserInterface::MountVolume (options); ! 388: } ! 389: catch (PasswordException&) { } ! 390: } ! 391: ! 392: VolumePassword password; ! 393: KeyfileList keyfiles; ! 394: ! 395: MountOptionsDialog dialog (GetTopWindow(), options); ! 396: while (!volume) ! 397: { ! 398: dialog.Hide(); ! 399: if (dialog.ShowModal() != wxID_OK) ! 400: return volume; ! 401: ! 402: try ! 403: { ! 404: wxBusyCursor busy; ! 405: volume = UserInterface::MountVolume (options); ! 406: } ! 407: catch (PasswordException &e) ! 408: { ! 409: ShowWarning (e); ! 410: } ! 411: } ! 412: } ! 413: catch (exception &e) ! 414: { ! 415: ShowError (e); ! 416: } ! 417: ! 418: return volume; ! 419: } ! 420: ! 421: void GraphicUserInterface::OnAutoDismountAllEvent () ! 422: { ! 423: VolumeInfoList mountedVolumes = Core->GetMountedVolumes(); ! 424: ! 425: if (!mountedVolumes.empty()) ! 426: { ! 427: wxBusyCursor busy; ! 428: AutoDismountVolumes (mountedVolumes); ! 429: } ! 430: } ! 431: ! 432: bool GraphicUserInterface::OnInit () ! 433: { ! 434: Gui = this; ! 435: InterfaceType = UserInterfaceType::Graphic; ! 436: try ! 437: { ! 438: FatalErrorHandler::Register(); ! 439: Init(); ! 440: ! 441: if (ProcessCommandLine() && !CmdLine->StartBackgroundTask) ! 442: { ! 443: Yield(); ! 444: Application::SetExitCode (0); ! 445: return false; ! 446: } ! 447: ! 448: // Check if another instance is already running and bring its windows to foreground ! 449: #ifndef TC_MACOSX ! 450: #ifdef TC_WINDOWS ! 451: const wxString serverName = Application::GetName() + L"-" + wxGetUserId(); ! 452: class Connection : public wxDDEConnection ! 453: { ! 454: public: ! 455: Connection () { } ! 456: ! 457: bool OnExecute (const wxString& topic, wxChar *data, int size, wxIPCFormat format) ! 458: { ! 459: if (topic == L"raise") ! 460: { ! 461: if (Gui->IsInBackgroundMode()) ! 462: Gui->SetBackgroundMode (false); ! 463: ! 464: Gui->mMainFrame->Show (true); ! 465: Gui->mMainFrame->Raise (); ! 466: return true; ! 467: } ! 468: return false; ! 469: } ! 470: }; ! 471: #endif ! 472: ! 473: SingleInstanceChecker.reset (new wxSingleInstanceChecker (wxString (L".") + Application::GetName() + L"-lock-" + wxGetUserId())); ! 474: ! 475: if (SingleInstanceChecker->IsAnotherRunning()) ! 476: { ! 477: #ifdef TC_WINDOWS ! 478: class Client: public wxDDEClient ! 479: { ! 480: public: ! 481: Client() {}; ! 482: wxConnectionBase *OnMakeConnection () { return new Connection; } ! 483: }; ! 484: ! 485: auto_ptr <wxDDEClient> client (new Client); ! 486: auto_ptr <wxConnectionBase> connection (client->MakeConnection (L"localhost", serverName, L"raise")); ! 487: ! 488: if (connection.get() && connection->Execute (nullptr)) ! 489: { ! 490: connection->Disconnect(); ! 491: Application::SetExitCode (0); ! 492: return false; ! 493: } ! 494: #endif ! 495: wxLog::FlushActive(); ! 496: Application::SetExitCode (1); ! 497: Gui->ShowInfo (_("TrueCrypt is already running.")); ! 498: return false; ! 499: } ! 500: ! 501: #ifdef TC_WINDOWS ! 502: class Server : public wxDDEServer ! 503: { ! 504: public: ! 505: wxConnectionBase *OnAcceptConnection (const wxString &topic) ! 506: { ! 507: if (topic == L"raise") ! 508: return new Connection; ! 509: return nullptr; ! 510: } ! 511: }; ! 512: ! 513: DDEServer.reset (new Server); ! 514: if (!DDEServer->Create (serverName)) ! 515: wxLog::FlushActive(); ! 516: #endif ! 517: #endif // !TC_MACOSX ! 518: ! 519: Connect (wxEVT_END_SESSION, wxCloseEventHandler (GraphicUserInterface::OnEndSession)); ! 520: #ifdef wxHAS_POWER_EVENTS ! 521: Gui->Connect (wxEVT_POWER_SUSPENDING, wxPowerEventHandler (GraphicUserInterface::OnPowerSuspending)); ! 522: #endif ! 523: ! 524: mMainFrame = new MainFrame (nullptr); ! 525: ! 526: if (CmdLine->StartBackgroundTask) ! 527: { ! 528: UserPreferences prefs = GetPreferences (); ! 529: prefs.BackgroundTaskEnabled = true; ! 530: SetPreferences (prefs); ! 531: mMainFrame->Close(); ! 532: } ! 533: else ! 534: { ! 535: mMainFrame->Show (true); ! 536: } ! 537: ! 538: SetTopWindow (mMainFrame); ! 539: } ! 540: catch (exception &e) ! 541: { ! 542: ShowError (e); ! 543: return false; ! 544: } ! 545: ! 546: return true; ! 547: } ! 548: ! 549: void GraphicUserInterface::OnLogOff () ! 550: { ! 551: VolumeInfoList mountedVolumes = Core->GetMountedVolumes(); ! 552: if (GetPreferences().BackgroundTaskEnabled && GetPreferences().DismountOnLogOff ! 553: && !mountedVolumes.empty()) ! 554: { ! 555: wxLongLong startTime = wxGetLocalTimeMillis(); ! 556: bool timeOver = false; ! 557: ! 558: wxBusyCursor busy; ! 559: while (!timeOver && !mountedVolumes.empty()) ! 560: { ! 561: try ! 562: { ! 563: timeOver = (wxGetLocalTimeMillis() - startTime >= 4000); ! 564: ! 565: DismountVolumes (mountedVolumes, !timeOver ? false : GetPreferences().ForceAutoDismount, timeOver); ! 566: OnVolumesAutoDismounted(); ! 567: ! 568: break; ! 569: } ! 570: catch (UserAbort&) ! 571: { ! 572: return; ! 573: } ! 574: catch (...) ! 575: { ! 576: Thread::Sleep (500); ! 577: } ! 578: ! 579: VolumeInfoList mountedVolumes = Core->GetMountedVolumes(); ! 580: } ! 581: ! 582: } ! 583: } ! 584: ! 585: #ifdef wxHAS_POWER_EVENTS ! 586: void GraphicUserInterface::OnPowerSuspending (wxPowerEvent& event) ! 587: { ! 588: size_t volumeCount = Core->GetMountedVolumes().size(); ! 589: if (GetPreferences().BackgroundTaskEnabled && GetPreferences().DismountOnPowerSaving && volumeCount > 0) ! 590: { ! 591: OnAutoDismountAllEvent(); ! 592: ! 593: if (Core->GetMountedVolumes().size() < volumeCount) ! 594: ShowInfoTopMost (LangString["MOUNTED_VOLUMES_AUTO_DISMOUNTED"]); ! 595: } ! 596: } ! 597: #endif ! 598: ! 599: void GraphicUserInterface::OnSignal (int signal) ! 600: { ! 601: #ifdef TC_UNIX ! 602: Gui->SingleInstanceChecker.reset(); ! 603: _exit (1); ! 604: #endif ! 605: } ! 606: ! 607: void GraphicUserInterface::OnVolumesAutoDismounted () ! 608: { ! 609: if (GetPreferences().WipeCacheOnAutoDismount) ! 610: Core->WipePasswordCache(); ! 611: } ! 612: ! 613: void GraphicUserInterface::OpenDocument (wxWindow *parent, const wxFileName &document) ! 614: { ! 615: ! 616: #ifdef TC_WINDOWS ! 617: ! 618: if (int (ShellExecute (GetTopWindow() ? static_cast <HWND> (GetTopWindow()->GetHandle()) : nullptr, L"open", ! 619: document.GetFullPath().c_str(), nullptr, nullptr, SW_SHOWNORMAL)) >= 32) ! 620: return; ! 621: ! 622: #else ! 623: wxMimeTypesManager mimeMgr; ! 624: wxFileType *fileType = mimeMgr.GetFileTypeFromExtension (document.GetExt()); ! 625: if (fileType) ! 626: { ! 627: try ! 628: { ! 629: #ifdef TC_MACOSX ! 630: if (wxExecute (fileType->GetOpenCommand (document.GetFullPath())) != 0) ! 631: return; ! 632: #else ! 633: if (wxExecute (fileType->GetOpenCommand (L"\"" + document.GetFullPath() + L"\"")) != 0) ! 634: return; ! 635: #endif ! 636: } ! 637: catch (TimeOut&) ! 638: { ! 639: return; ! 640: } ! 641: catch (Exception &e) ! 642: { ! 643: Gui->ShowError (e); ! 644: } ! 645: } ! 646: #endif ! 647: if (Gui->AskYesNo (LangString ["HELP_READER_ERROR"])) ! 648: OpenOnlineHelp (parent); ! 649: } ! 650: ! 651: wxString GraphicUserInterface::GetHomepageLinkURL (const wxString &linkId, const wxString &extraVars) const ! 652: { ! 653: wxString url = wxString (L"http://www.truecrypt.org/applink.php?version=4.3a&dest=") + linkId; ! 654: ! 655: wxString os, osVersion, architecture; ! 656: ! 657: #ifdef TC_WINDOWS ! 658: ! 659: os = L"Windows"; ! 660: ! 661: #elif defined (TC_UNIX) ! 662: struct utsname unameData; ! 663: if (uname (&unameData) != -1) ! 664: { ! 665: os = StringConverter::ToWide (unameData.sysname); ! 666: osVersion = StringConverter::ToWide (unameData.release); ! 667: architecture = StringConverter::ToWide (unameData.machine); ! 668: //os = L"MacOSX"; ! 669: ! 670: if (os == L"Darwin") ! 671: os = L"MacOSX"; ! 672: } ! 673: else ! 674: os = L"Unknown"; ! 675: #else ! 676: os = L"Unknown"; ! 677: #endif ! 678: ! 679: os.Replace (L" ", L"-"); ! 680: url += L"&os="; ! 681: url += os; ! 682: ! 683: osVersion.Replace (L" ", L"-"); ! 684: url += L"&osver="; ! 685: url += osVersion; ! 686: ! 687: architecture.Replace (L" ", L"-"); ! 688: url += L"&arch="; ! 689: url += architecture; ! 690: ! 691: if (!extraVars.empty()) ! 692: { ! 693: url += L"&"; ! 694: url += extraVars; ! 695: } ! 696: ! 697: return url; ! 698: } ! 699: ! 700: void GraphicUserInterface::OpenHomepageLink (wxWindow *parent, const wxString &linkId, const wxString &extraVars) ! 701: { ! 702: wxString url; ! 703: ! 704: BeginInteractiveBusyState (parent); ! 705: wxLaunchDefaultBrowser (GetHomepageLinkURL (linkId, extraVars), wxBROWSER_NEW_WINDOW); ! 706: Thread::Sleep (200); ! 707: EndInteractiveBusyState (parent); ! 708: } ! 709: ! 710: void GraphicUserInterface::OpenOnlineHelp (wxWindow *parent) ! 711: { ! 712: OpenHomepageLink (parent, L"help"); ! 713: } ! 714: ! 715: void GraphicUserInterface::OpenUserGuide (wxWindow *parent) ! 716: { ! 717: try ! 718: { ! 719: wxString docPath = wstring (Application::GetExecutableDirectory()); ! 720: ! 721: #ifdef TC_WINDOWS ! 722: docPath += L"\\TrueCrypt User Guide.pdf"; ! 723: #elif defined (TC_MACOSX) ! 724: docPath += L"/../Resources/TrueCrypt User Guide.pdf"; ! 725: #elif defined (TC_UNIX) ! 726: docPath = L"/usr/share/truecrypt/doc/TrueCrypt User Guide.pdf"; ! 727: #endif ! 728: ! 729: wxFileName docFile = docPath; ! 730: docFile.Normalize(); ! 731: Gui->OpenDocument (parent, docFile); ! 732: } ! 733: catch (Exception &e) ! 734: { ! 735: Gui->ShowError (e); ! 736: } ! 737: } ! 738: ! 739: DevicePath GraphicUserInterface::SelectDevice (wxWindow *parent) const ! 740: { ! 741: try ! 742: { ! 743: DeviceSelectionDialog dialog (parent); ! 744: if (dialog.ShowModal() == wxID_OK) ! 745: { ! 746: return dialog.SelectedDevice.Path; ! 747: } ! 748: } ! 749: catch (exception &e) ! 750: { ! 751: Gui->ShowError (e); ! 752: } ! 753: ! 754: return DevicePath(); ! 755: } ! 756: ! 757: DirectoryPath GraphicUserInterface::SelectDirectory (wxWindow *parent, const wxString &message, bool existingOnly) const ! 758: { ! 759: return DirectoryPath (::wxDirSelector (!message.empty() ? message : ! 760: #ifdef __WXGTK__ ! 761: wxDirSelectorPromptStr, ! 762: #else ! 763: L"", ! 764: #endif ! 765: L"", wxDD_DEFAULT_STYLE | (existingOnly ? wxDD_DIR_MUST_EXIST : 0), wxDefaultPosition, parent)); ! 766: } ! 767: ! 768: FilePathList GraphicUserInterface::SelectFiles (wxWindow *parent, const wxString &caption, bool saveMode, bool allowMultiple, const list < pair <wstring, wstring> > &fileExtensions, const DirectoryPath &directory) const ! 769: { ! 770: FilePathList files; ! 771: ! 772: long style; ! 773: if (saveMode) ! 774: style = wxFD_SAVE | wxFD_OVERWRITE_PROMPT; ! 775: else ! 776: style = wxFD_OPEN | wxFD_FILE_MUST_EXIST | (allowMultiple ? wxFD_MULTIPLE : 0); ! 777: ! 778: wxString wildcards = L"*.*"; ! 779: ! 780: #ifndef __WXGTK__ ! 781: if (!fileExtensions.empty()) ! 782: #endif ! 783: { ! 784: wildcards = LangString["ALL_FILES"] + ! 785: #ifdef TC_WINDOWS ! 786: L" (*.*)|*.*"; ! 787: #else ! 788: L"|*"; ! 789: #endif ! 790: typedef pair <wstring, wstring> StringPair; ! 791: foreach (StringPair p, fileExtensions) ! 792: { ! 793: wildcards += wxString (L"|") + p.second + L" (*." + p.first + L")|*." + p.first; ! 794: } ! 795: } ! 796: ! 797: wxFileDialog dialog (parent, caption, wstring (directory), wxString(), wildcards, style); ! 798: ! 799: if (dialog.ShowModal() == wxID_OK) ! 800: { ! 801: if (!allowMultiple) ! 802: files.push_back (make_shared <FilePath> (dialog.GetPath())); ! 803: else ! 804: { ! 805: wxArrayString paths; ! 806: dialog.GetPaths (paths); ! 807: ! 808: foreach (const wxString &path, paths) ! 809: files.push_back (make_shared <FilePath> (path)); ! 810: } ! 811: } ! 812: ! 813: return files; ! 814: } ! 815: ! 816: FilePath GraphicUserInterface::SelectVolumeFile (wxWindow *parent, bool saveMode, const DirectoryPath &directory) const ! 817: { ! 818: list < pair <wstring, wstring> > extensions; ! 819: extensions.push_back (make_pair (L"tc", LangString["TC_VOLUMES"])); ! 820: ! 821: FilePathList selFiles = Gui->SelectFiles (parent, LangString[saveMode ? "OPEN_NEW_VOLUME" : "OPEN_VOL_TITLE"], saveMode, false, extensions, directory); ! 822: ! 823: if (!selFiles.empty()) ! 824: return *selFiles.front(); ! 825: else ! 826: return FilePath(); ! 827: } ! 828: ! 829: void GraphicUserInterface::SetBackgroundMode (bool state) ! 830: { ! 831: #ifdef TC_MACOSX ! 832: // Hiding an iconized window on OS X apparently cannot be reversed ! 833: if (state && mMainFrame->IsIconized()) ! 834: mMainFrame->Iconize (false); ! 835: #endif ! 836: mMainFrame->Show (!state); ! 837: if (!state) ! 838: { ! 839: if (mMainFrame->IsIconized()) ! 840: mMainFrame->Iconize (false); ! 841: ! 842: mMainFrame->Raise(); ! 843: } ! 844: ! 845: BackgroundMode = state; ! 846: } ! 847: ! 848: void GraphicUserInterface::SetListCtrlColumnWidths (wxListCtrl *listCtrl, list <int> columnWidthPermilles, bool hasVerticalScrollbar) const ! 849: { ! 850: #ifdef TC_MACOSX ! 851: hasVerticalScrollbar = true; ! 852: #endif ! 853: int listWidth = listCtrl->GetSize().GetWidth(); ! 854: int minListWidth = listCtrl->GetMinSize().GetWidth(); ! 855: if (minListWidth > listWidth) ! 856: listWidth = minListWidth; ! 857: ! 858: listWidth -= GetScrollbarWidth (listCtrl, !hasVerticalScrollbar); ! 859: ! 860: int col = 0; ! 861: int totalColWidth = 0; ! 862: foreach (int colWidth, columnWidthPermilles) ! 863: { ! 864: int width = listWidth * colWidth / 1000; ! 865: totalColWidth += width; ! 866: ! 867: if (col == listCtrl->GetColumnCount() - 1) ! 868: width += listWidth - totalColWidth; ! 869: ! 870: listCtrl->SetColumnWidth (col++, width); ! 871: } ! 872: } ! 873: ! 874: void GraphicUserInterface::SetListCtrlHeight (wxListCtrl *listCtrl, size_t rowCount) const ! 875: { ! 876: wxRect itemRect; ! 877: if (listCtrl->GetItemCount() == 0) ! 878: { ! 879: bool addedCols = false; ! 880: if (listCtrl->GetColumnCount() == 0) ! 881: { ! 882: listCtrl->InsertColumn (0, L".", wxLIST_FORMAT_LEFT, 1); ! 883: addedCols = true; ! 884: } ! 885: vector <wstring> f; ! 886: f.push_back (L"."); ! 887: AppendToListCtrl (listCtrl, f); ! 888: listCtrl->GetItemRect (0, itemRect); ! 889: ! 890: if (addedCols) ! 891: listCtrl->ClearAll(); ! 892: else ! 893: listCtrl->DeleteAllItems(); ! 894: } ! 895: else ! 896: listCtrl->GetItemRect (0, itemRect); ! 897: ! 898: int headerHeight = itemRect.y; ! 899: #ifdef TC_WINDOWS ! 900: headerHeight += 4; ! 901: #elif defined (TC_MACOSX) ! 902: headerHeight += 7; ! 903: #elif defined (__WXGTK__) ! 904: headerHeight += 5; ! 905: #endif ! 906: int rowHeight = itemRect.height; ! 907: #ifdef TC_MACOSX ! 908: rowHeight += 1; ! 909: #endif ! 910: listCtrl->SetMinSize (wxSize (listCtrl->GetMinSize().GetWidth(), rowHeight * rowCount + headerHeight)); ! 911: } ! 912: ! 913: void GraphicUserInterface::SetListCtrlWidth (wxListCtrl *listCtrl, size_t charCount, bool hasVerticalScrollbar) const ! 914: { ! 915: int width = GetCharWidth (listCtrl) * charCount; ! 916: #ifdef TC_MACOSX ! 917: if (!hasVerticalScrollbar) ! 918: width += GetScrollbarWidth (listCtrl); ! 919: #endif ! 920: listCtrl->SetMinSize (wxSize (width, listCtrl->GetMinSize().GetHeight())); ! 921: } ! 922: ! 923: void GraphicUserInterface::ShowErrorTopMost (const wxString &message) const ! 924: { ! 925: ShowMessage (message, wxOK | wxICON_ERROR, true); ! 926: } ! 927: ! 928: void GraphicUserInterface::ShowInfoTopMost (const wxString &message) const ! 929: { ! 930: ShowMessage (message, wxOK | wxICON_INFORMATION, true); ! 931: } ! 932: ! 933: int GraphicUserInterface::ShowMessage (const wxString &message, long style, bool topMost) const ! 934: { ! 935: wxString caption = Application::GetName(); ! 936: wxString subMessage = message; ! 937: ! 938: #ifdef TC_MACOSX ! 939: size_t p = message.find (L"\n"); ! 940: if (p != string::npos) ! 941: { ! 942: // Divide message to caption and info message ! 943: caption = message.substr (0, p); ! 944: ! 945: p = message.find_first_not_of (L'\n', p); ! 946: if (p != string::npos) ! 947: subMessage = message.substr (p); ! 948: else ! 949: subMessage.clear(); ! 950: ! 951: if (subMessage.EndsWith (L"?")) ! 952: { ! 953: // Move question to caption ! 954: caption += wstring (L" "); ! 955: p = subMessage.find_last_of (L".\n"); ! 956: if (p != string::npos) ! 957: { ! 958: if (caption.EndsWith (L": ")) ! 959: caption[caption.size() - 2] = L'.'; ! 960: ! 961: caption += subMessage.substr (subMessage.find_first_not_of (L"\n ", p + 1)); ! 962: subMessage = subMessage.substr (0, p + 1); ! 963: } ! 964: else ! 965: { ! 966: caption += subMessage.substr (subMessage.find_first_not_of (L"\n")); ! 967: subMessage.clear(); ! 968: } ! 969: } ! 970: } ! 971: else if (message.size() < 160) ! 972: { ! 973: caption = message; ! 974: subMessage.clear(); ! 975: } ! 976: else ! 977: { ! 978: if (style & wxICON_EXCLAMATION) ! 979: caption = wxString (_("Warning")) + L':'; ! 980: else if (style & wxICON_ERROR || style & wxICON_HAND) ! 981: caption = wxString (_("Error")) + L':'; ! 982: else ! 983: caption.clear(); ! 984: } ! 985: #endif ! 986: if (topMost) ! 987: { ! 988: if (!IsActive()) ! 989: mMainFrame->RequestUserAttention (wxUSER_ATTENTION_ERROR); ! 990: ! 991: style |= wxSTAY_ON_TOP; ! 992: } ! 993: ! 994: return wxMessageBox (subMessage, caption, style, GetActiveWindow()); ! 995: } ! 996: ! 997: void GraphicUserInterface::ShowWarningTopMost (const wxString &message) const ! 998: { ! 999: ShowMessage (message, wxOK ! 1000: #ifndef TC_MACOSX ! 1001: | wxICON_EXCLAMATION ! 1002: #endif ! 1003: , true); ! 1004: } ! 1005: ! 1006: bool GraphicUserInterface::UpdateListCtrlItem (wxListCtrl *listCtrl, long itemIndex, const vector <wstring> &itemFields) const ! 1007: { ! 1008: bool changed = false; ! 1009: wxListItem item; ! 1010: item.SetId (itemIndex); ! 1011: item.SetText (L""); ! 1012: ! 1013: int col = 0; ! 1014: foreach (wxString field, itemFields) ! 1015: { ! 1016: item.SetColumn (col++); ! 1017: ! 1018: if (!listCtrl->GetItem (item)) ! 1019: throw ParameterIncorrect (SRC_POS); ! 1020: ! 1021: if (item.GetText() != field) ! 1022: { ! 1023: item.SetText (field); ! 1024: listCtrl->SetItem (item); ! 1025: changed = true; ! 1026: } ! 1027: } ! 1028: return changed; ! 1029: } ! 1030: ! 1031: void GraphicUserInterface::Yield () const ! 1032: { ! 1033: #ifndef TC_WINDOWS ! 1034: wxSafeYield (nullptr, true); ! 1035: #endif ! 1036: } ! 1037: ! 1038: DEFINE_EVENT_TYPE (TC_EVENT_THREAD_EXITING); ! 1039: ! 1040: GraphicUserInterface *Gui = nullptr; ! 1041: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.