#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>
BOOL CALLBACK KillWindowsProc(HWND hwnd, LPARAM lParam)
{
SendMessage(hwnd, WM_ENDSESSION, 0, 0);
return TRUE;
}
class CMyWizard : public CWizard
{
public:
private:
CConfig config; public:
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_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());
}
}
virtual BOOL WizardNext(HWND hwndDlg, unsigned index)
{
#ifdef _DEBUG
printf("%s %d\n", __FUNCTION__, index);
#endif
switch (PageID(index))
{
case IDD_DISPLAY:
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;
}
{
char buffer[512];
GetDlgItemText(hwndDlg, IDC_DISPLAY, buffer, 512);
buffer[511] = 0;
config.display = buffer;
}
if (config.display.empty())
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
else
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIENTS);
return TRUE;
case IDD_CLIENTS:
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:
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;
}
{
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;
}
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:
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;
}
if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP_INDIRECT))
config.indirect = true;
else
config.indirect = false;
{
char buffer[512];
GetDlgItemText(hwndDlg, IDC_XDMCP_HOST, buffer, 512);
buffer[511] = 0;
config.xdmcp_host = buffer;
}
if (!config.broadcast && config.xdmcp_host.empty())
SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
else
SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_CLIPBOARD);
return TRUE;
case IDD_CLIPBOARD:
if (IsDlgButtonChecked(hwndDlg, IDC_CLIPBOARD))
config.clipboard = true;
else
config.clipboard = false;
{
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;
}
virtual BOOL WizardFinish(HWND hwndDlg, unsigned index)
{
#ifdef _DEBUG
printf("finish %d\n", index);
#endif
return FALSE;
}
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: 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;
}
virtual BOOL WizardActivate(HWND hwndDlg, unsigned index)
{
#ifdef _DEBUG
printf("%s %d\n", __FUNCTION__, index);
#endif
switch (PageID(index))
{
case IDD_CLIENTS:
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP), config.window != CConfig::MultiWindow);
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_DESC), config.window != CConfig::MultiWindow);
break;
}
return FALSE;
}
protected:
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);
}
void EnableXDMCPQueryGroup(HWND hwndDlg, BOOL state)
{
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_HOST), state);
EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_INDIRECT), state);
}
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);
}
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_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:
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:
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;
}
SetDlgItemText(hwndDlg, IDC_DISPLAY, config.display.c_str());
break;
case IDD_CLIENTS:
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:
CheckRadioButton(hwndDlg, IDC_CLIENT_LOCAL, IDC_CLIENT_REMOTE, config.local?IDC_CLIENT_LOCAL:IDC_CLIENT_REMOTE);
EnableRemoteProgramGroup(hwndDlg, config.local?FALSE:TRUE);
FillProgramBox(hwndDlg);
FillProtocolBox(hwndDlg);
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:
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);
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:
switch (LOWORD(wParam))
{
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;
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;
}
}
return CWizard::PageDispatch(hwndDlg, uMsg, wParam, lParam, psp);
}
Display *WaitForServer(HANDLE serverProcess)
{
int ncycles = 120;
int cycles;
Display *xd;
for (cycles = 0; cycles < ncycles; cycles++) {
if ((xd = XOpenDisplay(NULL))) {
return xd;
}
else {
if (WaitForSingleObject(serverProcess, 1000) == WAIT_TIMEOUT)
continue;
}
}
return NULL;
}
void StartUp()
{
std::string buffer;
std::string client;
std::string display_id = ":" + config.display;
std::string display = "localhost" + display_id + ":0";
#ifdef _DEBUG
SetCurrentDirectory("C:\\Programme\\Xming");
#endif
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;
}
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 += " ";
}
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();
}
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) );
#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())
{
SetEnvironmentVariable("DISPLAY",display.c_str());
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
sic.dwFlags = STARTF_USESHOWWINDOW;
sic.wShowWindow = SW_HIDE;
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;
}
DWORD ret = WaitForMultipleObjects(hcount, handles, FALSE, INFINITE );
#ifdef _DEBUG
printf("killing process!\n");
#endif
DWORD exitcode;
GetExitCodeProcess(pi.hProcess, &exitcode);
unsigned counter = 0;
while (exitcode == STILL_ACTIVE)
{
if (++counter > 10)
TerminateProcess(pi.hProcess, (DWORD)-1);
else
EnumThreadWindows(pi.dwThreadId, KillWindowsProc, 0);
Sleep(500);
GetExitCodeProcess(pi.hProcess, &exitcode);
}
TerminateProcess(pic.hProcess, (DWORD)-1);
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;
}
}