aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xwin/xlaunch/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xwin/xlaunch/main.cc')
-rw-r--r--xorg-server/hw/xwin/xlaunch/main.cc811
1 files changed, 811 insertions, 0 deletions
diff --git a/xorg-server/hw/xwin/xlaunch/main.cc b/xorg-server/hw/xwin/xlaunch/main.cc
new file mode 100644
index 000000000..1bdcf6ae3
--- /dev/null
+++ b/xorg-server/hw/xwin/xlaunch/main.cc
@@ -0,0 +1,811 @@
+/*
+ * 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>
+
+#include <stdlib.h>
+#include <sstream>
+
+/// @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_EXTRA, IDS_EXTRA_TITLE, IDS_EXTRA_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)
+ {
+ char Message[255];
+ sprintf(Message,"Failure: %s\n", e.what());
+ MessageBox(NULL,Message,"Exception",MB_OK);
+ }
+ }
+
+ /// @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())
+ {
+ MessageBox(hwndDlg,"Please fill in a display number.","Error",MB_OK);
+ 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_EXTRA);
+ } 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.localprogram = buffer;
+ GetDlgItemText(hwndDlg, IDC_CLIENT_REMOTEPROGRAM, buffer, 512);
+ buffer[511] = 0;
+ config.remoteprogram = buffer;
+ GetDlgItemText(hwndDlg, IDC_CLIENT_PASSWORD, buffer, 512);
+ buffer[511] = 0;
+ config.remotepassword = buffer;
+ }
+ // Check for valid input
+ if (!config.local && (config.host.empty() || config.localprogram.empty() || config.remoteprogram.empty()))
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ else
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_EXTRA);
+ 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_EXTRA);
+ if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP_TERMINATE))
+ config.xdmcpterminate = true;
+ else
+ config.xdmcpterminate = false;
+ return TRUE;
+ case IDD_EXTRA:
+ // check for clipboard
+ if (IsDlgButtonChecked(hwndDlg, IDC_CLIPBOARD))
+ config.clipboard = true;
+ else
+ config.clipboard = false;
+ // check for clipboard primary selection
+ if (IsDlgButtonChecked(hwndDlg, IDC_CLIPBOARDPRIMARY))
+ config.clipboardprimary = true;
+ else
+ config.clipboardprimary = false;
+ // check for wgl
+ if (IsDlgButtonChecked(hwndDlg, IDC_WGL))
+ config.wgl = true;
+ else
+ config.wgl = false;
+ // check for access control
+ if (IsDlgButtonChecked(hwndDlg, IDC_DISABLEAC))
+ config.disableac = true;
+ else
+ config.disableac = 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_EXTRA: // 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
+ if (config.window != CConfig::MultiWindow)
+ {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP), true);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_DESC), true);
+ }
+ else
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_XDMCP))
+ CheckRadioButton(hwndDlg, IDC_CLIENT_NONE, IDC_CLIENT, IDC_CLIENT_NONE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP), false);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_XDMCP_DESC), false);
+ }
+ 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_PASSWORD), state);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_HOST), state);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_USER), state);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_PASSWORD_DESC), state);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_HOST_DESC), state);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_USER_DESC), state);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_REMOTEPROGRAM), state);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_REMOTEPROGRAM_DESC), state);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_PROGRAM), !state);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CLIENT_PROGRAM_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) "xcalc");
+ SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "xclock");
+ SendMessage(cbwnd, CB_ADDSTRING, 0, (LPARAM) "xwininfo");
+ 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)
+ {
+ char Message[255];
+ sprintf(Message,"Failure: %s\n", e.what());
+ MessageBox(NULL,Message,"Exception",MB_OK);
+ }
+ }
+ }
+ 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);
+ // Set edit fields
+ if (!config.localprogram.empty())
+ SetDlgItemText(hwndDlg, IDC_CLIENT_PROGRAM, config.localprogram.c_str());
+ if (!config.remoteprogram.empty())
+ SetDlgItemText(hwndDlg, IDC_CLIENT_REMOTEPROGRAM, config.remoteprogram.c_str());
+ SetDlgItemText(hwndDlg, IDC_CLIENT_USER, config.user.c_str());
+ SetDlgItemText(hwndDlg, IDC_CLIENT_HOST, config.host.c_str());
+ SetDlgItemText(hwndDlg, IDC_CLIENT_PASSWORD, config.remotepassword.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());
+ CheckDlgButton(hwndDlg, IDC_XDMCP_TERMINATE, config.xdmcpterminate?BST_CHECKED:BST_UNCHECKED);
+ break;
+ case IDD_EXTRA:
+ CheckDlgButton(hwndDlg, IDC_CLIPBOARD, config.clipboard?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CLIPBOARDPRIMARY, config.clipboardprimary?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_WGL, config.wgl?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DISABLEAC, config.disableac?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 VCXsrv and clients
+ void StartUp()
+ {
+ std::string buffer;
+ std::string client;
+
+ // Construct display strings
+ int DisplayNbr=atoi(config.display.c_str());
+ std::string display_id = ":" + config.display;
+ std::string display = "DISPLAY=127.0.0.1" + display_id + ".0";
+
+ // Build Xsrv commandline
+ buffer = "vcxsrv ";
+ if (DisplayNbr!=-1)
+ buffer += 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.xdmcpterminate)
+ buffer += "-terminate ";
+ }
+ if (config.clipboard)
+ buffer += "-clipboard ";
+ if (!config.clipboardprimary)
+ buffer += "-noclipboardprimary ";
+ if (config.wgl)
+ buffer += "-wgl ";
+ if (config.disableac)
+ buffer += "-ac ";
+ if (!config.extra_params.empty())
+ {
+ buffer += config.extra_params;
+ buffer += " ";
+ }
+
+ int *pDisplayfd;
+ if (DisplayNbr==-1)
+ {
+ // Pass the handle of some shared memory to vcxsrv to getting back the display nbr
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength=sizeof(sa);
+ sa.lpSecurityDescriptor=NULL;
+ sa.bInheritHandle=TRUE;
+ HANDLE hDisplayFdMem=CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, sizeof(int), NULL);
+ pDisplayfd=(int*)MapViewOfFile(hDisplayFdMem, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 0);
+ *pDisplayfd=-1; // Not yet initialised
+ buffer+="-displayfd ";
+ std::stringstream ss;
+ ss<<(int)hDisplayFdMem;
+ buffer+=ss.str();
+ }
+ // Construct client commandline
+ if (config.client == CConfig::StartProgram)
+ {
+ if (!config.local)
+ {
+ char cmdline[512];
+ std::string host = config.host;
+ std::string remotepassword;
+ if (!config.user.empty())
+ host = config.user + "@" + config.host;
+ if (!config.remotepassword.empty())
+ remotepassword=std::string(" -pw ")+config.remotepassword;
+ // Need to use -console since certain commands will not execute when no console
+ _snprintf(cmdline,512,"plink -console -ssh -X%s %s %s",
+ remotepassword.c_str(), host.c_str(),config.remoteprogram.c_str());
+ client += cmdline;
+ }
+ else
+ {
+ client += config.localprogram.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 VCXsrv process.
+#ifdef _DEBUG
+ printf("%s\n", buffer.c_str());
+#endif
+ char CurDir[MAX_PATH];
+ GetModuleFileName(NULL,CurDir,MAX_PATH);
+ *strrchr(CurDir,'\\')=0;
+
+ if( !CreateProcess( NULL, (CHAR*)buffer.c_str(), NULL, NULL,
+ TRUE, 0, NULL, CurDir, &si, &pi ))
+ throw win32_error("CreateProcess failed");
+ handles[hcount++] = pi.hProcess;
+
+ if (!client.empty())
+ {
+ if (DisplayNbr==-1)
+ {
+ // Wait maximum 10 seconds
+ int Count=1000;
+ while (-1==*pDisplayfd)
+ {
+ if (Count-- < 0)
+ throw std::runtime_error("Connection to server failed");
+ Sleep(10);
+ }
+ std::stringstream ss;
+ ss<<*pDisplayfd;
+ display_id = ":" + ss.str();
+ display = "DISPLAY=127.0.0.1" + display_id + ".0";
+ }
+ // Set DISPLAY variable
+ _putenv(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.
+
+ // Create a console, otherwise some commands will not execute with plink
+ #ifdef WITH_FLASH
+ AllocConsole();
+ #else
+ HWINSTA h=GetProcessWindowStation();
+ HWINSTA horig=h;
+ if (h)
+ {
+ h=CreateWindowStationW(NULL, 0, STANDARD_RIGHTS_READ, NULL);
+ if (h)
+ SetProcessWindowStation(h);
+ AllocConsole();
+ SetProcessWindowStation(horig);
+ CloseWindowStation(h);
+ }
+ #endif
+
+ if( !CreateProcess( NULL, (CHAR*)client.c_str(), NULL, NULL,
+ FALSE, 0, NULL, CurDir, &sic, &pic ))
+ {
+ DWORD err = GetLastError();
+ while (hcount--)
+ TerminateProcess(handles[hcount], (DWORD)-1);
+ throw win32_error("CreateProcess failed", err);
+ }
+ handles[hcount++] = pic.hProcess;
+ #ifdef WITHFLASH
+ ShowWindow( GetConsoleWindow(), SW_HIDE ); // make it hidden
+ #endif
+ }
+
+ // Wait until any child process exits.
+ DWORD ret = WaitForMultipleObjects(hcount, handles, FALSE, INFINITE );
+
+#ifdef _DEBUG
+ printf("killing process!\n");
+#endif
+ // Check if Xsrv is still running, but only when we started a local program
+ if (config.local)
+ {
+ DWORD exitcode;
+ GetExitCodeProcess(pi.hProcess, &exitcode);
+ unsigned counter = 0;
+ while (exitcode == STILL_ACTIVE)
+ {
+ if (++counter > 10)
+ TerminateProcess(pi.hProcess, (DWORD)-1);
+ else
+ // Shutdown Xsrv (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)
+ {
+ char Message[255];
+ sprintf(Message,"Failure: %s\n", e.what());
+ MessageBox(NULL,Message,"Exception",MB_OK);
+ return -1;
+ }
+}
+
+
+
+