701 lines
24 KiB
C++
701 lines
24 KiB
C++
|
/*
|
||
|
* Copyright (c) 2005 Alexander Gottwald
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
* copy of this software and associated documentation files (the "Software"),
|
||
|
* to deal in the Software without restriction, including without limitation
|
||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||
|
* Software is furnished to do so, subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included in
|
||
|
* all copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
* THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
* DEALINGS IN THE SOFTWARE.
|
||
|
*
|
||
|
* Except as contained in this notice, the name(s) of the above copyright
|
||
|
* holders shall not be used in advertising or otherwise to promote the sale,
|
||
|
* use or other dealings in this Software without prior written authorization.
|
||
|
*/
|
||
|
#include "window/util.h"
|
||
|
#include "window/wizard.h"
|
||
|
#include "resources/resources.h"
|
||
|
#include "config.h"
|
||
|
#include <prsht.h>
|
||
|
#include <commctrl.h>
|
||
|
|
||
|
#include <stdexcept>
|
||
|
|
||
|
#include <X11/Xlib.h>
|
||
|
|
||
|
/// @brief Send WM_ENDSESSION to all program windows.
|
||
|
/// This will shutdown the started xserver
|
||
|
BOOL CALLBACK KillWindowsProc(HWND hwnd, LPARAM lParam)
|
||
|
{
|
||
|
SendMessage(hwnd, WM_ENDSESSION, 0, 0);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/// @brief Actual wizard implementation.
|
||
|
/// This is based on generic CWizard but handles the special dialogs
|
||
|
class CMyWizard : public CWizard
|
||
|
{
|
||
|
public:
|
||
|
private:
|
||
|
CConfig config; /// Storage for config options.
|
||
|
public:
|
||
|
/// @brief Constructor.
|
||
|
/// Set wizard pages.
|
||
|
CMyWizard() : CWizard()
|
||
|
{
|
||
|
AddPage(IDD_DISPLAY, IDS_DISPLAY_TITLE, IDS_DISPLAY_SUBTITLE);
|
||
|
AddPage(IDD_CLIENTS, IDS_CLIENTS_TITLE, IDS_CLIENTS_SUBTITLE);
|
||
|
AddPage(IDD_PROGRAM, IDS_PROGRAM_TITLE, IDS_PROGRAM_SUBTITLE);
|
||
|
AddPage(IDD_XDMCP, IDS_XDMCP_TITLE, IDS_XDMCP_SUBTITLE);
|
||
|
//AddPage(IDD_FONTPATH, IDS_FONTPATH_TITLE, IDS_FONTPATH_SUBTITLE);
|
||
|
AddPage(IDD_CLIPBOARD, IDS_CLIPBOARD_TITLE, IDS_CLIPBOARD_SUBTITLE);
|
||
|
AddPage(IDD_FINISH, IDS_FINISH_TITLE, IDS_FINISH_SUBTITLE);
|
||
|
}
|
||
|
|
||
|
virtual void LoadConfig(const char *filename)
|
||
|
{
|
||
|
try {
|
||
|
config.Load(filename);
|
||
|
} catch (std::runtime_error &e)
|
||
|
{
|
||
|
printf("Fehler: %s\n", e.what());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// @brief Handle the PSN_WIZNEXT message.
|
||
|
/// @param hwndDlg Handle to active page dialog.
|
||
|
/// @param index Index of current page.
|
||
|
/// @return TRUE if the message was handled. FALSE otherwise.
|
||
|
virtual BOOL WizardNext(HWND hwndDlg, unsigned index)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
printf("%s %d\n", __FUNCTION__, index);
|
||
|
#endif
|
||
|
switch (PageID(index))
|
||
|
{
|
||
|
case IDD_DISPLAY:
|
||
|
// Check for select window mode
|
||
|
if (IsDlgButtonChecked(hwndDlg, IDC_MULTIWINDOW))
|
||
|
config.window = CConfig::MultiWindow;
|
||
|
else if (IsDlgButtonChecked(hwndDlg, IDC_FULLSCREEN))
|
||
|
config.window = CConfig::Fullscreen;
|
||
|
else if (IsDlgButtonChecked(hwndDlg, IDC_WINDOWED))
|
||
|
config.window = CConfig::Windowed;
|
||
|
else if (IsDlgButtonChecked(hwndDlg, IDC_NODECORATION))
|
||
|
config.window = CConfig::Nodecoration;
|
||
|
else
|
||
|
{
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
|
||
|
return TRUE;
|
||
|
}
|
||
|
// Get selected display number
|
||
|
{
|
||
|
char buffer[512];
|
||
|
GetDlgItemText(hwndDlg, IDC_DISPLAY, buffer, 512);
|
||
|
buffer[511] = 0;
|
||
|
config.display = buffer;
|
||
|
}
|
||
|
// Check for valid input
|
||
|
if (config.display.empty())
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
|
||
|
else
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIENTS);
|
||
|
return TRUE;
|
||
|
case IDD_CLIENTS:
|
||
|
// Check for select client startup method
|
||
|
if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT))
|
||
|
{
|
||
|
config.client = CConfig::StartProgram;
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_PROGRAM);
|
||
|
} else if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP))
|
||
|
{
|
||
|
config.client = CConfig::XDMCP;
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_XDMCP);
|
||
|
} else if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT_NONE))
|
||
|
{
|
||
|
config.client = CConfig::NoClient;
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIPBOARD);
|
||
|
} else
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
|
||
|
return TRUE;
|
||
|
case IDD_PROGRAM:
|
||
|
// Check wether local or remote client should be started
|
||
|
if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT_LOCAL))
|
||
|
config.local = true;
|
||
|
else if (IsDlgButtonChecked(hwndDlg, IDC_CLIENT_REMOTE))
|
||
|
config.local = false;
|
||
|
else
|
||
|
{
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
|
||
|
return TRUE;
|
||
|
}
|
||
|
// Read program, user and host name
|
||
|
{
|
||
|
char buffer[512];
|
||
|
GetDlgItemText(hwndDlg, IDC_CLIENT_USER, buffer, 512);
|
||
|
buffer[511] = 0;
|
||
|
config.user = buffer;
|
||
|
GetDlgItemText(hwndDlg, IDC_CLIENT_HOST, buffer, 512);
|
||
|
buffer[511] = 0;
|
||
|
config.host = buffer;
|
||
|
GetDlgItemText(hwndDlg, IDC_CLIENT_PROGRAM, buffer, 512);
|
||
|
buffer[511] = 0;
|
||
|
config.program = buffer;
|
||
|
}
|
||
|
// Check for valid input
|
||
|
if (!config.local && (config.host.empty() || config.program.empty()))
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
|
||
|
else
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIPBOARD);
|
||
|
return TRUE;
|
||
|
case IDD_XDMCP:
|
||
|
// Check for broadcast
|
||
|
if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP_BROADCAST))
|
||
|
config.broadcast = true;
|
||
|
else if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP_QUERY))
|
||
|
config.broadcast = false;
|
||
|
else
|
||
|
{
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
|
||
|
return TRUE;
|
||
|
}
|
||
|
// Check for indirect mode
|
||
|
if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP_INDIRECT))
|
||
|
config.indirect = true;
|
||
|
else
|
||
|
config.indirect = false;
|
||
|
// Read hostname
|
||
|
{
|
||
|
char buffer[512];
|
||
|
GetDlgItemText(hwndDlg, IDC_XDMCP_HOST, buffer, 512);
|
||
|
buffer[511] = 0;
|
||
|
config.xdmcp_host = buffer;
|
||
|
}
|
||
|
// Check for valid input
|
||
|
if (!config.broadcast && config.xdmcp_host.empty())
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
|
||
|
else
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIPBOARD);
|
||
|
return TRUE;
|
||
|
case IDD_CLIPBOARD:
|
||
|
// check for clipboard
|
||
|
if (IsDlgButtonChecked(hwndDlg, IDC_CLIPBOARD))
|
||
|
config.clipboard = true;
|
||
|
else
|
||
|
config.clipboard = false;
|
||
|
// read parameters
|
||
|
{
|
||
|
char buffer[512];
|
||
|
GetDlgItemText(hwndDlg, IDC_EXTRA_PARAMS, buffer, 512);
|
||
|
buffer[511] = 0;
|
||
|
config.extra_params = buffer;
|
||
|
}
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_FINISH);
|
||
|
return TRUE;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
/// @brief Handle PSN_WIZFINISH message.
|
||
|
/// @param hwndDlg Handle to active page dialog.
|
||
|
/// @param index Index of current page.
|
||
|
/// @return TRUE if the message was handled. FALSE otherwise.
|
||
|
virtual BOOL WizardFinish(HWND hwndDlg, unsigned index)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
printf("finish %d\n", index);
|
||
|
#endif
|
||
|
return FALSE;
|
||
|
}
|
||
|
/// @brief Handle PSN_WIZBACK message.
|
||
|
/// Basicly handles switching to proper page (skipping XDMCP or program page
|
||
|
/// if required).
|
||
|
/// @param hwndDlg Handle to active page dialog.
|
||
|
/// @param index Index of current page.
|
||
|
/// @return TRUE if the message was handled. FALSE otherwise.
|
||
|
virtual BOOL WizardBack(HWND hwndDlg, unsigned index)
|
||
|
{
|
||
|
switch (PageID(index))
|
||
|
{
|
||
|
case IDD_PROGRAM:
|
||
|
case IDD_XDMCP:
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIENTS);
|
||
|
return TRUE;
|
||
|
case IDD_FONTPATH:
|
||
|
case IDD_CLIPBOARD: // temporary. fontpath is disabled
|
||
|
switch (config.client)
|
||
|
{
|
||
|
case CConfig::NoClient:
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIENTS);
|
||
|
return TRUE;
|
||
|
case CConfig::StartProgram:
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_PROGRAM);
|
||
|
return TRUE;
|
||
|
case CConfig::XDMCP:
|
||
|
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_XDMCP);
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
/// @brief Handle PSN_SETACTIVE message.
|
||
|
/// @param hwndDlg Handle to active page dialog.
|
||
|
/// @param index Index of current page.
|
||
|
/// @return TRUE if the message was handled. FALSE otherwise.
|
||
|
virtual BOOL WizardActivate(HWND hwndDlg, unsigned index)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
printf("%s %d\n", __FUNCTION__, index);
|
||
|
#endif
|
||
|
switch (PageID(index))
|
||
|
{
|
||
|
case IDD_CLIENTS:
|
||
|
// Enable or disable XDMCP radiobutton and text
|
||
|
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP), config.window != CConfig::MultiWindow);
|
||
|
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_DESC), config.window != CConfig::MultiWindow);
|
||
|
break;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
protected:
|
||
|
/// @brief Enable or disable the control for remote clients.
|
||
|
/// @param hwndDlg Handle to active page dialog.
|
||
|
/// @param state State of control group.
|
||
|
void EnableRemoteProgramGroup(HWND hwndDlg, BOOL state)
|
||
|
{
|
||
|
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_PROTOCOL), state);
|
||
|
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_HOST), state);
|
||
|
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_USER), state);
|
||
|
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_PROTOCOL_DESC), state);
|
||
|
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_HOST_DESC), state);
|
||
|
EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_USER_DESC), state);
|
||
|
}
|
||
|
/// @brief Enable or disable the control for XDMCP connection.
|
||
|
/// @param hwndDlg Handle to active page dialog.
|
||
|
/// @param state State of control group.
|
||
|
void EnableXDMCPQueryGroup(HWND hwndDlg, BOOL state)
|
||
|
{
|
||
|
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_HOST), state);
|
||
|
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_INDIRECT), state);
|
||
|
}
|
||
|
/// @brief Fill program box with default values.
|
||
|
/// @param hwndDlg Handle to active page dialog.
|
||
|
void FillProgramBox(HWND hwndDlg)
|
||
|
{
|
||
|
HWND cbwnd = GetDlgItem(hwndDlg, IDC_CLIENT_PROGRAM);
|
||
|
if (cbwnd == NULL)
|
||
|
return;
|
||
|
SendMessage(cbwnd, CB_RESETCONTENT, 0, 0);
|
||
|
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "xterm");
|
||
|
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "startkde");
|
||
|
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "gnome-session");
|
||
|
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) ".xinitrc");
|
||
|
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "wmaker");
|
||
|
SendMessage(cbwnd, CB_SETCURSEL, 0, 0);
|
||
|
}
|
||
|
/// @brief Fill protocol box with default values.
|
||
|
/// @param hwndDlg Handle to active page dialog.
|
||
|
void FillProtocolBox(HWND hwndDlg)
|
||
|
{
|
||
|
HWND cbwnd = GetDlgItem(hwndDlg, IDC_CLIENT_PROTOCOL);
|
||
|
if (cbwnd == NULL)
|
||
|
return;
|
||
|
SendMessage(cbwnd, CB_RESETCONTENT, 0, 0);
|
||
|
SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "Putty");
|
||
|
//SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "OpenSSH");
|
||
|
SendMessage(cbwnd, CB_SETCURSEL, 0, 0);
|
||
|
}
|
||
|
void ShowSaveDialog(HWND parent)
|
||
|
{
|
||
|
char szTitle[512];
|
||
|
char szFilter[512];
|
||
|
char szFileTitle[512];
|
||
|
char szFile[MAX_PATH];
|
||
|
HINSTANCE hInst = GetModuleHandle(NULL);
|
||
|
|
||
|
LoadString(hInst, IDS_SAVE_TITLE, szTitle, sizeof(szTitle));
|
||
|
LoadString(hInst, IDS_SAVE_FILETITLE, szFileTitle, sizeof(szFileTitle));
|
||
|
LoadString(hInst, IDS_SAVE_FILTER, szFilter, sizeof(szFilter));
|
||
|
for (unsigned i=0; szFilter[i]; i++)
|
||
|
if (szFilter[i] == '%')
|
||
|
szFilter[i] = '\0';
|
||
|
|
||
|
strcpy(szFile, "config.xlaunch");
|
||
|
|
||
|
OPENFILENAME ofn;
|
||
|
memset(&ofn, 0, sizeof(OPENFILENAME));
|
||
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
||
|
ofn.hwndOwner = parent;
|
||
|
ofn.lpstrFilter = szFilter;
|
||
|
ofn.lpstrFile= szFile;
|
||
|
ofn.nMaxFile = sizeof(szFile)/ sizeof(*szFile);
|
||
|
ofn.lpstrFileTitle = szFileTitle;
|
||
|
ofn.nMaxFileTitle = sizeof(szFileTitle);
|
||
|
ofn.lpstrInitialDir = (LPSTR)NULL;
|
||
|
ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
|
||
|
ofn.lpstrTitle = szTitle;
|
||
|
|
||
|
if (GetSaveFileName(&ofn))
|
||
|
{
|
||
|
try {
|
||
|
config.Save(ofn.lpstrFile);
|
||
|
} catch (std::runtime_error &e)
|
||
|
{
|
||
|
printf("Fehler: %s\n", e.what());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public:
|
||
|
|
||
|
/// @brief Handle messages fo the dialog pages.
|
||
|
/// @param hwndDlg Handle of active dialog.
|
||
|
/// @param uMsg Message code.
|
||
|
/// @param wParam Message parameter.
|
||
|
/// @param lParam Message parameter.
|
||
|
/// @param psp Handle to sheet paramters.
|
||
|
virtual INT_PTR PageDispatch(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, PROPSHEETPAGE *psp)
|
||
|
{
|
||
|
HWND hwnd;
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case WM_INITDIALOG:
|
||
|
switch (PageID(PageIndex(psp)))
|
||
|
{
|
||
|
case IDD_DISPLAY:
|
||
|
// Init display dialog. Enable correct check buttons
|
||
|
switch (config.window)
|
||
|
{
|
||
|
default:
|
||
|
case CConfig::MultiWindow:
|
||
|
CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_MULTIWINDOW);
|
||
|
break;
|
||
|
case CConfig::Fullscreen:
|
||
|
CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_FULLSCREEN);
|
||
|
break;
|
||
|
case CConfig::Windowed:
|
||
|
CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_WINDOWED);
|
||
|
break;
|
||
|
case CConfig::Nodecoration:
|
||
|
CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, IDC_NODECORATION);
|
||
|
break;
|
||
|
}
|
||
|
// Set display number
|
||
|
SetDlgItemText(hwndDlg, IDC_DISPLAY, config.display.c_str());
|
||
|
break;
|
||
|
case IDD_CLIENTS:
|
||
|
// Init client dialog. Enable correct check buttons
|
||
|
switch (config.client)
|
||
|
{
|
||
|
default:
|
||
|
case CConfig::NoClient:
|
||
|
CheckRadioButton(hwndDlg, IDC_CLIENT_NONE, IDC_CLIENT, IDC_CLIENT_NONE);
|
||
|
break;
|
||
|
case CConfig::StartProgram:
|
||
|
CheckRadioButton(hwndDlg, IDC_CLIENT_NONE, IDC_CLIENT, IDC_CLIENT);
|
||
|
break;
|
||
|
case CConfig::XDMCP:
|
||
|
CheckRadioButton(hwndDlg, IDC_CLIENT_NONE, IDC_CLIENT, IDC_XDMCP);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case IDD_PROGRAM:
|
||
|
// Init program dialog. Check local and remote buttons
|
||
|
CheckRadioButton(hwndDlg, IDC_CLIENT_LOCAL, IDC_CLIENT_REMOTE, config.local?IDC_CLIENT_LOCAL:IDC_CLIENT_REMOTE);
|
||
|
EnableRemoteProgramGroup(hwndDlg, config.local?FALSE:TRUE);
|
||
|
// Fill combo boxes
|
||
|
FillProgramBox(hwndDlg);
|
||
|
FillProtocolBox(hwndDlg);
|
||
|
// Set edit fields
|
||
|
if (!config.program.empty())
|
||
|
SetDlgItemText(hwndDlg, IDC_CLIENT_PROGRAM, config.program.c_str());
|
||
|
SetDlgItemText(hwndDlg, IDC_CLIENT_USER, config.user.c_str());
|
||
|
SetDlgItemText(hwndDlg, IDC_CLIENT_HOST, config.host.c_str());
|
||
|
break;
|
||
|
case IDD_XDMCP:
|
||
|
// Init XDMCP dialog. Check broadcast and indirect button
|
||
|
CheckRadioButton(hwndDlg, IDC_XDMCP_QUERY, IDC_XDMCP_BROADCAST, config.broadcast?IDC_XDMCP_BROADCAST:IDC_XDMCP_QUERY);
|
||
|
CheckDlgButton(hwndDlg, IDC_XDMCP_INDIRECT, config.indirect?BST_CHECKED:BST_UNCHECKED);
|
||
|
EnableXDMCPQueryGroup(hwndDlg, config.broadcast?FALSE:TRUE);
|
||
|
// Set hostname
|
||
|
SetDlgItemText(hwndDlg, IDC_XDMCP_HOST, config.xdmcp_host.c_str());
|
||
|
break;
|
||
|
case IDD_CLIPBOARD:
|
||
|
CheckDlgButton(hwndDlg, IDC_CLIPBOARD, config.clipboard?BST_CHECKED:BST_UNCHECKED);
|
||
|
SetDlgItemText(hwndDlg, IDC_EXTRA_PARAMS, config.extra_params.c_str());
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
case WM_COMMAND:
|
||
|
// Handle control messages
|
||
|
switch (LOWORD(wParam))
|
||
|
{
|
||
|
// Handle clicks on images. Check proper radiobutton
|
||
|
case IDC_MULTIWINDOW_IMG:
|
||
|
case IDC_FULLSCREEN_IMG:
|
||
|
case IDC_WINDOWED_IMG:
|
||
|
case IDC_NODECORATION_IMG:
|
||
|
CheckRadioButton(hwndDlg, IDC_MULTIWINDOW, IDC_NODECORATION, LOWORD(wParam)-4);
|
||
|
SetFocus(GetDlgItem(hwndDlg, LOWORD(wParam)-4));
|
||
|
break;
|
||
|
// Disable unavailable controls
|
||
|
case IDC_CLIENT_REMOTE:
|
||
|
case IDC_CLIENT_LOCAL:
|
||
|
EnableRemoteProgramGroup(hwndDlg, LOWORD(wParam) == IDC_CLIENT_REMOTE);
|
||
|
break;
|
||
|
case IDC_XDMCP_QUERY:
|
||
|
case IDC_XDMCP_BROADCAST:
|
||
|
EnableXDMCPQueryGroup(hwndDlg, LOWORD(wParam) == IDC_XDMCP_QUERY);
|
||
|
break;
|
||
|
case IDC_FINISH_SAVE:
|
||
|
ShowSaveDialog(hwndDlg);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// pass messages to parent
|
||
|
return CWizard::PageDispatch(hwndDlg, uMsg, wParam, lParam, psp);
|
||
|
}
|
||
|
|
||
|
/// @brief Try to connect to server.
|
||
|
/// Repeat until successful, server died or maximum number of retries
|
||
|
/// reached.
|
||
|
Display *WaitForServer(HANDLE serverProcess)
|
||
|
{
|
||
|
int ncycles = 120; /* # of cycles to wait */
|
||
|
int cycles; /* Wait cycle count */
|
||
|
Display *xd;
|
||
|
|
||
|
for (cycles = 0; cycles < ncycles; cycles++) {
|
||
|
if ((xd = XOpenDisplay(NULL))) {
|
||
|
return xd;
|
||
|
}
|
||
|
else {
|
||
|
if (WaitForSingleObject(serverProcess, 1000) == WAIT_TIMEOUT)
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/// @brief Do the actual start of Xming and clients
|
||
|
void StartUp()
|
||
|
{
|
||
|
std::string buffer;
|
||
|
std::string client;
|
||
|
|
||
|
// Construct display strings
|
||
|
std::string display_id = ":" + config.display;
|
||
|
std::string display = "localhost" + display_id + ":0";
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
// Debug only: Switch to Xming installation directory
|
||
|
SetCurrentDirectory("C:\\Programme\\Xming");
|
||
|
#endif
|
||
|
|
||
|
// Build Xming commandline
|
||
|
buffer = "Xming " + display_id + " ";
|
||
|
switch (config.window)
|
||
|
{
|
||
|
case CConfig::MultiWindow:
|
||
|
buffer += "-multiwindow ";
|
||
|
break;
|
||
|
case CConfig::Fullscreen:
|
||
|
buffer += "-fullscreen ";
|
||
|
break;
|
||
|
case CConfig::Nodecoration:
|
||
|
buffer += "-nodecoration ";
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
// Add XDMCP parameter
|
||
|
if (config.client == CConfig::XDMCP)
|
||
|
{
|
||
|
if (config.broadcast)
|
||
|
buffer += "-broadcast ";
|
||
|
else
|
||
|
{
|
||
|
if (config.indirect)
|
||
|
buffer += "-indirect ";
|
||
|
else
|
||
|
buffer += "-query ";
|
||
|
buffer += config.xdmcp_host;
|
||
|
buffer += " ";
|
||
|
}
|
||
|
}
|
||
|
if (config.clipboard)
|
||
|
buffer += "-clipboard ";
|
||
|
if (!config.extra_params.empty())
|
||
|
{
|
||
|
buffer += config.extra_params;
|
||
|
buffer += " ";
|
||
|
}
|
||
|
|
||
|
// Construct client commandline
|
||
|
if (config.client == CConfig::StartProgram)
|
||
|
{
|
||
|
if (!config.local)
|
||
|
{
|
||
|
char cmdline[512];
|
||
|
std::string host = config.host;
|
||
|
if (!config.user.empty())
|
||
|
host = config.user + "@" + config.host;
|
||
|
if (config.protocol == "Putty")
|
||
|
snprintf(cmdline,512,"plink -X %s %s",
|
||
|
host.c_str(),config.program.c_str());
|
||
|
else
|
||
|
snprintf(cmdline,512,"ssh -Y %s %s",
|
||
|
host.c_str(),config.program.c_str());
|
||
|
client += cmdline;
|
||
|
} else
|
||
|
client += config.program.c_str();
|
||
|
}
|
||
|
|
||
|
// Prepare program startup
|
||
|
STARTUPINFO si, sic;
|
||
|
PROCESS_INFORMATION pi, pic;
|
||
|
HANDLE handles[2];
|
||
|
DWORD hcount = 0;
|
||
|
Display *dpy = NULL;
|
||
|
|
||
|
ZeroMemory( &si, sizeof(si) );
|
||
|
si.cb = sizeof(si);
|
||
|
ZeroMemory( &pi, sizeof(pi) );
|
||
|
ZeroMemory( &sic, sizeof(sic) );
|
||
|
sic.cb = sizeof(sic);
|
||
|
ZeroMemory( &pic, sizeof(pic) );
|
||
|
|
||
|
// Start Xming process.
|
||
|
#ifdef _DEBUG
|
||
|
printf("%s\n", buffer.c_str());
|
||
|
#endif
|
||
|
if( !CreateProcess( NULL, (CHAR*)buffer.c_str(), NULL, NULL,
|
||
|
FALSE, 0, NULL, NULL, &si, &pi ))
|
||
|
throw win32_error("CreateProcess failed");
|
||
|
handles[hcount++] = pi.hProcess;
|
||
|
|
||
|
if (!client.empty())
|
||
|
{
|
||
|
// Set DISPLAY variable
|
||
|
SetEnvironmentVariable("DISPLAY",display.c_str());
|
||
|
|
||
|
// Wait for server to startup
|
||
|
dpy = WaitForServer(pi.hProcess);
|
||
|
if (dpy == NULL)
|
||
|
{
|
||
|
while (hcount--)
|
||
|
TerminateProcess(handles[hcount], (DWORD)-1);
|
||
|
throw std::runtime_error("Connection to server failed");
|
||
|
}
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
printf("%s\n", client.c_str());
|
||
|
#endif
|
||
|
|
||
|
// Hide a console window
|
||
|
// FIXME: This may make it impossible to enter the password
|
||
|
sic.dwFlags = STARTF_USESHOWWINDOW;
|
||
|
sic.wShowWindow = SW_HIDE;
|
||
|
|
||
|
// Start the child process.
|
||
|
if( !CreateProcess( NULL, (CHAR*)client.c_str(), NULL, NULL,
|
||
|
FALSE, 0, NULL, NULL, &sic, &pic ))
|
||
|
{
|
||
|
DWORD err = GetLastError();
|
||
|
while (hcount--)
|
||
|
TerminateProcess(handles[hcount], (DWORD)-1);
|
||
|
throw win32_error("CreateProcess failed", err);
|
||
|
}
|
||
|
handles[hcount++] = pic.hProcess;
|
||
|
}
|
||
|
|
||
|
// Wait until any child process exits.
|
||
|
DWORD ret = WaitForMultipleObjects(hcount, handles, FALSE, INFINITE );
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
printf("killing process!\n");
|
||
|
#endif
|
||
|
// Check if Xming is still running
|
||
|
DWORD exitcode;
|
||
|
GetExitCodeProcess(pi.hProcess, &exitcode);
|
||
|
unsigned counter = 0;
|
||
|
while (exitcode == STILL_ACTIVE)
|
||
|
{
|
||
|
if (++counter > 10)
|
||
|
TerminateProcess(pi.hProcess, (DWORD)-1);
|
||
|
else
|
||
|
// Shutdown Xming (the soft way!)
|
||
|
EnumThreadWindows(pi.dwThreadId, KillWindowsProc, 0);
|
||
|
Sleep(500);
|
||
|
GetExitCodeProcess(pi.hProcess, &exitcode);
|
||
|
}
|
||
|
// Kill the client
|
||
|
TerminateProcess(pic.hProcess, (DWORD)-1);
|
||
|
|
||
|
// Close process and thread handles.
|
||
|
CloseHandle( pi.hProcess );
|
||
|
CloseHandle( pi.hThread );
|
||
|
CloseHandle( pic.hProcess );
|
||
|
CloseHandle( pic.hThread );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
try {
|
||
|
InitCommonControls();
|
||
|
CMyWizard dialog;
|
||
|
|
||
|
bool skip_wizard = false;
|
||
|
|
||
|
for (int i = 1; i < argc; i++)
|
||
|
{
|
||
|
if (argv[i] == NULL)
|
||
|
continue;
|
||
|
|
||
|
std::string arg(argv[i]);
|
||
|
if (arg == "-load" && i + 1 < argc)
|
||
|
{
|
||
|
i++;
|
||
|
dialog.LoadConfig(argv[i]);
|
||
|
continue;
|
||
|
}
|
||
|
if (arg == "-run" && i + 1 < argc)
|
||
|
{
|
||
|
i++;
|
||
|
dialog.LoadConfig(argv[i]);
|
||
|
skip_wizard = true;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int ret = 0;
|
||
|
if (skip_wizard || (ret =dialog.ShowModal()) != 0)
|
||
|
dialog.StartUp();
|
||
|
#ifdef _DEBUG
|
||
|
printf("return %d\n", ret);
|
||
|
#endif
|
||
|
return 0;
|
||
|
} catch (std::runtime_error &e)
|
||
|
{
|
||
|
printf("Fehler: %s\n", e.what());
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|